diff --git a/source/Build b/source/Build
index 411e1d7bee84be5ed8eeb30c9acfd1adb163c780..a2fee663fd3d25665eeccf3ba975030ed96ae8a1 100755
--- a/source/Build
+++ b/source/Build
@@ -1,5 +1,5 @@
 #!/bin/sh
-# $Id: Build 40051 2016-03-17 01:20:14Z mojca $
+# $Id: Build 46257 2018-01-09 18:53:05Z karl $
 # Public domain.  Originally written many years ago by Sebastian Rahtz.
 # The basic idea is to run configure && make, but with a multitude of
 # environment variables to allow overriding everything.
@@ -61,10 +61,12 @@ if test "x$1" = x--debug || test "x$1" = x-g; then
   # The idea is that with Build -g, you can set TL_COMPILER_GFLAGS in
   # the environment with options common to all compilers --
   # not necessarily anything to do with debugging, e.g., -mcpu=sparvc9.
+  # Or you can set TL_{C,CXX,OBJCXX}FLAGS for per-language flags,
+  # notably TL_CFLAGS=-Wdeclaration-after-statement.
   : ${TL_COMPILER_GFLAGS=-g}
-  c="CFLAGS='$TL_COMPILER_GFLAGS'"
-  cxx="CXXFLAGS='$TL_COMPILER_GFLAGS'"
-  objcxx="OBJCXXFLAGS='$TL_COMPILER_GFLAGS'"  # needed only on macs
+  c="CFLAGS='$TL_COMPILER_GFLAGS $TL_CFLAGS'"
+  cxx="CXXFLAGS='$TL_COMPILER_GFLAGS $TL_CXXFLAGS'"
+  objcxx="OBJCXXFLAGS='$TL_COMPILER_GFLAGS $TL_OBJCXXFLAGS'" # only for macs
   TL_BUILD_ENV="$c $cxx $objcxx $TL_BUILD_ENV"
 fi
 
diff --git a/source/README b/source/README
index dc12619a81117aadb2e95f706e6fce79a570d883..6552bd172631e307ad94f99cf0c3c14da3e8b3cb 100644
--- a/source/README
+++ b/source/README
@@ -1,4 +1,4 @@
-$Id: README 44143 2017-05-01 21:58:19Z karl $
+$Id: README 46228 2018-01-05 23:02:24Z karl $
 Public domain.  Originally written 2005 by Karl Berry.
 
 For a high-level overview of building TeX Live, see
@@ -26,8 +26,13 @@ that document).
 
 Build information for some of the platforms.
 
-x86_64-linux: Debian 6.0 (Squeeze), Feb 2009.
-  
+aarch64-linux:
+  aarch64 Debian GNU/Linux 9 (stretch)
+  gcc (Debian 6.3.0-18) 6.3.0 20170516
+  ./Build --enable-xindy --without-x --enable-arm-neon=check
+    with the libpng-1.6.34 source directory copied over from SVN -r45971
+    (where it has been reconfigured to expose --enable-arm-neon)
+
 amd64-netbsd:
   gcc version 4.5.3 (NetBSD nb2 20110806)
   NetBSD/amd64 6.1.3
@@ -69,3 +74,5 @@ x86_64-darwinlegacy, i386-darwin, powerpc-darwin:
   x86_64 binaries only work on >= 10.6 (and should work on any >= 10.6 machine)
     but will only be used for < 10.10 since x86_64-darwin covers newer.
   PPC binaries made with gcc-4.2 and Intel binaries with clang-3.7.
+
+x86_64-linux: Debian 6.0 (Squeeze), Feb 2009.
diff --git a/source/build-aux/compile b/source/build-aux/compile
index f8e99f0fb6f111ab6cc6a48cff9ecd1b605c03f1..0bb9d0f53abe465ae27679ef9d40ddbff6d0aea6 100644
--- a/source/build-aux/compile
+++ b/source/build-aux/compile
@@ -3,7 +3,7 @@
 
 scriptversion=2017-09-16.17; # UTC
 
-# Copyright (C) 1999-2017 Free Software Foundation, Inc.
+# Copyright (C) 1999-2018 Free Software Foundation, Inc.
 # Written by Tom Tromey <tromey@cygnus.com>.
 #
 # This program is free software; you can redistribute it and/or modify
diff --git a/source/build-aux/depcomp b/source/build-aux/depcomp
index 5ff3c6feb4ba8c9cacfae53687d24683becc3d34..49eb4bff6e0e5359969b29b81209d90d84eb13dc 100755
--- a/source/build-aux/depcomp
+++ b/source/build-aux/depcomp
@@ -3,7 +3,7 @@
 
 scriptversion=2017-09-16.17; # UTC
 
-# Copyright (C) 1999-2017 Free Software Foundation, Inc.
+# Copyright (C) 1999-2018 Free Software Foundation, Inc.
 
 # 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
diff --git a/source/libs/README b/source/libs/README
index 564132aae195319e3a4f274377169fde0c0d210b..d22b9c9d16ef120d22b46ab37da7db4cd8114d99 100644
--- a/source/libs/README
+++ b/source/libs/README
@@ -1,4 +1,4 @@
-$Id: README 46140 2017-12-26 11:50:03Z kakuto $
+$Id: README 46257 2018-01-09 18:53:05Z karl $
 Public domain.  Originally created by Karl Berry, 2005.
 
 Libraries we compile for TeX Live.
@@ -12,7 +12,7 @@ See also comments in ../texk/README.
 cairo 1.14.12 - checked 07dec17
   http://cairographics.org/releases/
 
-freetype2 2.8.1 - checked 16sep17
+freetype2 2.9.0 - checked 09jan18
   http://savannah.nongnu.org/download/freetype/
 
 gd 2.2.5 - checked 30aug17
@@ -49,8 +49,9 @@ mpfr 4.0.0 - checked 26dec17
 pixman 0.34.0 - checked 04feb16
   http://cairographics.org/releases/
 
-poppler 0.52.0 - checked 17feb17
+poppler 0.62.0 - checked 9jan18
   http://poppler.freedesktop.org/ - used by luatex and xetex
+  (requires C++11)
 
 potrace 1.15 - checked 07aug17
   http://potrace.sourceforge.net
diff --git a/source/libs/poppler/ChangeLog b/source/libs/poppler/ChangeLog
index 0fbe8ab9942060f6fdfd824e5e6d7c54ec09da07..02dd81b55b52efb6fcd9bd05ffe719ba08be67dc 100644
--- a/source/libs/poppler/ChangeLog
+++ b/source/libs/poppler/ChangeLog
@@ -1,28 +1,3 @@
-2018-01-06  Luigi Scarso  <luigi.scarso@gmail.com>
-
-	Import poppler-0.62.0.
-	* version.ac: Adjusted.
-	* manually created poppler-config.h.in from poppler-config.h.cmake
-	* deleted useless files from splash folder
-	* deleted goo/glibc_strtok_r.cc
-
-
-2017-11-26  Luigi Scarso  <luigi.scarso@gmail.com>
-
-	Import poppler-0.60.1.
-	* version.ac: Adjust.
-	* manually created poppler-config.h.in from poppler-config.h.cmake
-	* deleted useless files from splash folder
-	* deleted goo/glibc_strtok_r.cc
-
-2017-10-04  Luigi Scarso  <luigi.scarso@gmail.com>
-
-	Import poppler-0.60.0.
-	* version.ac: Adjust.
-	* manually created poppler-config.h.in from poppler-config.h.cmake
-	* deleted useless files from splash folder
-
-
 2017-02-17  Akira Kakuto  <kakuto@fuk.kindai.ac.jp>
 
 	Import poppler-0.52.0.
diff --git a/source/libs/poppler/Makefile.am b/source/libs/poppler/Makefile.am
index c145329ee89726459418b5bf1850eb92ee8960fb..12fedeed21cb42eb5c320599b114b3f9fd14752f 100644
--- a/source/libs/poppler/Makefile.am
+++ b/source/libs/poppler/Makefile.am
@@ -1,7 +1,7 @@
-## $Id: Makefile.am 43567 2017-03-21 17:43:10Z karl $
+## $Id: Makefile.am 46257 2018-01-09 18:53:05Z karl $
 ## Proxy Makefile.am to build poppler for TeX Live.
 ##
-##   Copyright 2016-2017 Karl Berry <tex-live@tug.org>
+##   Copyright 2016-2018 Karl Berry <tex-live@tug.org>
 ##   Copyright 2011-2015 Peter Breitenlohner <tex-live@tug.org>
 ##
 ##   This file is free software; the copyright holder
@@ -41,22 +41,17 @@ nodist_libpoppler_a_SOURCES = \
 	$(poppler_libpoppler_a_sources)
 
 goo_libGoo_a_sources = \
-	@POPPLER_TREE@/goo/FixedPoint.cc \
-	@POPPLER_TREE@/goo/GooHash.cc \
-	@POPPLER_TREE@/goo/GooList.cc \
-	@POPPLER_TREE@/goo/GooString.cc \
-	@POPPLER_TREE@/goo/GooTimer.cc \
-	@POPPLER_TREE@/goo/ImgWriter.cc \
-	@POPPLER_TREE@/goo/JpegWriter.cc \
-	@POPPLER_TREE@/goo/NetPBMWriter.cc \
-	@POPPLER_TREE@/goo/PNGWriter.cc \
-	@POPPLER_TREE@/goo/TiffWriter.cc \
 	@POPPLER_TREE@/goo/gfile.cc \
 	@POPPLER_TREE@/goo/glibc.cc \
 	@POPPLER_TREE@/goo/gmem.cc \
 	@POPPLER_TREE@/goo/gmempp.cc \
 	@POPPLER_TREE@/goo/grandom.cc \
-	@POPPLER_TREE@/goo/gstrtod.cc 
+	@POPPLER_TREE@/goo/gstrtod.cc \
+	@POPPLER_TREE@/goo/FixedPoint.cc \
+	@POPPLER_TREE@/goo/GooHash.cc \
+	@POPPLER_TREE@/goo/GooList.cc \
+	@POPPLER_TREE@/goo/GooString.cc \
+	@POPPLER_TREE@/goo/GooTimer.cc
 
 fofi_libfofi_a_sources = \
 	@POPPLER_TREE@/fofi/FoFiBase.cc \
@@ -64,7 +59,9 @@ fofi_libfofi_a_sources = \
 	@POPPLER_TREE@/fofi/FoFiIdentifier.cc \
 	@POPPLER_TREE@/fofi/FoFiTrueType.cc \
 	@POPPLER_TREE@/fofi/FoFiType1.cc \
-	@POPPLER_TREE@/fofi/FoFiType1C.cc 
+	@POPPLER_TREE@/fofi/FoFiType1C.cc
+
+
 
 poppler_libpoppler_a_sources = \
 	@POPPLER_TREE@/poppler/Annot.cc \
@@ -80,7 +77,6 @@ poppler_libpoppler_a_sources = \
 	@POPPLER_TREE@/poppler/Dict.cc \
 	@POPPLER_TREE@/poppler/Error.cc \
 	@POPPLER_TREE@/poppler/FileSpec.cc \
-	@POPPLER_TREE@/poppler/FlateEncoder.cc \
 	@POPPLER_TREE@/poppler/FlateStream.cc \
 	@POPPLER_TREE@/poppler/FontEncodingTables.cc \
 	@POPPLER_TREE@/poppler/FontInfo.cc \
@@ -97,7 +93,6 @@ poppler_libpoppler_a_sources = \
 	@POPPLER_TREE@/poppler/Lexer.cc \
 	@POPPLER_TREE@/poppler/Linearization.cc \
 	@POPPLER_TREE@/poppler/Link.cc \
-	@POPPLER_TREE@/poppler/LocalPDFDocBuilder.cc \
 	@POPPLER_TREE@/poppler/MarkedContentOutputDev.cc \
 	@POPPLER_TREE@/poppler/Movie.cc \
 	@POPPLER_TREE@/poppler/NameToCharCode.cc \
@@ -108,7 +103,6 @@ poppler_libpoppler_a_sources = \
 	@POPPLER_TREE@/poppler/PDFDoc.cc \
 	@POPPLER_TREE@/poppler/PDFDocEncoding.cc \
 	@POPPLER_TREE@/poppler/PDFDocFactory.cc \
-	@POPPLER_TREE@/poppler/PSOutputDev.cc \
 	@POPPLER_TREE@/poppler/PSTokenizer.cc \
 	@POPPLER_TREE@/poppler/Page.cc \
 	@POPPLER_TREE@/poppler/PageLabelInfo.cc \
@@ -131,7 +125,7 @@ poppler_libpoppler_a_sources = \
 	@POPPLER_TREE@/poppler/UnicodeTypeTable.cc \
 	@POPPLER_TREE@/poppler/ViewerPreferences.cc \
 	@POPPLER_TREE@/poppler/XRef.cc \
-	@POPPLER_TREE@/poppler/XpdfPluginAPI.cc 
+	@POPPLER_TREE@/poppler/XpdfPluginAPI.cc
 
 $(libpoppler_a_OBJECTS): config.force
 
diff --git a/source/libs/poppler/Makefile.in b/source/libs/poppler/Makefile.in
index ebb0426b2acc5b7499a28b93f08493f4179b7a25..ce07c4d3d8c14df42f426e523f7447c554ea1677 100644
--- a/source/libs/poppler/Makefile.in
+++ b/source/libs/poppler/Makefile.in
@@ -88,7 +88,8 @@ PRE_UNINSTALL = :
 POST_UNINSTALL = :
 subdir = .
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/../../m4/kpse-common.m4 \
+am__aclocal_m4_deps = $(top_srcdir)/../../m4/ax_cxx_compile_stdcxx.m4 \
+	$(top_srcdir)/../../m4/kpse-common.m4 \
 	$(top_srcdir)/../../m4/kpse-visibility.m4 \
 	$(top_srcdir)/../../m4/kpse-warnings.m4 \
 	$(top_srcdir)/../../m4/kpse-win32.m4 \
@@ -114,22 +115,17 @@ am__v_AR_1 =
 libpoppler_a_AR = $(AR) $(ARFLAGS)
 libpoppler_a_LIBADD =
 am__dirstamp = $(am__leading_dot)dirstamp
-am__objects_1 = @POPPLER_TREE@/goo/FixedPoint.$(OBJEXT) \
-	@POPPLER_TREE@/goo/GooHash.$(OBJEXT) \
-	@POPPLER_TREE@/goo/GooList.$(OBJEXT) \
-	@POPPLER_TREE@/goo/GooString.$(OBJEXT) \
-	@POPPLER_TREE@/goo/GooTimer.$(OBJEXT) \
-	@POPPLER_TREE@/goo/ImgWriter.$(OBJEXT) \
-	@POPPLER_TREE@/goo/JpegWriter.$(OBJEXT) \
-	@POPPLER_TREE@/goo/NetPBMWriter.$(OBJEXT) \
-	@POPPLER_TREE@/goo/PNGWriter.$(OBJEXT) \
-	@POPPLER_TREE@/goo/TiffWriter.$(OBJEXT) \
-	@POPPLER_TREE@/goo/gfile.$(OBJEXT) \
+am__objects_1 = @POPPLER_TREE@/goo/gfile.$(OBJEXT) \
 	@POPPLER_TREE@/goo/glibc.$(OBJEXT) \
 	@POPPLER_TREE@/goo/gmem.$(OBJEXT) \
 	@POPPLER_TREE@/goo/gmempp.$(OBJEXT) \
 	@POPPLER_TREE@/goo/grandom.$(OBJEXT) \
-	@POPPLER_TREE@/goo/gstrtod.$(OBJEXT)
+	@POPPLER_TREE@/goo/gstrtod.$(OBJEXT) \
+	@POPPLER_TREE@/goo/FixedPoint.$(OBJEXT) \
+	@POPPLER_TREE@/goo/GooHash.$(OBJEXT) \
+	@POPPLER_TREE@/goo/GooList.$(OBJEXT) \
+	@POPPLER_TREE@/goo/GooString.$(OBJEXT) \
+	@POPPLER_TREE@/goo/GooTimer.$(OBJEXT)
 am__objects_2 = @POPPLER_TREE@/fofi/FoFiBase.$(OBJEXT) \
 	@POPPLER_TREE@/fofi/FoFiEncodings.$(OBJEXT) \
 	@POPPLER_TREE@/fofi/FoFiIdentifier.$(OBJEXT) \
@@ -149,7 +145,6 @@ am__objects_3 = @POPPLER_TREE@/poppler/Annot.$(OBJEXT) \
 	@POPPLER_TREE@/poppler/Dict.$(OBJEXT) \
 	@POPPLER_TREE@/poppler/Error.$(OBJEXT) \
 	@POPPLER_TREE@/poppler/FileSpec.$(OBJEXT) \
-	@POPPLER_TREE@/poppler/FlateEncoder.$(OBJEXT) \
 	@POPPLER_TREE@/poppler/FlateStream.$(OBJEXT) \
 	@POPPLER_TREE@/poppler/FontEncodingTables.$(OBJEXT) \
 	@POPPLER_TREE@/poppler/FontInfo.$(OBJEXT) \
@@ -166,7 +161,6 @@ am__objects_3 = @POPPLER_TREE@/poppler/Annot.$(OBJEXT) \
 	@POPPLER_TREE@/poppler/Lexer.$(OBJEXT) \
 	@POPPLER_TREE@/poppler/Linearization.$(OBJEXT) \
 	@POPPLER_TREE@/poppler/Link.$(OBJEXT) \
-	@POPPLER_TREE@/poppler/LocalPDFDocBuilder.$(OBJEXT) \
 	@POPPLER_TREE@/poppler/MarkedContentOutputDev.$(OBJEXT) \
 	@POPPLER_TREE@/poppler/Movie.$(OBJEXT) \
 	@POPPLER_TREE@/poppler/NameToCharCode.$(OBJEXT) \
@@ -177,7 +171,6 @@ am__objects_3 = @POPPLER_TREE@/poppler/Annot.$(OBJEXT) \
 	@POPPLER_TREE@/poppler/PDFDoc.$(OBJEXT) \
 	@POPPLER_TREE@/poppler/PDFDocEncoding.$(OBJEXT) \
 	@POPPLER_TREE@/poppler/PDFDocFactory.$(OBJEXT) \
-	@POPPLER_TREE@/poppler/PSOutputDev.$(OBJEXT) \
 	@POPPLER_TREE@/poppler/PSTokenizer.$(OBJEXT) \
 	@POPPLER_TREE@/poppler/Page.$(OBJEXT) \
 	@POPPLER_TREE@/poppler/PageLabelInfo.$(OBJEXT) \
@@ -357,6 +350,7 @@ ECHO_T = @ECHO_T@
 EGREP = @EGREP@
 EXEEXT = @EXEEXT@
 GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
 INSTALL = @INSTALL@
 INSTALL_DATA = @INSTALL_DATA@
 INSTALL_PROGRAM = @INSTALL_PROGRAM@
@@ -459,22 +453,17 @@ nodist_libpoppler_a_SOURCES = \
 	$(poppler_libpoppler_a_sources)
 
 goo_libGoo_a_sources = \
-	@POPPLER_TREE@/goo/FixedPoint.cc \
-	@POPPLER_TREE@/goo/GooHash.cc \
-	@POPPLER_TREE@/goo/GooList.cc \
-	@POPPLER_TREE@/goo/GooString.cc \
-	@POPPLER_TREE@/goo/GooTimer.cc \
-	@POPPLER_TREE@/goo/ImgWriter.cc \
-	@POPPLER_TREE@/goo/JpegWriter.cc \
-	@POPPLER_TREE@/goo/NetPBMWriter.cc \
-	@POPPLER_TREE@/goo/PNGWriter.cc \
-	@POPPLER_TREE@/goo/TiffWriter.cc \
 	@POPPLER_TREE@/goo/gfile.cc \
 	@POPPLER_TREE@/goo/glibc.cc \
 	@POPPLER_TREE@/goo/gmem.cc \
 	@POPPLER_TREE@/goo/gmempp.cc \
 	@POPPLER_TREE@/goo/grandom.cc \
-	@POPPLER_TREE@/goo/gstrtod.cc 
+	@POPPLER_TREE@/goo/gstrtod.cc \
+	@POPPLER_TREE@/goo/FixedPoint.cc \
+	@POPPLER_TREE@/goo/GooHash.cc \
+	@POPPLER_TREE@/goo/GooList.cc \
+	@POPPLER_TREE@/goo/GooString.cc \
+	@POPPLER_TREE@/goo/GooTimer.cc
 
 fofi_libfofi_a_sources = \
 	@POPPLER_TREE@/fofi/FoFiBase.cc \
@@ -482,7 +471,7 @@ fofi_libfofi_a_sources = \
 	@POPPLER_TREE@/fofi/FoFiIdentifier.cc \
 	@POPPLER_TREE@/fofi/FoFiTrueType.cc \
 	@POPPLER_TREE@/fofi/FoFiType1.cc \
-	@POPPLER_TREE@/fofi/FoFiType1C.cc 
+	@POPPLER_TREE@/fofi/FoFiType1C.cc
 
 poppler_libpoppler_a_sources = \
 	@POPPLER_TREE@/poppler/Annot.cc \
@@ -498,7 +487,6 @@ poppler_libpoppler_a_sources = \
 	@POPPLER_TREE@/poppler/Dict.cc \
 	@POPPLER_TREE@/poppler/Error.cc \
 	@POPPLER_TREE@/poppler/FileSpec.cc \
-	@POPPLER_TREE@/poppler/FlateEncoder.cc \
 	@POPPLER_TREE@/poppler/FlateStream.cc \
 	@POPPLER_TREE@/poppler/FontEncodingTables.cc \
 	@POPPLER_TREE@/poppler/FontInfo.cc \
@@ -515,7 +503,6 @@ poppler_libpoppler_a_sources = \
 	@POPPLER_TREE@/poppler/Lexer.cc \
 	@POPPLER_TREE@/poppler/Linearization.cc \
 	@POPPLER_TREE@/poppler/Link.cc \
-	@POPPLER_TREE@/poppler/LocalPDFDocBuilder.cc \
 	@POPPLER_TREE@/poppler/MarkedContentOutputDev.cc \
 	@POPPLER_TREE@/poppler/Movie.cc \
 	@POPPLER_TREE@/poppler/NameToCharCode.cc \
@@ -526,7 +513,6 @@ poppler_libpoppler_a_sources = \
 	@POPPLER_TREE@/poppler/PDFDoc.cc \
 	@POPPLER_TREE@/poppler/PDFDocEncoding.cc \
 	@POPPLER_TREE@/poppler/PDFDocFactory.cc \
-	@POPPLER_TREE@/poppler/PSOutputDev.cc \
 	@POPPLER_TREE@/poppler/PSTokenizer.cc \
 	@POPPLER_TREE@/poppler/Page.cc \
 	@POPPLER_TREE@/poppler/PageLabelInfo.cc \
@@ -549,7 +535,7 @@ poppler_libpoppler_a_sources = \
 	@POPPLER_TREE@/poppler/UnicodeTypeTable.cc \
 	@POPPLER_TREE@/poppler/ViewerPreferences.cc \
 	@POPPLER_TREE@/poppler/XRef.cc \
-	@POPPLER_TREE@/poppler/XpdfPluginAPI.cc 
+	@POPPLER_TREE@/poppler/XpdfPluginAPI.cc
 
 
 # Reconfig
@@ -631,51 +617,36 @@ clean-noinstLIBRARIES:
 @POPPLER_TREE@/goo/$(DEPDIR)/$(am__dirstamp):
 	@$(MKDIR_P) @POPPLER_TREE@/goo/$(DEPDIR)
 	@: > @POPPLER_TREE@/goo/$(DEPDIR)/$(am__dirstamp)
-@POPPLER_TREE@/goo/FixedPoint.$(OBJEXT):  \
-	@POPPLER_TREE@/goo/$(am__dirstamp) \
-	@POPPLER_TREE@/goo/$(DEPDIR)/$(am__dirstamp)
-@POPPLER_TREE@/goo/GooHash.$(OBJEXT):  \
-	@POPPLER_TREE@/goo/$(am__dirstamp) \
-	@POPPLER_TREE@/goo/$(DEPDIR)/$(am__dirstamp)
-@POPPLER_TREE@/goo/GooList.$(OBJEXT):  \
-	@POPPLER_TREE@/goo/$(am__dirstamp) \
-	@POPPLER_TREE@/goo/$(DEPDIR)/$(am__dirstamp)
-@POPPLER_TREE@/goo/GooString.$(OBJEXT):  \
-	@POPPLER_TREE@/goo/$(am__dirstamp) \
-	@POPPLER_TREE@/goo/$(DEPDIR)/$(am__dirstamp)
-@POPPLER_TREE@/goo/GooTimer.$(OBJEXT):  \
+@POPPLER_TREE@/goo/gfile.$(OBJEXT):  \
 	@POPPLER_TREE@/goo/$(am__dirstamp) \
 	@POPPLER_TREE@/goo/$(DEPDIR)/$(am__dirstamp)
-@POPPLER_TREE@/goo/ImgWriter.$(OBJEXT):  \
+@POPPLER_TREE@/goo/glibc.$(OBJEXT):  \
 	@POPPLER_TREE@/goo/$(am__dirstamp) \
 	@POPPLER_TREE@/goo/$(DEPDIR)/$(am__dirstamp)
-@POPPLER_TREE@/goo/JpegWriter.$(OBJEXT):  \
-	@POPPLER_TREE@/goo/$(am__dirstamp) \
+@POPPLER_TREE@/goo/gmem.$(OBJEXT): @POPPLER_TREE@/goo/$(am__dirstamp) \
 	@POPPLER_TREE@/goo/$(DEPDIR)/$(am__dirstamp)
-@POPPLER_TREE@/goo/NetPBMWriter.$(OBJEXT):  \
+@POPPLER_TREE@/goo/gmempp.$(OBJEXT):  \
 	@POPPLER_TREE@/goo/$(am__dirstamp) \
 	@POPPLER_TREE@/goo/$(DEPDIR)/$(am__dirstamp)
-@POPPLER_TREE@/goo/PNGWriter.$(OBJEXT):  \
+@POPPLER_TREE@/goo/grandom.$(OBJEXT):  \
 	@POPPLER_TREE@/goo/$(am__dirstamp) \
 	@POPPLER_TREE@/goo/$(DEPDIR)/$(am__dirstamp)
-@POPPLER_TREE@/goo/TiffWriter.$(OBJEXT):  \
+@POPPLER_TREE@/goo/gstrtod.$(OBJEXT):  \
 	@POPPLER_TREE@/goo/$(am__dirstamp) \
 	@POPPLER_TREE@/goo/$(DEPDIR)/$(am__dirstamp)
-@POPPLER_TREE@/goo/gfile.$(OBJEXT):  \
+@POPPLER_TREE@/goo/FixedPoint.$(OBJEXT):  \
 	@POPPLER_TREE@/goo/$(am__dirstamp) \
 	@POPPLER_TREE@/goo/$(DEPDIR)/$(am__dirstamp)
-@POPPLER_TREE@/goo/glibc.$(OBJEXT):  \
+@POPPLER_TREE@/goo/GooHash.$(OBJEXT):  \
 	@POPPLER_TREE@/goo/$(am__dirstamp) \
 	@POPPLER_TREE@/goo/$(DEPDIR)/$(am__dirstamp)
-@POPPLER_TREE@/goo/gmem.$(OBJEXT): @POPPLER_TREE@/goo/$(am__dirstamp) \
-	@POPPLER_TREE@/goo/$(DEPDIR)/$(am__dirstamp)
-@POPPLER_TREE@/goo/gmempp.$(OBJEXT):  \
+@POPPLER_TREE@/goo/GooList.$(OBJEXT):  \
 	@POPPLER_TREE@/goo/$(am__dirstamp) \
 	@POPPLER_TREE@/goo/$(DEPDIR)/$(am__dirstamp)
-@POPPLER_TREE@/goo/grandom.$(OBJEXT):  \
+@POPPLER_TREE@/goo/GooString.$(OBJEXT):  \
 	@POPPLER_TREE@/goo/$(am__dirstamp) \
 	@POPPLER_TREE@/goo/$(DEPDIR)/$(am__dirstamp)
-@POPPLER_TREE@/goo/gstrtod.$(OBJEXT):  \
+@POPPLER_TREE@/goo/GooTimer.$(OBJEXT):  \
 	@POPPLER_TREE@/goo/$(am__dirstamp) \
 	@POPPLER_TREE@/goo/$(DEPDIR)/$(am__dirstamp)
 @POPPLER_TREE@/fofi/$(am__dirstamp):
@@ -747,9 +718,6 @@ clean-noinstLIBRARIES:
 @POPPLER_TREE@/poppler/FileSpec.$(OBJEXT):  \
 	@POPPLER_TREE@/poppler/$(am__dirstamp) \
 	@POPPLER_TREE@/poppler/$(DEPDIR)/$(am__dirstamp)
-@POPPLER_TREE@/poppler/FlateEncoder.$(OBJEXT):  \
-	@POPPLER_TREE@/poppler/$(am__dirstamp) \
-	@POPPLER_TREE@/poppler/$(DEPDIR)/$(am__dirstamp)
 @POPPLER_TREE@/poppler/FlateStream.$(OBJEXT):  \
 	@POPPLER_TREE@/poppler/$(am__dirstamp) \
 	@POPPLER_TREE@/poppler/$(DEPDIR)/$(am__dirstamp)
@@ -798,9 +766,6 @@ clean-noinstLIBRARIES:
 @POPPLER_TREE@/poppler/Link.$(OBJEXT):  \
 	@POPPLER_TREE@/poppler/$(am__dirstamp) \
 	@POPPLER_TREE@/poppler/$(DEPDIR)/$(am__dirstamp)
-@POPPLER_TREE@/poppler/LocalPDFDocBuilder.$(OBJEXT):  \
-	@POPPLER_TREE@/poppler/$(am__dirstamp) \
-	@POPPLER_TREE@/poppler/$(DEPDIR)/$(am__dirstamp)
 @POPPLER_TREE@/poppler/MarkedContentOutputDev.$(OBJEXT):  \
 	@POPPLER_TREE@/poppler/$(am__dirstamp) \
 	@POPPLER_TREE@/poppler/$(DEPDIR)/$(am__dirstamp)
@@ -831,9 +796,6 @@ clean-noinstLIBRARIES:
 @POPPLER_TREE@/poppler/PDFDocFactory.$(OBJEXT):  \
 	@POPPLER_TREE@/poppler/$(am__dirstamp) \
 	@POPPLER_TREE@/poppler/$(DEPDIR)/$(am__dirstamp)
-@POPPLER_TREE@/poppler/PSOutputDev.$(OBJEXT):  \
-	@POPPLER_TREE@/poppler/$(am__dirstamp) \
-	@POPPLER_TREE@/poppler/$(DEPDIR)/$(am__dirstamp)
 @POPPLER_TREE@/poppler/PSTokenizer.$(OBJEXT):  \
 	@POPPLER_TREE@/poppler/$(am__dirstamp) \
 	@POPPLER_TREE@/poppler/$(DEPDIR)/$(am__dirstamp)
@@ -929,11 +891,6 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@@POPPLER_TREE@/goo/$(DEPDIR)/GooList.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@@POPPLER_TREE@/goo/$(DEPDIR)/GooString.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@@POPPLER_TREE@/goo/$(DEPDIR)/GooTimer.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@@POPPLER_TREE@/goo/$(DEPDIR)/ImgWriter.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@@POPPLER_TREE@/goo/$(DEPDIR)/JpegWriter.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@@POPPLER_TREE@/goo/$(DEPDIR)/NetPBMWriter.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@@POPPLER_TREE@/goo/$(DEPDIR)/PNGWriter.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@@POPPLER_TREE@/goo/$(DEPDIR)/TiffWriter.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@@POPPLER_TREE@/goo/$(DEPDIR)/gfile.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@@POPPLER_TREE@/goo/$(DEPDIR)/glibc.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@@POPPLER_TREE@/goo/$(DEPDIR)/gmem.Po@am__quote@
@@ -953,7 +910,6 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@@POPPLER_TREE@/poppler/$(DEPDIR)/Dict.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@@POPPLER_TREE@/poppler/$(DEPDIR)/Error.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@@POPPLER_TREE@/poppler/$(DEPDIR)/FileSpec.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@@POPPLER_TREE@/poppler/$(DEPDIR)/FlateEncoder.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@@POPPLER_TREE@/poppler/$(DEPDIR)/FlateStream.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@@POPPLER_TREE@/poppler/$(DEPDIR)/FontEncodingTables.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@@POPPLER_TREE@/poppler/$(DEPDIR)/FontInfo.Po@am__quote@
@@ -970,7 +926,6 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@@POPPLER_TREE@/poppler/$(DEPDIR)/Lexer.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@@POPPLER_TREE@/poppler/$(DEPDIR)/Linearization.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@@POPPLER_TREE@/poppler/$(DEPDIR)/Link.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@@POPPLER_TREE@/poppler/$(DEPDIR)/LocalPDFDocBuilder.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@@POPPLER_TREE@/poppler/$(DEPDIR)/MarkedContentOutputDev.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@@POPPLER_TREE@/poppler/$(DEPDIR)/Movie.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@@POPPLER_TREE@/poppler/$(DEPDIR)/NameToCharCode.Po@am__quote@
@@ -981,7 +936,6 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@@POPPLER_TREE@/poppler/$(DEPDIR)/PDFDoc.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@@POPPLER_TREE@/poppler/$(DEPDIR)/PDFDocEncoding.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@@POPPLER_TREE@/poppler/$(DEPDIR)/PDFDocFactory.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@@POPPLER_TREE@/poppler/$(DEPDIR)/PSOutputDev.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@@POPPLER_TREE@/poppler/$(DEPDIR)/PSTokenizer.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@@POPPLER_TREE@/poppler/$(DEPDIR)/Page.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@@POPPLER_TREE@/poppler/$(DEPDIR)/PageLabelInfo.Po@am__quote@
diff --git a/source/libs/poppler/TLpatches/ChangeLog b/source/libs/poppler/TLpatches/ChangeLog
index 8b900ff4d67fe56d2d3eb29eb5ef93b77666aab7..3e382943737abea607f987a31e38344311244048 100644
--- a/source/libs/poppler/TLpatches/ChangeLog
+++ b/source/libs/poppler/TLpatches/ChangeLog
@@ -1,25 +1,10 @@
-2017-10-04  Luigi Scarso <luigi.scarso@gmail.com>
+2018-01-08  Karl Berry  <karl@freefriends.org>
 
-	Imported poppler-0.60.0 source tree from:
-	  http://poppler.freedesktop.org/
-	* patch-02-LLONG_MAX, patch-03-Object-functions: Adapted.
-	* removed all files but SplashTypes.h in the  splash/ directory
-
-2017-09-25  Luigi Scarso <luigi.scarso@gmail.com>
-
-	Imported poppler-0.59.0 source tree from:
-	  http://poppler.freedesktop.org/
-	* patch-02-LLONG_MAX, patch-03-Object-functions: Adapted.
-
-
-
-2017-06-15  Luigi Scarso <luigi.scarso@gmail.com>
-
-	Imported poppler-0.55.0 source tree from:
+	Imported poppler-0.52.0 source tree from:
 	  http://poppler.freedesktop.org/
-	* patch-02-LLONG_MAX, patch-03-Object-functions: Adapted.
-
-
+	* patch-02-LLONG_MAX, patch-03-Object-functions: try removing,
+	seems like the source may have moved on by now, especially
+	what with requiring C++11.
 
 2017-02-17  Akira Kakuto  <kakuto@fuk.kindai.ac.jp>
 
diff --git a/source/libs/poppler/TLpatches/TL-Changes b/source/libs/poppler/TLpatches/TL-Changes
index 9a1ab73cd2d9e671d0fece5ee600bf1ede51caaf..5d3ec566f7793289d515a8048c33a9b4ad37b7b0 100644
--- a/source/libs/poppler/TLpatches/TL-Changes
+++ b/source/libs/poppler/TLpatches/TL-Changes
@@ -1,29 +1,21 @@
-Changes applied to the poppler-0.60.0 tree as obtained from:
+Changes applied to the poppler-0.62.0 tree as obtained from:
 	http://poppler.freedesktop.org/
 
-Removed:
-	Makefile.in
-	aclocal.m4
-	compile
-	config.guess
-	config.sub
-	configure
-	depcomp
-	install-sh
-	ltmain.sh
-	missing
-	test-driver
-	fofi/Makefile.in
-	goo/Makefile.in
-	poppler/Makefile.in
-	splash/Makefile.in
-
 Removed unused dirs:
-	cmake
-	cpp
-	glib
-	m4
-	qt4
-	qt5
-	test
-	utils
+	cmake cpp glib m4 qt4 qt5 test utils
+
+General idea:
+update version.ac
+mv poppler-src poppler-prev
+tar xf poppler-*.tar.gz
+mv poppler-0.62.0 poppler-src
+cd poppler-src
+svn status >/tmp/s
+svn add # the ? lines
+svn remove # the ! lines
+# adapt Makefile.am for new files
+# adapt configure.ac as needed
+autoreconf
+make -C .../Work/libs/poppler/
+# until it succeeds
+# try build of everything, luatex/xetex may need updating.
diff --git a/source/libs/poppler/aclocal.m4 b/source/libs/poppler/aclocal.m4
index cc8ede0bbd901e55a591f155c60d55e11874a7e0..dc8942804a9c920ac6bc0f038cb172e6db9e44c1 100644
--- a/source/libs/poppler/aclocal.m4
+++ b/source/libs/poppler/aclocal.m4
@@ -20,6 +20,44 @@ You have another version of autoconf.  It may work, but is not guaranteed to.
 If you have problems, you may need to regenerate the build system entirely.
 To do so, use the procedure documented by the package, typically 'autoreconf'.])])
 
+# ===========================================================================
+#    http://www.gnu.org/software/autoconf-archive/ax_require_defined.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_REQUIRE_DEFINED(MACRO)
+#
+# DESCRIPTION
+#
+#   AX_REQUIRE_DEFINED is a simple helper for making sure other macros have
+#   been defined and thus are available for use.  This avoids random issues
+#   where a macro isn't expanded.  Instead the configure script emits a
+#   non-fatal:
+#
+#     ./configure: line 1673: AX_CFLAGS_WARN_ALL: command not found
+#
+#   It's like AC_REQUIRE except it doesn't expand the required macro.
+#
+#   Here's an example:
+#
+#     AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG])
+#
+# LICENSE
+#
+#   Copyright (c) 2014 Mike Frysinger <vapier@gentoo.org>
+#
+#   Copying and distribution of this file, with or without modification, are
+#   permitted in any medium without royalty provided the copyright notice
+#   and this notice are preserved. This file is offered as-is, without any
+#   warranty.
+
+#serial 1
+
+AC_DEFUN([AX_REQUIRE_DEFINED], [dnl
+  m4_ifndef([$1], [m4_fatal([macro ]$1[ is not defined; is a m4 file missing?])])
+])dnl AX_REQUIRE_DEFINED
+
 # Copyright (C) 2002-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
@@ -1186,6 +1224,7 @@ AC_SUBST([am__tar])
 AC_SUBST([am__untar])
 ]) # _AM_PROG_TAR
 
+m4_include([../../m4/ax_cxx_compile_stdcxx.m4])
 m4_include([../../m4/kpse-common.m4])
 m4_include([../../m4/kpse-visibility.m4])
 m4_include([../../m4/kpse-warnings.m4])
diff --git a/source/libs/poppler/config.h.in b/source/libs/poppler/config.h.in
index 7a1ad4fb73b4422a5958b5c6c1a5d55f518fa9f6..c598ea143ff2d6c74931e9eeb1512460f680d110 100644
--- a/source/libs/poppler/config.h.in
+++ b/source/libs/poppler/config.h.in
@@ -3,6 +3,9 @@
 /* Use zlib instead of builtin zlib decoder. */
 #undef ENABLE_ZLIB
 
+/* define if the compiler supports basic C++11 syntax */
+#undef HAVE_CXX11
+
 /* Do we have any DCT decoder?. */
 #undef HAVE_DCT_DECODER
 
@@ -28,6 +31,9 @@
 /* Do we have any JPX decoder?. */
 #undef HAVE_JPX_DECODER
 
+/* Define to 1 if you have the `localtime_r' function. */
+#undef HAVE_LOCALTIME_R
+
 /* Define to 1 if you have the <memory.h> header file. */
 #undef HAVE_MEMORY_H
 
diff --git a/source/libs/poppler/configure b/source/libs/poppler/configure
index af42d2f1b013bea507d905ef8950591a75d50196..2ca40b31b8cc5d442f96a76167cfebecf8e3b9b3 100755
--- a/source/libs/poppler/configure
+++ b/source/libs/poppler/configure
@@ -645,6 +645,7 @@ VISIBILITY_CXXFLAGS
 VISIBILITY_CFLAGS
 LN_S
 RANLIB
+HAVE_CXX11
 WARNING_CXXFLAGS
 am__fastdepCXX_FALSE
 am__fastdepCXX_TRUE
@@ -5364,6 +5365,992 @@ WARNING_CXXFLAGS=$kpse_cv_warning_cxxflags
 
 
 
+
+  ax_cxx_compile_alternatives="11 0x"    ax_cxx_compile_cxx11_required=true
+  ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+  ac_success=no
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features by default" >&5
+$as_echo_n "checking whether $CXX supports C++11 features by default... " >&6; }
+if ${ax_cv_cxx_compile_cxx11+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+
+// If the compiler admits that it is not ready for C++11, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus < 201103L
+
+#error "This is not a C++11 compiler"
+
+#else
+
+namespace cxx11
+{
+
+  namespace test_static_assert
+  {
+
+    template <typename T>
+    struct check
+    {
+      static_assert(sizeof(int) <= sizeof(T), "not big enough");
+    };
+
+  }
+
+  namespace test_final_override
+  {
+
+    struct Base
+    {
+      virtual void f() {}
+    };
+
+    struct Derived : public Base
+    {
+      virtual void f() override {}
+    };
+
+  }
+
+  namespace test_double_right_angle_brackets
+  {
+
+    template < typename T >
+    struct check {};
+
+    typedef check<void> single_type;
+    typedef check<check<void>> double_type;
+    typedef check<check<check<void>>> triple_type;
+    typedef check<check<check<check<void>>>> quadruple_type;
+
+  }
+
+  namespace test_decltype
+  {
+
+    int
+    f()
+    {
+      int a = 1;
+      decltype(a) b = 2;
+      return a + b;
+    }
+
+  }
+
+  namespace test_type_deduction
+  {
+
+    template < typename T1, typename T2 >
+    struct is_same
+    {
+      static const bool value = false;
+    };
+
+    template < typename T >
+    struct is_same<T, T>
+    {
+      static const bool value = true;
+    };
+
+    template < typename T1, typename T2 >
+    auto
+    add(T1 a1, T2 a2) -> decltype(a1 + a2)
+    {
+      return a1 + a2;
+    }
+
+    int
+    test(const int c, volatile int v)
+    {
+      static_assert(is_same<int, decltype(0)>::value == true, "");
+      static_assert(is_same<int, decltype(c)>::value == false, "");
+      static_assert(is_same<int, decltype(v)>::value == false, "");
+      auto ac = c;
+      auto av = v;
+      auto sumi = ac + av + 'x';
+      auto sumf = ac + av + 1.0;
+      static_assert(is_same<int, decltype(ac)>::value == true, "");
+      static_assert(is_same<int, decltype(av)>::value == true, "");
+      static_assert(is_same<int, decltype(sumi)>::value == true, "");
+      static_assert(is_same<int, decltype(sumf)>::value == false, "");
+      static_assert(is_same<int, decltype(add(c, v))>::value == true, "");
+      return (sumf > 0.0) ? sumi : add(c, v);
+    }
+
+  }
+
+  namespace test_noexcept
+  {
+
+    int f() { return 0; }
+    int g() noexcept { return 0; }
+
+    static_assert(noexcept(f()) == false, "");
+    static_assert(noexcept(g()) == true, "");
+
+  }
+
+  namespace test_constexpr
+  {
+
+    template < typename CharT >
+    unsigned long constexpr
+    strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
+    {
+      return *s ? strlen_c_r(s + 1, acc + 1) : acc;
+    }
+
+    template < typename CharT >
+    unsigned long constexpr
+    strlen_c(const CharT *const s) noexcept
+    {
+      return strlen_c_r(s, 0UL);
+    }
+
+    static_assert(strlen_c("") == 0UL, "");
+    static_assert(strlen_c("1") == 1UL, "");
+    static_assert(strlen_c("example") == 7UL, "");
+    static_assert(strlen_c("another\0example") == 7UL, "");
+
+  }
+
+  namespace test_rvalue_references
+  {
+
+    template < int N >
+    struct answer
+    {
+      static constexpr int value = N;
+    };
+
+    answer<1> f(int&)       { return answer<1>(); }
+    answer<2> f(const int&) { return answer<2>(); }
+    answer<3> f(int&&)      { return answer<3>(); }
+
+    void
+    test()
+    {
+      int i = 0;
+      const int c = 0;
+      static_assert(decltype(f(i))::value == 1, "");
+      static_assert(decltype(f(c))::value == 2, "");
+      static_assert(decltype(f(0))::value == 3, "");
+    }
+
+  }
+
+  namespace test_uniform_initialization
+  {
+
+    struct test
+    {
+      static const int zero {};
+      static const int one {1};
+    };
+
+    static_assert(test::zero == 0, "");
+    static_assert(test::one == 1, "");
+
+  }
+
+  namespace test_lambdas
+  {
+
+    void
+    test1()
+    {
+      auto lambda1 = [](){};
+      auto lambda2 = lambda1;
+      lambda1();
+      lambda2();
+    }
+
+    int
+    test2()
+    {
+      auto a = [](int i, int j){ return i + j; }(1, 2);
+      auto b = []() -> int { return '0'; }();
+      auto c = [=](){ return a + b; }();
+      auto d = [&](){ return c; }();
+      auto e = [a, &b](int x) mutable {
+        const auto identity = [](int y){ return y; };
+        for (auto i = 0; i < a; ++i)
+          a += b--;
+        return x + identity(a + b);
+      }(0);
+      return a + b + c + d + e;
+    }
+
+    int
+    test3()
+    {
+      const auto nullary = [](){ return 0; };
+      const auto unary = [](int x){ return x; };
+      using nullary_t = decltype(nullary);
+      using unary_t = decltype(unary);
+      const auto higher1st = [](nullary_t f){ return f(); };
+      const auto higher2nd = [unary](nullary_t f1){
+        return [unary, f1](unary_t f2){ return f2(unary(f1())); };
+      };
+      return higher1st(nullary) + higher2nd(nullary)(unary);
+    }
+
+  }
+
+  namespace test_variadic_templates
+  {
+
+    template <int...>
+    struct sum;
+
+    template <int N0, int... N1toN>
+    struct sum<N0, N1toN...>
+    {
+      static constexpr auto value = N0 + sum<N1toN...>::value;
+    };
+
+    template <>
+    struct sum<>
+    {
+      static constexpr auto value = 0;
+    };
+
+    static_assert(sum<>::value == 0, "");
+    static_assert(sum<1>::value == 1, "");
+    static_assert(sum<23>::value == 23, "");
+    static_assert(sum<1, 2>::value == 3, "");
+    static_assert(sum<5, 5, 11>::value == 21, "");
+    static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
+
+  }
+
+  // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
+  // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
+  // because of this.
+  namespace test_template_alias_sfinae
+  {
+
+    struct foo {};
+
+    template<typename T>
+    using member = typename T::member_type;
+
+    template<typename T>
+    void func(...) {}
+
+    template<typename T>
+    void func(member<T>*) {}
+
+    void test();
+
+    void test() { func<foo>(0); }
+
+  }
+
+}  // namespace cxx11
+
+#endif  // __cplusplus >= 201103L
+
+
+
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ax_cv_cxx_compile_cxx11=yes
+else
+  ax_cv_cxx_compile_cxx11=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_cxx_compile_cxx11" >&5
+$as_echo "$ax_cv_cxx_compile_cxx11" >&6; }
+  if test x$ax_cv_cxx_compile_cxx11 = xyes; then
+    ac_success=yes
+  fi
+
+    if test x$ac_success = xno; then
+    for alternative in ${ax_cxx_compile_alternatives}; do
+      switch="-std=gnu++${alternative}"
+      cachevar=`$as_echo "ax_cv_cxx_compile_cxx11_$switch" | $as_tr_sh`
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features with $switch" >&5
+$as_echo_n "checking whether $CXX supports C++11 features with $switch... " >&6; }
+if eval \${$cachevar+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_CXX="$CXX"
+         CXX="$CXX $switch"
+         cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+
+// If the compiler admits that it is not ready for C++11, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus < 201103L
+
+#error "This is not a C++11 compiler"
+
+#else
+
+namespace cxx11
+{
+
+  namespace test_static_assert
+  {
+
+    template <typename T>
+    struct check
+    {
+      static_assert(sizeof(int) <= sizeof(T), "not big enough");
+    };
+
+  }
+
+  namespace test_final_override
+  {
+
+    struct Base
+    {
+      virtual void f() {}
+    };
+
+    struct Derived : public Base
+    {
+      virtual void f() override {}
+    };
+
+  }
+
+  namespace test_double_right_angle_brackets
+  {
+
+    template < typename T >
+    struct check {};
+
+    typedef check<void> single_type;
+    typedef check<check<void>> double_type;
+    typedef check<check<check<void>>> triple_type;
+    typedef check<check<check<check<void>>>> quadruple_type;
+
+  }
+
+  namespace test_decltype
+  {
+
+    int
+    f()
+    {
+      int a = 1;
+      decltype(a) b = 2;
+      return a + b;
+    }
+
+  }
+
+  namespace test_type_deduction
+  {
+
+    template < typename T1, typename T2 >
+    struct is_same
+    {
+      static const bool value = false;
+    };
+
+    template < typename T >
+    struct is_same<T, T>
+    {
+      static const bool value = true;
+    };
+
+    template < typename T1, typename T2 >
+    auto
+    add(T1 a1, T2 a2) -> decltype(a1 + a2)
+    {
+      return a1 + a2;
+    }
+
+    int
+    test(const int c, volatile int v)
+    {
+      static_assert(is_same<int, decltype(0)>::value == true, "");
+      static_assert(is_same<int, decltype(c)>::value == false, "");
+      static_assert(is_same<int, decltype(v)>::value == false, "");
+      auto ac = c;
+      auto av = v;
+      auto sumi = ac + av + 'x';
+      auto sumf = ac + av + 1.0;
+      static_assert(is_same<int, decltype(ac)>::value == true, "");
+      static_assert(is_same<int, decltype(av)>::value == true, "");
+      static_assert(is_same<int, decltype(sumi)>::value == true, "");
+      static_assert(is_same<int, decltype(sumf)>::value == false, "");
+      static_assert(is_same<int, decltype(add(c, v))>::value == true, "");
+      return (sumf > 0.0) ? sumi : add(c, v);
+    }
+
+  }
+
+  namespace test_noexcept
+  {
+
+    int f() { return 0; }
+    int g() noexcept { return 0; }
+
+    static_assert(noexcept(f()) == false, "");
+    static_assert(noexcept(g()) == true, "");
+
+  }
+
+  namespace test_constexpr
+  {
+
+    template < typename CharT >
+    unsigned long constexpr
+    strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
+    {
+      return *s ? strlen_c_r(s + 1, acc + 1) : acc;
+    }
+
+    template < typename CharT >
+    unsigned long constexpr
+    strlen_c(const CharT *const s) noexcept
+    {
+      return strlen_c_r(s, 0UL);
+    }
+
+    static_assert(strlen_c("") == 0UL, "");
+    static_assert(strlen_c("1") == 1UL, "");
+    static_assert(strlen_c("example") == 7UL, "");
+    static_assert(strlen_c("another\0example") == 7UL, "");
+
+  }
+
+  namespace test_rvalue_references
+  {
+
+    template < int N >
+    struct answer
+    {
+      static constexpr int value = N;
+    };
+
+    answer<1> f(int&)       { return answer<1>(); }
+    answer<2> f(const int&) { return answer<2>(); }
+    answer<3> f(int&&)      { return answer<3>(); }
+
+    void
+    test()
+    {
+      int i = 0;
+      const int c = 0;
+      static_assert(decltype(f(i))::value == 1, "");
+      static_assert(decltype(f(c))::value == 2, "");
+      static_assert(decltype(f(0))::value == 3, "");
+    }
+
+  }
+
+  namespace test_uniform_initialization
+  {
+
+    struct test
+    {
+      static const int zero {};
+      static const int one {1};
+    };
+
+    static_assert(test::zero == 0, "");
+    static_assert(test::one == 1, "");
+
+  }
+
+  namespace test_lambdas
+  {
+
+    void
+    test1()
+    {
+      auto lambda1 = [](){};
+      auto lambda2 = lambda1;
+      lambda1();
+      lambda2();
+    }
+
+    int
+    test2()
+    {
+      auto a = [](int i, int j){ return i + j; }(1, 2);
+      auto b = []() -> int { return '0'; }();
+      auto c = [=](){ return a + b; }();
+      auto d = [&](){ return c; }();
+      auto e = [a, &b](int x) mutable {
+        const auto identity = [](int y){ return y; };
+        for (auto i = 0; i < a; ++i)
+          a += b--;
+        return x + identity(a + b);
+      }(0);
+      return a + b + c + d + e;
+    }
+
+    int
+    test3()
+    {
+      const auto nullary = [](){ return 0; };
+      const auto unary = [](int x){ return x; };
+      using nullary_t = decltype(nullary);
+      using unary_t = decltype(unary);
+      const auto higher1st = [](nullary_t f){ return f(); };
+      const auto higher2nd = [unary](nullary_t f1){
+        return [unary, f1](unary_t f2){ return f2(unary(f1())); };
+      };
+      return higher1st(nullary) + higher2nd(nullary)(unary);
+    }
+
+  }
+
+  namespace test_variadic_templates
+  {
+
+    template <int...>
+    struct sum;
+
+    template <int N0, int... N1toN>
+    struct sum<N0, N1toN...>
+    {
+      static constexpr auto value = N0 + sum<N1toN...>::value;
+    };
+
+    template <>
+    struct sum<>
+    {
+      static constexpr auto value = 0;
+    };
+
+    static_assert(sum<>::value == 0, "");
+    static_assert(sum<1>::value == 1, "");
+    static_assert(sum<23>::value == 23, "");
+    static_assert(sum<1, 2>::value == 3, "");
+    static_assert(sum<5, 5, 11>::value == 21, "");
+    static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
+
+  }
+
+  // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
+  // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
+  // because of this.
+  namespace test_template_alias_sfinae
+  {
+
+    struct foo {};
+
+    template<typename T>
+    using member = typename T::member_type;
+
+    template<typename T>
+    void func(...) {}
+
+    template<typename T>
+    void func(member<T>*) {}
+
+    void test();
+
+    void test() { func<foo>(0); }
+
+  }
+
+}  // namespace cxx11
+
+#endif  // __cplusplus >= 201103L
+
+
+
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  eval $cachevar=yes
+else
+  eval $cachevar=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+         CXX="$ac_save_CXX"
+fi
+eval ac_res=\$$cachevar
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+      if eval test x\$$cachevar = xyes; then
+        CXX="$CXX $switch"
+        if test -n "$CXXCPP" ; then
+          CXXCPP="$CXXCPP $switch"
+        fi
+        ac_success=yes
+        break
+      fi
+    done
+  fi
+
+    if test x$ac_success = xno; then
+                for alternative in ${ax_cxx_compile_alternatives}; do
+      for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do
+        cachevar=`$as_echo "ax_cv_cxx_compile_cxx11_$switch" | $as_tr_sh`
+        { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features with $switch" >&5
+$as_echo_n "checking whether $CXX supports C++11 features with $switch... " >&6; }
+if eval \${$cachevar+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_CXX="$CXX"
+           CXX="$CXX $switch"
+           cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+
+// If the compiler admits that it is not ready for C++11, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus < 201103L
+
+#error "This is not a C++11 compiler"
+
+#else
+
+namespace cxx11
+{
+
+  namespace test_static_assert
+  {
+
+    template <typename T>
+    struct check
+    {
+      static_assert(sizeof(int) <= sizeof(T), "not big enough");
+    };
+
+  }
+
+  namespace test_final_override
+  {
+
+    struct Base
+    {
+      virtual void f() {}
+    };
+
+    struct Derived : public Base
+    {
+      virtual void f() override {}
+    };
+
+  }
+
+  namespace test_double_right_angle_brackets
+  {
+
+    template < typename T >
+    struct check {};
+
+    typedef check<void> single_type;
+    typedef check<check<void>> double_type;
+    typedef check<check<check<void>>> triple_type;
+    typedef check<check<check<check<void>>>> quadruple_type;
+
+  }
+
+  namespace test_decltype
+  {
+
+    int
+    f()
+    {
+      int a = 1;
+      decltype(a) b = 2;
+      return a + b;
+    }
+
+  }
+
+  namespace test_type_deduction
+  {
+
+    template < typename T1, typename T2 >
+    struct is_same
+    {
+      static const bool value = false;
+    };
+
+    template < typename T >
+    struct is_same<T, T>
+    {
+      static const bool value = true;
+    };
+
+    template < typename T1, typename T2 >
+    auto
+    add(T1 a1, T2 a2) -> decltype(a1 + a2)
+    {
+      return a1 + a2;
+    }
+
+    int
+    test(const int c, volatile int v)
+    {
+      static_assert(is_same<int, decltype(0)>::value == true, "");
+      static_assert(is_same<int, decltype(c)>::value == false, "");
+      static_assert(is_same<int, decltype(v)>::value == false, "");
+      auto ac = c;
+      auto av = v;
+      auto sumi = ac + av + 'x';
+      auto sumf = ac + av + 1.0;
+      static_assert(is_same<int, decltype(ac)>::value == true, "");
+      static_assert(is_same<int, decltype(av)>::value == true, "");
+      static_assert(is_same<int, decltype(sumi)>::value == true, "");
+      static_assert(is_same<int, decltype(sumf)>::value == false, "");
+      static_assert(is_same<int, decltype(add(c, v))>::value == true, "");
+      return (sumf > 0.0) ? sumi : add(c, v);
+    }
+
+  }
+
+  namespace test_noexcept
+  {
+
+    int f() { return 0; }
+    int g() noexcept { return 0; }
+
+    static_assert(noexcept(f()) == false, "");
+    static_assert(noexcept(g()) == true, "");
+
+  }
+
+  namespace test_constexpr
+  {
+
+    template < typename CharT >
+    unsigned long constexpr
+    strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
+    {
+      return *s ? strlen_c_r(s + 1, acc + 1) : acc;
+    }
+
+    template < typename CharT >
+    unsigned long constexpr
+    strlen_c(const CharT *const s) noexcept
+    {
+      return strlen_c_r(s, 0UL);
+    }
+
+    static_assert(strlen_c("") == 0UL, "");
+    static_assert(strlen_c("1") == 1UL, "");
+    static_assert(strlen_c("example") == 7UL, "");
+    static_assert(strlen_c("another\0example") == 7UL, "");
+
+  }
+
+  namespace test_rvalue_references
+  {
+
+    template < int N >
+    struct answer
+    {
+      static constexpr int value = N;
+    };
+
+    answer<1> f(int&)       { return answer<1>(); }
+    answer<2> f(const int&) { return answer<2>(); }
+    answer<3> f(int&&)      { return answer<3>(); }
+
+    void
+    test()
+    {
+      int i = 0;
+      const int c = 0;
+      static_assert(decltype(f(i))::value == 1, "");
+      static_assert(decltype(f(c))::value == 2, "");
+      static_assert(decltype(f(0))::value == 3, "");
+    }
+
+  }
+
+  namespace test_uniform_initialization
+  {
+
+    struct test
+    {
+      static const int zero {};
+      static const int one {1};
+    };
+
+    static_assert(test::zero == 0, "");
+    static_assert(test::one == 1, "");
+
+  }
+
+  namespace test_lambdas
+  {
+
+    void
+    test1()
+    {
+      auto lambda1 = [](){};
+      auto lambda2 = lambda1;
+      lambda1();
+      lambda2();
+    }
+
+    int
+    test2()
+    {
+      auto a = [](int i, int j){ return i + j; }(1, 2);
+      auto b = []() -> int { return '0'; }();
+      auto c = [=](){ return a + b; }();
+      auto d = [&](){ return c; }();
+      auto e = [a, &b](int x) mutable {
+        const auto identity = [](int y){ return y; };
+        for (auto i = 0; i < a; ++i)
+          a += b--;
+        return x + identity(a + b);
+      }(0);
+      return a + b + c + d + e;
+    }
+
+    int
+    test3()
+    {
+      const auto nullary = [](){ return 0; };
+      const auto unary = [](int x){ return x; };
+      using nullary_t = decltype(nullary);
+      using unary_t = decltype(unary);
+      const auto higher1st = [](nullary_t f){ return f(); };
+      const auto higher2nd = [unary](nullary_t f1){
+        return [unary, f1](unary_t f2){ return f2(unary(f1())); };
+      };
+      return higher1st(nullary) + higher2nd(nullary)(unary);
+    }
+
+  }
+
+  namespace test_variadic_templates
+  {
+
+    template <int...>
+    struct sum;
+
+    template <int N0, int... N1toN>
+    struct sum<N0, N1toN...>
+    {
+      static constexpr auto value = N0 + sum<N1toN...>::value;
+    };
+
+    template <>
+    struct sum<>
+    {
+      static constexpr auto value = 0;
+    };
+
+    static_assert(sum<>::value == 0, "");
+    static_assert(sum<1>::value == 1, "");
+    static_assert(sum<23>::value == 23, "");
+    static_assert(sum<1, 2>::value == 3, "");
+    static_assert(sum<5, 5, 11>::value == 21, "");
+    static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
+
+  }
+
+  // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
+  // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
+  // because of this.
+  namespace test_template_alias_sfinae
+  {
+
+    struct foo {};
+
+    template<typename T>
+    using member = typename T::member_type;
+
+    template<typename T>
+    void func(...) {}
+
+    template<typename T>
+    void func(member<T>*) {}
+
+    void test();
+
+    void test() { func<foo>(0); }
+
+  }
+
+}  // namespace cxx11
+
+#endif  // __cplusplus >= 201103L
+
+
+
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  eval $cachevar=yes
+else
+  eval $cachevar=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+           CXX="$ac_save_CXX"
+fi
+eval ac_res=\$$cachevar
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+        if eval test x\$$cachevar = xyes; then
+          CXX="$CXX $switch"
+          if test -n "$CXXCPP" ; then
+            CXXCPP="$CXXCPP $switch"
+          fi
+          ac_success=yes
+          break
+        fi
+      done
+      if test x$ac_success = xyes; then
+        break
+      fi
+    done
+  fi
+  ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+  if test x$ax_cxx_compile_cxx11_required = xtrue; then
+    if test x$ac_success = xno; then
+      as_fn_error $? "*** A compiler with support for C++11 language features is required." "$LINENO" 5
+    fi
+  fi
+  if test x$ac_success = xno; then
+    HAVE_CXX11=0
+    { $as_echo "$as_me:${as_lineno-$LINENO}: No compiler with C++11 support was found" >&5
+$as_echo "$as_me: No compiler with C++11 support was found" >&6;}
+  else
+    HAVE_CXX11=1
+
+$as_echo "#define HAVE_CXX11 1" >>confdefs.h
+
+  fi
+
+
+
 if test -n "$ac_tool_prefix"; then
   # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
 set dummy ${ac_tool_prefix}ranlib; ac_word=$2
@@ -5468,7 +6455,6 @@ $as_echo "no, using $LN_S" >&6; }
 fi
 
 
-
 echo 'dbg:_KPSE_COMPILER_VISIBILITY called.' >&5
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking CFLAGS for C to hide external symbols" >&5
 $as_echo_n "checking CFLAGS for C to hide external symbols... " >&6; }
@@ -6000,7 +6986,10 @@ if test $ac_cv_sizeof_long_long -lt 8; then
   as_fn_error $? "Sorry, your compiler has no \`long long' with at least 8 bytes." "$LINENO" 5
 fi
 
-test "x$GXX" = xyes && NO_WARN_CXXFLAGS='-Wno-write-strings'
+if test "x$GXX" = xyes; then
+  NO_WARN_CXXFLAGS='-Wno-write-strings'
+fi
+
 
 
 # Check whether --enable-opi was given.
@@ -6047,7 +7036,6 @@ fi
 fi
 
 
-
 # Check whether --enable-dctdecoder was given.
 if test "${enable_dctdecoder+set}" = set; then :
   enableval=$enable_dctdecoder; if test "x$enableval" = xlibjpeg; then
@@ -6071,13 +7059,6 @@ fi
 
 
 
-
-
---enable-libopenjpeg=[auto/openjpeg1/openjpeg2
-
-
-
-
 for ac_header in strings.h
 do :
   ac_fn_c_check_header_mongrel "$LINENO" "strings.h" "ac_cv_header_strings_h" "$ac_includes_default"
@@ -6249,8 +7230,8 @@ fi
 fi
 
 
-
-for ac_func in gettimeofday gmtime_r mkstemp popen rand_r strtok_r timegm
+for ac_func in gettimeofday gmtime_r localtime_r mkstemp popen rand_r \
+                timegm strtok_r
 do :
   as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
 ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
diff --git a/source/libs/poppler/configure.ac b/source/libs/poppler/configure.ac
index ad574ae4106cf88fbbcb27afec5668d9d4145ddd..aaf8848f1639a865cfae8b57e03565dc8b1bff33 100644
--- a/source/libs/poppler/configure.ac
+++ b/source/libs/poppler/configure.ac
@@ -1,6 +1,8 @@
+dnl $Id: configure.ac 46257 2018-01-09 18:53:05Z karl $
 dnl Process this file with autoconf to produce a configure script.
 dnl
-dnl   Copyright (C) 2011-2013 Peter Breitenlohner <tex-live@tug.org>
+dnl   Copyright 2018 Karl Berry <tex-live@tug.org>
+dnl   Copyright 2011-2013 Peter Breitenlohner <tex-live@tug.org>
 dnl
 dnl   This file is free software; the copyright holder
 dnl   gives unlimited permission to copy and/or distribute it,
@@ -17,6 +19,7 @@ KPSE_BASIC([poppler], [no-define])
 
 AC_PROG_CC
 AC_PROG_CXX
+AX_CXX_COMPILE_STDCXX([11])
 AC_PROG_RANLIB
 AC_PROG_LN_S
 
@@ -27,7 +30,10 @@ if test $ac_cv_sizeof_long_long -lt 8; then
   AC_MSG_ERROR([Sorry, your compiler has no `long long' with at least 8 bytes.])
 fi
 
-test "x$GXX" = xyes && NO_WARN_CXXFLAGS='-Wno-write-strings'
+if test "x$GXX" = xyes; then
+  NO_WARN_CXXFLAGS='-Wno-write-strings'
+fi
+
 AC_SUBST([NO_WARN_CXXFLAGS])  
 
 dnl ##### Optional features.
@@ -63,7 +69,6 @@ AC_ARG_ENABLE([fixedpoint],
 fi
 ])
 
-
 AC_ARG_ENABLE([dctdecoder],
               AS_HELP_STRING([--enable-dctdecoder],
                              [use dctdecoder]),
@@ -80,21 +85,14 @@ AC_ARG_ENABLE([libopenjpeg],
 fi
 ])
 
-
-
-
---enable-libopenjpeg=@<:@auto/openjpeg1/openjpeg2
-
-
-
 dnl **** Checks for header files ****
 
 AC_CHECK_HEADERS([strings.h])
 AC_HEADER_DIRENT
 
-dnl **** Checks for library functions ****
-
-AC_CHECK_FUNCS([gettimeofday gmtime_r mkstemp popen rand_r strtok_r timegm])
+dnl Checks for library functions (from goo/glibc.h and more).
+AC_CHECK_FUNCS([gettimeofday gmtime_r localtime_r mkstemp popen rand_r \
+                timegm strtok_r])
 AC_SYS_LARGEFILE
 AC_FUNC_FSEEKO
 AC_CHECK_FUNC([ftell64], [AC_CHECK_FUNCS([fseek64])])
diff --git a/source/libs/poppler/include/Makefile.in b/source/libs/poppler/include/Makefile.in
index 8f5287b39a98b2d75645279404c5326360211fe3..0c87ea25257dd43ddb95a418a05f3a3c34ca151a 100644
--- a/source/libs/poppler/include/Makefile.in
+++ b/source/libs/poppler/include/Makefile.in
@@ -87,7 +87,8 @@ PRE_UNINSTALL = :
 POST_UNINSTALL = :
 subdir = include
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/../../m4/kpse-common.m4 \
+am__aclocal_m4_deps = $(top_srcdir)/../../m4/ax_cxx_compile_stdcxx.m4 \
+	$(top_srcdir)/../../m4/kpse-common.m4 \
 	$(top_srcdir)/../../m4/kpse-visibility.m4 \
 	$(top_srcdir)/../../m4/kpse-warnings.m4 \
 	$(top_srcdir)/../../m4/kpse-win32.m4 \
@@ -208,6 +209,7 @@ ECHO_T = @ECHO_T@
 EGREP = @EGREP@
 EXEEXT = @EXEEXT@
 GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
 INSTALL = @INSTALL@
 INSTALL_DATA = @INSTALL_DATA@
 INSTALL_PROGRAM = @INSTALL_PROGRAM@
diff --git a/source/libs/poppler/include/fofi/Makefile.in b/source/libs/poppler/include/fofi/Makefile.in
index e9cf8632cbf653318e9b34013cac606e56cc16e9..937cd8d674f7eaa872b7f2774fc0ab15b7af1b17 100644
--- a/source/libs/poppler/include/fofi/Makefile.in
+++ b/source/libs/poppler/include/fofi/Makefile.in
@@ -87,7 +87,8 @@ PRE_UNINSTALL = :
 POST_UNINSTALL = :
 subdir = include/fofi
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/../../m4/kpse-common.m4 \
+am__aclocal_m4_deps = $(top_srcdir)/../../m4/ax_cxx_compile_stdcxx.m4 \
+	$(top_srcdir)/../../m4/kpse-common.m4 \
 	$(top_srcdir)/../../m4/kpse-visibility.m4 \
 	$(top_srcdir)/../../m4/kpse-warnings.m4 \
 	$(top_srcdir)/../../m4/kpse-win32.m4 \
@@ -148,6 +149,7 @@ ECHO_T = @ECHO_T@
 EGREP = @EGREP@
 EXEEXT = @EXEEXT@
 GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
 INSTALL = @INSTALL@
 INSTALL_DATA = @INSTALL_DATA@
 INSTALL_PROGRAM = @INSTALL_PROGRAM@
diff --git a/source/libs/poppler/include/goo/Makefile.in b/source/libs/poppler/include/goo/Makefile.in
index 51b1954d6e7f748abb658a2958c243202119ba8a..05f0136474b08c043601a33a6544ced357830655 100644
--- a/source/libs/poppler/include/goo/Makefile.in
+++ b/source/libs/poppler/include/goo/Makefile.in
@@ -87,7 +87,8 @@ PRE_UNINSTALL = :
 POST_UNINSTALL = :
 subdir = include/goo
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/../../m4/kpse-common.m4 \
+am__aclocal_m4_deps = $(top_srcdir)/../../m4/ax_cxx_compile_stdcxx.m4 \
+	$(top_srcdir)/../../m4/kpse-common.m4 \
 	$(top_srcdir)/../../m4/kpse-visibility.m4 \
 	$(top_srcdir)/../../m4/kpse-warnings.m4 \
 	$(top_srcdir)/../../m4/kpse-win32.m4 \
@@ -148,6 +149,7 @@ ECHO_T = @ECHO_T@
 EGREP = @EGREP@
 EXEEXT = @EXEEXT@
 GREP = @GREP@
+HAVE_CXX11 = @HAVE_CXX11@
 INSTALL = @INSTALL@
 INSTALL_DATA = @INSTALL_DATA@
 INSTALL_PROGRAM = @INSTALL_PROGRAM@
diff --git a/source/libs/poppler/poppler-src/config.h.cmake b/source/libs/poppler/poppler-src/config.h.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..10ce55805677adee565ebb8511496d4d68a5af76
--- /dev/null
+++ b/source/libs/poppler/poppler-src/config.h.cmake
@@ -0,0 +1,209 @@
+/* config.h.  Generated from config.h.cmake by cmake.  */
+
+/* Build against libcurl. */
+#cmakedefine ENABLE_LIBCURL 1
+
+/* Use libjpeg instead of builtin jpeg decoder. */
+#cmakedefine ENABLE_LIBJPEG 1
+
+/* Use libopenjpeg instead of builtin jpeg2000 decoder. */
+#cmakedefine ENABLE_LIBOPENJPEG 1
+
+/* Build against libtiff. */
+#cmakedefine ENABLE_LIBTIFF 1
+
+/* Build against libpng. */
+#cmakedefine ENABLE_LIBPNG 1
+
+/* Do not hardcode the library location */
+#cmakedefine ENABLE_RELOCATABLE 1
+
+/* Build against zlib. */
+#cmakedefine ENABLE_ZLIB 1
+
+/* Use zlib instead of builtin zlib decoder to uncompress flate streams. */
+#cmakedefine ENABLE_ZLIB_UNCOMPRESS 1
+
+/* Build against libnss3 for digital signature validation */
+#cmakedefine ENABLE_NSS3 1
+
+/* Use cairo for rendering. */
+#cmakedefine HAVE_CAIRO 1
+
+/* Do we have any DCT decoder?. */
+#cmakedefine HAVE_DCT_DECODER 1
+
+/* Do we have any JPX decoder?. */
+#cmakedefine HAVE_JPX_DECODER 1
+
+/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
+   */
+#cmakedefine HAVE_DIRENT_H 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#cmakedefine HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#cmakedefine HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the `fseek64' function. */
+#cmakedefine HAVE_FSEEK64 1
+
+/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
+#cmakedefine HAVE_FSEEKO 1
+
+/* Define to 1 if you have the `ftell64' function. */
+#cmakedefine HAVE_FTELL64 1
+
+/* Define to 1 if you have the `pread64' function. */
+#cmakedefine HAVE_PREAD64 1
+
+/* Define to 1 if you have the `lseek64' function. */
+#cmakedefine HAVE_LSEEK64 1
+
+/* Defines if gettimeofday is available on your system */
+#cmakedefine HAVE_GETTIMEOFDAY 1
+
+/* Defines if gmtime_r is available on your system */
+#cmakedefine HAVE_GMTIME_R 1
+
+/* Defines if timegm is available on your system */
+#cmakedefine HAVE_TIMEGM 1
+
+/* Define if you have the iconv() function and it works. */
+#cmakedefine HAVE_ICONV 1
+
+/* Define to 1 if you have the `z' library (-lz). */
+#cmakedefine HAVE_LIBZ 1
+
+/* Defines if localtime_r is available on your system */
+#cmakedefine HAVE_LOCALTIME_R 1
+
+/* Define to 1 if you have the `mkstemp' function. */
+#cmakedefine HAVE_MKSTEMP 1
+
+/* Define to 1 if you have the `rand_r' function. */
+#cmakedefine HAVE_RAND_R 1
+
+/* Define to 1 if you have the `strcpy_s' function. */
+#cmakedefine HAVE_STRCPY_S 1
+
+/* Define to 1 if you have the `strcat_s' function. */
+#cmakedefine HAVE_STRCAT_S 1
+
+/* Defines if strtok_r is available on your system */
+#cmakedefine HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
+#cmakedefine HAVE_NDIR_H 1
+
+/* Define to 1 if you have the `popen' function. */
+#cmakedefine HAVE_POPEN 1
+
+/* Use splash for rendering. */
+#cmakedefine HAVE_SPLASH 1
+
+/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
+   */
+#cmakedefine HAVE_SYS_DIR_H 1
+
+/* Define to 1 if you have the <sys/mman.h> header file. */
+#cmakedefine HAVE_SYS_MMAN_H 1
+
+/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
+   */
+#cmakedefine HAVE_SYS_NDIR_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#cmakedefine HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#cmakedefine HAVE_UNISTD_H 1
+
+/* Define to 1 if you have a big endian machine */
+#cmakedefine WORDS_BIGENDIAN 1
+
+/* Define as const if the declaration of iconv() needs const. */
+#define ICONV_CONST ${ICONV_CONST}
+
+/* Enable multithreading support. */
+#cmakedefine MULTITHREADED 1
+
+/* Generate OPI comments in PS output. */
+#cmakedefine OPI_SUPPORT 1
+
+/* Name of package */
+#define PACKAGE "poppler"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "https://bugs.freedesktop.org/enter_bug.cgi?product=poppler"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "poppler"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "poppler ${POPPLER_VERSION}"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "poppler"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "${POPPLER_VERSION}"
+
+/* Poppler data dir */
+#define POPPLER_DATADIR "${POPPLER_DATADIR}"
+
+/* Support for curl based doc builder is compiled in. */
+#cmakedefine POPPLER_HAS_CURL_SUPPORT 1
+
+/* Include support for CMYK rasterization */
+#cmakedefine SPLASH_CMYK 1
+
+/* Enable word list support. */
+#cmakedefine TEXTOUT_WORD_LIST 1
+
+/* Defines if use cms */
+#cmakedefine USE_CMS 1
+
+/* Use fixed point arithmetic in the Splash backend */
+#cmakedefine USE_FIXEDPOINT 1
+
+/* Use single precision arithmetic in the Splash backend */
+#cmakedefine USE_FLOAT 1
+
+/* Version number of package */
+#define VERSION "${POPPLER_VERSION}"
+
+/* Use fontconfig font configuration backend */
+#cmakedefine WITH_FONTCONFIGURATION_FONTCONFIG 1
+
+/* Use win32 font configuration backend */
+#cmakedefine WITH_FONTCONFIGURATION_WIN32 1
+
+/* OpenJPEG with the OPJ_DPARAMETERS_IGNORE_PCLR_CMAP_CDEF_FLAG flag */
+#cmakedefine WITH_OPENJPEG_IGNORE_PCLR_CMAP_CDEF_FLAG 1
+
+/* MS defined snprintf as deprecated but then added it in Visual Studio 2015. */
+#if defined(_MSC_VER) && _MSC_VER < 1900
+#define snprintf _snprintf
+#endif
+
+//------------------------------------------------------------------------
+// popen
+//------------------------------------------------------------------------
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+#define popen _popen
+#define pclose _pclose
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#cmakedefine _FILE_OFFSET_BITS @_FILE_OFFSET_BITS@
+
+/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
+/* TODO This is wrong, port if needed #undef _LARGEFILE_SOURCE */
+
+/* Define for large files, on AIX-style hosts. */
+/* TODO This is wrong, port if needed #undef _LARGE_FILES */
diff --git a/source/libs/poppler/poppler-src/goo/glibc_strtok_r.cc b/source/libs/poppler/poppler-src/goo/glibc_strtok_r.cc
new file mode 100644
index 0000000000000000000000000000000000000000..e779bf50a2f2b73cc237f8759befd6ebdbba2e22
--- /dev/null
+++ b/source/libs/poppler/poppler-src/goo/glibc_strtok_r.cc
@@ -0,0 +1,95 @@
+/* Reentrant string tokenizer.  Generic version.
+   Copyright (C) 1991,1996-1999,2001,2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Copyright (C) 1991,93,96,97,99,2000,2002 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Based on strlen implementation by Torbjorn Granlund (tege@sics.se),
+   with help from Dan Sahlin (dan@sics.se) and
+   commentary by Jim Blandy (jimb@ai.mit.edu);
+   adaptation to memchr suggested by Dick Karpinski (dick@cca.ucsf.edu),
+   and implemented by Roland McGrath (roland@ai.mit.edu).
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2012 Alexey Pavlov <alexpux@gmail.com>
+// Copyright (C) 2012 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2017 Adrian Johnson <ajohnson@redneon.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef HAVE_STRTOK_R
+
+#include <string.h>
+
+#define __rawmemchr strchr
+
+char * strtok_r (char *s, const char *delim, char **save_ptr)
+{
+  char *token;
+
+  if (s == NULL)
+    s = *save_ptr;
+
+  /* Scan leading delimiters.  */
+  s += strspn (s, delim);
+  if (*s == '\0')
+    {
+      *save_ptr = s;
+      return NULL;
+    }
+
+  /* Find the end of the token.  */
+  token = s;
+  s = strpbrk (token, delim);
+  if (s == NULL)
+    /* This token finishes the string.  */
+    *save_ptr = __rawmemchr (token, '\0');
+  else
+    {
+      /* Terminate the token and make *SAVE_PTR point past it.  */
+      *s = '\0';
+      *save_ptr = s + 1;
+    }
+  return token;
+}
+
+#endif
diff --git a/source/libs/poppler/poppler-src/gtkdoc.py b/source/libs/poppler/poppler-src/gtkdoc.py
new file mode 100644
index 0000000000000000000000000000000000000000..48f862a31fa4757cee3d05ad11017e04ae3dc400
--- /dev/null
+++ b/source/libs/poppler/poppler-src/gtkdoc.py
@@ -0,0 +1,440 @@
+# Copyright (C) 2011 Igalia S.L.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+import errno
+import logging
+import os
+import os.path
+import subprocess
+import sys
+
+
+class GTKDoc(object):
+
+    """Class that controls a gtkdoc run.
+
+    Each instance of this class represents one gtkdoc configuration
+    and set of documentation. The gtkdoc package is a series of tools
+    run consecutively which converts inline C/C++ documentation into
+    docbook files and then into HTML. This class is suitable for
+    generating documentation or simply verifying correctness.
+
+    Keyword arguments:
+    output_dir         -- The path where gtkdoc output should be placed. Generation
+                          may overwrite file in this directory. Required.
+    module_name        -- The name of the documentation module. For libraries this
+                          is typically the library name. Required if not library path
+                          is given.
+    source_dirs        -- A list of paths to directories of source code to be scanned.
+                          Required if headers is not specified.
+    ignored_files      -- A list of filenames to ignore in the source directory. It is
+                          only necessary to provide the basenames of these files.
+                          Typically it is important to provide an updated list of
+                          ignored files to prevent warnings about undocumented symbols.
+    headers            -- A list of paths to headers to be scanned. Required if source_dirs
+                          is not specified.
+    namespace          -- The library namespace.
+    decorator          -- If a decorator is used to unhide certain symbols in header
+                          files this parameter is required for successful scanning.
+                          (default '')
+    deprecation_guard  -- gtkdoc tries to ensure that symbols marked as deprecated
+                          are encased in this C preprocessor define. This is required
+                          to avoid gtkdoc warnings. (default '')
+    cflags             -- This parameter specifies any preprocessor flags necessary for
+                          building the scanner binary during gtkdoc-scanobj. Typically
+                          this includes all absolute include paths necessary to resolve
+                          all header dependencies. (default '')
+    ldflags            -- This parameter specifies any linker flags necessary for
+                          building the scanner binary during gtkdoc-scanobj. Typically
+                          this includes "-lyourlibraryname". (default '')
+    library_path       -- This parameter specifies the path to the directory where you
+                          library resides used for building the scanner binary during
+                          gtkdoc-scanobj. (default '')
+
+    doc_dir            -- The path to other documentation files necessary to build
+                          the documentation. This files in this directory as well as
+                          the files in the 'html' subdirectory will be copied
+                          recursively into the output directory. (default '')
+    main_sgml_file     -- The path or name (if a doc_dir is given) of the SGML file
+                          that is the considered the main page of your documentation.
+                          (default: <module_name>-docs.sgml)
+    version            -- The version number of the module. If this is provided,
+                          a version.xml file containing the version will be created
+                          in the output directory during documentation generation.
+
+    interactive        -- Whether or not errors or warnings should prompt the user
+                          to continue or not. When this value is false, generation
+                          will continue despite warnings. (default False)
+
+    virtual_root       -- A temporary installation directory which is used as the root
+                          where the actual installation prefix lives; this is mostly
+                          useful for packagers, and should be set to what is given to
+                          make install as DESTDIR.
+    """
+
+    def __init__(self, args):
+
+        # Parameters specific to scanning.
+        self.module_name = ''
+        self.source_dirs = []
+        self.headers = []
+        self.ignored_files = []
+        self.namespace = ''
+        self.decorator = ''
+        self.deprecation_guard = ''
+
+        # Parameters specific to gtkdoc-scanobj.
+        self.cflags = ''
+        self.ldflags = ''
+        self.library_path = ''
+
+        # Parameters specific to generation.
+        self.output_dir = ''
+        self.doc_dir = ''
+        self.main_sgml_file = ''
+
+        # Parameters specific to gtkdoc-fixxref.
+        self.cross_reference_deps = []
+
+        self.interactive = False
+
+        self.logger = logging.getLogger('gtkdoc')
+
+        for key, value in iter(args.items()):
+            setattr(self, key, value)
+
+        if not getattr(self, 'output_dir'):
+            raise Exception('output_dir not specified.')
+        if not getattr(self, 'module_name'):
+            raise Exception('module_name not specified.')
+        if not getattr(self, 'source_dirs') and not getattr(self, 'headers'):
+            raise Exception('Neither source_dirs nor headers specified.' % key)
+
+        # Make all paths absolute in case we were passed relative paths, since
+        # we change the current working directory when executing subcommands.
+        self.output_dir = os.path.abspath(self.output_dir)
+        self.source_dirs = [os.path.abspath(x) for x in self.source_dirs]
+        self.headers = [os.path.abspath(x) for x in self.headers]
+        if self.library_path:
+            self.library_path = os.path.abspath(self.library_path)
+
+        if not self.main_sgml_file:
+            self.main_sgml_file = self.module_name + "-docs.sgml"
+
+    def generate(self, html=True):
+        self.saw_warnings = False
+
+        self._copy_doc_files_to_output_dir(html)
+        self._write_version_xml()
+        self._run_gtkdoc_scan()
+        self._run_gtkdoc_scangobj()
+        self._run_gtkdoc_mkdb()
+
+        if not html:
+            return
+
+        self._run_gtkdoc_mkhtml()
+        self._run_gtkdoc_fixxref()
+
+    def _delete_file_if_exists(self, path):
+        if not os.access(path, os.F_OK | os.R_OK):
+            return
+        self.logger.debug('deleting %s', path)
+        os.unlink(path)
+
+    def _create_directory_if_nonexistent(self, path):
+        try:
+            os.makedirs(path)
+        except OSError as error:
+            if error.errno != errno.EEXIST:
+                raise
+
+    def _raise_exception_if_file_inaccessible(self, path):
+        if not os.path.exists(path) or not os.access(path, os.R_OK):
+            raise Exception("Could not access file at: %s" % path)
+
+    def _output_has_warnings(self, outputs):
+        for output in outputs:
+            if output and output.find('warning'):
+                return True
+        return False
+
+    def _ask_yes_or_no_question(self, question):
+        if not self.interactive:
+            return True
+
+        question += ' [y/N] '
+        answer = None
+        while answer != 'y' and answer != 'n' and answer != '':
+            answer = raw_input(question).lower()
+        return answer == 'y'
+
+    def _run_command(self, args, env=None, cwd=None, print_output=True, ignore_warnings=False):
+        if print_output:
+            self.logger.debug("Running %s", args[0])
+        self.logger.debug("Full command args: %s", str(args))
+
+        process = subprocess.Popen(args, env=env, cwd=cwd,
+                                   stdout=subprocess.PIPE,
+                                   stderr=subprocess.PIPE)
+        stdout, stderr = [b.decode("utf-8") for b in process.communicate()]
+
+        if print_output:
+            if stdout:
+                try:
+                    sys.stdout.write(stdout.encode("utf-8"))
+                except UnicodeDecodeError:
+                    sys.stdout.write(stdout)
+            if stderr:
+                try:
+                    sys.stderr.write(stderr.encode("utf-8"))
+                except UnicodeDecodeError:
+                    sys.stderr.write(stderr)
+
+        if process.returncode != 0:
+            raise Exception('%s produced a non-zero return code %i'
+                             % (args[0], process.returncode))
+
+        if not ignore_warnings and ('warning' in stderr or 'warning' in stdout):
+            self.saw_warnings = True
+            if not self._ask_yes_or_no_question('%s produced warnings, '
+                                                'try to continue?' % args[0]):
+                raise Exception('%s step failed' % args[0])
+
+        return stdout.strip()
+
+    def _copy_doc_files_to_output_dir(self, html=True):
+        if not self.doc_dir:
+            self.logger.info('Not copying any files from doc directory,'
+                             ' because no doc directory given.')
+            return
+
+        def copy_file_replacing_existing(src, dest):
+            if os.path.isdir(src):
+                self.logger.debug('skipped directory %s',  src)
+                return
+            if not os.access(src, os.F_OK | os.R_OK):
+                self.logger.debug('skipped unreadable %s', src)
+                return
+
+            self._delete_file_if_exists(dest)
+
+            self.logger.debug('created %s', dest)
+            try:
+                os.link(src, dest)
+            except OSError:
+                os.symlink(src, dest)
+
+        def copy_all_files_in_directory(src, dest):
+            for path in os.listdir(src):
+                copy_file_replacing_existing(os.path.join(src, path),
+                                             os.path.join(dest, path))
+
+        self.logger.debug('Copying template files to output directory...')
+        self._create_directory_if_nonexistent(self.output_dir)
+        copy_all_files_in_directory(self.doc_dir, self.output_dir)
+
+        if not html:
+            return
+
+        self.logger.debug('Copying HTML files to output directory...')
+        html_src_dir = os.path.join(self.doc_dir, 'html')
+        html_dest_dir = os.path.join(self.output_dir, 'html')
+        self._create_directory_if_nonexistent(html_dest_dir)
+
+        if os.path.exists(html_src_dir):
+            copy_all_files_in_directory(html_src_dir, html_dest_dir)
+
+    def _write_version_xml(self):
+        if not self.version:
+            self.logger.info('No version specified, so not writing version.xml')
+            return
+
+        version_xml_path = os.path.join(self.output_dir, 'version.xml')
+        src_version_xml_path = os.path.join(self.doc_dir, 'version.xml')
+
+        # Don't overwrite version.xml if it was in the doc directory.
+        if os.path.exists(version_xml_path) and \
+           os.path.exists(src_version_xml_path):
+            return
+
+        output_file = open(version_xml_path, 'w')
+        output_file.write(self.version)
+        output_file.close()
+
+    def _ignored_files_basenames(self):
+        return ' '.join([os.path.basename(x) for x in self.ignored_files])
+
+    def _run_gtkdoc_scan(self):
+        args = ['gtkdoc-scan',
+                '--module=%s' % self.module_name,
+                '--rebuild-types']
+
+        if not self.headers:
+            # Each source directory should be have its own "--source-dir=" prefix.
+            args.extend(['--source-dir=%s' % path for path in self.source_dirs])
+
+        if self.decorator:
+            args.append('--ignore-decorators=%s' % self.decorator)
+        if self.deprecation_guard:
+            args.append('--deprecated-guards=%s' % self.deprecation_guard)
+        if self.output_dir:
+            args.append('--output-dir=%s' % self.output_dir)
+
+        # We only need to pass the list of ignored files if the we are not using an explicit list of headers.
+        if not self.headers:
+            # gtkdoc-scan wants the basenames of ignored headers, so strip the
+            # dirname. Different from "--source-dir", the headers should be
+            # specified as one long string.
+            ignored_files_basenames = self._ignored_files_basenames()
+            if ignored_files_basenames:
+                args.append('--ignore-headers=%s' % ignored_files_basenames)
+
+        if self.headers:
+            args.extend(self.headers)
+
+        self._run_command(args)
+
+    def _run_gtkdoc_scangobj(self):
+        env = os.environ
+        ldflags = self.ldflags
+        if self.library_path:
+            additional_ldflags = ''
+            for arg in env.get('LDFLAGS', '').split(' '):
+                if arg.startswith('-L'):
+                    additional_ldflags = '%s %s' % (additional_ldflags, arg)
+            ldflags = ' "-L%s" %s ' % (self.library_path, additional_ldflags) + ldflags
+            current_ld_library_path = env.get('LD_LIBRARY_PATH')
+            if current_ld_library_path:
+                env['RUN'] = 'LD_LIBRARY_PATH="%s:%s" ' % (self.library_path, current_ld_library_path)
+            else:
+                env['RUN'] = 'LD_LIBRARY_PATH="%s" ' % self.library_path
+
+        if ldflags:
+            env['LDFLAGS'] = '%s %s' % (ldflags, env.get('LDFLAGS', ''))
+        if self.cflags:
+            env['CFLAGS'] = '%s %s' % (self.cflags, env.get('CFLAGS', ''))
+
+        if 'CFLAGS' in env:
+            self.logger.debug('CFLAGS=%s', env['CFLAGS'])
+        if 'LDFLAGS' in env:
+            self.logger.debug('LDFLAGS %s', env['LDFLAGS'])
+        if 'RUN' in env:
+            self.logger.debug('RUN=%s', env['RUN'])
+        self._run_command(['gtkdoc-scangobj', '--module=%s' % self.module_name],
+                          env=env, cwd=self.output_dir)
+
+    def _run_gtkdoc_mkdb(self):
+        sgml_file = os.path.join(self.output_dir, self.main_sgml_file)
+        self._raise_exception_if_file_inaccessible(sgml_file)
+
+        args = ['gtkdoc-mkdb',
+                '--module=%s' % self.module_name,
+                '--main-sgml-file=%s' % sgml_file,
+                '--source-suffixes=h,c,cpp,cc',
+                '--output-format=xml',
+                '--sgml-mode']
+
+        if self.namespace:
+            args.append('--name-space=%s' % self.namespace)
+
+        ignored_files_basenames = self._ignored_files_basenames()
+        if ignored_files_basenames:
+            args.append('--ignore-files=%s' % ignored_files_basenames)
+
+        # Each directory should be have its own "--source-dir=" prefix.
+        args.extend(['--source-dir=%s' % path for path in self.source_dirs])
+        self._run_command(args, cwd=self.output_dir)
+
+    def _run_gtkdoc_mkhtml(self):
+        html_dest_dir = os.path.join(self.output_dir, 'html')
+        if not os.path.isdir(html_dest_dir):
+            raise Exception("%s is not a directory, could not generate HTML"
+                            % html_dest_dir)
+        elif not os.access(html_dest_dir, os.X_OK | os.R_OK | os.W_OK):
+            raise Exception("Could not access %s to generate HTML"
+                            % html_dest_dir)
+
+        # gtkdoc-mkhtml expects the SGML path to be absolute.
+        sgml_file = os.path.join(os.path.abspath(self.output_dir),
+                                 self.main_sgml_file)
+        self._raise_exception_if_file_inaccessible(sgml_file)
+
+        self._run_command(['gtkdoc-mkhtml', self.module_name, sgml_file],
+                          cwd=html_dest_dir)
+
+    def _run_gtkdoc_fixxref(self):
+        args = ['gtkdoc-fixxref',
+                '--module=%s' % self.module_name,
+                '--module-dir=html',
+                '--html-dir=html']
+        args.extend(['--extra-dir=%s' % extra_dir for extra_dir in self.cross_reference_deps])
+        self._run_command(args, cwd=self.output_dir, ignore_warnings=True)
+
+    def rebase_installed_docs(self):
+        if not os.path.isdir(self.output_dir):
+            raise Exception("Tried to rebase documentation before generating it.")
+        html_dir = os.path.join(self.virtual_root + self.prefix, 'share', 'gtk-doc', 'html', self.module_name)
+        if not os.path.isdir(html_dir):
+            return
+        args = ['gtkdoc-rebase',
+                '--relative',
+                '--html-dir=%s' % html_dir]
+        args.extend(['--other-dir=%s' % extra_dir for extra_dir in self.cross_reference_deps])
+        if self.virtual_root:
+            args.extend(['--dest-dir=%s' % self.virtual_root])
+        self._run_command(args, cwd=self.output_dir)
+
+    def api_missing_documentation(self):
+        unused_doc_file = os.path.join(self.output_dir, self.module_name + "-unused.txt")
+        if not os.path.exists(unused_doc_file) or not os.access(unused_doc_file, os.R_OK):
+            return []
+        return open(unused_doc_file).read().splitlines()
+
+class PkgConfigGTKDoc(GTKDoc):
+
+    """Class reads a library's pkgconfig file to guess gtkdoc parameters.
+
+    Some gtkdoc parameters can be guessed by reading a library's pkgconfig
+    file, including the cflags, ldflags and version parameters. If you
+    provide these parameters as well, they will be appended to the ones
+    guessed via the pkgconfig file.
+
+    Keyword arguments:
+      pkg_config_path -- Path to the pkgconfig file for the library. Required.
+    """
+
+    def __init__(self, pkg_config_path, args):
+        super(PkgConfigGTKDoc, self).__init__(args)
+
+        pkg_config = os.environ.get('PKG_CONFIG', 'pkg-config')
+
+        if not os.path.exists(pkg_config_path):
+            raise Exception('Could not find pkg-config file at: %s'
+                            % pkg_config_path)
+
+        self.cflags += " " + self._run_command([pkg_config,
+                                                pkg_config_path,
+                                                '--cflags'], print_output=False)
+        self.ldflags += " " + self._run_command([pkg_config,
+                                                pkg_config_path,
+                                                '--libs'], print_output=False)
+        self.version = self._run_command([pkg_config,
+                                          pkg_config_path,
+                                          '--modversion'], print_output=False)
+        self.prefix = self._run_command([pkg_config,
+                                         pkg_config_path,
+                                         '--variable=prefix'], print_output=False)
diff --git a/source/libs/poppler/poppler-src/make-glib-api-docs b/source/libs/poppler/poppler-src/make-glib-api-docs
new file mode 100755
index 0000000000000000000000000000000000000000..6fbe4494cf06230a7298fb63a416e1ba09e7c4aa
--- /dev/null
+++ b/source/libs/poppler/poppler-src/make-glib-api-docs
@@ -0,0 +1,66 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2017 Carlos Garcia Campos <carlosgc@gnome.org>
+#
+# 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 2 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+import argparse
+import logging
+import os
+from gtkdoc import PkgConfigGTKDoc
+
+def configure_logging(verbose):
+    level = logging.DEBUG if verbose else logging.INFO
+    logger = logging.getLogger('gtkdoc')
+    logger.setLevel(level)
+    handler = logging.StreamHandler()
+    handler.setLevel(level)
+    logger.addHandler(handler)
+    if level == logging.DEBUG:
+        handler.setFormatter(logging.Formatter('[%(asctime)s]  %(message)s'))
+    else:
+        handler.setFormatter(logging.Formatter('%(message)s'))
+
+
+parser = argparse.ArgumentParser(description='Make poppler GLib API documentation.')
+parser.add_argument('-v', '--verbose', action='store_true', default = False,
+                    help='Whether or not to run in verbose mode.')
+parser.add_argument('--skip-html', action='store_true',
+                    help='Whether or not to skip HTML generation, which can be slow.')
+parser.add_argument('-s', '--src-dir', action='store', default='.', dest='src_dir',
+                    help='The source directory')
+parser.add_argument('-b', '--build-dir', action='store', default='build', dest='build_dir',
+                    help='The build directory')
+args = parser.parse_args()
+configure_logging(args.verbose)
+
+pkgconfig_file = os.path.join(args.build_dir, 'poppler-glib.pc')
+pkgconfig_path = os.environ.get("PKG_CONFIG_PATH")
+os.environ['PKG_CONFIG_PATH'] = args.build_dir
+if pkgconfig_path:
+    os.environ['PKG_CONFIG_PATH'] += ':' + pkgconfig_path
+
+gtkdoc = PkgConfigGTKDoc(pkgconfig_file, {
+    'library_path': os.path.join(args.build_dir, 'glib'),
+    'module_name': 'poppler',
+    'doc_dir': os.path.join(args.src_dir, 'glib', 'reference'),
+    'output_dir': os.path.join(args.build_dir, 'glib', 'reference'),
+    'main_sgml_file': 'poppler-docs.sgml',
+    'source_dirs': [os.path.join(args.src_dir, 'glib')],
+    'cflags': '-I%s' % os.path.join(args.src_dir, 'glib'),
+    'ignored_files': ['poppler-private.h', 'poppler-input-stream.h', 'poppler-cached-file-loader.h', 'demo']
+})
+
+gtkdoc.generate(not args.skip_html)
diff --git a/source/libs/poppler/poppler-src/poppler-cairo.pc.cmake b/source/libs/poppler/poppler-src/poppler-cairo.pc.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..e68cceab3813a601b287a667929dcf9dfa2daca6
--- /dev/null
+++ b/source/libs/poppler/poppler-src/poppler-cairo.pc.cmake
@@ -0,0 +1,8 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+libdir=@CMAKE_INSTALL_FULL_LIBDIR@
+includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
+
+Name: poppler-cairo
+Description: Cairo backend for Poppler PDF rendering library
+Version: @POPPLER_VERSION@
+Requires: poppler = @POPPLER_VERSION@ cairo >= @CAIRO_VERSION@
diff --git a/source/libs/poppler/poppler-src/poppler-cpp.pc.cmake b/source/libs/poppler/poppler-src/poppler-cpp.pc.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..3eb68b3810c16ab484c3e873a486de4cb7f45e3b
--- /dev/null
+++ b/source/libs/poppler/poppler-src/poppler-cpp.pc.cmake
@@ -0,0 +1,12 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+libdir=@CMAKE_INSTALL_FULL_LIBDIR@
+includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
+
+Name: poppler-cpp
+Description: cpp backend for Poppler PDF rendering library
+Version: @POPPLER_VERSION@
+Requires: @PC_REQUIRES@
+@PC_REQUIRES_PRIVATE@
+
+Libs: -L${libdir} -lpoppler-cpp
+Cflags: -I${includedir}/poppler/cpp
diff --git a/source/libs/poppler/poppler-src/poppler-glib.pc.cmake b/source/libs/poppler/poppler-src/poppler-glib.pc.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..ac248192509ef987278347d418c11369711112eb
--- /dev/null
+++ b/source/libs/poppler/poppler-src/poppler-glib.pc.cmake
@@ -0,0 +1,12 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+libdir=@CMAKE_INSTALL_FULL_LIBDIR@
+includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
+
+Name: poppler-glib
+Description: GLib wrapper for poppler
+Version: @POPPLER_VERSION@
+Requires: glib-2.0 >= @GLIB_REQUIRED@ gobject-2.0 >= @GLIB_REQUIRED@ cairo >= @CAIRO_VERSION@
+@PC_REQUIRES_PRIVATE@
+
+Libs: -L${libdir} -lpoppler-glib
+Cflags: -I${includedir}/poppler/glib
diff --git a/source/libs/poppler/poppler-src/poppler-qt5.pc.cmake b/source/libs/poppler/poppler-src/poppler-qt5.pc.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..946368922087a328bf19ab26a513e6a6e0231ca3
--- /dev/null
+++ b/source/libs/poppler/poppler-src/poppler-qt5.pc.cmake
@@ -0,0 +1,12 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+libdir=@CMAKE_INSTALL_FULL_LIBDIR@
+includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
+
+Name: poppler-qt5
+Description: Qt5 bindings for poppler
+Version: @POPPLER_VERSION@
+Requires: @PC_REQUIRES@
+@PC_REQUIRES_PRIVATE@
+
+Libs: -L${libdir} -lpoppler-qt5
+Cflags: -I${includedir}/poppler/qt5
diff --git a/source/libs/poppler/poppler-src/poppler-splash.pc.cmake b/source/libs/poppler/poppler-src/poppler-splash.pc.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..f9eceebe8159a39e795c86500376aa9ba9d16870
--- /dev/null
+++ b/source/libs/poppler/poppler-src/poppler-splash.pc.cmake
@@ -0,0 +1,8 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+libdir=@CMAKE_INSTALL_FULL_LIBDIR@
+includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
+
+Name: poppler-splash
+Description: Splash backend for Poppler PDF rendering library
+Version: @POPPLER_VERSION@
+Requires: poppler = @POPPLER_VERSION@
diff --git a/source/libs/poppler/poppler-src/poppler.pc.cmake b/source/libs/poppler/poppler-src/poppler.pc.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..00b734883c34fe4808fbe74b804b31d2d8fd76aa
--- /dev/null
+++ b/source/libs/poppler/poppler-src/poppler.pc.cmake
@@ -0,0 +1,10 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+libdir=@CMAKE_INSTALL_FULL_LIBDIR@
+includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
+
+Name: poppler
+Description: PDF rendering library
+Version: @POPPLER_VERSION@
+
+Libs: -L${libdir} -lpoppler
+Cflags: -I${includedir}/poppler
diff --git a/source/libs/poppler/poppler-src/poppler/Lexer.cc b/source/libs/poppler/poppler-src/poppler/Lexer.cc
index 6e05484bf18e1e1d0b04ca201d0f3b8f9f7aa646..d2329b5363159e5ff7529a7579bbdc93b0871895 100644
--- a/source/libs/poppler/poppler-src/poppler/Lexer.cc
+++ b/source/libs/poppler/poppler-src/poppler/Lexer.cc
@@ -39,21 +39,6 @@
 #include "Error.h"
 #include "XRef.h"
 
-
-/* <limits.h> and/or the compiler may or may not define these.  */
-/* Minimum and maximum values a `signed long long int' can hold.  */
-#ifndef LLONG_MAX
-# define LLONG_MAX     9223372036854775807LL
-#endif
-#ifndef LLONG_MIN
-# define LLONG_MIN     (-LLONG_MAX - 1LL)
-#endif
-
-/* Maximum value an `unsigned long long int' can hold.  (Minimum is 0.)  */
-#ifndef ULLONG_MAX
-# define ULLONG_MAX    18446744073709551615ULL
-#endif
-
 //------------------------------------------------------------------------
 
 // A '1' in this array means the character is white space.  A '1' or
diff --git a/source/libs/poppler/poppler-src/poppler/Object.h b/source/libs/poppler/poppler-src/poppler/Object.h
index e8f0710256980cc30709a82cdaaf5dca241fd477..f2ca20d1559892ac56ff02ac773b9622c6c3a76e 100644
--- a/source/libs/poppler/poppler-src/poppler/Object.h
+++ b/source/libs/poppler/poppler-src/poppler/Object.h
@@ -208,7 +208,7 @@ public:
   GBool isName(const char *nameA) const
     { return type == objName && !strcmp(cString, nameA); }
   GBool isDict(const char *dictType) const;
-  GBool isStream(const char *dictType) const;
+  GBool isStream(char *dictType) const;
   GBool isCmd(const char *cmdA) const
     { return type == objCmd && !strcmp(cString, cmdA); }
 
@@ -265,7 +265,7 @@ public:
   Object dictGetValNF(int i) const;
 
   // Stream accessors.
-  GBool streamIs(const char *dictType) const;
+  GBool streamIs(char *dictType) const;
   void streamReset();
   void streamClose();
   int streamGetChar() const;
@@ -380,10 +380,10 @@ inline Object Object::dictGetValNF(int i) const
 
 #include "Stream.h"
 
-inline GBool Object::streamIs(const char *dictType) const
+inline GBool Object::streamIs(char *dictType) const
   { OBJECT_TYPE_CHECK(objStream); return stream->getDict()->is(dictType); }
 
-inline GBool Object::isStream(const char *dictType) const
+inline GBool Object::isStream(char *dictType) const
   { return type == objStream && streamIs(dictType); }
 
 inline void Object::streamReset()
diff --git a/source/libs/poppler/poppler-src/poppler/PDFDoc.cc b/source/libs/poppler/poppler-src/poppler/PDFDoc.cc
index da7af38ed05ad02c5e682685a1b4c1965c59200f..90f039d8ec859911d207c36f3de3292abab27737 100644
--- a/source/libs/poppler/poppler-src/poppler/PDFDoc.cc
+++ b/source/libs/poppler/poppler-src/poppler/PDFDoc.cc
@@ -85,20 +85,6 @@
 #include "Hints.h"
 #include "UTF.h"
 
-/* <limits.h> and/or the compiler may or may not define these.  */
-/* Minimum and maximum values a `signed long long int' can hold.  */
-#ifndef LLONG_MAX
-# define LLONG_MAX     9223372036854775807LL
-#endif
-#ifndef LLONG_MIN
-# define LLONG_MIN     (-LLONG_MAX - 1LL)
-#endif
-
-/* Maximum value an `unsigned long long int' can hold.  (Minimum is 0.)  */
-#ifndef ULLONG_MAX
-# define ULLONG_MAX    18446744073709551615ULL
-#endif
-
 #ifdef MULTITHREADED
 #  define pdfdocLocker()   MutexLocker locker(&mutex)
 #else
diff --git a/source/libs/poppler/poppler-src/poppler/poppler-config.h.in b/source/libs/poppler/poppler-src/poppler/poppler-config.h.in
index a4a1d4267afb41488604187b0776ca7b464d4901..0d0aa9e52b4d3670902f7950d516d4cd53c4b592 100644
--- a/source/libs/poppler/poppler-src/poppler/poppler-config.h.in
+++ b/source/libs/poppler/poppler-src/poppler/poppler-config.h.in
@@ -16,7 +16,6 @@
 // Copyright (C) 2014 Bogdan Cristea <cristeab@gmail.com>
 // Copyright (C) 2014 Hib Eris <hib@hiberis.nl>
 // Copyright (C) 2016 Tor Lillqvist <tml@collabora.com>
-// Copyright (C) 2017 Adrian Johnson <ajohnson@redneon.com>
 //
 // To see a description of the changes please see the Changelog file that
 // came with your tarball or type make ChangeLog if you are building from git
@@ -26,6 +25,8 @@
 #ifndef POPPLER_CONFIG_H
 #define POPPLER_CONFIG_H
 
+#include <stdio.h>
+
 // We duplicate some of the config.h #define's here since they are
 // used in some of the header files we install.  The #ifndef/#endif
 // around #undef look odd, but it's to silence warnings about
@@ -33,7 +34,7 @@
 
 /* Defines the poppler version. */
 #ifndef POPPLER_VERSION
-#define POPPLER_VERSION "${POPPLER_VERSION}"
+#undef POPPLER_VERSION
 #endif
 
 /* Enable multithreading support. */
@@ -81,9 +82,9 @@
 #undef ENABLE_LIBPNG
 #endif
 
-/* Use zlib instead of builtin zlib decoder. */
-#ifndef ENABLE_ZLIB
-#undef ENABLE_ZLIB
+/* Use zlib instead of builtin zlib decoder for uncompressing flate streams. */
+#ifndef ENABLE_ZLIB_UNCOMPRESS
+#undef ENABLE_ZLIB_UNCOMPRESS
 #endif
 
 /* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
@@ -114,6 +115,11 @@
 #undef HAVE_SYS_NDIR_H
 #endif
 
+/* Have FreeType2 include files */
+#ifndef HAVE_FREETYPE_H
+#undef HAVE_FREETYPE_H
+#endif
+
 /* Defines if use cms */
 #ifndef USE_CMS
 #undef USE_CMS
@@ -121,8 +127,8 @@
 
 // Also, there are preprocessor symbols in the header files
 // that are used but never defined when building poppler using configure
-// or cmake: DISABLE_OUTLINE, DEBUG_MEM,
-// ENABLE_PLUGINS, DEBUG_FORMS
+// or cmake: DISABLE_OUTLINE, DEBUG_MEM, SPLASH_CMYK, HAVE_T1LIB_H,
+// ENABLE_PLUGINS, DEBUG_FORMS, HAVE_FREETYPE_FREETYPE_H
 
 //------------------------------------------------------------------------
 // version
@@ -132,6 +138,21 @@
 #define popplerCopyright "Copyright 2005-2017 The Poppler Developers - http://poppler.freedesktop.org"
 #define xpdfCopyright "Copyright 1996-2011 Glyph & Cog, LLC"
 
+//------------------------------------------------------------------------
+// popen
+//------------------------------------------------------------------------
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+#define popen _popen
+#define pclose _pclose
+#endif
+
+#if defined(VMS) || defined(VMCMS) || defined(DOS) || defined(OS2) || defined(__EMX__) || defined(_WIN32) || defined(__DJGPP__) || defined(MACOS)
+#define POPEN_READ_MODE "rb"
+#else
+#define POPEN_READ_MODE "r"
+#endif
+
 //------------------------------------------------------------------------
 // Win32 stuff
 //------------------------------------------------------------------------
@@ -142,12 +163,19 @@
 #define CDECL
 #endif
 
+#if defined(_WIN32)
+#ifdef _MSC_VER
+#define strtok_r strtok_s
+#elif __MINGW32__ && !defined(__WINPTHREADS_VERSION)
+char * strtok_r (char *s, const char *delim, char **save_ptr);
+#endif
+#endif
+
 //------------------------------------------------------------------------
 // Compiler
 //------------------------------------------------------------------------
 
 #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
-#include <stdio.h> // __MINGW_PRINTF_FORMAT is defined in the mingw stdio.h
 #ifdef __MINGW_PRINTF_FORMAT
 #define GCC_PRINTF_FORMAT(fmt_index, va_index) \
 	__attribute__((__format__(__MINGW_PRINTF_FORMAT, fmt_index, va_index)))
@@ -159,4 +187,10 @@
 #define GCC_PRINTF_FORMAT(fmt_index, va_index)
 #endif
 
+#if defined(_MSC_VER) && _MSC_VER < 1800
+#define fmax(a, b) std::max(a, b)
+#define fmin(a, b) std::min(a, b)
+#endif
+
+
 #endif /* POPPLER_CONFIG_H */
diff --git a/source/libs/poppler/poppler-src/splash/Splash.cc b/source/libs/poppler/poppler-src/splash/Splash.cc
new file mode 100644
index 0000000000000000000000000000000000000000..129d01f02ce847950c1bd905a9f35ce73fe1b9ba
--- /dev/null
+++ b/source/libs/poppler/poppler-src/splash/Splash.cc
@@ -0,0 +1,6479 @@
+//========================================================================
+//
+// Splash.cc
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005-2017 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2005 Marco Pesenti Gritti <mpg@redhat.com>
+// Copyright (C) 2010-2016 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2010 Christian Feuersänger <cfeuersaenger@googlemail.com>
+// Copyright (C) 2011-2013, 2015 William Bader <williambader@hotmail.com>
+// Copyright (C) 2012 Markus Trippelsdorf <markus@trippelsdorf.de>
+// Copyright (C) 2012, 2017 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2012 Matthias Kramm <kramm@quiss.org>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <assert.h>
+#include <math.h>
+#include "goo/gmem.h"
+#include "goo/GooLikely.h"
+#include "goo/GooList.h"
+#include "poppler/Error.h"
+#include "SplashErrorCodes.h"
+#include "SplashMath.h"
+#include "SplashBitmap.h"
+#include "SplashState.h"
+#include "SplashPath.h"
+#include "SplashXPath.h"
+#include "SplashXPathScanner.h"
+#include "SplashPattern.h"
+#include "SplashScreen.h"
+#include "SplashFont.h"
+#include "SplashGlyphBitmap.h"
+#include "Splash.h"
+#include <algorithm>
+
+//------------------------------------------------------------------------
+
+#define splashAAGamma 1.5
+
+// distance of Bezier control point from center for circle approximation
+// = (4 * (sqrt(2) - 1) / 3) * r
+#define bezierCircle ((SplashCoord)0.55228475)
+#define bezierCircle2 ((SplashCoord)(0.5 * 0.55228475))
+
+// Divide a 16-bit value (in [0, 255*255]) by 255, returning an 8-bit result.
+static inline Guchar div255(int x) {
+  return (Guchar)((x + (x >> 8) + 0x80) >> 8);
+}
+
+// Clip x to lie in [0, 255].
+static inline Guchar clip255(int x) {
+  return x < 0 ? 0 : x > 255 ? 255 : x;
+}
+
+template<typename T>
+inline void Guswap( T&a, T&b ) { T tmp = a; a=b; b=tmp; }
+
+// The PDF spec says that all pixels whose *centers* lie within the
+// image target region get painted, so we want to round n+0.5 down to
+// n.  But this causes problems, e.g., with PDF files that fill a
+// rectangle with black and then draw an image to the exact same
+// rectangle, so we instead use the fill scan conversion rule.
+// However, the correct rule works better for glyphs, so we also
+// provide that option in fillImageMask.
+#if 0
+static inline int imgCoordMungeLower(SplashCoord x) {
+  return splashCeil(x + 0.5) - 1;
+}
+static inline int imgCoordMungeUpper(SplashCoord x) {
+  return splashCeil(x + 0.5) - 1;
+}
+#else
+static inline int imgCoordMungeLower(SplashCoord x) {
+  return splashFloor(x);
+}
+static inline int imgCoordMungeUpper(SplashCoord x) {
+  return splashFloor(x) + 1;
+}
+static inline int imgCoordMungeLowerC(SplashCoord x, GBool glyphMode) {
+  return glyphMode ? (splashCeil(x + 0.5) - 1) : splashFloor(x);
+}
+static inline int imgCoordMungeUpperC(SplashCoord x, GBool glyphMode) {
+  return glyphMode ? (splashCeil(x + 0.5) - 1) : (splashFloor(x) + 1);
+}
+#endif
+
+// Used by drawImage and fillImageMask to divide the target
+// quadrilateral into sections.
+struct ImageSection {
+  int y0, y1;				// actual y range
+  int ia0, ia1;				// vertex indices for edge A
+  int ib0, ib1;				// vertex indices for edge A
+  SplashCoord xa0, ya0, xa1, ya1;	// edge A
+  SplashCoord dxdya;			// slope of edge A
+  SplashCoord xb0, yb0, xb1, yb1;	// edge B
+  SplashCoord dxdyb;			// slope of edge B
+};
+
+//------------------------------------------------------------------------
+// SplashPipe
+//------------------------------------------------------------------------
+
+#define splashPipeMaxStages 9
+
+struct SplashPipe {
+  // pixel coordinates
+  int x, y;
+
+  // source pattern
+  SplashPattern *pattern;
+
+  // source alpha and color
+  Guchar aInput;
+  GBool usesShape;
+  SplashColorPtr cSrc;
+  SplashColor cSrcVal;
+
+  // non-isolated group alpha0
+  Guchar *alpha0Ptr;
+
+  // knockout groups
+  GBool knockout;
+  Guchar knockoutOpacity;
+
+  // soft mask
+  SplashColorPtr softMaskPtr;
+
+  // destination alpha and color
+  SplashColorPtr destColorPtr;
+  int destColorMask;
+  Guchar *destAlphaPtr;
+
+  // shape
+  Guchar shape;
+
+  // result alpha and color
+  GBool noTransparency;
+  SplashPipeResultColorCtrl resultColorCtrl;
+
+  // non-isolated group correction
+  GBool nonIsolatedGroup;
+
+  // the "run" function
+  void (Splash::*run)(SplashPipe *pipe);
+};
+
+SplashPipeResultColorCtrl Splash::pipeResultColorNoAlphaBlend[] = {
+  splashPipeResultColorNoAlphaBlendMono,
+  splashPipeResultColorNoAlphaBlendMono,
+  splashPipeResultColorNoAlphaBlendRGB,
+  splashPipeResultColorNoAlphaBlendRGB,
+  splashPipeResultColorNoAlphaBlendRGB
+#ifdef SPLASH_CMYK
+  ,
+  splashPipeResultColorNoAlphaBlendCMYK,
+  splashPipeResultColorNoAlphaBlendDeviceN
+#endif
+};
+
+SplashPipeResultColorCtrl Splash::pipeResultColorAlphaNoBlend[] = {
+  splashPipeResultColorAlphaNoBlendMono,
+  splashPipeResultColorAlphaNoBlendMono,
+  splashPipeResultColorAlphaNoBlendRGB,
+  splashPipeResultColorAlphaNoBlendRGB,
+  splashPipeResultColorAlphaNoBlendRGB
+#ifdef SPLASH_CMYK
+  ,
+  splashPipeResultColorAlphaNoBlendCMYK,
+  splashPipeResultColorAlphaNoBlendDeviceN
+#endif
+};
+
+SplashPipeResultColorCtrl Splash::pipeResultColorAlphaBlend[] = {
+  splashPipeResultColorAlphaBlendMono,
+  splashPipeResultColorAlphaBlendMono,
+  splashPipeResultColorAlphaBlendRGB,
+  splashPipeResultColorAlphaBlendRGB,
+  splashPipeResultColorAlphaBlendRGB
+#ifdef SPLASH_CMYK
+  ,
+  splashPipeResultColorAlphaBlendCMYK,
+  splashPipeResultColorAlphaBlendDeviceN
+#endif
+};
+
+//------------------------------------------------------------------------
+
+static void blendXor(SplashColorPtr src, SplashColorPtr dest,
+		     SplashColorPtr blend, SplashColorMode cm) {
+  int i;
+
+  for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+    blend[i] = src[i] ^ dest[i];
+  }
+}
+
+//------------------------------------------------------------------------
+// modified region
+//------------------------------------------------------------------------
+
+void Splash::clearModRegion() {
+  modXMin = bitmap->getWidth();
+  modYMin = bitmap->getHeight();
+  modXMax = -1;
+  modYMax = -1;
+}
+
+inline void Splash::updateModX(int x) {
+  if (x < modXMin) {
+    modXMin = x;
+  }
+  if (x > modXMax) {
+    modXMax = x;
+  }
+}
+
+inline void Splash::updateModY(int y) {
+  if (y < modYMin) {
+    modYMin = y;
+  }
+  if (y > modYMax) {
+    modYMax = y;
+  }
+}
+
+//------------------------------------------------------------------------
+// pipeline
+//------------------------------------------------------------------------
+
+inline void Splash::pipeInit(SplashPipe *pipe, int x, int y,
+			     SplashPattern *pattern, SplashColorPtr cSrc,
+			     Guchar aInput, GBool usesShape,
+			     GBool nonIsolatedGroup,
+			     GBool knockout, Guchar knockoutOpacity) {
+  pipeSetXY(pipe, x, y);
+  pipe->pattern = NULL;
+
+  // source color
+  if (pattern) {
+    if (pattern->isStatic()) {
+      pattern->getColor(x, y, pipe->cSrcVal);
+    } else {
+      pipe->pattern = pattern;
+    }
+    pipe->cSrc = pipe->cSrcVal;
+  } else {
+    pipe->cSrc = cSrc;
+  }
+
+  // source alpha
+  pipe->aInput = aInput;
+  pipe->usesShape = usesShape;
+  pipe->shape = 0;
+
+  // knockout
+  pipe->knockout = knockout;
+  pipe->knockoutOpacity = knockoutOpacity;
+
+  // result alpha
+  if (aInput == 255 && !state->softMask && !usesShape &&
+      !state->inNonIsolatedGroup && !nonIsolatedGroup) {
+    pipe->noTransparency = gTrue;
+  } else {
+    pipe->noTransparency = gFalse;
+  }
+
+  // result color
+  if (pipe->noTransparency) {
+    // the !state->blendFunc case is handled separately in pipeRun
+    pipe->resultColorCtrl = pipeResultColorNoAlphaBlend[bitmap->mode];
+  } else if (!state->blendFunc) {
+    pipe->resultColorCtrl = pipeResultColorAlphaNoBlend[bitmap->mode];
+  } else {
+    pipe->resultColorCtrl = pipeResultColorAlphaBlend[bitmap->mode];
+  }
+
+  // non-isolated group correction
+  pipe->nonIsolatedGroup = nonIsolatedGroup;
+
+  // select the 'run' function
+  pipe->run = &Splash::pipeRun;
+  if (!pipe->pattern && pipe->noTransparency && !state->blendFunc) {
+    if (bitmap->mode == splashModeMono1 && !pipe->destAlphaPtr) {
+      pipe->run = &Splash::pipeRunSimpleMono1;
+    } else if (bitmap->mode == splashModeMono8 && pipe->destAlphaPtr) {
+      pipe->run = &Splash::pipeRunSimpleMono8;
+    } else if (bitmap->mode == splashModeRGB8 && pipe->destAlphaPtr) {
+      pipe->run = &Splash::pipeRunSimpleRGB8;
+    } else if (bitmap->mode == splashModeXBGR8 && pipe->destAlphaPtr) {
+      pipe->run = &Splash::pipeRunSimpleXBGR8;
+    } else if (bitmap->mode == splashModeBGR8 && pipe->destAlphaPtr) {
+      pipe->run = &Splash::pipeRunSimpleBGR8;
+#ifdef SPLASH_CMYK
+    } else if (bitmap->mode == splashModeCMYK8 && pipe->destAlphaPtr) {
+      pipe->run = &Splash::pipeRunSimpleCMYK8;
+    } else if (bitmap->mode == splashModeDeviceN8 && pipe->destAlphaPtr) {
+      pipe->run = &Splash::pipeRunSimpleDeviceN8;
+#endif
+    }
+  } else if (!pipe->pattern && !pipe->noTransparency && !state->softMask &&
+	     pipe->usesShape &&
+	     !(state->inNonIsolatedGroup && alpha0Bitmap->alpha) &&
+	     !state->blendFunc && !pipe->nonIsolatedGroup) {
+    if (bitmap->mode == splashModeMono1 && !pipe->destAlphaPtr) {
+      pipe->run = &Splash::pipeRunAAMono1;
+    } else if (bitmap->mode == splashModeMono8 && pipe->destAlphaPtr) {
+      pipe->run = &Splash::pipeRunAAMono8;
+    } else if (bitmap->mode == splashModeRGB8 && pipe->destAlphaPtr) {
+      pipe->run = &Splash::pipeRunAARGB8;
+    } else if (bitmap->mode == splashModeXBGR8 && pipe->destAlphaPtr) {
+      pipe->run = &Splash::pipeRunAAXBGR8;
+    } else if (bitmap->mode == splashModeBGR8 && pipe->destAlphaPtr) {
+      pipe->run = &Splash::pipeRunAABGR8;
+#ifdef SPLASH_CMYK
+    } else if (bitmap->mode == splashModeCMYK8 && pipe->destAlphaPtr) {
+      pipe->run = &Splash::pipeRunAACMYK8;
+    } else if (bitmap->mode == splashModeDeviceN8 && pipe->destAlphaPtr) {
+      pipe->run = &Splash::pipeRunAADeviceN8;
+#endif
+    }
+  }
+}
+
+// general case
+void Splash::pipeRun(SplashPipe *pipe) {
+  Guchar aSrc, aDest, alphaI, alphaIm1, alpha0, aResult;
+  SplashColor cSrcNonIso, cDest, cBlend;
+  SplashColorPtr cSrc;
+  Guchar cResult0, cResult1, cResult2, cResult3;
+  int t;
+#ifdef SPLASH_CMYK
+  int cp, mask;
+  Guchar cResult[SPOT_NCOMPS+4];
+#endif
+
+  //----- source color
+
+  // static pattern: handled in pipeInit
+  // fixed color: handled in pipeInit
+
+  // dynamic pattern
+  if (pipe->pattern) {
+    if (!pipe->pattern->getColor(pipe->x, pipe->y, pipe->cSrcVal)) {
+      pipeIncX(pipe);
+      return;
+    }
+#ifdef SPLASH_CMYK
+    if (bitmap->mode == splashModeCMYK8 || bitmap->mode == splashModeDeviceN8) {
+      if (state->fillOverprint && state->overprintMode && pipe->pattern->isCMYK()) {
+        Guint mask = 15;
+        if (pipe->cSrcVal[0] == 0) {
+          mask &= ~1;
+        }
+        if (pipe->cSrcVal[1] == 0) {
+          mask &= ~2;
+        }
+        if (pipe->cSrcVal[2] == 0) {
+          mask &= ~4;
+        }
+        if (pipe->cSrcVal[3] == 0) {
+          mask &= ~8;
+        }
+        state->overprintMask = mask;
+      }
+    }
+#endif
+  }
+
+  if (pipe->noTransparency && !state->blendFunc) {
+
+    //----- write destination pixel
+
+    switch (bitmap->mode) {
+    case splashModeMono1:
+      cResult0 = state->grayTransfer[pipe->cSrc[0]];
+      if (state->screen->test(pipe->x, pipe->y, cResult0)) {
+	*pipe->destColorPtr |= pipe->destColorMask;
+      } else {
+	*pipe->destColorPtr &= ~pipe->destColorMask;
+      }
+      if (!(pipe->destColorMask >>= 1)) {
+	pipe->destColorMask = 0x80;
+	++pipe->destColorPtr;
+      }
+      break;
+    case splashModeMono8:
+      *pipe->destColorPtr++ = state->grayTransfer[pipe->cSrc[0]];
+      break;
+    case splashModeRGB8:
+      *pipe->destColorPtr++ = state->rgbTransferR[pipe->cSrc[0]];
+      *pipe->destColorPtr++ = state->rgbTransferG[pipe->cSrc[1]];
+      *pipe->destColorPtr++ = state->rgbTransferB[pipe->cSrc[2]];
+      break;
+    case splashModeXBGR8:
+      *pipe->destColorPtr++ = state->rgbTransferB[pipe->cSrc[2]];
+      *pipe->destColorPtr++ = state->rgbTransferG[pipe->cSrc[1]];
+      *pipe->destColorPtr++ = state->rgbTransferR[pipe->cSrc[0]];
+      *pipe->destColorPtr++ = 255;
+      break;
+    case splashModeBGR8:
+      *pipe->destColorPtr++ = state->rgbTransferB[pipe->cSrc[2]];
+      *pipe->destColorPtr++ = state->rgbTransferG[pipe->cSrc[1]];
+      *pipe->destColorPtr++ = state->rgbTransferR[pipe->cSrc[0]];
+      break;
+#ifdef SPLASH_CMYK
+    case splashModeCMYK8:
+      if (state->overprintMask & 1) {
+	pipe->destColorPtr[0] = (state->overprintAdditive) ? 
+              std::min<int>(pipe->destColorPtr[0] + state->cmykTransferC[pipe->cSrc[0]], 255) :
+              state->cmykTransferC[pipe->cSrc[0]];
+      }
+      if (state->overprintMask & 2) {
+	pipe->destColorPtr[1] = (state->overprintAdditive) ? 
+              std::min<int>(pipe->destColorPtr[1] + state->cmykTransferM[pipe->cSrc[1]], 255) :
+              state->cmykTransferM[pipe->cSrc[1]];
+      }
+      if (state->overprintMask & 4) {
+	pipe->destColorPtr[2] = (state->overprintAdditive) ? 
+              std::min<int>(pipe->destColorPtr[2] + state->cmykTransferY[pipe->cSrc[2]], 255) :
+              state->cmykTransferY[pipe->cSrc[2]];
+      }
+      if (state->overprintMask & 8) {
+	pipe->destColorPtr[3] = (state->overprintAdditive) ? 
+              std::min<int>(pipe->destColorPtr[3] + state->cmykTransferK[pipe->cSrc[3]], 255) :
+              state->cmykTransferK[pipe->cSrc[3]];
+      }
+      pipe->destColorPtr += 4;
+      break;
+    case splashModeDeviceN8:
+      mask = 1;
+      for (cp = 0; cp < SPOT_NCOMPS + 4; cp ++) {
+        if (state->overprintMask & mask) {
+          pipe->destColorPtr[cp] = state->deviceNTransfer[cp][pipe->cSrc[cp]];
+        }
+        mask <<= 1;
+      }
+      pipe->destColorPtr += (SPOT_NCOMPS+4);
+      break;
+#endif
+    }
+    if (pipe->destAlphaPtr) {
+      *pipe->destAlphaPtr++ = 255;
+    }
+
+  } else {
+
+    //----- read destination pixel
+
+    Guchar *destColorPtr;
+    if (pipe->shape && state->blendFunc && pipe->knockout && alpha0Bitmap != NULL) {
+      destColorPtr = alpha0Bitmap->data + (alpha0Y+pipe->y)*alpha0Bitmap->rowSize;
+      switch (bitmap->mode) {
+        case splashModeMono1:
+          destColorPtr += (alpha0X+pipe->x) / 8;
+          break;
+        case splashModeMono8:
+          destColorPtr += (alpha0X+pipe->x);
+          break;
+        case splashModeRGB8:
+        case splashModeBGR8:
+          destColorPtr += (alpha0X+pipe->x) * 3;
+          break;
+        case splashModeXBGR8:
+#ifdef SPLASH_CMYK
+        case splashModeCMYK8:
+#endif
+          destColorPtr += (alpha0X+pipe->x) * 4;
+          break;
+#ifdef SPLASH_CMYK
+        case splashModeDeviceN8:
+          destColorPtr += (alpha0X+pipe->x) * (SPOT_NCOMPS + 4);
+          break;
+#endif
+      }
+    } else {
+      destColorPtr = pipe->destColorPtr;
+    }
+    switch (bitmap->mode) {
+    case splashModeMono1:
+      cDest[0] = (*destColorPtr & pipe->destColorMask) ? 0xff : 0x00;
+      break;
+    case splashModeMono8:
+      cDest[0] = *destColorPtr;
+      break;
+    case splashModeRGB8:
+      cDest[0] = destColorPtr[0];
+      cDest[1] = destColorPtr[1];
+      cDest[2] = destColorPtr[2];
+      break;
+    case splashModeXBGR8:
+      cDest[0] = destColorPtr[2];
+      cDest[1] = destColorPtr[1];
+      cDest[2] = destColorPtr[0];
+      cDest[3] = 255;
+      break;
+    case splashModeBGR8:
+      cDest[0] = destColorPtr[2];
+      cDest[1] = destColorPtr[1];
+      cDest[2] = destColorPtr[0];
+      break;
+#ifdef SPLASH_CMYK
+    case splashModeCMYK8:
+      cDest[0] = destColorPtr[0];
+      cDest[1] = destColorPtr[1];
+      cDest[2] = destColorPtr[2];
+      cDest[3] = destColorPtr[3];
+      break;
+    case splashModeDeviceN8:
+      for (cp = 0; cp < SPOT_NCOMPS + 4; cp++)
+        cDest[cp] = destColorPtr[cp];
+      break;
+#endif
+    }
+    if (pipe->destAlphaPtr) {
+      aDest = *pipe->destAlphaPtr;
+    } else {
+      aDest = 0xff;
+    }
+
+    //----- source alpha
+
+    if (state->softMask) {
+      if (pipe->usesShape) {
+	aSrc = div255(div255(pipe->aInput * *pipe->softMaskPtr++) *
+		      pipe->shape);
+      } else {
+	aSrc = div255(pipe->aInput * *pipe->softMaskPtr++);
+      }
+    } else if (pipe->usesShape) {
+      aSrc = div255(pipe->aInput * pipe->shape);
+    } else {
+      aSrc = pipe->aInput;
+    }
+
+    //----- non-isolated group correction
+
+    if (pipe->nonIsolatedGroup) {
+      // This path is only used when Splash::composite() is called to
+      // composite a non-isolated group onto the backdrop.  In this
+      // case, pipe->shape is the source (group) alpha.
+      if (pipe->shape == 0) {
+	// this value will be multiplied by zero later, so it doesn't
+	// matter what we use
+	cSrc = pipe->cSrc;
+      } else {
+	t = (aDest * 255) / pipe->shape - aDest;
+	switch (bitmap->mode) {
+#ifdef SPLASH_CMYK
+	case splashModeDeviceN8:
+	  for (cp = 0; cp < SPOT_NCOMPS + 4; cp++)
+	    cSrcNonIso[cp] = clip255(pipe->cSrc[cp] +
+				  ((pipe->cSrc[cp] - cDest[cp]) * t) / 255);
+	  break;
+	case splashModeCMYK8:
+	  for (cp = 0; cp < 4; cp++)
+	    cSrcNonIso[cp] = clip255(pipe->cSrc[cp] +
+				  ((pipe->cSrc[cp] - cDest[cp]) * t) / 255);
+	  break;
+#endif
+	case splashModeXBGR8:
+	  cSrcNonIso[3] = 255;
+      // fallthrough
+	case splashModeRGB8:
+	case splashModeBGR8:
+	  cSrcNonIso[2] = clip255(pipe->cSrc[2] +
+				  ((pipe->cSrc[2] - cDest[2]) * t) / 255);
+	  cSrcNonIso[1] = clip255(pipe->cSrc[1] +
+				  ((pipe->cSrc[1] - cDest[1]) * t) / 255);
+      // fallthrough
+	case splashModeMono1:
+	case splashModeMono8:
+	  cSrcNonIso[0] = clip255(pipe->cSrc[0] +
+				  ((pipe->cSrc[0] - cDest[0]) * t) / 255);
+	  break;
+	}
+	cSrc = cSrcNonIso;
+        // knockout: remove backdrop color
+        if (pipe->knockout && pipe->shape >= pipe->knockoutOpacity) {
+          aDest = 0;
+        }
+      }
+    } else {
+      cSrc = pipe->cSrc;
+    }
+
+    //----- blend function
+
+    if (state->blendFunc) {
+#ifdef SPLASH_CMYK
+      if (bitmap->mode == splashModeDeviceN8) {
+        for (int k = 4; k < 4 + SPOT_NCOMPS; k++) {
+          cBlend[k] = 0;
+        }
+      }
+#endif
+      (*state->blendFunc)(cSrc, cDest, cBlend, bitmap->mode);
+    }
+
+    //----- result alpha and non-isolated group element correction
+
+    if (pipe->noTransparency) {
+      alphaI = alphaIm1 = aResult = 255;
+    } else {
+      aResult = aSrc + aDest - div255(aSrc * aDest);
+
+      // alphaI = alpha_i
+      // alphaIm1 = alpha_(i-1)
+      if (pipe->alpha0Ptr) {
+	alpha0 = *pipe->alpha0Ptr++;
+	alphaI = aResult + alpha0 - div255(aResult * alpha0);
+	alphaIm1 = alpha0 + aDest - div255(alpha0 * aDest);
+      } else {
+	alphaI = aResult;
+	alphaIm1 = aDest;
+      }
+    }
+
+    //----- result color
+
+    cResult0 = cResult1 = cResult2 = cResult3 = 0; // make gcc happy
+
+    switch (pipe->resultColorCtrl) {
+
+    case splashPipeResultColorNoAlphaBlendMono:
+      cResult0 = state->grayTransfer[div255((255 - aDest) * cSrc[0] +
+					    aDest * cBlend[0])];
+      break;
+    case splashPipeResultColorNoAlphaBlendRGB:
+      cResult0 = state->rgbTransferR[div255((255 - aDest) * cSrc[0] +
+					    aDest * cBlend[0])];
+      cResult1 = state->rgbTransferG[div255((255 - aDest) * cSrc[1] +
+					    aDest * cBlend[1])];
+      cResult2 = state->rgbTransferB[div255((255 - aDest) * cSrc[2] +
+					    aDest * cBlend[2])];
+      break;
+#ifdef SPLASH_CMYK
+    case splashPipeResultColorNoAlphaBlendCMYK:
+      cResult0 = state->cmykTransferC[div255((255 - aDest) * cSrc[0] +
+					     aDest * cBlend[0])];
+      cResult1 = state->cmykTransferM[div255((255 - aDest) * cSrc[1] +
+					     aDest * cBlend[1])];
+      cResult2 = state->cmykTransferY[div255((255 - aDest) * cSrc[2] +
+					     aDest * cBlend[2])];
+      cResult3 = state->cmykTransferK[div255((255 - aDest) * cSrc[3] +
+					     aDest * cBlend[3])];
+      break;
+    case splashPipeResultColorNoAlphaBlendDeviceN:
+      for (cp = 0; cp < SPOT_NCOMPS+4; cp++)
+        cResult[cp] = state->deviceNTransfer[cp][div255((255 - aDest) * cSrc[cp] +
+					     aDest * cBlend[cp])];
+      break;
+#endif
+
+    case splashPipeResultColorAlphaNoBlendMono:
+      if (alphaI == 0) {
+	cResult0 = 0;
+      } else {
+	cResult0 = state->grayTransfer[((alphaI - aSrc) * cDest[0] +
+					aSrc * cSrc[0]) / alphaI];
+      }
+      break;
+    case splashPipeResultColorAlphaNoBlendRGB:
+      if (alphaI == 0) {
+	cResult0 = 0;
+	cResult1 = 0;
+	cResult2 = 0;
+      } else {
+	cResult0 = state->rgbTransferR[((alphaI - aSrc) * cDest[0] +
+					aSrc * cSrc[0]) / alphaI];
+	cResult1 = state->rgbTransferG[((alphaI - aSrc) * cDest[1] +
+					aSrc * cSrc[1]) / alphaI];
+	cResult2 = state->rgbTransferB[((alphaI - aSrc) * cDest[2] +
+					aSrc * cSrc[2]) / alphaI];
+      }
+      break;
+#ifdef SPLASH_CMYK
+    case splashPipeResultColorAlphaNoBlendCMYK:
+      if (alphaI == 0) {
+	cResult0 = 0;
+	cResult1 = 0;
+	cResult2 = 0;
+	cResult3 = 0;
+      } else {
+	cResult0 = state->cmykTransferC[((alphaI - aSrc) * cDest[0] +
+					 aSrc * cSrc[0]) / alphaI];
+	cResult1 = state->cmykTransferM[((alphaI - aSrc) * cDest[1] +
+					 aSrc * cSrc[1]) / alphaI];
+	cResult2 = state->cmykTransferY[((alphaI - aSrc) * cDest[2] +
+					 aSrc * cSrc[2]) / alphaI];
+	cResult3 = state->cmykTransferK[((alphaI - aSrc) * cDest[3] +
+					 aSrc * cSrc[3]) / alphaI];
+      }
+      break;
+    case splashPipeResultColorAlphaNoBlendDeviceN:
+      if (alphaI == 0) {
+        for (cp = 0; cp < SPOT_NCOMPS+4; cp++)
+          cResult[cp] = 0;
+      } else {
+        for (cp = 0; cp < SPOT_NCOMPS+4; cp++)
+          cResult[cp] = state->deviceNTransfer[cp][((alphaI - aSrc) * cDest[cp] +
+					 aSrc * cSrc[cp]) / alphaI];
+      }
+      break;
+#endif
+
+    case splashPipeResultColorAlphaBlendMono:
+      if (alphaI == 0) {
+	cResult0 = 0;
+      } else {
+	cResult0 = state->grayTransfer[((alphaI - aSrc) * cDest[0] +
+					aSrc * ((255 - alphaIm1) * cSrc[0] +
+						alphaIm1 * cBlend[0]) / 255) /
+				       alphaI];
+      }
+      break;
+    case splashPipeResultColorAlphaBlendRGB:
+      if (alphaI == 0) {
+	cResult0 = 0;
+	cResult1 = 0;
+	cResult2 = 0;
+      } else {
+	cResult0 = state->rgbTransferR[((alphaI - aSrc) * cDest[0] +
+					aSrc * ((255 - alphaIm1) * cSrc[0] +
+						alphaIm1 * cBlend[0]) / 255) /
+				       alphaI];
+	cResult1 = state->rgbTransferG[((alphaI - aSrc) * cDest[1] +
+					aSrc * ((255 - alphaIm1) * cSrc[1] +
+						alphaIm1 * cBlend[1]) / 255) /
+				       alphaI];
+	cResult2 = state->rgbTransferB[((alphaI - aSrc) * cDest[2] +
+					aSrc * ((255 - alphaIm1) * cSrc[2] +
+						alphaIm1 * cBlend[2]) / 255) /
+				       alphaI];
+      }
+      break;
+#ifdef SPLASH_CMYK
+    case splashPipeResultColorAlphaBlendCMYK:
+      if (alphaI == 0) {
+	cResult0 = 0;
+	cResult1 = 0;
+	cResult2 = 0;
+	cResult3 = 0;
+      } else {
+	cResult0 = state->cmykTransferC[((alphaI - aSrc) * cDest[0] +
+					 aSrc * ((255 - alphaIm1) * cSrc[0] +
+						 alphaIm1 * cBlend[0]) / 255) /
+					alphaI];
+	cResult1 = state->cmykTransferM[((alphaI - aSrc) * cDest[1] +
+					 aSrc * ((255 - alphaIm1) * cSrc[1] +
+						 alphaIm1 * cBlend[1]) / 255) /
+					alphaI];
+	cResult2 = state->cmykTransferY[((alphaI - aSrc) * cDest[2] +
+					 aSrc * ((255 - alphaIm1) * cSrc[2] +
+						 alphaIm1 * cBlend[2]) / 255) /
+					alphaI];
+	cResult3 = state->cmykTransferK[((alphaI - aSrc) * cDest[3] +
+					 aSrc * ((255 - alphaIm1) * cSrc[3] +
+						 alphaIm1 * cBlend[3]) / 255) /
+					alphaI];
+      }
+      break;
+    case splashPipeResultColorAlphaBlendDeviceN:
+      if (alphaI == 0) {
+        for (cp = 0; cp < SPOT_NCOMPS+4; cp++)
+          cResult[cp] = 0;
+      } else {
+        for (cp = 0; cp < SPOT_NCOMPS+4; cp++)
+          cResult[cp] = state->deviceNTransfer[cp][((alphaI - aSrc) * cDest[cp] +
+            aSrc * ((255 - alphaIm1) * cSrc[cp] +
+						alphaIm1 * cBlend[cp]) / 255) /
+					  alphaI];
+      }
+      break;
+#endif
+    }
+
+    //----- write destination pixel
+
+    switch (bitmap->mode) {
+    case splashModeMono1:
+      if (state->screen->test(pipe->x, pipe->y, cResult0)) {
+	*pipe->destColorPtr |= pipe->destColorMask;
+      } else {
+	*pipe->destColorPtr &= ~pipe->destColorMask;
+      }
+      if (!(pipe->destColorMask >>= 1)) {
+	pipe->destColorMask = 0x80;
+	++pipe->destColorPtr;
+      }
+      break;
+    case splashModeMono8:
+      *pipe->destColorPtr++ = cResult0;
+      break;
+    case splashModeRGB8:
+      *pipe->destColorPtr++ = cResult0;
+      *pipe->destColorPtr++ = cResult1;
+      *pipe->destColorPtr++ = cResult2;
+      break;
+    case splashModeXBGR8:
+      *pipe->destColorPtr++ = cResult2;
+      *pipe->destColorPtr++ = cResult1;
+      *pipe->destColorPtr++ = cResult0;
+      *pipe->destColorPtr++ = 255;
+      break;
+    case splashModeBGR8:
+      *pipe->destColorPtr++ = cResult2;
+      *pipe->destColorPtr++ = cResult1;
+      *pipe->destColorPtr++ = cResult0;
+      break;
+#ifdef SPLASH_CMYK
+    case splashModeCMYK8:
+      if (state->overprintMask & 1) {
+	pipe->destColorPtr[0] = (state->overprintAdditive) ? 
+              std::min<int>(pipe->destColorPtr[0] + cResult0, 255) :
+              cResult0;
+      }
+      if (state->overprintMask & 2) {
+	pipe->destColorPtr[1] = (state->overprintAdditive) ? 
+              std::min<int>(pipe->destColorPtr[1] + cResult1, 255) :
+              cResult1;
+      }
+      if (state->overprintMask & 4) {
+	pipe->destColorPtr[2] = (state->overprintAdditive) ? 
+              std::min<int>(pipe->destColorPtr[2] + cResult2, 255) :
+              cResult2;
+      }
+      if (state->overprintMask & 8) {
+	pipe->destColorPtr[3] = (state->overprintAdditive) ? 
+              std::min<int>(pipe->destColorPtr[3] + cResult3, 255) :
+              cResult3;
+      }
+      pipe->destColorPtr += 4;
+      break;
+    case splashModeDeviceN8:
+      mask = 1;
+      for (cp = 0; cp < SPOT_NCOMPS+4; cp++) {
+        if (state->overprintMask & mask) {
+          pipe->destColorPtr[cp] = cResult[cp];
+        }
+        mask <<=1;
+      }
+      pipe->destColorPtr += (SPOT_NCOMPS+4);
+      break;
+#endif
+    }
+    if (pipe->destAlphaPtr) {
+      *pipe->destAlphaPtr++ = aResult;
+    }
+
+  }
+
+  ++pipe->x;
+}
+
+// special case:
+// !pipe->pattern && pipe->noTransparency && !state->blendFunc &&
+// bitmap->mode == splashModeMono1 && !pipe->destAlphaPtr) {
+void Splash::pipeRunSimpleMono1(SplashPipe *pipe) {
+  Guchar cResult0;
+
+  //----- write destination pixel
+  cResult0 = state->grayTransfer[pipe->cSrc[0]];
+  if (state->screen->test(pipe->x, pipe->y, cResult0)) {
+    *pipe->destColorPtr |= pipe->destColorMask;
+  } else {
+    *pipe->destColorPtr &= ~pipe->destColorMask;
+  }
+  if (!(pipe->destColorMask >>= 1)) {
+    pipe->destColorMask = 0x80;
+    ++pipe->destColorPtr;
+  }
+
+  ++pipe->x;
+}
+
+// special case:
+// !pipe->pattern && pipe->noTransparency && !state->blendFunc &&
+// bitmap->mode == splashModeMono8 && pipe->destAlphaPtr) {
+void Splash::pipeRunSimpleMono8(SplashPipe *pipe) {
+  //----- write destination pixel
+  *pipe->destColorPtr++ = state->grayTransfer[pipe->cSrc[0]];
+  *pipe->destAlphaPtr++ = 255;
+
+  ++pipe->x;
+}
+
+// special case:
+// !pipe->pattern && pipe->noTransparency && !state->blendFunc &&
+// bitmap->mode == splashModeRGB8 && pipe->destAlphaPtr) {
+void Splash::pipeRunSimpleRGB8(SplashPipe *pipe) {
+  //----- write destination pixel
+  *pipe->destColorPtr++ = state->rgbTransferR[pipe->cSrc[0]];
+  *pipe->destColorPtr++ = state->rgbTransferG[pipe->cSrc[1]];
+  *pipe->destColorPtr++ = state->rgbTransferB[pipe->cSrc[2]];
+  *pipe->destAlphaPtr++ = 255;
+
+  ++pipe->x;
+}
+
+// special case:
+// !pipe->pattern && pipe->noTransparency && !state->blendFunc &&
+// bitmap->mode == splashModeXBGR8 && pipe->destAlphaPtr) {
+void Splash::pipeRunSimpleXBGR8(SplashPipe *pipe) {
+  //----- write destination pixel
+  *pipe->destColorPtr++ = state->rgbTransferB[pipe->cSrc[2]];
+  *pipe->destColorPtr++ = state->rgbTransferG[pipe->cSrc[1]];
+  *pipe->destColorPtr++ = state->rgbTransferR[pipe->cSrc[0]];
+  *pipe->destColorPtr++ = 255;
+  *pipe->destAlphaPtr++ = 255;
+
+  ++pipe->x;
+}
+
+// special case:
+// !pipe->pattern && pipe->noTransparency && !state->blendFunc &&
+// bitmap->mode == splashModeBGR8 && pipe->destAlphaPtr) {
+void Splash::pipeRunSimpleBGR8(SplashPipe *pipe) {
+  //----- write destination pixel
+  *pipe->destColorPtr++ = state->rgbTransferB[pipe->cSrc[2]];
+  *pipe->destColorPtr++ = state->rgbTransferG[pipe->cSrc[1]];
+  *pipe->destColorPtr++ = state->rgbTransferR[pipe->cSrc[0]];
+  *pipe->destAlphaPtr++ = 255;
+
+  ++pipe->x;
+}
+
+#ifdef SPLASH_CMYK
+// special case:
+// !pipe->pattern && pipe->noTransparency && !state->blendFunc &&
+// bitmap->mode == splashModeCMYK8 && pipe->destAlphaPtr) {
+void Splash::pipeRunSimpleCMYK8(SplashPipe *pipe) {
+  //----- write destination pixel
+  if (state->overprintMask & 1) {
+    pipe->destColorPtr[0] = (state->overprintAdditive) ? 
+              std::min<int>(pipe->destColorPtr[0] + state->cmykTransferC[pipe->cSrc[0]], 255) :
+              state->cmykTransferC[pipe->cSrc[0]];
+  }
+  if (state->overprintMask & 2) {
+    pipe->destColorPtr[1] = (state->overprintAdditive) ? 
+              std::min<int>(pipe->destColorPtr[1] + state->cmykTransferM[pipe->cSrc[1]], 255) :
+              state->cmykTransferM[pipe->cSrc[1]];
+  }
+  if (state->overprintMask & 4) {
+    pipe->destColorPtr[2] = (state->overprintAdditive) ? 
+              std::min<int>(pipe->destColorPtr[2] + state->cmykTransferY[pipe->cSrc[2]], 255) :
+              state->cmykTransferY[pipe->cSrc[2]];
+  }
+  if (state->overprintMask & 8) {
+    pipe->destColorPtr[3] = (state->overprintAdditive) ? 
+              std::min<int>(pipe->destColorPtr[3] + state->cmykTransferK[pipe->cSrc[3]], 255) :
+              state->cmykTransferK[pipe->cSrc[3]];
+  }
+  pipe->destColorPtr += 4;
+  *pipe->destAlphaPtr++ = 255;
+
+  ++pipe->x;
+}
+
+// special case:
+// !pipe->pattern && pipe->noTransparency && !state->blendFunc &&
+// bitmap->mode == splashModeDeviceN8 && pipe->destAlphaPtr) {
+void Splash::pipeRunSimpleDeviceN8(SplashPipe *pipe) {
+  //----- write destination pixel
+  int mask = 1;
+  for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) {
+    if (state->overprintMask & mask) {
+      pipe->destColorPtr[cp] = state->deviceNTransfer[cp][pipe->cSrc[cp]];
+    }
+    mask <<=1;
+  }
+  pipe->destColorPtr += (SPOT_NCOMPS+4);
+  *pipe->destAlphaPtr++ = 255;
+
+  ++pipe->x;
+}
+#endif
+
+// special case:
+// !pipe->pattern && !pipe->noTransparency && !state->softMask &&
+// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
+// !pipe->nonIsolatedGroup &&
+// bitmap->mode == splashModeMono1 && !pipe->destAlphaPtr
+void Splash::pipeRunAAMono1(SplashPipe *pipe) {
+  Guchar aSrc;
+  SplashColor cDest;
+  Guchar cResult0;
+
+  //----- read destination pixel
+  cDest[0] = (*pipe->destColorPtr & pipe->destColorMask) ? 0xff : 0x00;
+
+  //----- source alpha
+  aSrc = div255(pipe->aInput * pipe->shape);
+
+  //----- result color
+  // note: aDest = alpha2 = aResult = 0xff
+  cResult0 = state->grayTransfer[(Guchar)div255((0xff - aSrc) * cDest[0] +
+						aSrc * pipe->cSrc[0])];
+
+  //----- write destination pixel
+  if (state->screen->test(pipe->x, pipe->y, cResult0)) {
+    *pipe->destColorPtr |= pipe->destColorMask;
+  } else {
+    *pipe->destColorPtr &= ~pipe->destColorMask;
+  }
+  if (!(pipe->destColorMask >>= 1)) {
+    pipe->destColorMask = 0x80;
+    ++pipe->destColorPtr;
+  }
+
+  ++pipe->x;
+}
+
+// special case:
+// !pipe->pattern && !pipe->noTransparency && !state->softMask &&
+// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
+// !pipe->nonIsolatedGroup &&
+// bitmap->mode == splashModeMono8 && pipe->destAlphaPtr
+void Splash::pipeRunAAMono8(SplashPipe *pipe) {
+  Guchar aSrc, aDest, alpha2, aResult;
+  SplashColor cDest;
+  Guchar cResult0;
+
+  //----- read destination pixel
+  cDest[0] = *pipe->destColorPtr;
+  aDest = *pipe->destAlphaPtr;
+
+  //----- source alpha
+  aSrc = div255(pipe->aInput * pipe->shape);
+
+  //----- result alpha and non-isolated group element correction
+  aResult = aSrc + aDest - div255(aSrc * aDest);
+  alpha2 = aResult;
+
+  //----- result color
+  if (alpha2 == 0) {
+    cResult0 = 0;
+  } else {
+    cResult0 = state->grayTransfer[(Guchar)(((alpha2 - aSrc) * cDest[0] +
+					     aSrc * pipe->cSrc[0]) / alpha2)];
+  }
+
+  //----- write destination pixel
+  *pipe->destColorPtr++ = cResult0;
+  *pipe->destAlphaPtr++ = aResult;
+
+  ++pipe->x;
+}
+
+// special case:
+// !pipe->pattern && !pipe->noTransparency && !state->softMask &&
+// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
+// !pipe->nonIsolatedGroup &&
+// bitmap->mode == splashModeRGB8 && pipe->destAlphaPtr
+void Splash::pipeRunAARGB8(SplashPipe *pipe) {
+  Guchar aSrc, aDest, alpha2, aResult;
+  SplashColor cDest;
+  Guchar cResult0, cResult1, cResult2;
+
+  //----- read destination pixel
+  cDest[0] = pipe->destColorPtr[0];
+  cDest[1] = pipe->destColorPtr[1];
+  cDest[2] = pipe->destColorPtr[2];
+  aDest = *pipe->destAlphaPtr;
+
+  //----- source alpha
+  aSrc = div255(pipe->aInput * pipe->shape);
+
+  //----- result alpha and non-isolated group element correction
+  aResult = aSrc + aDest - div255(aSrc * aDest);
+  alpha2 = aResult;
+
+  //----- result color
+  if (alpha2 == 0) {
+    cResult0 = 0;
+    cResult1 = 0;
+    cResult2 = 0;
+  } else {
+    cResult0 = state->rgbTransferR[(Guchar)(((alpha2 - aSrc) * cDest[0] +
+					     aSrc * pipe->cSrc[0]) / alpha2)];
+    cResult1 = state->rgbTransferG[(Guchar)(((alpha2 - aSrc) * cDest[1] +
+					     aSrc * pipe->cSrc[1]) / alpha2)];
+    cResult2 = state->rgbTransferB[(Guchar)(((alpha2 - aSrc) * cDest[2] +
+					     aSrc * pipe->cSrc[2]) / alpha2)];
+  }
+
+  //----- write destination pixel
+  *pipe->destColorPtr++ = cResult0;
+  *pipe->destColorPtr++ = cResult1;
+  *pipe->destColorPtr++ = cResult2;
+  *pipe->destAlphaPtr++ = aResult;
+
+  ++pipe->x;
+}
+
+// special case:
+// !pipe->pattern && !pipe->noTransparency && !state->softMask &&
+// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
+// !pipe->nonIsolatedGroup &&
+// bitmap->mode == splashModeXBGR8 && pipe->destAlphaPtr
+void Splash::pipeRunAAXBGR8(SplashPipe *pipe) {
+  Guchar aSrc, aDest, alpha2, aResult;
+  SplashColor cDest;
+  Guchar cResult0, cResult1, cResult2;
+
+  //----- read destination pixel
+  cDest[0] = pipe->destColorPtr[2];
+  cDest[1] = pipe->destColorPtr[1];
+  cDest[2] = pipe->destColorPtr[0];
+  aDest = *pipe->destAlphaPtr;
+
+  //----- source alpha
+  aSrc = div255(pipe->aInput * pipe->shape);
+
+  //----- result alpha and non-isolated group element correction
+  aResult = aSrc + aDest - div255(aSrc * aDest);
+  alpha2 = aResult;
+
+  //----- result color
+  if (alpha2 == 0) {
+    cResult0 = 0;
+    cResult1 = 0;
+    cResult2 = 0;
+  } else {
+    cResult0 = state->rgbTransferR[(Guchar)(((alpha2 - aSrc) * cDest[0] +
+					     aSrc * pipe->cSrc[0]) / alpha2)];
+    cResult1 = state->rgbTransferG[(Guchar)(((alpha2 - aSrc) * cDest[1] +
+					     aSrc * pipe->cSrc[1]) / alpha2)];
+    cResult2 = state->rgbTransferB[(Guchar)(((alpha2 - aSrc) * cDest[2] +
+					     aSrc * pipe->cSrc[2]) / alpha2)];
+  }
+
+  //----- write destination pixel
+  *pipe->destColorPtr++ = cResult2;
+  *pipe->destColorPtr++ = cResult1;
+  *pipe->destColorPtr++ = cResult0;
+  *pipe->destColorPtr++ = 255;
+  *pipe->destAlphaPtr++ = aResult;
+
+  ++pipe->x;
+}
+
+// special case:
+// !pipe->pattern && !pipe->noTransparency && !state->softMask &&
+// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
+// !pipe->nonIsolatedGroup &&
+// bitmap->mode == splashModeBGR8 && pipe->destAlphaPtr
+void Splash::pipeRunAABGR8(SplashPipe *pipe) {
+  Guchar aSrc, aDest, alpha2, aResult;
+  SplashColor cDest;
+  Guchar cResult0, cResult1, cResult2;
+
+  //----- read destination pixel
+  cDest[0] = pipe->destColorPtr[2];
+  cDest[1] = pipe->destColorPtr[1];
+  cDest[2] = pipe->destColorPtr[0];
+  aDest = *pipe->destAlphaPtr;
+
+  //----- source alpha
+  aSrc = div255(pipe->aInput * pipe->shape);
+
+  //----- result alpha and non-isolated group element correction
+  aResult = aSrc + aDest - div255(aSrc * aDest);
+  alpha2 = aResult;
+
+  //----- result color
+  if (alpha2 == 0) {
+    cResult0 = 0;
+    cResult1 = 0;
+    cResult2 = 0;
+  } else {
+    cResult0 = state->rgbTransferR[(Guchar)(((alpha2 - aSrc) * cDest[0] +
+					     aSrc * pipe->cSrc[0]) / alpha2)];
+    cResult1 = state->rgbTransferG[(Guchar)(((alpha2 - aSrc) * cDest[1] +
+					     aSrc * pipe->cSrc[1]) / alpha2)];
+    cResult2 = state->rgbTransferB[(Guchar)(((alpha2 - aSrc) * cDest[2] +
+					     aSrc * pipe->cSrc[2]) / alpha2)];
+  }
+
+  //----- write destination pixel
+  *pipe->destColorPtr++ = cResult2;
+  *pipe->destColorPtr++ = cResult1;
+  *pipe->destColorPtr++ = cResult0;
+  *pipe->destAlphaPtr++ = aResult;
+
+  ++pipe->x;
+}
+
+#ifdef SPLASH_CMYK
+// special case:
+// !pipe->pattern && !pipe->noTransparency && !state->softMask &&
+// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
+// !pipe->nonIsolatedGroup &&
+// bitmap->mode == splashModeCMYK8 && pipe->destAlphaPtr
+void Splash::pipeRunAACMYK8(SplashPipe *pipe) {
+  Guchar aSrc, aDest, alpha2, aResult;
+  SplashColor cDest;
+  Guchar cResult0, cResult1, cResult2, cResult3;
+
+  //----- read destination pixel
+  cDest[0] = pipe->destColorPtr[0];
+  cDest[1] = pipe->destColorPtr[1];
+  cDest[2] = pipe->destColorPtr[2];
+  cDest[3] = pipe->destColorPtr[3];
+  aDest = *pipe->destAlphaPtr;
+
+  //----- source alpha
+  aSrc = div255(pipe->aInput * pipe->shape);
+
+  //----- result alpha and non-isolated group element correction
+  aResult = aSrc + aDest - div255(aSrc * aDest);
+  alpha2 = aResult;
+
+  //----- result color
+  if (alpha2 == 0) {
+    cResult0 = 0;
+    cResult1 = 0;
+    cResult2 = 0;
+    cResult3 = 0;
+  } else {
+    cResult0 = state->cmykTransferC[(Guchar)(((alpha2 - aSrc) * cDest[0] +
+					      aSrc * pipe->cSrc[0]) / alpha2)];
+    cResult1 = state->cmykTransferM[(Guchar)(((alpha2 - aSrc) * cDest[1] +
+					      aSrc * pipe->cSrc[1]) / alpha2)];
+    cResult2 = state->cmykTransferY[(Guchar)(((alpha2 - aSrc) * cDest[2] +
+					      aSrc * pipe->cSrc[2]) / alpha2)];
+    cResult3 = state->cmykTransferK[(Guchar)(((alpha2 - aSrc) * cDest[3] +
+					      aSrc * pipe->cSrc[3]) / alpha2)];
+  }
+
+  //----- write destination pixel
+  if (state->overprintMask & 1) {
+    pipe->destColorPtr[0] = (state->overprintAdditive && pipe->shape != 0) ? 
+              std::min<int>(pipe->destColorPtr[0] + cResult0, 255) :
+              cResult0;
+  }
+  if (state->overprintMask & 2) {
+    pipe->destColorPtr[1] = (state->overprintAdditive && pipe->shape != 0) ? 
+              std::min<int>(pipe->destColorPtr[1] + cResult1, 255) :
+              cResult1;
+  }
+  if (state->overprintMask & 4) {
+    pipe->destColorPtr[2] = (state->overprintAdditive && pipe->shape != 0) ? 
+              std::min<int>(pipe->destColorPtr[2] + cResult2, 255) :
+              cResult2;
+  }
+  if (state->overprintMask & 8) {
+    pipe->destColorPtr[3] = (state->overprintAdditive && pipe->shape != 0) ? 
+              std::min<int>(pipe->destColorPtr[3] + cResult3, 255) :
+              cResult3;
+  }
+  pipe->destColorPtr += 4;
+  *pipe->destAlphaPtr++ = aResult;
+
+  ++pipe->x;
+}
+
+// special case:
+// !pipe->pattern && !pipe->noTransparency && !state->softMask &&
+// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
+// !pipe->nonIsolatedGroup &&
+// bitmap->mode == splashModeDeviceN8 && pipe->destAlphaPtr
+void Splash::pipeRunAADeviceN8(SplashPipe *pipe) {
+  Guchar aSrc, aDest, alpha2, aResult;
+  SplashColor cDest;
+  Guchar cResult[SPOT_NCOMPS+4];
+  int cp, mask;
+
+  //----- read destination pixel
+  for (cp=0; cp < SPOT_NCOMPS+4; cp++)
+    cDest[cp] = pipe->destColorPtr[cp];
+  aDest = *pipe->destAlphaPtr;
+
+  //----- source alpha
+  aSrc = div255(pipe->aInput * pipe->shape);
+
+  //----- result alpha and non-isolated group element correction
+  aResult = aSrc + aDest - div255(aSrc * aDest);
+  alpha2 = aResult;
+
+  //----- result color
+  if (alpha2 == 0) {
+    for (cp=0; cp < SPOT_NCOMPS+4; cp++)
+      cResult[cp] = 0;
+  } else {
+    for (cp=0; cp < SPOT_NCOMPS+4; cp++)
+      cResult[cp] = state->deviceNTransfer[cp][(Guchar)(((alpha2 - aSrc) * cDest[cp] +
+					      aSrc * pipe->cSrc[cp]) / alpha2)];
+  }
+
+  //----- write destination pixel
+  mask = 1;
+  for (cp=0; cp < SPOT_NCOMPS+4; cp++) {
+    if (state->overprintMask & mask) {
+      pipe->destColorPtr[cp] = cResult[cp];
+    }
+    mask <<= 1;
+  }
+  pipe->destColorPtr += (SPOT_NCOMPS+4);
+  *pipe->destAlphaPtr++ = aResult;
+
+  ++pipe->x;
+}
+#endif
+
+inline void Splash::pipeSetXY(SplashPipe *pipe, int x, int y) {
+  pipe->x = x;
+  pipe->y = y;
+  if (state->softMask) {
+    pipe->softMaskPtr =
+        &state->softMask->data[y * state->softMask->rowSize + x];
+  }
+  switch (bitmap->mode) {
+  case splashModeMono1:
+    pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + (x >> 3)];
+    pipe->destColorMask = 0x80 >> (x & 7);
+    break;
+  case splashModeMono8:
+    pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + x];
+    break;
+  case splashModeRGB8:
+  case splashModeBGR8:
+    pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x];
+    break;
+  case splashModeXBGR8:
+    pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x];
+    break;
+#ifdef SPLASH_CMYK
+  case splashModeCMYK8:
+    pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x];
+    break;
+  case splashModeDeviceN8:
+    pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + (SPOT_NCOMPS + 4) * x];
+    break;
+#endif
+  }
+  if (bitmap->alpha) {
+    pipe->destAlphaPtr = &bitmap->alpha[y * bitmap->width + x];
+  } else {
+    pipe->destAlphaPtr = NULL;
+  }
+  if (state->inNonIsolatedGroup && alpha0Bitmap->alpha) {
+    pipe->alpha0Ptr =
+        &alpha0Bitmap->alpha[(alpha0Y + y) * alpha0Bitmap->width +
+			     (alpha0X + x)];
+  } else {
+    pipe->alpha0Ptr = NULL;
+  }
+}
+
+inline void Splash::pipeIncX(SplashPipe *pipe) {
+  ++pipe->x;
+  if (state->softMask) {
+    ++pipe->softMaskPtr;
+  }
+  switch (bitmap->mode) {
+  case splashModeMono1:
+    if (!(pipe->destColorMask >>= 1)) {
+      pipe->destColorMask = 0x80;
+      ++pipe->destColorPtr;
+    }
+    break;
+  case splashModeMono8:
+    ++pipe->destColorPtr;
+    break;
+  case splashModeRGB8:
+  case splashModeBGR8:
+    pipe->destColorPtr += 3;
+    break;
+  case splashModeXBGR8:
+    pipe->destColorPtr += 4;
+    break;
+#ifdef SPLASH_CMYK
+  case splashModeCMYK8:
+    pipe->destColorPtr += 4;
+    break;
+  case splashModeDeviceN8:
+    pipe->destColorPtr += (SPOT_NCOMPS+4);
+    break;
+#endif
+  }
+  if (pipe->destAlphaPtr) {
+    ++pipe->destAlphaPtr;
+  }
+  if (pipe->alpha0Ptr) {
+    ++pipe->alpha0Ptr;
+  }
+}
+
+inline void Splash::drawPixel(SplashPipe *pipe, int x, int y, GBool noClip) {
+  if (unlikely(y < 0))
+    return;
+
+  if (noClip || state->clip->test(x, y)) {
+    pipeSetXY(pipe, x, y);
+    (this->*pipe->run)(pipe);
+    updateModX(x);
+    updateModY(y);
+  }
+}
+
+inline void Splash::drawAAPixelInit() {
+  aaBufY = -1;
+}
+
+inline void Splash::drawAAPixel(SplashPipe *pipe, int x, int y) {
+#if splashAASize == 4
+  static int bitCount4[16] = { 0, 1, 1, 2, 1, 2, 2, 3,
+			       1, 2, 2, 3, 2, 3, 3, 4 };
+  int w;
+#else
+  int xx, yy;
+#endif
+  SplashColorPtr p;
+  int x0, x1, t;
+
+  if (x < 0 || x >= bitmap->width ||
+      y < state->clip->getYMinI() || y > state->clip->getYMaxI()) {
+    return;
+  }
+
+  // update aaBuf
+  if (y != aaBufY) {
+    memset(aaBuf->getDataPtr(), 0xff,
+	   aaBuf->getRowSize() * aaBuf->getHeight());
+    x0 = 0;
+    x1 = bitmap->width - 1;
+    state->clip->clipAALine(aaBuf, &x0, &x1, y);
+    aaBufY = y;
+  }
+
+  // compute the shape value
+#if splashAASize == 4
+  p = aaBuf->getDataPtr() + (x >> 1);
+  w = aaBuf->getRowSize();
+  if (x & 1) {
+    t = bitCount4[*p & 0x0f] + bitCount4[p[w] & 0x0f] +
+        bitCount4[p[2*w] & 0x0f] + bitCount4[p[3*w] & 0x0f];
+  } else {
+    t = bitCount4[*p >> 4] + bitCount4[p[w] >> 4] +
+        bitCount4[p[2*w] >> 4] + bitCount4[p[3*w] >> 4];
+  }
+#else
+  t = 0;
+  for (yy = 0; yy < splashAASize; ++yy) {
+    for (xx = 0; xx < splashAASize; ++xx) {
+      p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() +
+	  ((x * splashAASize + xx) >> 3);
+      t += (*p >> (7 - ((x * splashAASize + xx) & 7))) & 1;
+    }
+  }
+#endif
+
+  // draw the pixel
+  if (t != 0) {
+    pipeSetXY(pipe, x, y);
+    pipe->shape = div255(aaGamma[t] * pipe->shape);
+    (this->*pipe->run)(pipe);
+    updateModX(x);
+    updateModY(y);
+  }
+}
+
+inline void Splash::drawSpan(SplashPipe *pipe, int x0, int x1, int y,
+			     GBool noClip) {
+  int x;
+
+  if (noClip) {
+    pipeSetXY(pipe, x0, y);
+    for (x = x0; x <= x1; ++x) {
+      (this->*pipe->run)(pipe);
+    }
+    updateModX(x0);
+    updateModX(x1);
+    updateModY(y);
+  } else {
+    if (x0 < state->clip->getXMinI()) {
+      x0 = state->clip->getXMinI();
+    }
+    if (x1 > state->clip->getXMaxI()) {
+      x1 = state->clip->getXMaxI();
+    }
+    pipeSetXY(pipe, x0, y);
+    for (x = x0; x <= x1; ++x) {
+      if (state->clip->test(x, y)) {
+	(this->*pipe->run)(pipe);
+	updateModX(x);
+	updateModY(y);
+      } else {
+	pipeIncX(pipe);
+      }
+    }
+  }
+}
+
+inline void Splash::drawAALine(SplashPipe *pipe, int x0, int x1, int y, GBool adjustLine, Guchar lineOpacity) {
+#if splashAASize == 4
+  static int bitCount4[16] = { 0, 1, 1, 2, 1, 2, 2, 3,
+			       1, 2, 2, 3, 2, 3, 3, 4 };
+  SplashColorPtr p0, p1, p2, p3;
+  int t;
+#else
+  SplashColorPtr p;
+  int xx, yy, t;
+#endif
+  int x;
+
+#if splashAASize == 4
+  p0 = aaBuf->getDataPtr() + (x0 >> 1);
+  p1 = p0 + aaBuf->getRowSize();
+  p2 = p1 + aaBuf->getRowSize();
+  p3 = p2 + aaBuf->getRowSize();
+#endif
+  pipeSetXY(pipe, x0, y);
+  for (x = x0; x <= x1; ++x) {
+
+    // compute the shape value
+#if splashAASize == 4
+    if (x & 1) {
+      t = bitCount4[*p0 & 0x0f] + bitCount4[*p1 & 0x0f] +
+	  bitCount4[*p2 & 0x0f] + bitCount4[*p3 & 0x0f];
+      ++p0; ++p1; ++p2; ++p3;
+    } else {
+      t = bitCount4[*p0 >> 4] + bitCount4[*p1 >> 4] +
+	  bitCount4[*p2 >> 4] + bitCount4[*p3 >> 4];
+    }
+#else
+    t = 0;
+    for (yy = 0; yy < splashAASize; ++yy) {
+      for (xx = 0; xx < splashAASize; ++xx) {
+	p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() +
+	    ((x * splashAASize + xx) >> 3);
+	t += (*p >> (7 - ((x * splashAASize + xx) & 7))) & 1;
+      }
+    }
+#endif
+
+    if (t != 0) {
+      pipe->shape = (adjustLine) ? div255((int) lineOpacity * (double)aaGamma[t]) : (double)aaGamma[t];
+      (this->*pipe->run)(pipe);
+      updateModX(x);
+      updateModY(y);
+    } else {
+      pipeIncX(pipe);
+    }
+  }
+}
+
+//------------------------------------------------------------------------
+
+// Transform a point from user space to device space.
+inline void Splash::transform(SplashCoord *matrix,
+			      SplashCoord xi, SplashCoord yi,
+			      SplashCoord *xo, SplashCoord *yo) {
+  //                          [ m[0] m[1] 0 ]
+  // [xo yo 1] = [xi yi 1] *  [ m[2] m[3] 0 ]
+  //                          [ m[4] m[5] 1 ]
+  *xo = xi * matrix[0] + yi * matrix[2] + matrix[4];
+  *yo = xi * matrix[1] + yi * matrix[3] + matrix[5];
+}
+
+//------------------------------------------------------------------------
+// Splash
+//------------------------------------------------------------------------
+
+Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA,
+	       SplashScreenParams *screenParams) {
+  int i;
+
+  bitmap = bitmapA;
+  vectorAntialias = vectorAntialiasA;
+  inShading = gFalse;
+  state = new SplashState(bitmap->width, bitmap->height, vectorAntialias,
+			  screenParams);
+  if (vectorAntialias) {
+    aaBuf = new SplashBitmap(splashAASize * bitmap->width, splashAASize,
+			     1, splashModeMono1, gFalse);
+    for (i = 0; i <= splashAASize * splashAASize; ++i) {
+      aaGamma[i] = (Guchar)splashRound(
+		       splashPow((SplashCoord)i /
+				 (SplashCoord)(splashAASize * splashAASize),
+				 splashAAGamma) * 255);
+    }
+  } else {
+    aaBuf = NULL;
+  }
+  minLineWidth = 0;
+  thinLineMode = splashThinLineDefault;
+  clearModRegion();
+  debugMode = gFalse;
+  alpha0Bitmap = NULL;
+}
+
+Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA,
+	       SplashScreen *screenA) {
+  int i;
+
+  bitmap = bitmapA;
+  inShading = gFalse;
+  vectorAntialias = vectorAntialiasA;
+  state = new SplashState(bitmap->width, bitmap->height, vectorAntialias,
+			  screenA);
+  if (vectorAntialias) {
+    aaBuf = new SplashBitmap(splashAASize * bitmap->width, splashAASize,
+			     1, splashModeMono1, gFalse);
+    for (i = 0; i <= splashAASize * splashAASize; ++i) {
+      aaGamma[i] = (Guchar)splashRound(
+		       splashPow((SplashCoord)i /
+				 (SplashCoord)(splashAASize * splashAASize),
+				 splashAAGamma) * 255);
+    }
+  } else {
+    aaBuf = NULL;
+  }
+  minLineWidth = 0;
+  thinLineMode = splashThinLineDefault;
+  clearModRegion();
+  debugMode = gFalse;
+  alpha0Bitmap = NULL;
+}
+
+Splash::~Splash() {
+  while (state->next) {
+    restoreState();
+  }
+  delete state;
+  delete aaBuf;
+}
+
+//------------------------------------------------------------------------
+// state read
+//------------------------------------------------------------------------
+
+SplashCoord *Splash::getMatrix() {
+  return state->matrix;
+}
+
+SplashPattern *Splash::getStrokePattern() {
+  return state->strokePattern;
+}
+
+SplashPattern *Splash::getFillPattern() {
+  return state->fillPattern;
+}
+
+SplashScreen *Splash::getScreen() {
+  return state->screen;
+}
+
+SplashBlendFunc Splash::getBlendFunc() {
+  return state->blendFunc;
+}
+
+SplashCoord Splash::getStrokeAlpha() {
+  return state->strokeAlpha;
+}
+
+SplashCoord Splash::getFillAlpha() {
+  return state->fillAlpha;
+}
+
+SplashCoord Splash::getLineWidth() {
+  return state->lineWidth;
+}
+
+int Splash::getLineCap() {
+  return state->lineCap;
+}
+
+int Splash::getLineJoin() {
+  return state->lineJoin;
+}
+
+SplashCoord Splash::getMiterLimit() {
+  return state->miterLimit;
+}
+
+SplashCoord Splash::getFlatness() {
+  return state->flatness;
+}
+
+SplashCoord *Splash::getLineDash() {
+  return state->lineDash;
+}
+
+int Splash::getLineDashLength() {
+  return state->lineDashLength;
+}
+
+SplashCoord Splash::getLineDashPhase() {
+  return state->lineDashPhase;
+}
+
+GBool Splash::getStrokeAdjust() {
+  return state->strokeAdjust;
+}
+
+SplashClip *Splash::getClip() {
+  return state->clip;
+}
+
+SplashBitmap *Splash::getSoftMask() {
+  return state->softMask;
+}
+
+GBool Splash::getInNonIsolatedGroup() {
+  return state->inNonIsolatedGroup;
+}
+
+//------------------------------------------------------------------------
+// state write
+//------------------------------------------------------------------------
+
+void Splash::setMatrix(SplashCoord *matrix) {
+  memcpy(state->matrix, matrix, 6 * sizeof(SplashCoord));
+}
+
+void Splash::setStrokePattern(SplashPattern *strokePattern) {
+  state->setStrokePattern(strokePattern);
+}
+
+void Splash::setFillPattern(SplashPattern *fillPattern) {
+  state->setFillPattern(fillPattern);
+}
+
+void Splash::setScreen(SplashScreen *screen) {
+  state->setScreen(screen);
+}
+
+void Splash::setBlendFunc(SplashBlendFunc func) {
+  state->blendFunc = func;
+}
+
+void Splash::setStrokeAlpha(SplashCoord alpha) {
+  state->strokeAlpha = (state->multiplyPatternAlpha) ? alpha *  state->patternStrokeAlpha : alpha;
+}
+
+void Splash::setFillAlpha(SplashCoord alpha) {
+  state->fillAlpha = (state->multiplyPatternAlpha) ? alpha *  state->patternFillAlpha : alpha;
+}
+
+void Splash::setPatternAlpha(SplashCoord strokeAlpha, SplashCoord fillAlpha) {
+  state->patternStrokeAlpha = strokeAlpha;
+  state->patternFillAlpha = fillAlpha;
+  state->multiplyPatternAlpha = gTrue;
+}
+
+void Splash::clearPatternAlpha() {
+  state->patternStrokeAlpha = 1;
+  state->patternFillAlpha = 1;
+  state->multiplyPatternAlpha = gFalse;
+}
+
+void Splash::setFillOverprint(GBool fop) {
+  state->fillOverprint = fop;
+}
+
+void Splash::setStrokeOverprint(GBool gop) {
+  state->strokeOverprint = gop;
+}
+
+void Splash::setOverprintMode(int opm) {
+  state->overprintMode = opm;
+}
+
+void Splash::setLineWidth(SplashCoord lineWidth) {
+  state->lineWidth = lineWidth;
+}
+
+void Splash::setLineCap(int lineCap) {
+  state->lineCap = lineCap;
+}
+
+void Splash::setLineJoin(int lineJoin) {
+  state->lineJoin = lineJoin;
+}
+
+void Splash::setMiterLimit(SplashCoord miterLimit) {
+  state->miterLimit = miterLimit;
+}
+
+void Splash::setFlatness(SplashCoord flatness) {
+  if (flatness < 1) {
+    state->flatness = 1;
+  } else {
+    state->flatness = flatness;
+  }
+}
+
+void Splash::setLineDash(SplashCoord *lineDash, int lineDashLength,
+			 SplashCoord lineDashPhase) {
+  state->setLineDash(lineDash, lineDashLength, lineDashPhase);
+}
+
+void Splash::setStrokeAdjust(GBool strokeAdjust) {
+  state->strokeAdjust = strokeAdjust;
+}
+
+void Splash::clipResetToRect(SplashCoord x0, SplashCoord y0,
+			     SplashCoord x1, SplashCoord y1) {
+  state->clip->resetToRect(x0, y0, x1, y1);
+}
+
+SplashError Splash::clipToRect(SplashCoord x0, SplashCoord y0,
+			       SplashCoord x1, SplashCoord y1) {
+  return state->clip->clipToRect(x0, y0, x1, y1);
+}
+
+SplashError Splash::clipToPath(SplashPath *path, GBool eo) {
+  return state->clip->clipToPath(path, state->matrix, state->flatness, eo);
+}
+
+void Splash::setSoftMask(SplashBitmap *softMask) {
+  state->setSoftMask(softMask);
+}
+
+void Splash::setInNonIsolatedGroup(SplashBitmap *alpha0BitmapA,
+				   int alpha0XA, int alpha0YA) {
+  alpha0Bitmap = alpha0BitmapA;
+  alpha0X = alpha0XA;
+  alpha0Y = alpha0YA;
+  state->inNonIsolatedGroup = gTrue;
+}
+
+void Splash::setTransfer(Guchar *red, Guchar *green, Guchar *blue,
+			 Guchar *gray) {
+  state->setTransfer(red, green, blue, gray);
+}
+
+void Splash::setOverprintMask(Guint overprintMask, GBool additive) {
+  state->overprintMask = overprintMask;
+  state->overprintAdditive = additive;
+}
+
+//------------------------------------------------------------------------
+// state save/restore
+//------------------------------------------------------------------------
+
+void Splash::saveState() {
+  SplashState *newState;
+
+  newState = state->copy();
+  newState->next = state;
+  state = newState;
+}
+
+SplashError Splash::restoreState() {
+  SplashState *oldState;
+
+  if (!state->next) {
+    return splashErrNoSave;
+  }
+  oldState = state;
+  state = state->next;
+  delete oldState;
+  return splashOk;
+}
+
+//------------------------------------------------------------------------
+// drawing operations
+//------------------------------------------------------------------------
+
+void Splash::clear(SplashColorPtr color, Guchar alpha) {
+  SplashColorPtr row, p;
+  Guchar mono;
+  int x, y;
+
+  switch (bitmap->mode) {
+  case splashModeMono1:
+    mono = (color[0] & 0x80) ? 0xff : 0x00;
+    if (bitmap->rowSize < 0) {
+      memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
+	     mono, -bitmap->rowSize * bitmap->height);
+    } else {
+      memset(bitmap->data, mono, bitmap->rowSize * bitmap->height);
+    }
+    break;
+  case splashModeMono8:
+    if (bitmap->rowSize < 0) {
+      memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
+	     color[0], -bitmap->rowSize * bitmap->height);
+    } else {
+      memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height);
+    }
+    break;
+  case splashModeRGB8:
+    if (color[0] == color[1] && color[1] == color[2]) {
+      if (bitmap->rowSize < 0) {
+	memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
+	       color[0], -bitmap->rowSize * bitmap->height);
+      } else {
+	memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height);
+      }
+    } else {
+      row = bitmap->data;
+      for (y = 0; y < bitmap->height; ++y) {
+	p = row;
+	for (x = 0; x < bitmap->width; ++x) {
+	  *p++ = color[2];
+	  *p++ = color[1];
+	  *p++ = color[0];
+	}
+	row += bitmap->rowSize;
+      }
+    }
+    break;
+  case splashModeXBGR8:
+    if (color[0] == color[1] && color[1] == color[2]) {
+      if (bitmap->rowSize < 0) {
+	memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
+	       color[0], -bitmap->rowSize * bitmap->height);
+      } else {
+	memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height);
+      }
+    } else {
+      row = bitmap->data;
+      for (y = 0; y < bitmap->height; ++y) {
+	p = row;
+	for (x = 0; x < bitmap->width; ++x) {
+	  *p++ = color[0];
+	  *p++ = color[1];
+	  *p++ = color[2];
+	  *p++ = 255;
+	}
+	row += bitmap->rowSize;
+      }
+    }
+    break;
+  case splashModeBGR8:
+    if (color[0] == color[1] && color[1] == color[2]) {
+      if (bitmap->rowSize < 0) {
+	memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
+	       color[0], -bitmap->rowSize * bitmap->height);
+      } else {
+	memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height);
+      }
+    } else {
+      row = bitmap->data;
+      for (y = 0; y < bitmap->height; ++y) {
+	p = row;
+	for (x = 0; x < bitmap->width; ++x) {
+	  *p++ = color[0];
+	  *p++ = color[1];
+	  *p++ = color[2];
+	}
+	row += bitmap->rowSize;
+      }
+    }
+    break;
+#ifdef SPLASH_CMYK
+  case splashModeCMYK8:
+    if (color[0] == color[1] && color[1] == color[2] && color[2] == color[3]) {
+      if (bitmap->rowSize < 0) {
+	memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
+	       color[0], -bitmap->rowSize * bitmap->height);
+      } else {
+	memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height);
+      }
+    } else {
+      row = bitmap->data;
+      for (y = 0; y < bitmap->height; ++y) {
+	p = row;
+	for (x = 0; x < bitmap->width; ++x) {
+	  *p++ = color[0];
+	  *p++ = color[1];
+	  *p++ = color[2];
+	  *p++ = color[3];
+	}
+	row += bitmap->rowSize;
+      }
+    }
+    break;
+  case splashModeDeviceN8:
+    row = bitmap->data;
+    for (y = 0; y < bitmap->height; ++y) {
+      p = row;
+      for (x = 0; x < bitmap->width; ++x) {
+        for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+          *p++ = color[cp];
+      }
+      row += bitmap->rowSize;
+    }
+    break;
+#endif
+  }
+
+  if (bitmap->alpha) {
+    memset(bitmap->alpha, alpha, bitmap->width * bitmap->height);
+  }
+
+  updateModX(0);
+  updateModY(0);
+  updateModX(bitmap->width - 1);
+  updateModY(bitmap->height - 1);
+}
+
+SplashError Splash::stroke(SplashPath *path) {
+  SplashPath *path2, *dPath;
+  SplashCoord d1, d2, t1, t2, w;
+
+  if (debugMode) {
+    printf("stroke [dash:%d] [width:%.2f]:\n",
+	   state->lineDashLength, (double)state->lineWidth);
+    dumpPath(path);
+  }
+  opClipRes = splashClipAllOutside;
+  if (path->length == 0) {
+    return splashErrEmptyPath;
+  }
+  path2 = flattenPath(path, state->matrix, state->flatness);
+  if (state->lineDashLength > 0) {
+    dPath = makeDashedPath(path2);
+    delete path2;
+    path2 = dPath;
+    if (path2->length == 0) {
+      delete path2;
+      return splashErrEmptyPath;
+    }
+  }
+
+  // transform a unit square, and take the half the max of the two
+  // diagonals; the product of this number and the line width is the
+  // (approximate) transformed line width
+  t1 = state->matrix[0] + state->matrix[2];
+  t2 = state->matrix[1] + state->matrix[3];
+  d1 = t1 * t1 + t2 * t2;
+  t1 = state->matrix[0] - state->matrix[2];
+  t2 = state->matrix[1] - state->matrix[3];
+  d2 = t1 * t1 + t2 * t2;
+  if (d2 > d1) {
+    d1 = d2;
+  }
+  d1 *= 0.5;
+  if (d1 > 0 &&
+      d1 * state->lineWidth * state->lineWidth < minLineWidth * minLineWidth) {
+    w = minLineWidth / splashSqrt(d1);
+    strokeWide(path2, w);
+  } else if (bitmap->mode == splashModeMono1) {
+    // this gets close to Adobe's behavior in mono mode
+    if (d1 * state->lineWidth <= 2) {
+      strokeNarrow(path2);
+    } else {
+      strokeWide(path2, state->lineWidth);
+    }
+  } else {
+    if (state->lineWidth == 0) {
+      strokeNarrow(path2);
+    } else {
+      strokeWide(path2, state->lineWidth);
+    }
+  }
+
+  delete path2;
+  return splashOk;
+}
+
+void Splash::strokeNarrow(SplashPath *path) {
+  SplashPipe pipe;
+  SplashXPath *xPath;
+  SplashXPathSeg *seg;
+  int x0, x1, y0, y1, xa, xb, y;
+  SplashCoord dxdy;
+  SplashClipResult clipRes;
+  int nClipRes[3];
+  int i;
+
+  nClipRes[0] = nClipRes[1] = nClipRes[2] = 0;
+
+  xPath = new SplashXPath(path, state->matrix, state->flatness, gFalse);
+
+  pipeInit(&pipe, 0, 0, state->strokePattern, NULL,
+	   (Guchar)splashRound(state->strokeAlpha * 255),
+	   gFalse, gFalse);
+
+  for (i = 0, seg = xPath->segs; i < xPath->length; ++i, ++seg) {
+    if (seg->y0 <= seg->y1) {
+      y0 = splashFloor(seg->y0);
+      y1 = splashFloor(seg->y1);
+      x0 = splashFloor(seg->x0);
+      x1 = splashFloor(seg->x1);
+    } else {
+      y0 = splashFloor(seg->y1);
+      y1 = splashFloor(seg->y0);
+      x0 = splashFloor(seg->x1);
+      x1 = splashFloor(seg->x0);
+    }
+    if ((clipRes = state->clip->testRect(x0 <= x1 ? x0 : x1, y0,
+					 x0 <= x1 ? x1 : x0, y1))
+	!= splashClipAllOutside) {
+      if (y0 == y1) {
+	if (x0 <= x1) {
+	  drawSpan(&pipe, x0, x1, y0, clipRes == splashClipAllInside);
+	} else {
+	  drawSpan(&pipe, x1, x0, y0, clipRes == splashClipAllInside);
+	}
+      } else {
+	dxdy = seg->dxdy;
+	if (y0 < state->clip->getYMinI()) {
+	  y0 = state->clip->getYMinI();
+	  x0 = splashFloor(seg->x0 + ((SplashCoord)y0 - seg->y0) * dxdy);
+	}
+	if (y1 > state->clip->getYMaxI()) {
+	  y1 = state->clip->getYMaxI();
+	  x1 = splashFloor(seg->x0 + ((SplashCoord)y1 - seg->y0) * dxdy);
+	}
+	if (x0 <= x1) {
+	  xa = x0;
+	  for (y = y0; y <= y1; ++y) {
+	    if (y < y1) {
+	      xb = splashFloor(seg->x0 +
+			       ((SplashCoord)y + 1 - seg->y0) * dxdy);
+	    } else {
+	      xb = x1 + 1;
+	    }
+	    if (xa == xb) {
+	      drawPixel(&pipe, xa, y, clipRes == splashClipAllInside);
+	    } else {
+	      drawSpan(&pipe, xa, xb - 1, y, clipRes == splashClipAllInside);
+	    }
+	    xa = xb;
+	  }
+	} else {
+	  xa = x0;
+	  for (y = y0; y <= y1; ++y) {
+	    if (y < y1) {
+	      xb = splashFloor(seg->x0 +
+			       ((SplashCoord)y + 1 - seg->y0) * dxdy);
+	    } else {
+	      xb = x1 - 1;
+	    }
+	    if (xa == xb) {
+	      drawPixel(&pipe, xa, y, clipRes == splashClipAllInside);
+	    } else {
+	      drawSpan(&pipe, xb + 1, xa, y, clipRes == splashClipAllInside);
+	    }
+	    xa = xb;
+	  }
+	}
+      }
+    }
+    ++nClipRes[clipRes];
+  }
+  if (nClipRes[splashClipPartial] ||
+      (nClipRes[splashClipAllInside] && nClipRes[splashClipAllOutside])) {
+    opClipRes = splashClipPartial;
+  } else if (nClipRes[splashClipAllInside]) {
+    opClipRes = splashClipAllInside;
+  } else {
+    opClipRes = splashClipAllOutside;
+  }
+
+  delete xPath;
+}
+
+void Splash::strokeWide(SplashPath *path, SplashCoord w) {
+  SplashPath *path2;
+
+  path2 = makeStrokePath(path, w, gFalse);
+  fillWithPattern(path2, gFalse, state->strokePattern, state->strokeAlpha);
+  delete path2;
+}
+
+SplashPath *Splash::flattenPath(SplashPath *path, SplashCoord *matrix,
+				SplashCoord flatness) {
+  SplashPath *fPath;
+  SplashCoord flatness2;
+  Guchar flag;
+  int i;
+
+  fPath = new SplashPath();
+#ifdef USE_FIXEDPOINT
+  flatness2 = flatness;
+#else
+  flatness2 = flatness * flatness;
+#endif
+  i = 0;
+  while (i < path->length) {
+    flag = path->flags[i];
+    if (flag & splashPathFirst) {
+      fPath->moveTo(path->pts[i].x, path->pts[i].y);
+      ++i;
+    } else {
+      if (flag & splashPathCurve) {
+	flattenCurve(path->pts[i-1].x, path->pts[i-1].y,
+		     path->pts[i  ].x, path->pts[i  ].y,
+		     path->pts[i+1].x, path->pts[i+1].y,
+		     path->pts[i+2].x, path->pts[i+2].y,
+		     matrix, flatness2, fPath);
+	i += 3;
+      } else {
+	fPath->lineTo(path->pts[i].x, path->pts[i].y);
+	++i;
+      }
+      if (path->flags[i-1] & splashPathClosed) {
+	fPath->close();
+      }
+    }
+  }
+  return fPath;
+}
+
+void Splash::flattenCurve(SplashCoord x0, SplashCoord y0,
+			  SplashCoord x1, SplashCoord y1,
+			  SplashCoord x2, SplashCoord y2,
+			  SplashCoord x3, SplashCoord y3,
+			  SplashCoord *matrix, SplashCoord flatness2,
+			  SplashPath *fPath) {
+  SplashCoord cx[splashMaxCurveSplits + 1][3];
+  SplashCoord cy[splashMaxCurveSplits + 1][3];
+  int cNext[splashMaxCurveSplits + 1];
+  SplashCoord xl0, xl1, xl2, xr0, xr1, xr2, xr3, xx1, xx2, xh;
+  SplashCoord yl0, yl1, yl2, yr0, yr1, yr2, yr3, yy1, yy2, yh;
+  SplashCoord dx, dy, mx, my, tx, ty, d1, d2;
+  int p1, p2, p3;
+
+  // initial segment
+  p1 = 0;
+  p2 = splashMaxCurveSplits;
+  cx[p1][0] = x0;  cy[p1][0] = y0;
+  cx[p1][1] = x1;  cy[p1][1] = y1;
+  cx[p1][2] = x2;  cy[p1][2] = y2;
+  cx[p2][0] = x3;  cy[p2][0] = y3;
+  cNext[p1] = p2;
+
+  while (p1 < splashMaxCurveSplits) {
+
+    // get the next segment
+    xl0 = cx[p1][0];  yl0 = cy[p1][0];
+    xx1 = cx[p1][1];  yy1 = cy[p1][1];
+    xx2 = cx[p1][2];  yy2 = cy[p1][2];
+    p2 = cNext[p1];
+    xr3 = cx[p2][0];  yr3 = cy[p2][0];
+
+    // compute the distances (in device space) from the control points
+    // to the midpoint of the straight line (this is a bit of a hack,
+    // but it's much faster than computing the actual distances to the
+    // line)
+    transform(matrix, (xl0 + xr3) * 0.5, (yl0 + yr3) * 0.5, &mx, &my);
+    transform(matrix, xx1, yy1, &tx, &ty);
+#ifdef USE_FIXEDPOINT
+    d1 = splashDist(tx, ty, mx, my);
+#else
+    dx = tx - mx;
+    dy = ty - my;
+    d1 = dx*dx + dy*dy;
+#endif
+    transform(matrix, xx2, yy2, &tx, &ty);
+#ifdef USE_FIXEDPOINT
+    d2 = splashDist(tx, ty, mx, my);
+#else
+    dx = tx - mx;
+    dy = ty - my;
+    d2 = dx*dx + dy*dy;
+#endif
+
+    // if the curve is flat enough, or no more subdivisions are
+    // allowed, add the straight line segment
+    if (p2 - p1 == 1 || (d1 <= flatness2 && d2 <= flatness2)) {
+      fPath->lineTo(xr3, yr3);
+      p1 = p2;
+
+    // otherwise, subdivide the curve
+    } else {
+      xl1 = splashAvg(xl0, xx1);
+      yl1 = splashAvg(yl0, yy1);
+      xh = splashAvg(xx1, xx2);
+      yh = splashAvg(yy1, yy2);
+      xl2 = splashAvg(xl1, xh);
+      yl2 = splashAvg(yl1, yh);
+      xr2 = splashAvg(xx2, xr3);
+      yr2 = splashAvg(yy2, yr3);
+      xr1 = splashAvg(xh, xr2);
+      yr1 = splashAvg(yh, yr2);
+      xr0 = splashAvg(xl2, xr1);
+      yr0 = splashAvg(yl2, yr1);
+      // add the new subdivision points
+      p3 = (p1 + p2) / 2;
+      cx[p1][1] = xl1;  cy[p1][1] = yl1;
+      cx[p1][2] = xl2;  cy[p1][2] = yl2;
+      cNext[p1] = p3;
+      cx[p3][0] = xr0;  cy[p3][0] = yr0;
+      cx[p3][1] = xr1;  cy[p3][1] = yr1;
+      cx[p3][2] = xr2;  cy[p3][2] = yr2;
+      cNext[p3] = p2;
+    }
+  }
+}
+
+SplashPath *Splash::makeDashedPath(SplashPath *path) {
+  SplashPath *dPath;
+  SplashCoord lineDashTotal;
+  SplashCoord lineDashStartPhase, lineDashDist, segLen;
+  SplashCoord x0, y0, x1, y1, xa, ya;
+  GBool lineDashStartOn, lineDashOn, newPath;
+  int lineDashStartIdx, lineDashIdx;
+  int i, j, k;
+
+  lineDashTotal = 0;
+  for (i = 0; i < state->lineDashLength; ++i) {
+    lineDashTotal += state->lineDash[i];
+  }
+  // Acrobat simply draws nothing if the dash array is [0]
+  if (lineDashTotal == 0) {
+    return new SplashPath();
+  }
+  lineDashStartPhase = state->lineDashPhase;
+  i = splashFloor(lineDashStartPhase / lineDashTotal);
+  lineDashStartPhase -= (SplashCoord)i * lineDashTotal;
+  lineDashStartOn = gTrue;
+  lineDashStartIdx = 0;
+  if (lineDashStartPhase > 0) {
+    while (lineDashStartIdx < state->lineDashLength && lineDashStartPhase >= state->lineDash[lineDashStartIdx]) {
+      lineDashStartOn = !lineDashStartOn;
+      lineDashStartPhase -= state->lineDash[lineDashStartIdx];
+      ++lineDashStartIdx;
+    }
+    if (unlikely(lineDashStartIdx == state->lineDashLength)) {
+      return new SplashPath();
+    }
+  }
+
+  dPath = new SplashPath();
+
+  // process each subpath
+  i = 0;
+  while (i < path->length) {
+
+    // find the end of the subpath
+    for (j = i;
+	 j < path->length - 1 && !(path->flags[j] & splashPathLast);
+	 ++j) ;
+
+    // initialize the dash parameters
+    lineDashOn = lineDashStartOn;
+    lineDashIdx = lineDashStartIdx;
+    lineDashDist = state->lineDash[lineDashIdx] - lineDashStartPhase;
+
+    // process each segment of the subpath
+    newPath = gTrue;
+    for (k = i; k < j; ++k) {
+
+      // grab the segment
+      x0 = path->pts[k].x;
+      y0 = path->pts[k].y;
+      x1 = path->pts[k+1].x;
+      y1 = path->pts[k+1].y;
+      segLen = splashDist(x0, y0, x1, y1);
+
+      // process the segment
+      while (segLen > 0) {
+
+	if (lineDashDist >= segLen) {
+	  if (lineDashOn) {
+	    if (newPath) {
+	      dPath->moveTo(x0, y0);
+	      newPath = gFalse;
+	    }
+	    dPath->lineTo(x1, y1);
+	  }
+	  lineDashDist -= segLen;
+	  segLen = 0;
+
+	} else {
+	  xa = x0 + (lineDashDist / segLen) * (x1 - x0);
+	  ya = y0 + (lineDashDist / segLen) * (y1 - y0);
+	  if (lineDashOn) {
+	    if (newPath) {
+	      dPath->moveTo(x0, y0);
+	      newPath = gFalse;
+	    }
+	    dPath->lineTo(xa, ya);
+	  }
+	  x0 = xa;
+	  y0 = ya;
+	  segLen -= lineDashDist;
+	  lineDashDist = 0;
+	}
+
+	// get the next entry in the dash array
+	if (lineDashDist <= 0) {
+	  lineDashOn = !lineDashOn;
+	  if (++lineDashIdx == state->lineDashLength) {
+	    lineDashIdx = 0;
+	  }
+	  lineDashDist = state->lineDash[lineDashIdx];
+	  newPath = gTrue;
+	}
+      }
+    }
+    i = j + 1;
+  }
+  
+  if (dPath->length == 0) {
+    GBool allSame = gTrue;
+    for (int i = 0; allSame && i < path->length - 1; ++i) {
+      allSame = path->pts[i].x == path->pts[i + 1].x && path->pts[i].y == path->pts[i + 1].y;
+    }
+    if (allSame) {
+      x0 = path->pts[0].x;
+      y0 = path->pts[0].y;
+      dPath->moveTo(x0, y0);
+      dPath->lineTo(x0, y0);
+    }
+  }
+
+  return dPath;
+}
+
+SplashError Splash::fill(SplashPath *path, GBool eo) {
+  if (debugMode) {
+    printf("fill [eo:%d]:\n", eo);
+    dumpPath(path);
+  }
+  return fillWithPattern(path, eo, state->fillPattern, state->fillAlpha);
+}
+
+inline void Splash::getBBoxFP(SplashPath *path, SplashCoord *xMinA, SplashCoord *yMinA,
+				   SplashCoord *xMaxA, SplashCoord *yMaxA) {
+  SplashCoord xMinFP, yMinFP, xMaxFP, yMaxFP, tx, ty;
+
+  // make compiler happy:
+  xMinFP = xMaxFP = yMinFP = yMaxFP = 0;
+  for (int i = 0; i < path->length; ++i) {
+    transform(state->matrix, path->pts[i].x, path->pts[i].y, &tx, &ty);
+    if (i == 0) {
+      xMinFP = xMaxFP = tx;
+      yMinFP = yMaxFP = ty;
+    } else {
+      if (tx < xMinFP) xMinFP = tx;
+      if (tx > xMaxFP) xMaxFP = tx;
+      if (ty < yMinFP) yMinFP = ty;
+      if (ty > yMaxFP) yMaxFP = ty;
+    }
+  }
+
+  *xMinA = xMinFP;
+  *yMinA = yMinFP;
+  *xMaxA = xMaxFP;
+  *yMaxA = yMaxFP;
+}
+
+SplashError Splash::fillWithPattern(SplashPath *path, GBool eo,
+				    SplashPattern *pattern,
+				    SplashCoord alpha) {
+  SplashPipe pipe;
+  SplashXPath *xPath;
+  SplashXPathScanner *scanner;
+  int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y;
+  SplashClipResult clipRes, clipRes2;
+  GBool adjustLine = gFalse; 
+  int linePosI = 0;
+
+  if (path->length == 0) {
+    return splashErrEmptyPath;
+  }
+  if (pathAllOutside(path)) {
+    opClipRes = splashClipAllOutside;
+    return splashOk;
+  }
+
+  // add stroke adjustment hints for filled rectangles -- this only
+  // applies to paths that consist of a single subpath
+  // (this appears to match Acrobat's behavior)
+  if (state->strokeAdjust && !path->hints) {
+    int n;
+    n = path->getLength();
+    if (n == 4 &&
+	!(path->flags[0] & splashPathClosed) &&
+	!(path->flags[1] & splashPathLast) &&
+	!(path->flags[2] & splashPathLast)) {
+      path->close(gTrue);
+      path->addStrokeAdjustHint(0, 2, 0, 4);
+      path->addStrokeAdjustHint(1, 3, 0, 4);
+    } else if (n == 5 &&
+	       (path->flags[0] & splashPathClosed) &&
+	       !(path->flags[1] & splashPathLast) &&
+	       !(path->flags[2] & splashPathLast) &&
+	       !(path->flags[3] & splashPathLast)) {
+      path->addStrokeAdjustHint(0, 2, 0, 4);
+      path->addStrokeAdjustHint(1, 3, 0, 4);
+    }
+  }
+
+  if (thinLineMode != splashThinLineDefault) {
+    if (state->clip->getXMinI() == state->clip->getXMaxI()) {
+      linePosI = state->clip->getXMinI();
+      adjustLine = gTrue;
+    } else if (state->clip->getXMinI() == state->clip->getXMaxI() - 1) {
+      adjustLine = gTrue;
+      linePosI = splashFloor(state->clip->getXMin() + state->lineWidth);
+    } else if (state->clip->getYMinI() == state->clip->getYMaxI()) {
+      linePosI = state->clip->getYMinI();
+      adjustLine = gTrue;
+    } else if (state->clip->getYMinI() == state->clip->getYMaxI() - 1) {
+      adjustLine = gTrue;
+      linePosI = splashFloor(state->clip->getYMin() + state->lineWidth);
+    }
+  }
+
+  xPath = new SplashXPath(path, state->matrix, state->flatness, gTrue, 
+    adjustLine, linePosI);
+  if (vectorAntialias && !inShading) {
+    xPath->aaScale();
+  }
+  xPath->sort();
+  yMinI = state->clip->getYMinI();
+  yMaxI = state->clip->getYMaxI();
+  if (vectorAntialias && !inShading) {
+    yMinI = yMinI * splashAASize;
+    yMaxI = (yMaxI + 1) * splashAASize - 1;
+  }
+  scanner = new SplashXPathScanner(xPath, eo, yMinI, yMaxI);
+
+  // get the min and max x and y values
+  if (vectorAntialias && !inShading) {
+    scanner->getBBoxAA(&xMinI, &yMinI, &xMaxI, &yMaxI);
+  } else {
+    scanner->getBBox(&xMinI, &yMinI, &xMaxI, &yMaxI);
+  }
+
+  if (eo && (yMinI == yMaxI || xMinI == xMaxI) && thinLineMode != splashThinLineDefault) {
+    SplashCoord delta, xMinFP, yMinFP, xMaxFP, yMaxFP;
+    getBBoxFP(path, &xMinFP, &yMinFP, &xMaxFP, &yMaxFP);
+    delta = (yMinI == yMaxI) ? yMaxFP - yMinFP : xMaxFP - xMinFP;
+    if (delta < 0.2) {
+      opClipRes = splashClipAllOutside;
+      delete scanner;
+      delete xPath;
+      return splashOk;
+    }
+  }
+
+  // check clipping
+  if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI))
+      != splashClipAllOutside) {
+    if (scanner->hasPartialClip()) {
+      clipRes = splashClipPartial;
+    }
+
+    pipeInit(&pipe, 0, yMinI, pattern, NULL, (Guchar)splashRound(alpha * 255),
+	     vectorAntialias && !inShading, gFalse);
+
+    // draw the spans
+    if (vectorAntialias && !inShading) {
+      for (y = yMinI; y <= yMaxI; ++y) {
+	scanner->renderAALine(aaBuf, &x0, &x1, y, thinLineMode != splashThinLineDefault && xMinI == xMaxI);
+	if (clipRes != splashClipAllInside) {
+	  state->clip->clipAALine(aaBuf, &x0, &x1, y, thinLineMode != splashThinLineDefault && xMinI == xMaxI);
+	}
+	Guchar lineShape = 255;
+	GBool adjustLine = gFalse;
+	if (thinLineMode == splashThinLineShape && (xMinI == xMaxI || yMinI == yMaxI)) {
+	  // compute line shape for thin lines:
+	  SplashCoord mx, my, delta;
+	  transform(state->matrix, 0, 0, &mx, &my);
+	  transform(state->matrix, state->lineWidth, 0, &delta, &my);
+	  adjustLine = gTrue;
+	  lineShape = clip255((delta - mx) * 255);
+	}
+	drawAALine(&pipe, x0, x1, y, adjustLine, lineShape);
+      }
+    } else {
+      for (y = yMinI; y <= yMaxI; ++y) {
+	while (scanner->getNextSpan(y, &x0, &x1)) {
+	  if (clipRes == splashClipAllInside) {
+	    drawSpan(&pipe, x0, x1, y, gTrue);
+	  } else {
+	    // limit the x range
+	    if (x0 < state->clip->getXMinI()) {
+	      x0 = state->clip->getXMinI();
+	    }
+	    if (x1 > state->clip->getXMaxI()) {
+	      x1 = state->clip->getXMaxI();
+	    }
+	    clipRes2 = state->clip->testSpan(x0, x1, y);
+	    drawSpan(&pipe, x0, x1, y, clipRes2 == splashClipAllInside);
+	  }
+	}
+      }
+    }
+  }
+  opClipRes = clipRes;
+
+  delete scanner;
+  delete xPath;
+  return splashOk;
+}
+
+GBool Splash::pathAllOutside(SplashPath *path) {
+  SplashCoord xMin1, yMin1, xMax1, yMax1;
+  SplashCoord xMin2, yMin2, xMax2, yMax2;
+  SplashCoord x, y;
+  int xMinI, yMinI, xMaxI, yMaxI;
+  int i;
+
+  xMin1 = xMax1 = path->pts[0].x;
+  yMin1 = yMax1 = path->pts[0].y;
+  for (i = 1; i < path->length; ++i) {
+    if (path->pts[i].x < xMin1) {
+      xMin1 = path->pts[i].x;
+    } else if (path->pts[i].x > xMax1) {
+      xMax1 = path->pts[i].x;
+    }
+    if (path->pts[i].y < yMin1) {
+      yMin1 = path->pts[i].y;
+    } else if (path->pts[i].y > yMax1) {
+      yMax1 = path->pts[i].y;
+    }
+  }
+
+  transform(state->matrix, xMin1, yMin1, &x, &y);
+  xMin2 = xMax2 = x;
+  yMin2 = yMax2 = y;
+  transform(state->matrix, xMin1, yMax1, &x, &y);
+  if (x < xMin2) {
+    xMin2 = x;
+  } else if (x > xMax2) {
+    xMax2 = x;
+  }
+  if (y < yMin2) {
+    yMin2 = y;
+  } else if (y > yMax2) {
+    yMax2 = y;
+  }
+  transform(state->matrix, xMax1, yMin1, &x, &y);
+  if (x < xMin2) {
+    xMin2 = x;
+  } else if (x > xMax2) {
+    xMax2 = x;
+  }
+  if (y < yMin2) {
+    yMin2 = y;
+  } else if (y > yMax2) {
+    yMax2 = y;
+  }
+  transform(state->matrix, xMax1, yMax1, &x, &y);
+  if (x < xMin2) {
+    xMin2 = x;
+  } else if (x > xMax2) {
+    xMax2 = x;
+  }
+  if (y < yMin2) {
+    yMin2 = y;
+  } else if (y > yMax2) {
+    yMax2 = y;
+  }
+  xMinI = splashFloor(xMin2);
+  yMinI = splashFloor(yMin2);
+  xMaxI = splashFloor(xMax2);
+  yMaxI = splashFloor(yMax2);
+
+  return state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI) ==
+         splashClipAllOutside;
+}
+
+SplashError Splash::xorFill(SplashPath *path, GBool eo) {
+  SplashPipe pipe;
+  SplashXPath *xPath;
+  SplashXPathScanner *scanner;
+  int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y;
+  SplashClipResult clipRes, clipRes2;
+  SplashBlendFunc origBlendFunc;
+
+  if (path->length == 0) {
+    return splashErrEmptyPath;
+  }
+  xPath = new SplashXPath(path, state->matrix, state->flatness, gTrue);
+  xPath->sort();
+  scanner = new SplashXPathScanner(xPath, eo, state->clip->getYMinI(),
+				   state->clip->getYMaxI());
+
+  // get the min and max x and y values
+  scanner->getBBox(&xMinI, &yMinI, &xMaxI, &yMaxI);
+
+  // check clipping
+  if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI))
+      != splashClipAllOutside) {
+    if (scanner->hasPartialClip()) {
+      clipRes = splashClipPartial;
+    }
+
+    origBlendFunc = state->blendFunc;
+    state->blendFunc = &blendXor;
+    pipeInit(&pipe, 0, yMinI, state->fillPattern, NULL, 255, gFalse, gFalse);
+
+    // draw the spans
+    for (y = yMinI; y <= yMaxI; ++y) {
+      while (scanner->getNextSpan(y, &x0, &x1)) {
+	if (clipRes == splashClipAllInside) {
+	  drawSpan(&pipe, x0, x1, y, gTrue);
+	} else {
+	  // limit the x range
+	  if (x0 < state->clip->getXMinI()) {
+	    x0 = state->clip->getXMinI();
+	  }
+	  if (x1 > state->clip->getXMaxI()) {
+	    x1 = state->clip->getXMaxI();
+	  }
+	  clipRes2 = state->clip->testSpan(x0, x1, y);
+	  drawSpan(&pipe, x0, x1, y, clipRes2 == splashClipAllInside);
+	}
+      }
+    }
+    state->blendFunc = origBlendFunc;
+  }
+  opClipRes = clipRes;
+
+  delete scanner;
+  delete xPath;
+  return splashOk;
+}
+
+SplashError Splash::fillChar(SplashCoord x, SplashCoord y,
+			     int c, SplashFont *font) {
+  SplashGlyphBitmap glyph;
+  SplashCoord xt, yt;
+  int x0, y0, xFrac, yFrac;
+  SplashClipResult clipRes;
+
+  if (debugMode) {
+    printf("fillChar: x=%.2f y=%.2f c=%3d=0x%02x='%c'\n",
+	   (double)x, (double)y, c, c, c);
+  }
+  transform(state->matrix, x, y, &xt, &yt);
+  x0 = splashFloor(xt);
+  xFrac = splashFloor((xt - x0) * splashFontFraction);
+  y0 = splashFloor(yt);
+  yFrac = splashFloor((yt - y0) * splashFontFraction);
+  if (!font->getGlyph(c, xFrac, yFrac, &glyph, x0, y0, state->clip, &clipRes)) {
+    return splashErrNoGlyph;
+  }
+  if (clipRes != splashClipAllOutside) {
+    fillGlyph2(x0, y0, &glyph, clipRes == splashClipAllInside);
+  }
+  opClipRes = clipRes;
+  if (glyph.freeData) {
+    gfree(glyph.data);
+  }
+  return splashOk;
+}
+
+void Splash::fillGlyph(SplashCoord x, SplashCoord y,
+			      SplashGlyphBitmap *glyph) {
+  SplashCoord xt, yt;
+  int x0, y0;
+
+  transform(state->matrix, x, y, &xt, &yt);
+  x0 = splashFloor(xt);
+  y0 = splashFloor(yt);
+  SplashClipResult clipRes = state->clip->testRect(x0 - glyph->x,
+                             y0 - glyph->y,
+                             x0 - glyph->x + glyph->w - 1,
+                             y0 - glyph->y + glyph->h - 1);
+  if (clipRes != splashClipAllOutside) {
+    fillGlyph2(x0, y0, glyph, clipRes == splashClipAllInside);
+  }
+  opClipRes = clipRes;
+}
+
+void Splash::fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph, GBool noClip) {
+  SplashPipe pipe;
+  int alpha0;
+  Guchar alpha;
+  Guchar *p;
+  int x1, y1, xx, xx1, yy;
+
+  p = glyph->data;
+  int xStart = x0 - glyph->x;
+  int yStart = y0 - glyph->y;
+  int xxLimit = glyph->w;
+  int yyLimit = glyph->h;
+  int xShift = 0;
+
+  if (yStart < 0)
+  {
+    p += (glyph->aa ? glyph->w : splashCeil(glyph->w / 8.0)) * -yStart; // move p to the beginning of the first painted row
+    yyLimit += yStart;
+    yStart = 0;
+  }
+
+  if (xStart < 0)
+  {
+    if (glyph->aa) {
+      p += -xStart;
+    } else {
+      p += (-xStart) / 8;
+      xShift = (-xStart) % 8;
+    }
+    xxLimit += xStart;
+    xStart = 0;
+  }
+
+  if (xxLimit + xStart >= bitmap->width) xxLimit = bitmap->width - xStart;
+  if (yyLimit + yStart >= bitmap->height) yyLimit = bitmap->height - yStart;
+
+  if (noClip) {
+    if (glyph->aa) {
+      pipeInit(&pipe, xStart, yStart,
+               state->fillPattern, NULL, (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse);
+      for (yy = 0, y1 = yStart; yy < yyLimit; ++yy, ++y1) {
+        pipeSetXY(&pipe, xStart, y1);
+        for (xx = 0, x1 = xStart; xx < xxLimit; ++xx, ++x1) {
+          alpha = p[xx];
+          if (alpha != 0) {
+            pipe.shape = alpha;
+            (this->*pipe.run)(&pipe);
+            updateModX(x1);
+            updateModY(y1);
+          } else {
+            pipeIncX(&pipe);
+          }
+        }
+        p += glyph->w;
+      }
+    } else {
+      const int widthEight = splashCeil(glyph->w / 8.0);
+
+      pipeInit(&pipe, xStart, yStart,
+               state->fillPattern, NULL, (Guchar)splashRound(state->fillAlpha * 255), gFalse, gFalse);
+      for (yy = 0, y1 = yStart; yy < yyLimit; ++yy, ++y1) {
+        pipeSetXY(&pipe, xStart, y1);
+        for (xx = 0, x1 = xStart; xx < xxLimit; xx += 8) {
+          alpha0 = (xShift > 0 ? (p[xx / 8] << xShift) | (p[xx / 8 + 1] >> (8 - xShift)) : p[xx / 8]);
+          for (xx1 = 0; xx1 < 8 && xx + xx1 < xxLimit; ++xx1, ++x1) {
+            if (alpha0 & 0x80) {
+              (this->*pipe.run)(&pipe);
+              updateModX(x1);
+              updateModY(y1);
+            } else {
+              pipeIncX(&pipe);
+            }
+            alpha0 <<= 1;
+          }
+        }
+        p += widthEight;
+      }
+    }
+  } else {
+    if (glyph->aa) {
+      pipeInit(&pipe, xStart, yStart,
+               state->fillPattern, NULL, (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse);
+      for (yy = 0, y1 = yStart; yy < yyLimit; ++yy, ++y1) {
+        pipeSetXY(&pipe, xStart, y1);
+        for (xx = 0, x1 = xStart; xx < xxLimit; ++xx, ++x1) {
+          if (state->clip->test(x1, y1)) {
+            alpha = p[xx];
+            if (alpha != 0) {
+              pipe.shape = alpha;
+              (this->*pipe.run)(&pipe);
+              updateModX(x1);
+              updateModY(y1);
+            } else {
+              pipeIncX(&pipe);
+            }
+          } else {
+            pipeIncX(&pipe);
+          }
+        }
+        p += glyph->w;
+      }
+    } else {
+      const int widthEight = splashCeil(glyph->w / 8.0);
+
+      pipeInit(&pipe, xStart, yStart,
+               state->fillPattern, NULL, (Guchar)splashRound(state->fillAlpha * 255), gFalse, gFalse);
+      for (yy = 0, y1 = yStart; yy < yyLimit; ++yy, ++y1) {
+        pipeSetXY(&pipe, xStart, y1);
+        for (xx = 0, x1 = xStart; xx < xxLimit; xx += 8) {
+          alpha0 = (xShift > 0 ? (p[xx / 8] << xShift) | (p[xx / 8 + 1] >> (8 - xShift)) : p[xx / 8]);
+          for (xx1 = 0; xx1 < 8 && xx + xx1 < xxLimit; ++xx1, ++x1) {
+            if (state->clip->test(x1, y1)) {
+              if (alpha0 & 0x80) {
+                (this->*pipe.run)(&pipe);
+                updateModX(x1);
+                updateModY(y1);
+              } else {
+                pipeIncX(&pipe);
+              }
+            } else {
+              pipeIncX(&pipe);
+            }
+            alpha0 <<= 1;
+          }
+        }
+        p += widthEight;
+      }
+    }
+  }
+}
+
+SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData,
+				  int w, int h, SplashCoord *mat,
+				  GBool glyphMode) {
+  SplashBitmap *scaledMask;
+  SplashClipResult clipRes;
+  GBool minorAxisZero;
+  int x0, y0, x1, y1, scaledWidth, scaledHeight;
+  int yp;
+
+  if (debugMode) {
+    printf("fillImageMask: w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n",
+	   w, h, (double)mat[0], (double)mat[1], (double)mat[2],
+	   (double)mat[3], (double)mat[4], (double)mat[5]);
+  }
+
+  if (w == 0 && h == 0) return splashErrZeroImage;
+
+  // check for singular matrix
+  if (!splashCheckDet(mat[0], mat[1], mat[2], mat[3], 0.000001)) {
+    return splashErrSingularMatrix;
+  }
+
+  minorAxisZero = mat[1] == 0 && mat[2] == 0;
+
+  // scaling only
+  if (mat[0] > 0 && minorAxisZero && mat[3] > 0) {
+    x0 = imgCoordMungeLowerC(mat[4], glyphMode);
+    y0 = imgCoordMungeLowerC(mat[5], glyphMode);
+    x1 = imgCoordMungeUpperC(mat[0] + mat[4], glyphMode);
+    y1 = imgCoordMungeUpperC(mat[3] + mat[5], glyphMode);
+    // make sure narrow images cover at least one pixel
+    if (x0 == x1) {
+      ++x1;
+    }
+    if (y0 == y1) {
+      ++y1;
+    }
+    clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1);
+    opClipRes = clipRes;
+    if (clipRes != splashClipAllOutside) {
+      scaledWidth = x1 - x0;
+      scaledHeight = y1 - y0;
+      yp = h / scaledHeight;
+      if (yp < 0 || yp > INT_MAX - 1) {
+        return splashErrBadArg;
+      }
+      scaledMask = scaleMask(src, srcData, w, h, scaledWidth, scaledHeight);
+      blitMask(scaledMask, x0, y0, clipRes);
+      delete scaledMask;
+    }
+
+  // scaling plus vertical flip
+  } else if (mat[0] > 0 && minorAxisZero && mat[3] < 0) {
+    x0 = imgCoordMungeLowerC(mat[4], glyphMode);
+    y0 = imgCoordMungeLowerC(mat[3] + mat[5], glyphMode);
+    x1 = imgCoordMungeUpperC(mat[0] + mat[4], glyphMode);
+    y1 = imgCoordMungeUpperC(mat[5], glyphMode);
+    // make sure narrow images cover at least one pixel
+    if (x0 == x1) {
+      ++x1;
+    }
+    if (y0 == y1) {
+      ++y1;
+    }
+    clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1);
+    opClipRes = clipRes;
+    if (clipRes != splashClipAllOutside) {
+      scaledWidth = x1 - x0;
+      scaledHeight = y1 - y0;
+      yp = h / scaledHeight;
+      if (yp < 0 || yp > INT_MAX - 1) {
+        return splashErrBadArg;
+      }
+      scaledMask = scaleMask(src, srcData, w, h, scaledWidth, scaledHeight);
+      vertFlipImage(scaledMask, scaledWidth, scaledHeight, 1);
+      blitMask(scaledMask, x0, y0, clipRes);
+      delete scaledMask;
+    }
+
+  // all other cases
+  } else {
+    arbitraryTransformMask(src, srcData, w, h, mat, glyphMode);
+  }
+
+  return splashOk;
+}
+
+void Splash::arbitraryTransformMask(SplashImageMaskSource src, void *srcData,
+				    int srcWidth, int srcHeight,
+				    SplashCoord *mat, GBool glyphMode) {
+  SplashBitmap *scaledMask;
+  SplashClipResult clipRes, clipRes2;
+  SplashPipe pipe;
+  int scaledWidth, scaledHeight, t0, t1;
+  SplashCoord r00, r01, r10, r11, det, ir00, ir01, ir10, ir11;
+  SplashCoord vx[4], vy[4];
+  int xMin, yMin, xMax, yMax;
+  ImageSection section[3];
+  int nSections;
+  int y, xa, xb, x, i, xx, yy;
+
+  // compute the four vertices of the target quadrilateral
+  vx[0] = mat[4];                    vy[0] = mat[5];
+  vx[1] = mat[2] + mat[4];           vy[1] = mat[3] + mat[5];
+  vx[2] = mat[0] + mat[2] + mat[4];  vy[2] = mat[1] + mat[3] + mat[5];
+  vx[3] = mat[0] + mat[4];           vy[3] = mat[1] + mat[5];
+
+  // clipping
+  xMin = imgCoordMungeLowerC(vx[0], glyphMode);
+  xMax = imgCoordMungeUpperC(vx[0], glyphMode);
+  yMin = imgCoordMungeLowerC(vy[0], glyphMode);
+  yMax = imgCoordMungeUpperC(vy[0], glyphMode);
+  for (i = 1; i < 4; ++i) {
+    t0 = imgCoordMungeLowerC(vx[i], glyphMode);
+    if (t0 < xMin) {
+      xMin = t0;
+    }
+    t0 = imgCoordMungeUpperC(vx[i], glyphMode);
+    if (t0 > xMax) {
+      xMax = t0;
+    }
+    t1 = imgCoordMungeLowerC(vy[i], glyphMode);
+    if (t1 < yMin) {
+      yMin = t1;
+    }
+    t1 = imgCoordMungeUpperC(vy[i], glyphMode);
+    if (t1 > yMax) {
+      yMax = t1;
+    }
+  }
+  clipRes = state->clip->testRect(xMin, yMin, xMax - 1, yMax - 1);
+  opClipRes = clipRes;
+  if (clipRes == splashClipAllOutside) {
+    return;
+  }
+
+  // compute the scale factors
+  if (mat[0] >= 0) {
+    t0 = imgCoordMungeUpperC(mat[0] + mat[4], glyphMode) -
+         imgCoordMungeLowerC(mat[4], glyphMode);
+  } else {
+    t0 = imgCoordMungeUpperC(mat[4], glyphMode) -
+         imgCoordMungeLowerC(mat[0] + mat[4], glyphMode);
+  }
+  if (mat[1] >= 0) {
+    t1 = imgCoordMungeUpperC(mat[1] + mat[5], glyphMode) -
+         imgCoordMungeLowerC(mat[5], glyphMode);
+  } else {
+    t1 = imgCoordMungeUpperC(mat[5], glyphMode) -
+         imgCoordMungeLowerC(mat[1] + mat[5], glyphMode);
+  }
+  scaledWidth = t0 > t1 ? t0 : t1;
+  if (mat[2] >= 0) {
+    t0 = imgCoordMungeUpperC(mat[2] + mat[4], glyphMode) -
+         imgCoordMungeLowerC(mat[4], glyphMode);
+  } else {
+    t0 = imgCoordMungeUpperC(mat[4], glyphMode) -
+         imgCoordMungeLowerC(mat[2] + mat[4], glyphMode);
+  }
+  if (mat[3] >= 0) {
+    t1 = imgCoordMungeUpperC(mat[3] + mat[5], glyphMode) -
+         imgCoordMungeLowerC(mat[5], glyphMode);
+  } else {
+    t1 = imgCoordMungeUpperC(mat[5], glyphMode) -
+         imgCoordMungeLowerC(mat[3] + mat[5], glyphMode);
+  }
+  scaledHeight = t0 > t1 ? t0 : t1;
+  if (scaledWidth == 0) {
+    scaledWidth = 1;
+  }
+  if (scaledHeight == 0) {
+    scaledHeight = 1;
+  }
+
+  // compute the inverse transform (after scaling) matrix
+  r00 = mat[0] / scaledWidth;
+  r01 = mat[1] / scaledWidth;
+  r10 = mat[2] / scaledHeight;
+  r11 = mat[3] / scaledHeight;
+  det = r00 * r11 - r01 * r10;
+  if (splashAbs(det) < 1e-6) {
+    // this should be caught by the singular matrix check in fillImageMask
+    return;
+  }
+  ir00 = r11 / det;
+  ir01 = -r01 / det;
+  ir10 = -r10 / det;
+  ir11 = r00 / det;
+
+  // scale the input image
+  scaledMask = scaleMask(src, srcData, srcWidth, srcHeight,
+			 scaledWidth, scaledHeight);
+  if (scaledMask->data == NULL) {
+    error(errInternal, -1, "scaledMask->data is NULL in Splash::arbitraryTransformMask");
+    delete scaledMask;
+    return;
+  }
+
+  // construct the three sections
+  i = (vy[2] <= vy[3]) ? 2 : 3;
+  if (vy[1] <= vy[i]) {
+    i = 1;
+  }
+  if (vy[0] < vy[i] || (i != 3 && vy[0] == vy[i])) {
+    i = 0;
+  }
+  if (vy[i] == vy[(i+1) & 3]) {
+    section[0].y0 = imgCoordMungeLowerC(vy[i], glyphMode);
+    section[0].y1 = imgCoordMungeUpperC(vy[(i+2) & 3], glyphMode) - 1;
+    if (vx[i] < vx[(i+1) & 3]) {
+      section[0].ia0 = i;
+      section[0].ia1 = (i+3) & 3;
+      section[0].ib0 = (i+1) & 3;
+      section[0].ib1 = (i+2) & 3;
+    } else {
+      section[0].ia0 = (i+1) & 3;
+      section[0].ia1 = (i+2) & 3;
+      section[0].ib0 = i;
+      section[0].ib1 = (i+3) & 3;
+    }
+    nSections = 1;
+  } else {
+    section[0].y0 = imgCoordMungeLowerC(vy[i], glyphMode);
+    section[2].y1 = imgCoordMungeUpperC(vy[(i+2) & 3], glyphMode) - 1;
+    section[0].ia0 = section[0].ib0 = i;
+    section[2].ia1 = section[2].ib1 = (i+2) & 3;
+    if (vx[(i+1) & 3] < vx[(i+3) & 3]) {
+      section[0].ia1 = section[2].ia0 = (i+1) & 3;
+      section[0].ib1 = section[2].ib0 = (i+3) & 3;
+    } else {
+      section[0].ia1 = section[2].ia0 = (i+3) & 3;
+      section[0].ib1 = section[2].ib0 = (i+1) & 3;
+    }
+    if (vy[(i+1) & 3] < vy[(i+3) & 3]) {
+      section[1].y0 = imgCoordMungeLowerC(vy[(i+1) & 3], glyphMode);
+      section[2].y0 = imgCoordMungeUpperC(vy[(i+3) & 3], glyphMode);
+      if (vx[(i+1) & 3] < vx[(i+3) & 3]) {
+	section[1].ia0 = (i+1) & 3;
+	section[1].ia1 = (i+2) & 3;
+	section[1].ib0 = i;
+	section[1].ib1 = (i+3) & 3;
+      } else {
+	section[1].ia0 = i;
+	section[1].ia1 = (i+3) & 3;
+	section[1].ib0 = (i+1) & 3;
+	section[1].ib1 = (i+2) & 3;
+      }
+    } else {
+      section[1].y0 = imgCoordMungeLowerC(vy[(i+3) & 3], glyphMode);
+      section[2].y0 = imgCoordMungeUpperC(vy[(i+1) & 3], glyphMode);
+      if (vx[(i+1) & 3] < vx[(i+3) & 3]) {
+	section[1].ia0 = i;
+	section[1].ia1 = (i+1) & 3;
+	section[1].ib0 = (i+3) & 3;
+	section[1].ib1 = (i+2) & 3;
+      } else {
+	section[1].ia0 = (i+3) & 3;
+	section[1].ia1 = (i+2) & 3;
+	section[1].ib0 = i;
+	section[1].ib1 = (i+1) & 3;
+      }
+    }
+    section[0].y1 = section[1].y0 - 1;
+    section[1].y1 = section[2].y0 - 1;
+    nSections = 3;
+  }
+  for (i = 0; i < nSections; ++i) {
+    section[i].xa0 = vx[section[i].ia0];
+    section[i].ya0 = vy[section[i].ia0];
+    section[i].xa1 = vx[section[i].ia1];
+    section[i].ya1 = vy[section[i].ia1];
+    section[i].xb0 = vx[section[i].ib0];
+    section[i].yb0 = vy[section[i].ib0];
+    section[i].xb1 = vx[section[i].ib1];
+    section[i].yb1 = vy[section[i].ib1];
+    section[i].dxdya = (section[i].xa1 - section[i].xa0) /
+                       (section[i].ya1 - section[i].ya0);
+    section[i].dxdyb = (section[i].xb1 - section[i].xb0) /
+                       (section[i].yb1 - section[i].yb0);
+  }
+
+  // initialize the pixel pipe
+  pipeInit(&pipe, 0, 0, state->fillPattern, NULL,
+	   (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse);
+  if (vectorAntialias) {
+    drawAAPixelInit();
+  }
+
+  // make sure narrow images cover at least one pixel
+  if (nSections == 1) {
+    if (section[0].y0 == section[0].y1) {
+      ++section[0].y1;
+      clipRes = opClipRes = splashClipPartial;
+    }
+  } else {
+    if (section[0].y0 == section[2].y1) {
+      ++section[1].y1;
+      clipRes = opClipRes = splashClipPartial;
+    }
+  }
+
+  // scan all pixels inside the target region
+  for (i = 0; i < nSections; ++i) {
+    for (y = section[i].y0; y <= section[i].y1; ++y) {
+      xa = imgCoordMungeLowerC(section[i].xa0 +
+			         ((SplashCoord)y + 0.5 - section[i].ya0) *
+			           section[i].dxdya,
+			       glyphMode);
+      xb = imgCoordMungeUpperC(section[i].xb0 +
+			         ((SplashCoord)y + 0.5 - section[i].yb0) *
+			           section[i].dxdyb,
+			       glyphMode);
+      if (unlikely(xa < 0))
+        xa = 0;
+      // make sure narrow images cover at least one pixel
+      if (xa == xb) {
+	++xb;
+      }
+      if (clipRes != splashClipAllInside) {
+	clipRes2 = state->clip->testSpan(xa, xb - 1, y);
+      } else {
+	clipRes2 = clipRes;
+      }
+      for (x = xa; x < xb; ++x) {
+	// map (x+0.5, y+0.5) back to the scaled image
+	xx = splashFloor(((SplashCoord)x + 0.5 - mat[4]) * ir00 +
+			 ((SplashCoord)y + 0.5 - mat[5]) * ir10);
+	yy = splashFloor(((SplashCoord)x + 0.5 - mat[4]) * ir01 +
+			 ((SplashCoord)y + 0.5 - mat[5]) * ir11);
+	// xx should always be within bounds, but floating point
+	// inaccuracy can cause problems
+	if (xx < 0) {
+	  xx = 0;
+	} else if (xx >= scaledWidth) {
+	  xx = scaledWidth - 1;
+	}
+	if (yy < 0) {
+	  yy = 0;
+	} else if (yy >= scaledHeight) {
+	  yy = scaledHeight - 1;
+	}
+	pipe.shape = scaledMask->data[yy * scaledWidth + xx];
+	if (vectorAntialias && clipRes2 != splashClipAllInside) {
+	  drawAAPixel(&pipe, x, y);
+	} else {
+	  drawPixel(&pipe, x, y, clipRes2 == splashClipAllInside);
+	}
+      }
+    }
+  }
+
+  delete scaledMask;
+}
+
+// Scale an image mask into a SplashBitmap.
+SplashBitmap *Splash::scaleMask(SplashImageMaskSource src, void *srcData,
+				int srcWidth, int srcHeight,
+				int scaledWidth, int scaledHeight) {
+  SplashBitmap *dest;
+
+  dest = new SplashBitmap(scaledWidth, scaledHeight, 1, splashModeMono8,
+			  gFalse);
+  if (scaledHeight < srcHeight) {
+    if (scaledWidth < srcWidth) {
+      scaleMaskYdXd(src, srcData, srcWidth, srcHeight,
+		    scaledWidth, scaledHeight, dest);
+    } else {
+      scaleMaskYdXu(src, srcData, srcWidth, srcHeight,
+		    scaledWidth, scaledHeight, dest);
+    }
+  } else {
+    if (scaledWidth < srcWidth) {
+      scaleMaskYuXd(src, srcData, srcWidth, srcHeight,
+		    scaledWidth, scaledHeight, dest);
+    } else {
+      scaleMaskYuXu(src, srcData, srcWidth, srcHeight,
+		    scaledWidth, scaledHeight, dest);
+    }
+  }
+  return dest;
+}
+
+void Splash::scaleMaskYdXd(SplashImageMaskSource src, void *srcData,
+			   int srcWidth, int srcHeight,
+			   int scaledWidth, int scaledHeight,
+			   SplashBitmap *dest) {
+  Guchar *lineBuf;
+  Guint *pixBuf;
+  Guint pix;
+  Guchar *destPtr;
+  int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx, d, d0, d1;
+  int i, j;
+
+  // Bresenham parameters for y scale
+  yp = srcHeight / scaledHeight;
+  yq = srcHeight % scaledHeight;
+
+  // Bresenham parameters for x scale
+  xp = srcWidth / scaledWidth;
+  xq = srcWidth % scaledWidth;
+
+  // allocate buffers
+  lineBuf = (Guchar *)gmalloc(srcWidth);
+  pixBuf = (Guint *)gmallocn(srcWidth, sizeof(int));
+
+  // init y scale Bresenham
+  yt = 0;
+
+  destPtr = dest->data;
+  for (y = 0; y < scaledHeight; ++y) {
+
+    // y scale Bresenham
+    if ((yt += yq) >= scaledHeight) {
+      yt -= scaledHeight;
+      yStep = yp + 1;
+    } else {
+      yStep = yp;
+    }
+
+    // read rows from image
+    memset(pixBuf, 0, srcWidth * sizeof(int));
+    for (i = 0; i < yStep; ++i) {
+      (*src)(srcData, lineBuf);
+      for (j = 0; j < srcWidth; ++j) {
+	pixBuf[j] += lineBuf[j];
+      }
+    }
+
+    // init x scale Bresenham
+    xt = 0;
+    d0 = (255 << 23) / (yStep * xp);
+    d1 = (255 << 23) / (yStep * (xp + 1));
+
+    xx = 0;
+    for (x = 0; x < scaledWidth; ++x) {
+
+      // x scale Bresenham
+      if ((xt += xq) >= scaledWidth) {
+	xt -= scaledWidth;
+	xStep = xp + 1;
+	d = d1;
+      } else {
+	xStep = xp;
+	d = d0;
+      }
+
+      // compute the final pixel
+      pix = 0;
+      for (i = 0; i < xStep; ++i) {
+	pix += pixBuf[xx++];
+      }
+      // (255 * pix) / xStep * yStep
+      pix = (pix * d) >> 23;
+
+      // store the pixel
+      *destPtr++ = (Guchar)pix;
+    }
+  }
+
+  gfree(pixBuf);
+  gfree(lineBuf);
+}
+
+void Splash::scaleMaskYdXu(SplashImageMaskSource src, void *srcData,
+			   int srcWidth, int srcHeight,
+			   int scaledWidth, int scaledHeight,
+			   SplashBitmap *dest) {
+  Guchar *lineBuf;
+  Guint *pixBuf;
+  Guint pix;
+  Guchar *destPtr;
+  int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, d;
+  int i, j;
+  
+  destPtr = dest->data;
+  if (destPtr == NULL) {
+    error(errInternal, -1, "dest->data is NULL in Splash::scaleMaskYdXu");
+    return;
+  }
+
+  // Bresenham parameters for y scale
+  yp = srcHeight / scaledHeight;
+  yq = srcHeight % scaledHeight;
+
+  // Bresenham parameters for x scale
+  xp = scaledWidth / srcWidth;
+  xq = scaledWidth % srcWidth;
+
+  // allocate buffers
+  lineBuf = (Guchar *)gmalloc(srcWidth);
+  pixBuf = (Guint *)gmallocn(srcWidth, sizeof(int));
+
+  // init y scale Bresenham
+  yt = 0;
+
+  for (y = 0; y < scaledHeight; ++y) {
+
+    // y scale Bresenham
+    if ((yt += yq) >= scaledHeight) {
+      yt -= scaledHeight;
+      yStep = yp + 1;
+    } else {
+      yStep = yp;
+    }
+
+    // read rows from image
+    memset(pixBuf, 0, srcWidth * sizeof(int));
+    for (i = 0; i < yStep; ++i) {
+      (*src)(srcData, lineBuf);
+      for (j = 0; j < srcWidth; ++j) {
+	pixBuf[j] += lineBuf[j];
+      }
+    }
+
+    // init x scale Bresenham
+    xt = 0;
+    d = (255 << 23) / yStep;
+
+    for (x = 0; x < srcWidth; ++x) {
+
+      // x scale Bresenham
+      if ((xt += xq) >= srcWidth) {
+	xt -= srcWidth;
+	xStep = xp + 1;
+      } else {
+	xStep = xp;
+      }
+
+      // compute the final pixel
+      pix = pixBuf[x];
+      // (255 * pix) / yStep
+      pix = (pix * d) >> 23;
+
+      // store the pixel
+      for (i = 0; i < xStep; ++i) {
+	*destPtr++ = (Guchar)pix;
+      }
+    }
+  }
+
+  gfree(pixBuf);
+  gfree(lineBuf);
+}
+
+void Splash::scaleMaskYuXd(SplashImageMaskSource src, void *srcData,
+			   int srcWidth, int srcHeight,
+			   int scaledWidth, int scaledHeight,
+			   SplashBitmap *dest) {
+  Guchar *lineBuf;
+  Guint pix;
+  Guchar *destPtr0, *destPtr;
+  int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx, d, d0, d1;
+  int i;
+  
+  destPtr0 = dest->data;
+  if (destPtr0 == NULL) {
+    error(errInternal, -1, "dest->data is NULL in Splash::scaleMaskYuXd");
+    return;
+  }
+
+  // Bresenham parameters for y scale
+  yp = scaledHeight / srcHeight;
+  yq = scaledHeight % srcHeight;
+
+  // Bresenham parameters for x scale
+  xp = srcWidth / scaledWidth;
+  xq = srcWidth % scaledWidth;
+
+  // allocate buffers
+  lineBuf = (Guchar *)gmalloc(srcWidth);
+
+  // init y scale Bresenham
+  yt = 0;
+
+  for (y = 0; y < srcHeight; ++y) {
+
+    // y scale Bresenham
+    if ((yt += yq) >= srcHeight) {
+      yt -= srcHeight;
+      yStep = yp + 1;
+    } else {
+      yStep = yp;
+    }
+
+    // read row from image
+    (*src)(srcData, lineBuf);
+
+    // init x scale Bresenham
+    xt = 0;
+    d0 = (255 << 23) / xp;
+    d1 = (255 << 23) / (xp + 1);
+
+    xx = 0;
+    for (x = 0; x < scaledWidth; ++x) {
+
+      // x scale Bresenham
+      if ((xt += xq) >= scaledWidth) {
+	xt -= scaledWidth;
+	xStep = xp + 1;
+	d = d1;
+      } else {
+	xStep = xp;
+	d = d0;
+      }
+
+      // compute the final pixel
+      pix = 0;
+      for (i = 0; i < xStep; ++i) {
+	pix += lineBuf[xx++];
+      }
+      // (255 * pix) / xStep
+      pix = (pix * d) >> 23;
+
+      // store the pixel
+      for (i = 0; i < yStep; ++i) {
+	destPtr = destPtr0 + i * scaledWidth + x;
+	*destPtr = (Guchar)pix;
+      }
+    }
+
+    destPtr0 += yStep * scaledWidth;
+  }
+
+  gfree(lineBuf);
+}
+
+void Splash::scaleMaskYuXu(SplashImageMaskSource src, void *srcData,
+			   int srcWidth, int srcHeight,
+			   int scaledWidth, int scaledHeight,
+			   SplashBitmap *dest) {
+  Guchar *lineBuf;
+  Guint pix;
+  Guchar *destPtr0, *destPtr;
+  int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx;
+  int i, j;
+
+  destPtr0 = dest->data;
+  if (destPtr0 == NULL) {
+    error(errInternal, -1, "dest->data is NULL in Splash::scaleMaskYuXu");
+    return;
+  }
+
+  // Bresenham parameters for y scale
+  yp = scaledHeight / srcHeight;
+  yq = scaledHeight % srcHeight;
+
+  // Bresenham parameters for x scale
+  xp = scaledWidth / srcWidth;
+  xq = scaledWidth % srcWidth;
+
+  // allocate buffers
+  lineBuf = (Guchar *)gmalloc(srcWidth);
+
+  // init y scale Bresenham
+  yt = 0;
+
+  for (y = 0; y < srcHeight; ++y) {
+
+    // y scale Bresenham
+    if ((yt += yq) >= srcHeight) {
+      yt -= srcHeight;
+      yStep = yp + 1;
+    } else {
+      yStep = yp;
+    }
+
+    // read row from image
+    (*src)(srcData, lineBuf);
+
+    // init x scale Bresenham
+    xt = 0;
+
+    xx = 0;
+    for (x = 0; x < srcWidth; ++x) {
+
+      // x scale Bresenham
+      if ((xt += xq) >= srcWidth) {
+	xt -= srcWidth;
+	xStep = xp + 1;
+      } else {
+	xStep = xp;
+      }
+
+      // compute the final pixel
+      pix = lineBuf[x] ? 255 : 0;
+
+      // store the pixel
+      for (i = 0; i < yStep; ++i) {
+	for (j = 0; j < xStep; ++j) {
+	  destPtr = destPtr0 + i * scaledWidth + xx + j;
+	  *destPtr++ = (Guchar)pix;
+	}
+      }
+
+      xx += xStep;
+    }
+
+    destPtr0 += yStep * scaledWidth;
+  }
+
+  gfree(lineBuf);
+}
+
+void Splash::blitMask(SplashBitmap *src, int xDest, int yDest,
+		      SplashClipResult clipRes) {
+  SplashPipe pipe;
+  Guchar *p;
+  int w, h, x, y;
+
+  w = src->getWidth();
+  h = src->getHeight();
+  p = src->getDataPtr();
+  if (p == NULL) {
+    error(errInternal, -1, "src->getDataPtr() is NULL in Splash::blitMask");
+    return;    
+  }
+  if (vectorAntialias && clipRes != splashClipAllInside) {
+    pipeInit(&pipe, xDest, yDest, state->fillPattern, NULL,
+	     (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse);
+    drawAAPixelInit();
+    for (y = 0; y < h; ++y) {
+      for (x = 0; x < w; ++x) {
+	pipe.shape = *p++;
+	drawAAPixel(&pipe, xDest + x, yDest + y);
+      }
+    }
+  } else {
+    pipeInit(&pipe, xDest, yDest, state->fillPattern, NULL,
+	     (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse);
+    if (clipRes == splashClipAllInside) {
+      for (y = 0; y < h; ++y) {
+	pipeSetXY(&pipe, xDest, yDest + y);
+	for (x = 0; x < w; ++x) {
+	  if (*p) {
+	    pipe.shape = *p;
+	    (this->*pipe.run)(&pipe);
+	  } else {
+	    pipeIncX(&pipe);
+	  }
+	  ++p;
+	}
+      }
+      updateModX(xDest);
+      updateModX(xDest + w - 1);
+      updateModY(yDest);
+      updateModY(yDest + h - 1);
+    } else {
+      for (y = 0; y < h; ++y) {
+	pipeSetXY(&pipe, xDest, yDest + y);
+	for (x = 0; x < w; ++x) {
+	  if (*p && state->clip->test(xDest + x, yDest + y)) {
+	    pipe.shape = *p;
+	    (this->*pipe.run)(&pipe);
+	    updateModX(xDest + x);
+	    updateModY(yDest + y);
+	  } else {
+	    pipeIncX(&pipe);
+	  }
+	  ++p;
+	}
+      }
+    }
+  }
+}
+
+SplashError Splash::drawImage(SplashImageSource src, SplashICCTransform tf, void *srcData,
+			      SplashColorMode srcMode, GBool srcAlpha,
+			      int w, int h, SplashCoord *mat, GBool interpolate,
+			      GBool tilingPattern) {
+  GBool ok;
+  SplashBitmap *scaledImg;
+  SplashClipResult clipRes;
+  GBool minorAxisZero;
+  int x0, y0, x1, y1, scaledWidth, scaledHeight;
+  int nComps;
+  int yp;
+
+  if (debugMode) {
+    printf("drawImage: srcMode=%d srcAlpha=%d w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n",
+	   srcMode, srcAlpha, w, h, (double)mat[0], (double)mat[1], (double)mat[2],
+	   (double)mat[3], (double)mat[4], (double)mat[5]);
+  }
+
+  // check color modes
+  ok = gFalse; // make gcc happy
+  nComps = 0; // make gcc happy
+  switch (bitmap->mode) {
+  case splashModeMono1:
+  case splashModeMono8:
+    ok = srcMode == splashModeMono8;
+    nComps = 1;
+    break;
+  case splashModeRGB8:
+    ok = srcMode == splashModeRGB8;
+    nComps = 3;
+    break;
+  case splashModeXBGR8:
+    ok = srcMode == splashModeXBGR8;
+    nComps = 4;
+    break;
+  case splashModeBGR8:
+    ok = srcMode == splashModeBGR8;
+    nComps = 3;
+    break;
+#ifdef SPLASH_CMYK
+  case splashModeCMYK8:
+    ok = srcMode == splashModeCMYK8;
+    nComps = 4;
+    break;
+  case splashModeDeviceN8:
+    ok = srcMode == splashModeDeviceN8;
+    nComps = SPOT_NCOMPS+4;
+    break;
+#endif
+  default:
+    ok = gFalse;
+    break;
+  }
+  if (!ok) {
+    return splashErrModeMismatch;
+  }
+
+  // check for singular matrix
+  if (!splashCheckDet(mat[0], mat[1], mat[2], mat[3], 0.000001)) {
+    return splashErrSingularMatrix;
+  }
+
+  minorAxisZero = mat[1] == 0 && mat[2] == 0;
+
+  // scaling only
+  if (mat[0] > 0 && minorAxisZero && mat[3] > 0) {
+    x0 = imgCoordMungeLower(mat[4]);
+    y0 = imgCoordMungeLower(mat[5]);
+    x1 = imgCoordMungeUpper(mat[0] + mat[4]);
+    y1 = imgCoordMungeUpper(mat[3] + mat[5]);
+    // make sure narrow images cover at least one pixel
+    if (x0 == x1) {
+      ++x1;
+    }
+    if (y0 == y1) {
+      ++y1;
+    }
+    clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1);
+    opClipRes = clipRes;
+    if (clipRes != splashClipAllOutside) {
+      scaledWidth = x1 - x0;
+      scaledHeight = y1 - y0;
+      yp = h / scaledHeight;
+      if (yp < 0 || yp > INT_MAX - 1) {
+        return splashErrBadArg;
+      }
+      scaledImg = scaleImage(src, srcData, srcMode, nComps, srcAlpha, w, h,
+			     scaledWidth, scaledHeight, interpolate, tilingPattern);
+      if (scaledImg == NULL) {
+        return splashErrBadArg;
+      }
+      if  (tf != NULL) {
+	(*tf)(srcData, scaledImg);
+      }
+      blitImage(scaledImg, srcAlpha, x0, y0, clipRes);
+      delete scaledImg;
+    }
+
+  // scaling plus vertical flip
+  } else if (mat[0] > 0 && minorAxisZero && mat[3] < 0) {
+    x0 = imgCoordMungeLower(mat[4]);
+    y0 = imgCoordMungeLower(mat[3] + mat[5]);
+    x1 = imgCoordMungeUpper(mat[0] + mat[4]);
+    y1 = imgCoordMungeUpper(mat[5]);
+    if (x0 == x1) {
+      if (mat[4] + mat[0] * 0.5 < x0) {
+	--x0;
+      } else {
+	++x1;
+      }
+    }
+    if (y0 == y1) {
+      if (mat[5] + mat[1] * 0.5 < y0) {
+	--y0;
+      } else {
+	++y1;
+      }
+    }
+    clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1);
+    opClipRes = clipRes;
+    if (clipRes != splashClipAllOutside) {
+      scaledWidth = x1 - x0;
+      scaledHeight = y1 - y0;
+      yp = h / scaledHeight;
+      if (yp < 0 || yp > INT_MAX - 1) {
+        return splashErrBadArg;
+      }
+      scaledImg = scaleImage(src, srcData, srcMode, nComps, srcAlpha, w, h,
+			     scaledWidth, scaledHeight, interpolate, tilingPattern);
+      if (scaledImg == NULL) {
+        return splashErrBadArg;
+      }
+      if  (tf != NULL) {
+	(*tf)(srcData, scaledImg);
+      }
+      vertFlipImage(scaledImg, scaledWidth, scaledHeight, nComps);
+      blitImage(scaledImg, srcAlpha, x0, y0, clipRes);
+      delete scaledImg;
+    }
+
+  // all other cases
+  } else {
+    return arbitraryTransformImage(src, tf, srcData, srcMode, nComps, srcAlpha,
+			    w, h, mat, interpolate, tilingPattern);
+  }
+
+  return splashOk;
+}
+
+SplashError Splash::arbitraryTransformImage(SplashImageSource src, SplashICCTransform tf, void *srcData,
+				     SplashColorMode srcMode, int nComps,
+				     GBool srcAlpha,
+				     int srcWidth, int srcHeight,
+				     SplashCoord *mat, GBool interpolate,
+             GBool tilingPattern) {
+  SplashBitmap *scaledImg;
+  SplashClipResult clipRes, clipRes2;
+  SplashPipe pipe;
+  SplashColor pixel;
+  int scaledWidth, scaledHeight, t0, t1, th;
+  SplashCoord r00, r01, r10, r11, det, ir00, ir01, ir10, ir11;
+  SplashCoord vx[4], vy[4];
+  int xMin, yMin, xMax, yMax;
+  ImageSection section[3];
+  int nSections;
+  int y, xa, xb, x, i, xx, yy, yp;
+
+  // compute the four vertices of the target quadrilateral
+  vx[0] = mat[4];                    vy[0] = mat[5];
+  vx[1] = mat[2] + mat[4];           vy[1] = mat[3] + mat[5];
+  vx[2] = mat[0] + mat[2] + mat[4];  vy[2] = mat[1] + mat[3] + mat[5];
+  vx[3] = mat[0] + mat[4];           vy[3] = mat[1] + mat[5];
+
+  // clipping
+  xMin = imgCoordMungeLower(vx[0]);
+  xMax = imgCoordMungeUpper(vx[0]);
+  yMin = imgCoordMungeLower(vy[0]);
+  yMax = imgCoordMungeUpper(vy[0]);
+  for (i = 1; i < 4; ++i) {
+    t0 = imgCoordMungeLower(vx[i]);
+    if (t0 < xMin) {
+      xMin = t0;
+    }
+    t0 = imgCoordMungeUpper(vx[i]);
+    if (t0 > xMax) {
+      xMax = t0;
+    }
+    t1 = imgCoordMungeLower(vy[i]);
+    if (t1 < yMin) {
+      yMin = t1;
+    }
+    t1 = imgCoordMungeUpper(vy[i]);
+    if (t1 > yMax) {
+      yMax = t1;
+    }
+  }
+  clipRes = state->clip->testRect(xMin, yMin, xMax, yMax);
+  opClipRes = clipRes;
+  if (clipRes == splashClipAllOutside) {
+    return splashOk;
+  }
+
+  // compute the scale factors
+  if (splashAbs(mat[0]) >= splashAbs(mat[1])) {
+    scaledWidth = xMax - xMin;
+    scaledHeight = yMax - yMin;
+  } else {
+    scaledWidth = yMax - yMin;
+    scaledHeight = xMax - xMin;
+  }
+  if (scaledHeight <= 1 || scaledWidth <= 1 || tilingPattern) {
+    if (mat[0] >= 0) {
+      t0 = imgCoordMungeUpper(mat[0] + mat[4]) - imgCoordMungeLower(mat[4]);
+    } else {
+      t0 = imgCoordMungeUpper(mat[4]) - imgCoordMungeLower(mat[0] + mat[4]);
+    }
+    if (mat[1] >= 0) {
+      t1 = imgCoordMungeUpper(mat[1] + mat[5]) - imgCoordMungeLower(mat[5]);
+    } else {
+      t1 = imgCoordMungeUpper(mat[5]) - imgCoordMungeLower(mat[1] + mat[5]);
+    }
+    scaledWidth = t0 > t1 ? t0 : t1;
+    if (mat[2] >= 0) {
+      t0 = imgCoordMungeUpper(mat[2] + mat[4]) - imgCoordMungeLower(mat[4]);
+      if (splashAbs(mat[1]) >= 1) {
+        th = imgCoordMungeUpper(mat[2]) - imgCoordMungeLower(mat[0] * mat[3] / mat[1]);
+	    if (th > t0) t0 = th;
+      }
+    } else {
+      t0 = imgCoordMungeUpper(mat[4]) - imgCoordMungeLower(mat[2] + mat[4]);
+      if (splashAbs(mat[1]) >= 1) {
+        th = imgCoordMungeUpper(mat[0] * mat[3] / mat[1]) - imgCoordMungeLower(mat[2]);
+        if (th > t0) t0 = th;
+      }
+    }
+    if (mat[3] >= 0) {
+      t1 = imgCoordMungeUpper(mat[3] + mat[5]) - imgCoordMungeLower(mat[5]);
+      if (splashAbs(mat[0]) >= 1) {
+        th = imgCoordMungeUpper(mat[3]) - imgCoordMungeLower(mat[1] * mat[2] / mat[0]);
+	    if (th > t1) t1 = th;
+      }
+    } else {
+      t1 = imgCoordMungeUpper(mat[5]) - imgCoordMungeLower(mat[3] + mat[5]);
+      if (splashAbs(mat[0]) >= 1) {
+        th = imgCoordMungeUpper(mat[1] * mat[2] / mat[0]) - imgCoordMungeLower(mat[3]);
+	    if (th > t1) t1 = th;
+      }
+    }
+    scaledHeight = t0 > t1 ? t0 : t1;
+  }
+  if (scaledWidth == 0) {
+    scaledWidth = 1;
+  }
+  if (scaledHeight == 0) {
+    scaledHeight = 1;
+  }
+
+  // compute the inverse transform (after scaling) matrix
+  r00 = mat[0] / scaledWidth;
+  r01 = mat[1] / scaledWidth;
+  r10 = mat[2] / scaledHeight;
+  r11 = mat[3] / scaledHeight;
+  det = r00 * r11 - r01 * r10;
+  if (splashAbs(det) < 1e-6) {
+    // this should be caught by the singular matrix check in drawImage
+    return splashErrBadArg;
+  }
+  ir00 = r11 / det;
+  ir01 = -r01 / det;
+  ir10 = -r10 / det;
+  ir11 = r00 / det;
+
+  // scale the input image
+  yp = srcHeight / scaledHeight;
+  if (yp < 0 || yp > INT_MAX - 1) {
+    return splashErrBadArg;
+  }
+  scaledImg = scaleImage(src, srcData, srcMode, nComps, srcAlpha,
+			 srcWidth, srcHeight, scaledWidth, scaledHeight, interpolate);
+
+  if (scaledImg == NULL) {
+    return splashErrBadArg;
+  }
+
+  if  (tf != NULL) {
+    (*tf)(srcData, scaledImg);
+  }
+  // construct the three sections
+  i = 0;
+  if (vy[1] < vy[i]) {
+    i = 1;
+  }
+  if (vy[2] < vy[i]) {
+    i = 2;
+  }
+  if (vy[3] < vy[i]) {
+    i = 3;
+  }
+  // NB: if using fixed point, 0.000001 will be truncated to zero,
+  // so these two comparisons must be <=, not <
+  if (splashAbs(vy[i] - vy[(i-1) & 3]) <= 0.000001 &&
+      vy[(i-1) & 3] < vy[(i+1) & 3]) {
+    i = (i-1) & 3;
+  }
+  if (splashAbs(vy[i] - vy[(i+1) & 3]) <= 0.000001) {
+    section[0].y0 = imgCoordMungeLower(vy[i]);
+    section[0].y1 = imgCoordMungeUpper(vy[(i+2) & 3]) - 1;
+    if (vx[i] < vx[(i+1) & 3]) {
+      section[0].ia0 = i;
+      section[0].ia1 = (i+3) & 3;
+      section[0].ib0 = (i+1) & 3;
+      section[0].ib1 = (i+2) & 3;
+    } else {
+      section[0].ia0 = (i+1) & 3;
+      section[0].ia1 = (i+2) & 3;
+      section[0].ib0 = i;
+      section[0].ib1 = (i+3) & 3;
+    }
+    nSections = 1;
+  } else {
+    section[0].y0 = imgCoordMungeLower(vy[i]);
+    section[2].y1 = imgCoordMungeUpper(vy[(i+2) & 3]) - 1;
+    section[0].ia0 = section[0].ib0 = i;
+    section[2].ia1 = section[2].ib1 = (i+2) & 3;
+    if (vx[(i+1) & 3] < vx[(i+3) & 3]) {
+      section[0].ia1 = section[2].ia0 = (i+1) & 3;
+      section[0].ib1 = section[2].ib0 = (i+3) & 3;
+    } else {
+      section[0].ia1 = section[2].ia0 = (i+3) & 3;
+      section[0].ib1 = section[2].ib0 = (i+1) & 3;
+    }
+    if (vy[(i+1) & 3] < vy[(i+3) & 3]) {
+      section[1].y0 = imgCoordMungeLower(vy[(i+1) & 3]);
+      section[2].y0 = imgCoordMungeUpper(vy[(i+3) & 3]);
+      if (vx[(i+1) & 3] < vx[(i+3) & 3]) {
+	section[1].ia0 = (i+1) & 3;
+	section[1].ia1 = (i+2) & 3;
+	section[1].ib0 = i;
+	section[1].ib1 = (i+3) & 3;
+      } else {
+	section[1].ia0 = i;
+	section[1].ia1 = (i+3) & 3;
+	section[1].ib0 = (i+1) & 3;
+	section[1].ib1 = (i+2) & 3;
+      }
+    } else {
+      section[1].y0 = imgCoordMungeLower(vy[(i+3) & 3]);
+      section[2].y0 = imgCoordMungeUpper(vy[(i+1) & 3]);
+      if (vx[(i+1) & 3] < vx[(i+3) & 3]) {
+	section[1].ia0 = i;
+	section[1].ia1 = (i+1) & 3;
+	section[1].ib0 = (i+3) & 3;
+	section[1].ib1 = (i+2) & 3;
+      } else {
+	section[1].ia0 = (i+3) & 3;
+	section[1].ia1 = (i+2) & 3;
+	section[1].ib0 = i;
+	section[1].ib1 = (i+1) & 3;
+      }
+    }
+    section[0].y1 = section[1].y0 - 1;
+    section[1].y1 = section[2].y0 - 1;
+    nSections = 3;
+  }
+  for (i = 0; i < nSections; ++i) {
+    section[i].xa0 = vx[section[i].ia0];
+    section[i].ya0 = vy[section[i].ia0];
+    section[i].xa1 = vx[section[i].ia1];
+    section[i].ya1 = vy[section[i].ia1];
+    section[i].xb0 = vx[section[i].ib0];
+    section[i].yb0 = vy[section[i].ib0];
+    section[i].xb1 = vx[section[i].ib1];
+    section[i].yb1 = vy[section[i].ib1];
+    section[i].dxdya = (section[i].xa1 - section[i].xa0) /
+                       (section[i].ya1 - section[i].ya0);
+    section[i].dxdyb = (section[i].xb1 - section[i].xb0) /
+                       (section[i].yb1 - section[i].yb0);
+  }
+
+  // initialize the pixel pipe
+  pipeInit(&pipe, 0, 0, NULL, pixel,
+	   (Guchar)splashRound(state->fillAlpha * 255),
+	   srcAlpha || (vectorAntialias && clipRes != splashClipAllInside),
+	   gFalse);
+  if (vectorAntialias) {
+    drawAAPixelInit();
+  }
+
+  // make sure narrow images cover at least one pixel
+  if (nSections == 1) {
+    if (section[0].y0 == section[0].y1) {
+      ++section[0].y1;
+      clipRes = opClipRes = splashClipPartial;
+    }
+  } else {
+    if (section[0].y0 == section[2].y1) {
+      ++section[1].y1;
+      clipRes = opClipRes = splashClipPartial;
+    }
+  }
+
+  // scan all pixels inside the target region
+  for (i = 0; i < nSections; ++i) {
+    for (y = section[i].y0; y <= section[i].y1; ++y) {
+      xa = imgCoordMungeLower(section[i].xa0 +
+			      ((SplashCoord)y + 0.5 - section[i].ya0) *
+			        section[i].dxdya);
+      if (unlikely(xa < 0))
+        xa = 0;
+      xb = imgCoordMungeUpper(section[i].xb0 +
+			      ((SplashCoord)y + 0.5 - section[i].yb0) *
+			        section[i].dxdyb);
+      // make sure narrow images cover at least one pixel
+      if (xa == xb) {
+	++xb;
+      }
+      if (clipRes != splashClipAllInside) {
+	clipRes2 = state->clip->testSpan(xa, xb - 1, y);
+      } else {
+	clipRes2 = clipRes;
+      }
+      for (x = xa; x < xb; ++x) {
+	// map (x+0.5, y+0.5) back to the scaled image
+	xx = splashFloor(((SplashCoord)x + 0.5 - mat[4]) * ir00 +
+			 ((SplashCoord)y + 0.5 - mat[5]) * ir10);
+	yy = splashFloor(((SplashCoord)x + 0.5 - mat[4]) * ir01 +
+			 ((SplashCoord)y + 0.5 - mat[5]) * ir11);
+	// xx should always be within bounds, but floating point
+	// inaccuracy can cause problems
+	if (xx < 0) {
+	  xx = 0;
+	} else if (xx >= scaledWidth) {
+	  xx = scaledWidth - 1;
+	}
+	if (yy < 0) {
+	  yy = 0;
+	} else if (yy >= scaledHeight) {
+	  yy = scaledHeight - 1;
+	}
+	scaledImg->getPixel(xx, yy, pixel);
+	if (srcAlpha) {
+	  pipe.shape = scaledImg->alpha[yy * scaledWidth + xx];
+	} else {
+	  pipe.shape = 255;
+	}
+	if (vectorAntialias && clipRes2 != splashClipAllInside) {
+	  drawAAPixel(&pipe, x, y);
+	} else {
+	  drawPixel(&pipe, x, y, clipRes2 == splashClipAllInside);
+	}
+      }
+    }
+  }
+
+  delete scaledImg;
+  return splashOk;
+}
+
+// determine if a scaled image requires interpolation based on the scale and
+// the interpolate flag from the image dictionary
+static GBool isImageInterpolationRequired(int srcWidth, int srcHeight,
+                                          int scaledWidth, int scaledHeight,
+                                          GBool interpolate) {
+  if (interpolate || srcWidth == 0 || srcHeight == 0)
+    return gTrue;
+
+  /* When scale factor is >= 400% we don't interpolate. See bugs #25268, #9860 */
+  if (scaledWidth / srcWidth >= 4 || scaledHeight / srcHeight >= 4)
+    return gFalse;
+
+  return gTrue;
+}
+
+// Scale an image into a SplashBitmap.
+SplashBitmap *Splash::scaleImage(SplashImageSource src, void *srcData,
+				 SplashColorMode srcMode, int nComps,
+				 GBool srcAlpha, int srcWidth, int srcHeight,
+				 int scaledWidth, int scaledHeight, GBool interpolate, GBool tilingPattern) {
+  SplashBitmap *dest;
+
+  dest = new SplashBitmap(scaledWidth, scaledHeight, 1, srcMode, srcAlpha, gTrue, bitmap->getSeparationList());
+  if (dest->getDataPtr() != NULL && srcHeight > 0 && srcWidth > 0) {
+    if (scaledHeight < srcHeight) {
+      if (scaledWidth < srcWidth) {
+	scaleImageYdXd(src, srcData, srcMode, nComps, srcAlpha,
+		      srcWidth, srcHeight, scaledWidth, scaledHeight, dest);
+      } else {
+	scaleImageYdXu(src, srcData, srcMode, nComps, srcAlpha,
+		      srcWidth, srcHeight, scaledWidth, scaledHeight, dest);
+      }
+    } else {
+      if (scaledWidth < srcWidth) {
+	scaleImageYuXd(src, srcData, srcMode, nComps, srcAlpha,
+		      srcWidth, srcHeight, scaledWidth, scaledHeight, dest);
+      } else {
+	if (!tilingPattern && isImageInterpolationRequired(srcWidth, srcHeight, scaledWidth, scaledHeight, interpolate)) {
+	  scaleImageYuXuBilinear(src, srcData, srcMode, nComps, srcAlpha,
+				srcWidth, srcHeight, scaledWidth, scaledHeight, dest);
+	} else {
+	  scaleImageYuXu(src, srcData, srcMode, nComps, srcAlpha,
+			srcWidth, srcHeight, scaledWidth, scaledHeight, dest);
+	}
+      }
+    }
+  } else {
+    delete dest;
+    dest = NULL;
+  }
+  return dest;
+}
+
+void Splash::scaleImageYdXd(SplashImageSource src, void *srcData,
+			    SplashColorMode srcMode, int nComps,
+			    GBool srcAlpha, int srcWidth, int srcHeight,
+			    int scaledWidth, int scaledHeight,
+			    SplashBitmap *dest) {
+  Guchar *lineBuf, *alphaLineBuf;
+  Guint *pixBuf, *alphaPixBuf;
+  Guint pix0, pix1, pix2;
+#ifdef SPLASH_CMYK
+  Guint pix3;
+  Guint pix[SPOT_NCOMPS+4], cp;
+#endif
+  Guint alpha;
+  Guchar *destPtr, *destAlphaPtr;
+  int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx, xxa, d, d0, d1;
+  int i, j;
+
+  // Bresenham parameters for y scale
+  yp = srcHeight / scaledHeight;
+  yq = srcHeight % scaledHeight;
+
+  // Bresenham parameters for x scale
+  xp = srcWidth / scaledWidth;
+  xq = srcWidth % scaledWidth;
+
+  // allocate buffers
+  lineBuf = (Guchar *)gmallocn(srcWidth, nComps);
+  pixBuf = (Guint *)gmallocn(srcWidth, nComps * sizeof(int));
+  if (srcAlpha) {
+    alphaLineBuf = (Guchar *)gmalloc(srcWidth);
+    alphaPixBuf = (Guint *)gmallocn(srcWidth, sizeof(int));
+  } else {
+    alphaLineBuf = NULL;
+    alphaPixBuf = NULL;
+  }
+
+  // init y scale Bresenham
+  yt = 0;
+
+  destPtr = dest->data;
+  destAlphaPtr = dest->alpha;
+  for (y = 0; y < scaledHeight; ++y) {
+
+    // y scale Bresenham
+    if ((yt += yq) >= scaledHeight) {
+      yt -= scaledHeight;
+      yStep = yp + 1;
+    } else {
+      yStep = yp;
+    }
+
+    // read rows from image
+    memset(pixBuf, 0, srcWidth * nComps * sizeof(int));
+    if (srcAlpha) {
+      memset(alphaPixBuf, 0, srcWidth * sizeof(int));
+    }
+    for (i = 0; i < yStep; ++i) {
+      (*src)(srcData, lineBuf, alphaLineBuf);
+      for (j = 0; j < srcWidth * nComps; ++j) {
+	pixBuf[j] += lineBuf[j];
+      }
+      if (srcAlpha) {
+	for (j = 0; j < srcWidth; ++j) {
+	  alphaPixBuf[j] += alphaLineBuf[j];
+	}
+      }
+    }
+
+    // init x scale Bresenham
+    xt = 0;
+    d0 = (1 << 23) / (yStep * xp);
+    d1 = (1 << 23) / (yStep * (xp + 1));
+
+    xx = xxa = 0;
+    for (x = 0; x < scaledWidth; ++x) {
+
+      // x scale Bresenham
+      if ((xt += xq) >= scaledWidth) {
+	xt -= scaledWidth;
+	xStep = xp + 1;
+	d = d1;
+      } else {
+	xStep = xp;
+	d = d0;
+      }
+
+      switch (srcMode) {
+
+      case splashModeMono8:
+
+	// compute the final pixel
+	pix0 = 0;
+	for (i = 0; i < xStep; ++i) {
+	  pix0 += pixBuf[xx++];
+	}
+	// pix / xStep * yStep
+	pix0 = (pix0 * d) >> 23;
+
+	// store the pixel
+	*destPtr++ = (Guchar)pix0;
+	break;
+
+      case splashModeRGB8:
+
+	// compute the final pixel
+	pix0 = pix1 = pix2 = 0;
+	for (i = 0; i < xStep; ++i) {
+	  pix0 += pixBuf[xx];
+	  pix1 += pixBuf[xx+1];
+	  pix2 += pixBuf[xx+2];
+	  xx += 3;
+	}
+	// pix / xStep * yStep
+	pix0 = (pix0 * d) >> 23;
+	pix1 = (pix1 * d) >> 23;
+	pix2 = (pix2 * d) >> 23;
+
+	// store the pixel
+	*destPtr++ = (Guchar)pix0;
+	*destPtr++ = (Guchar)pix1;
+	*destPtr++ = (Guchar)pix2;
+	break;
+
+      case splashModeXBGR8:
+
+	// compute the final pixel
+	pix0 = pix1 = pix2 = 0;
+	for (i = 0; i < xStep; ++i) {
+	  pix0 += pixBuf[xx];
+	  pix1 += pixBuf[xx+1];
+	  pix2 += pixBuf[xx+2];
+	  xx += 4;
+	}
+	// pix / xStep * yStep
+	pix0 = (pix0 * d) >> 23;
+	pix1 = (pix1 * d) >> 23;
+	pix2 = (pix2 * d) >> 23;
+
+	// store the pixel
+	*destPtr++ = (Guchar)pix2;
+	*destPtr++ = (Guchar)pix1;
+	*destPtr++ = (Guchar)pix0;
+	*destPtr++ = (Guchar)255;
+	break;
+
+      case splashModeBGR8:
+
+	// compute the final pixel
+	pix0 = pix1 = pix2 = 0;
+	for (i = 0; i < xStep; ++i) {
+	  pix0 += pixBuf[xx];
+	  pix1 += pixBuf[xx+1];
+	  pix2 += pixBuf[xx+2];
+	  xx += 3;
+	}
+	// pix / xStep * yStep
+	pix0 = (pix0 * d) >> 23;
+	pix1 = (pix1 * d) >> 23;
+	pix2 = (pix2 * d) >> 23;
+
+	// store the pixel
+	*destPtr++ = (Guchar)pix2;
+	*destPtr++ = (Guchar)pix1;
+	*destPtr++ = (Guchar)pix0;
+	break;
+
+#ifdef SPLASH_CMYK
+      case splashModeCMYK8:
+
+	// compute the final pixel
+	pix0 = pix1 = pix2 = pix3 = 0;
+	for (i = 0; i < xStep; ++i) {
+	  pix0 += pixBuf[xx];
+	  pix1 += pixBuf[xx+1];
+	  pix2 += pixBuf[xx+2];
+	  pix3 += pixBuf[xx+3];
+	  xx += 4;
+	}
+	// pix / xStep * yStep
+	pix0 = (pix0 * d) >> 23;
+	pix1 = (pix1 * d) >> 23;
+	pix2 = (pix2 * d) >> 23;
+	pix3 = (pix3 * d) >> 23;
+
+	// store the pixel
+	*destPtr++ = (Guchar)pix0;
+	*destPtr++ = (Guchar)pix1;
+	*destPtr++ = (Guchar)pix2;
+	*destPtr++ = (Guchar)pix3;
+	break;
+      case splashModeDeviceN8:
+
+	// compute the final pixel
+  for (cp = 0; cp < SPOT_NCOMPS+4; cp++)
+    pix[cp] = 0;
+	for (i = 0; i < xStep; ++i) {
+    for (cp = 0; cp < SPOT_NCOMPS+4; cp++) {
+      pix[cp] += pixBuf[xx + cp];
+    }
+    xx += (SPOT_NCOMPS+4);
+	}
+	// pix / xStep * yStep
+  for (cp = 0; cp < SPOT_NCOMPS+4; cp++)
+    pix[cp] = (pix[cp] * d) >> 23;
+
+	// store the pixel
+  for (cp = 0; cp < SPOT_NCOMPS+4; cp++)
+    *destPtr++ = (Guchar)pix[cp];
+	break;
+#endif
+
+
+      case splashModeMono1: // mono1 is not allowed
+      default:
+	break;
+      }
+
+      // process alpha
+      if (srcAlpha) {
+	alpha = 0;
+	for (i = 0; i < xStep; ++i, ++xxa) {
+	  alpha += alphaPixBuf[xxa];
+	}
+	// alpha / xStep * yStep
+	alpha = (alpha * d) >> 23;
+	*destAlphaPtr++ = (Guchar)alpha;
+      }
+    }
+  }
+
+  gfree(alphaPixBuf);
+  gfree(alphaLineBuf);
+  gfree(pixBuf);
+  gfree(lineBuf);
+}
+
+void Splash::scaleImageYdXu(SplashImageSource src, void *srcData,
+			    SplashColorMode srcMode, int nComps,
+			    GBool srcAlpha, int srcWidth, int srcHeight,
+			    int scaledWidth, int scaledHeight,
+			    SplashBitmap *dest) {
+  Guchar *lineBuf, *alphaLineBuf;
+  Guint *pixBuf, *alphaPixBuf;
+  Guint pix[splashMaxColorComps];
+  Guint alpha;
+  Guchar *destPtr, *destAlphaPtr;
+  int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, d;
+  int i, j;
+
+  // Bresenham parameters for y scale
+  yp = srcHeight / scaledHeight;
+  yq = srcHeight % scaledHeight;
+
+  // Bresenham parameters for x scale
+  xp = scaledWidth / srcWidth;
+  xq = scaledWidth % srcWidth;
+
+  // allocate buffers
+  lineBuf = (Guchar *)gmallocn(srcWidth, nComps);
+  pixBuf = (Guint *)gmallocn(srcWidth, nComps * sizeof(int));
+  if (srcAlpha) {
+    alphaLineBuf = (Guchar *)gmalloc(srcWidth);
+    alphaPixBuf = (Guint *)gmallocn(srcWidth, sizeof(int));
+  } else {
+    alphaLineBuf = NULL;
+    alphaPixBuf = NULL;
+  }
+
+  // init y scale Bresenham
+  yt = 0;
+
+  destPtr = dest->data;
+  destAlphaPtr = dest->alpha;
+  for (y = 0; y < scaledHeight; ++y) {
+
+    // y scale Bresenham
+    if ((yt += yq) >= scaledHeight) {
+      yt -= scaledHeight;
+      yStep = yp + 1;
+    } else {
+      yStep = yp;
+    }
+
+    // read rows from image
+    memset(pixBuf, 0, srcWidth * nComps * sizeof(int));
+    if (srcAlpha) {
+      memset(alphaPixBuf, 0, srcWidth * sizeof(int));
+    }
+    for (i = 0; i < yStep; ++i) {
+      (*src)(srcData, lineBuf, alphaLineBuf);
+      for (j = 0; j < srcWidth * nComps; ++j) {
+	pixBuf[j] += lineBuf[j];
+      }
+      if (srcAlpha) {
+	for (j = 0; j < srcWidth; ++j) {
+	  alphaPixBuf[j] += alphaLineBuf[j];
+	}
+      }
+    }
+
+    // init x scale Bresenham
+    xt = 0;
+    d = (1 << 23) / yStep;
+
+    for (x = 0; x < srcWidth; ++x) {
+
+      // x scale Bresenham
+      if ((xt += xq) >= srcWidth) {
+	xt -= srcWidth;
+	xStep = xp + 1;
+      } else {
+	xStep = xp;
+      }
+
+      // compute the final pixel
+      for (i = 0; i < nComps; ++i) {
+	// pixBuf[] / yStep
+	pix[i] = (pixBuf[x * nComps + i] * d) >> 23;
+      }
+
+      // store the pixel
+      switch (srcMode) {
+      case splashModeMono1: // mono1 is not allowed
+	break;
+      case splashModeMono8:
+	for (i = 0; i < xStep; ++i) {
+	  *destPtr++ = (Guchar)pix[0];
+	}
+	break;
+      case splashModeRGB8:
+	for (i = 0; i < xStep; ++i) {
+	  *destPtr++ = (Guchar)pix[0];
+	  *destPtr++ = (Guchar)pix[1];
+	  *destPtr++ = (Guchar)pix[2];
+	}
+	break;
+      case splashModeXBGR8:
+	for (i = 0; i < xStep; ++i) {
+	  *destPtr++ = (Guchar)pix[2];
+	  *destPtr++ = (Guchar)pix[1];
+	  *destPtr++ = (Guchar)pix[0];
+	  *destPtr++ = (Guchar)255;
+	}
+	break;
+      case splashModeBGR8:
+	for (i = 0; i < xStep; ++i) {
+	  *destPtr++ = (Guchar)pix[2];
+	  *destPtr++ = (Guchar)pix[1];
+	  *destPtr++ = (Guchar)pix[0];
+	}
+	break;
+#ifdef SPLASH_CMYK
+      case splashModeCMYK8:
+	for (i = 0; i < xStep; ++i) {
+	  *destPtr++ = (Guchar)pix[0];
+	  *destPtr++ = (Guchar)pix[1];
+	  *destPtr++ = (Guchar)pix[2];
+	  *destPtr++ = (Guchar)pix[3];
+	}
+	break;
+      case splashModeDeviceN8:
+	for (i = 0; i < xStep; ++i) {
+    for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+      *destPtr++ = (Guchar)pix[cp];
+	}
+	break;
+#endif
+      }
+
+      // process alpha
+      if (srcAlpha) {
+	// alphaPixBuf[] / yStep
+	alpha = (alphaPixBuf[x] * d) >> 23;
+	for (i = 0; i < xStep; ++i) {
+	  *destAlphaPtr++ = (Guchar)alpha;
+	}
+      }
+    }
+  }
+
+  gfree(alphaPixBuf);
+  gfree(alphaLineBuf);
+  gfree(pixBuf);
+  gfree(lineBuf);
+}
+
+void Splash::scaleImageYuXd(SplashImageSource src, void *srcData,
+			    SplashColorMode srcMode, int nComps,
+			    GBool srcAlpha, int srcWidth, int srcHeight,
+			    int scaledWidth, int scaledHeight,
+			    SplashBitmap *dest) {
+  Guchar *lineBuf, *alphaLineBuf;
+  Guint pix[splashMaxColorComps];
+  Guint alpha;
+  Guchar *destPtr0, *destPtr, *destAlphaPtr0, *destAlphaPtr;
+  int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx, xxa, d, d0, d1;
+  int i, j;
+
+  // Bresenham parameters for y scale
+  yp = scaledHeight / srcHeight;
+  yq = scaledHeight % srcHeight;
+
+  // Bresenham parameters for x scale
+  xp = srcWidth / scaledWidth;
+  xq = srcWidth % scaledWidth;
+
+  // allocate buffers
+  lineBuf = (Guchar *)gmallocn_checkoverflow(srcWidth, nComps);
+  if (unlikely(!lineBuf))
+    return;
+  if (srcAlpha) {
+    alphaLineBuf = (Guchar *)gmalloc(srcWidth);
+  } else {
+    alphaLineBuf = NULL;
+  }
+
+  // init y scale Bresenham
+  yt = 0;
+
+  destPtr0 = dest->data;
+  destAlphaPtr0 = dest->alpha;
+  for (y = 0; y < srcHeight; ++y) {
+
+    // y scale Bresenham
+    if ((yt += yq) >= srcHeight) {
+      yt -= srcHeight;
+      yStep = yp + 1;
+    } else {
+      yStep = yp;
+    }
+
+    // read row from image
+    (*src)(srcData, lineBuf, alphaLineBuf);
+
+    // init x scale Bresenham
+    xt = 0;
+    d0 = (1 << 23) / xp;
+    d1 = (1 << 23) / (xp + 1);
+
+    xx = xxa = 0;
+    for (x = 0; x < scaledWidth; ++x) {
+
+      // x scale Bresenham
+      if ((xt += xq) >= scaledWidth) {
+	xt -= scaledWidth;
+	xStep = xp + 1;
+	d = d1;
+      } else {
+	xStep = xp;
+	d = d0;
+      }
+
+      // compute the final pixel
+      for (i = 0; i < nComps; ++i) {
+	pix[i] = 0;
+      }
+      for (i = 0; i < xStep; ++i) {
+	for (j = 0; j < nComps; ++j, ++xx) {
+	  pix[j] += lineBuf[xx];
+	}
+      }
+      for (i = 0; i < nComps; ++i) {
+	// pix[] / xStep
+	pix[i] = (pix[i] * d) >> 23;
+      }
+
+      // store the pixel
+      switch (srcMode) {
+      case splashModeMono1: // mono1 is not allowed
+	break;
+      case splashModeMono8:
+	for (i = 0; i < yStep; ++i) {
+	  destPtr = destPtr0 + (i * scaledWidth + x) * nComps;
+	  *destPtr++ = (Guchar)pix[0];
+	}
+	break;
+      case splashModeRGB8:
+	for (i = 0; i < yStep; ++i) {
+	  destPtr = destPtr0 + (i * scaledWidth + x) * nComps;
+	  *destPtr++ = (Guchar)pix[0];
+	  *destPtr++ = (Guchar)pix[1];
+	  *destPtr++ = (Guchar)pix[2];
+	}
+	break;
+      case splashModeXBGR8:
+	for (i = 0; i < yStep; ++i) {
+	  destPtr = destPtr0 + (i * scaledWidth + x) * nComps;
+	  *destPtr++ = (Guchar)pix[2];
+	  *destPtr++ = (Guchar)pix[1];
+	  *destPtr++ = (Guchar)pix[0];
+	  *destPtr++ = (Guchar)255;
+	}
+	break;
+      case splashModeBGR8:
+	for (i = 0; i < yStep; ++i) {
+	  destPtr = destPtr0 + (i * scaledWidth + x) * nComps;
+	  *destPtr++ = (Guchar)pix[2];
+	  *destPtr++ = (Guchar)pix[1];
+	  *destPtr++ = (Guchar)pix[0];
+	}
+	break;
+#ifdef SPLASH_CMYK
+      case splashModeCMYK8:
+	for (i = 0; i < yStep; ++i) {
+	  destPtr = destPtr0 + (i * scaledWidth + x) * nComps;
+	  *destPtr++ = (Guchar)pix[0];
+	  *destPtr++ = (Guchar)pix[1];
+	  *destPtr++ = (Guchar)pix[2];
+	  *destPtr++ = (Guchar)pix[3];
+	}
+	break;
+      case splashModeDeviceN8:
+	for (i = 0; i < yStep; ++i) {
+	  destPtr = destPtr0 + (i * scaledWidth + x) * nComps;
+    for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+      *destPtr++ = (Guchar)pix[cp];
+	}
+	break;
+#endif
+      }
+
+      // process alpha
+      if (srcAlpha) {
+	alpha = 0;
+	for (i = 0; i < xStep; ++i, ++xxa) {
+	  alpha += alphaLineBuf[xxa];
+	}
+	// alpha / xStep
+	alpha = (alpha * d) >> 23;
+	for (i = 0; i < yStep; ++i) {
+	  destAlphaPtr = destAlphaPtr0 + i * scaledWidth + x;
+	  *destAlphaPtr = (Guchar)alpha;
+	}
+      }
+    }
+
+    destPtr0 += yStep * scaledWidth * nComps;
+    if (srcAlpha) {
+      destAlphaPtr0 += yStep * scaledWidth;
+    }
+  }
+
+  gfree(alphaLineBuf);
+  gfree(lineBuf);
+}
+
+void Splash::scaleImageYuXu(SplashImageSource src, void *srcData,
+			    SplashColorMode srcMode, int nComps,
+			    GBool srcAlpha, int srcWidth, int srcHeight,
+			    int scaledWidth, int scaledHeight,
+			    SplashBitmap *dest) {
+  Guchar *lineBuf, *alphaLineBuf;
+  Guint pix[splashMaxColorComps];
+  Guint alpha;
+  Guchar *destPtr0, *destPtr, *destAlphaPtr0, *destAlphaPtr;
+  int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx;
+  int i, j;
+
+  // Bresenham parameters for y scale
+  yp = scaledHeight / srcHeight;
+  yq = scaledHeight % srcHeight;
+
+  // Bresenham parameters for x scale
+  xp = scaledWidth / srcWidth;
+  xq = scaledWidth % srcWidth;
+
+  // allocate buffers
+  lineBuf = (Guchar *)gmallocn(srcWidth, nComps);
+  if (srcAlpha) {
+    alphaLineBuf = (Guchar *)gmalloc(srcWidth);
+  } else {
+    alphaLineBuf = NULL;
+  }
+
+  // init y scale Bresenham
+  yt = 0;
+
+  destPtr0 = dest->data;
+  destAlphaPtr0 = dest->alpha;
+  for (y = 0; y < srcHeight; ++y) {
+
+    // y scale Bresenham
+    if ((yt += yq) >= srcHeight) {
+      yt -= srcHeight;
+      yStep = yp + 1;
+    } else {
+      yStep = yp;
+    }
+
+    // read row from image
+    (*src)(srcData, lineBuf, alphaLineBuf);
+
+    // init x scale Bresenham
+    xt = 0;
+
+    xx = 0;
+    for (x = 0; x < srcWidth; ++x) {
+
+      // x scale Bresenham
+      if ((xt += xq) >= srcWidth) {
+	xt -= srcWidth;
+	xStep = xp + 1;
+      } else {
+	xStep = xp;
+      }
+
+      // compute the final pixel
+      for (i = 0; i < nComps; ++i) {
+	pix[i] = lineBuf[x * nComps + i];
+      }
+
+      // store the pixel
+      switch (srcMode) {
+      case splashModeMono1: // mono1 is not allowed
+	break;
+      case splashModeMono8:
+	for (i = 0; i < yStep; ++i) {
+	  for (j = 0; j < xStep; ++j) {
+	    destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps;
+	    *destPtr++ = (Guchar)pix[0];
+	  }
+	}
+	break;
+      case splashModeRGB8:
+	for (i = 0; i < yStep; ++i) {
+	  for (j = 0; j < xStep; ++j) {
+	    destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps;
+	    *destPtr++ = (Guchar)pix[0];
+	    *destPtr++ = (Guchar)pix[1];
+	    *destPtr++ = (Guchar)pix[2];
+	  }
+	}
+	break;
+      case splashModeXBGR8:
+	for (i = 0; i < yStep; ++i) {
+	  for (j = 0; j < xStep; ++j) {
+	    destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps;
+	    *destPtr++ = (Guchar)pix[2];
+	    *destPtr++ = (Guchar)pix[1];
+	    *destPtr++ = (Guchar)pix[0];
+	    *destPtr++ = (Guchar)255;
+	  }
+	}
+	break;
+      case splashModeBGR8:
+	for (i = 0; i < yStep; ++i) {
+	  for (j = 0; j < xStep; ++j) {
+	    destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps;
+	    *destPtr++ = (Guchar)pix[2];
+	    *destPtr++ = (Guchar)pix[1];
+	    *destPtr++ = (Guchar)pix[0];
+	  }
+	}
+	break;
+#ifdef SPLASH_CMYK
+      case splashModeCMYK8:
+	for (i = 0; i < yStep; ++i) {
+	  for (j = 0; j < xStep; ++j) {
+	    destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps;
+	    *destPtr++ = (Guchar)pix[0];
+	    *destPtr++ = (Guchar)pix[1];
+	    *destPtr++ = (Guchar)pix[2];
+	    *destPtr++ = (Guchar)pix[3];
+	  }
+	}
+	break;
+      case splashModeDeviceN8:
+	for (i = 0; i < yStep; ++i) {
+	  for (j = 0; j < xStep; ++j) {
+	    destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps;
+      for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+        *destPtr++ = (Guchar)pix[cp];
+	  }
+	}
+	break;
+#endif
+      }
+
+      // process alpha
+      if (srcAlpha) {
+	alpha = alphaLineBuf[x];
+	for (i = 0; i < yStep; ++i) {
+	  for (j = 0; j < xStep; ++j) {
+	    destAlphaPtr = destAlphaPtr0 + i * scaledWidth + xx + j;
+	    *destAlphaPtr = (Guchar)alpha;
+	  }
+	}
+      }
+
+      xx += xStep;
+    }
+
+    destPtr0 += yStep * scaledWidth * nComps;
+    if (srcAlpha) {
+      destAlphaPtr0 += yStep * scaledWidth;
+    }
+  }
+
+  gfree(alphaLineBuf);
+  gfree(lineBuf);
+}
+
+// expand source row to scaledWidth using linear interpolation
+static void expandRow(Guchar *srcBuf, Guchar *dstBuf, int srcWidth, int scaledWidth, int nComps)
+{
+  double xStep = (double)srcWidth/scaledWidth;
+  double xSrc = 0.0;
+  double xFrac, xInt;
+  int p;
+
+  // pad the source with an extra pixel equal to the last pixel
+  // so that when xStep is inside the last pixel we still have two
+  // pixels to interpolate between.
+  for (int i = 0; i < nComps; i++)
+    srcBuf[srcWidth*nComps + i] = srcBuf[(srcWidth-1)*nComps + i];
+
+  for (int x = 0; x < scaledWidth; x++) {
+    xFrac = modf(xSrc, &xInt);
+    p = (int)xInt;
+    for (int c = 0; c < nComps; c++) {
+      dstBuf[nComps*x + c] = srcBuf[nComps*p + c]*(1.0 - xFrac) + srcBuf[nComps*(p+1) + c]*xFrac;
+    }
+    xSrc += xStep;
+  }
+}
+
+// Scale up image using bilinear interpolation
+void Splash::scaleImageYuXuBilinear(SplashImageSource src, void *srcData,
+                                    SplashColorMode srcMode, int nComps,
+                                    GBool srcAlpha, int srcWidth, int srcHeight,
+                                    int scaledWidth, int scaledHeight,
+                                    SplashBitmap *dest) {
+  Guchar *srcBuf, *lineBuf1, *lineBuf2, *alphaSrcBuf, *alphaLineBuf1, *alphaLineBuf2;
+  Guint pix[splashMaxColorComps];
+  Guchar *destPtr0, *destPtr, *destAlphaPtr0, *destAlphaPtr;
+  int i;
+
+  if (srcWidth < 1 || srcHeight < 1)
+    return;
+
+  // allocate buffers
+  srcBuf = (Guchar *)gmallocn(srcWidth+1, nComps); // + 1 pixel of padding
+  lineBuf1 = (Guchar *)gmallocn(scaledWidth, nComps);
+  lineBuf2 = (Guchar *)gmallocn(scaledWidth, nComps);
+  if (srcAlpha) {
+    alphaSrcBuf = (Guchar *)gmalloc(srcWidth+1); // + 1 pixel of padding
+    alphaLineBuf1 = (Guchar *)gmalloc(scaledWidth);
+    alphaLineBuf2 = (Guchar *)gmalloc(scaledWidth);
+  } else {
+    alphaSrcBuf = NULL;
+    alphaLineBuf1 = NULL;
+    alphaLineBuf2 = NULL;
+  }
+
+  double ySrc = 0.0;
+  double yStep = (double)srcHeight/scaledHeight;
+  double yFrac, yInt;
+  int currentSrcRow = -1;
+  (*src)(srcData, srcBuf, alphaSrcBuf);
+  expandRow(srcBuf, lineBuf2, srcWidth, scaledWidth, nComps);
+  if (srcAlpha)
+    expandRow(alphaSrcBuf, alphaLineBuf2, srcWidth, scaledWidth, 1);
+
+  destPtr0 = dest->data;
+  destAlphaPtr0 = dest->alpha;
+  for (int y = 0; y < scaledHeight; y++) {
+    yFrac = modf(ySrc, &yInt);
+    if ((int)yInt > currentSrcRow) {
+      currentSrcRow++;
+      // Copy line2 data to line1 and get next line2 data.
+      // If line2 already contains the last source row we don't touch it.
+      // This effectively adds an extra row of padding for interpolating the
+      // last source row with.
+      memcpy(lineBuf1, lineBuf2, scaledWidth * nComps);
+      if (srcAlpha)
+        memcpy(alphaLineBuf1, alphaLineBuf2, scaledWidth);
+      if (currentSrcRow < srcHeight) {
+        (*src)(srcData, srcBuf, alphaSrcBuf);
+        expandRow(srcBuf, lineBuf2, srcWidth, scaledWidth, nComps);
+        if (srcAlpha)
+          expandRow(alphaSrcBuf, alphaLineBuf2, srcWidth, scaledWidth, 1);
+      }
+    }
+
+    // write row y using linear interpolation on lineBuf1 and lineBuf2
+    for (int x = 0; x < scaledWidth; ++x) {
+      // compute the final pixel
+      for (i = 0; i < nComps; ++i) {
+	pix[i] = lineBuf1[x*nComps + i]*(1.0 - yFrac) + lineBuf2[x*nComps + i]*yFrac;
+      }
+
+      // store the pixel
+      destPtr = destPtr0 + (y * scaledWidth + x) * nComps;
+      switch (srcMode) {
+        case splashModeMono1: // mono1 is not allowed
+          break;
+        case splashModeMono8:
+          *destPtr++ = (Guchar)pix[0];
+          break;
+        case splashModeRGB8:
+          *destPtr++ = (Guchar)pix[0];
+          *destPtr++ = (Guchar)pix[1];
+          *destPtr++ = (Guchar)pix[2];
+          break;
+        case splashModeXBGR8:
+          *destPtr++ = (Guchar)pix[2];
+          *destPtr++ = (Guchar)pix[1];
+          *destPtr++ = (Guchar)pix[0];
+          *destPtr++ = (Guchar)255;
+          break;
+        case splashModeBGR8:
+          *destPtr++ = (Guchar)pix[2];
+          *destPtr++ = (Guchar)pix[1];
+          *destPtr++ = (Guchar)pix[0];
+          break;
+#ifdef SPLASH_CMYK
+        case splashModeCMYK8:
+          *destPtr++ = (Guchar)pix[0];
+          *destPtr++ = (Guchar)pix[1];
+          *destPtr++ = (Guchar)pix[2];
+          *destPtr++ = (Guchar)pix[3];
+          break;
+        case splashModeDeviceN8:
+          for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+            *destPtr++ = (Guchar)pix[cp];
+          break;
+#endif
+      }
+
+      // process alpha
+      if (srcAlpha) {
+        destAlphaPtr = destAlphaPtr0 + y*scaledWidth + x;
+        *destAlphaPtr = alphaLineBuf1[x]*(1.0 - yFrac) + alphaLineBuf2[x]*yFrac;
+      }
+    }
+
+    ySrc += yStep;
+  }
+
+  gfree(alphaSrcBuf);
+  gfree(alphaLineBuf1);
+  gfree(alphaLineBuf2);
+  gfree(srcBuf);
+  gfree(lineBuf1);
+  gfree(lineBuf2);
+}
+
+void Splash::vertFlipImage(SplashBitmap *img, int width, int height,
+			   int nComps) {
+  Guchar *lineBuf;
+  Guchar *p0, *p1;
+  int w;
+  
+  if (unlikely(img->data == NULL)) {
+    error(errInternal, -1, "img->data is NULL in Splash::vertFlipImage");
+    return;
+  }
+
+  w = width * nComps;
+  lineBuf = (Guchar *)gmalloc(w);
+  for (p0 = img->data, p1 = img->data + (height - 1) * w;
+       p0 < p1;
+       p0 += w, p1 -= w) {
+    memcpy(lineBuf, p0, w);
+    memcpy(p0, p1, w);
+    memcpy(p1, lineBuf, w);
+  }
+  if (img->alpha) {
+    for (p0 = img->alpha, p1 = img->alpha + (height - 1) * width;
+	 p0 < p1;
+	 p0 += width, p1 -= width) {
+      memcpy(lineBuf, p0, width);
+      memcpy(p0, p1, width);
+      memcpy(p1, lineBuf, width);
+    }
+  }
+  gfree(lineBuf);
+}
+
+void Splash::blitImage(SplashBitmap *src, GBool srcAlpha, int xDest, int yDest) {
+  SplashClipResult clipRes = state->clip->testRect(xDest, yDest, xDest + src->getWidth() - 1, yDest + src->getHeight() - 1);
+  if (clipRes != splashClipAllOutside) {
+    blitImage(src, srcAlpha, xDest, yDest, clipRes);
+  }
+}
+
+void Splash::blitImage(SplashBitmap *src, GBool srcAlpha, int xDest, int yDest,
+		       SplashClipResult clipRes) {
+  SplashPipe pipe;
+  SplashColor pixel;
+  Guchar *ap;
+  int w, h, x0, y0, x1, y1, x, y;
+
+  // split the image into clipped and unclipped regions
+  w = src->getWidth();
+  h = src->getHeight();
+  if (clipRes == splashClipAllInside) {
+    x0 = 0;
+    y0 = 0;
+    x1 = w;
+    y1 = h;
+  } else {
+    if (state->clip->getNumPaths()) {
+      x0 = x1 = w;
+      y0 = y1 = h;
+    } else {
+      if ((x0 = splashCeil(state->clip->getXMin()) - xDest) < 0) {
+	x0 = 0;
+      }
+      if ((y0 = splashCeil(state->clip->getYMin()) - yDest) < 0) {
+	y0 = 0;
+      }
+      if ((x1 = splashFloor(state->clip->getXMax()) - xDest) > w) {
+	x1 = w;
+      }
+      if (x1 < x0) {
+	x1 = x0;
+      }
+      if ((y1 = splashFloor(state->clip->getYMax()) - yDest) > h) {
+	y1 = h;
+      }
+      if (y1 < y0) {
+	y1 = y0;
+      }
+    }
+  }
+
+  // draw the unclipped region
+  if (x0 < w && y0 < h && x0 < x1 && y0 < y1) {
+    pipeInit(&pipe, xDest + x0, yDest + y0, NULL, pixel,
+	     (Guchar)splashRound(state->fillAlpha * 255), srcAlpha, gFalse);
+    if (srcAlpha) {
+      for (y = y0; y < y1; ++y) {
+	pipeSetXY(&pipe, xDest + x0, yDest + y);
+	ap = src->getAlphaPtr() + y * w + x0;
+	for (x = x0; x < x1; ++x) {
+	  src->getPixel(x, y, pixel);
+	  pipe.shape = *ap++;
+	  (this->*pipe.run)(&pipe);
+	}
+      }
+    } else {
+      for (y = y0; y < y1; ++y) {
+	pipeSetXY(&pipe, xDest + x0, yDest + y);
+	for (x = x0; x < x1; ++x) {
+	  src->getPixel(x, y, pixel);
+	  (this->*pipe.run)(&pipe);
+	}
+      }
+    }
+    updateModX(xDest + x0);
+    updateModX(xDest + x1 - 1);
+    updateModY(yDest + y0);
+    updateModY(yDest + y1 - 1);
+  }
+
+  // draw the clipped regions
+  if (y0 > 0) {
+    blitImageClipped(src, srcAlpha, 0, 0, xDest, yDest, w, y0);
+  }
+  if (y1 < h) {
+    blitImageClipped(src, srcAlpha, 0, y1, xDest, yDest + y1, w, h - y1);
+  }
+  if (x0 > 0 && y0 < y1) {
+    blitImageClipped(src, srcAlpha, 0, y0, xDest, yDest + y0, x0, y1 - y0);
+  }
+  if (x1 < w && y0 < y1) {
+    blitImageClipped(src, srcAlpha, x1, y0, xDest + x1, yDest + y0,
+		     w - x1, y1 - y0);
+  }
+}
+
+void Splash::blitImageClipped(SplashBitmap *src, GBool srcAlpha,
+			      int xSrc, int ySrc, int xDest, int yDest,
+			      int w, int h) {
+  SplashPipe pipe;
+  SplashColor pixel;
+  Guchar *ap;
+  int x, y;
+
+  if (vectorAntialias) {
+    pipeInit(&pipe, xDest, yDest, NULL, pixel,
+	     (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse);
+    drawAAPixelInit();
+    if (srcAlpha) {
+      for (y = 0; y < h; ++y) {
+	ap = src->getAlphaPtr() + (ySrc + y) * src->getWidth() + xSrc;
+	for (x = 0; x < w; ++x) {
+	  src->getPixel(xSrc + x, ySrc + y, pixel);
+	  pipe.shape = *ap++;
+	  drawAAPixel(&pipe, xDest + x, yDest + y);
+	}
+      }
+    } else {
+      for (y = 0; y < h; ++y) {
+	for (x = 0; x < w; ++x) {
+	  src->getPixel(xSrc + x, ySrc + y, pixel);
+	  pipe.shape = 255;
+	  drawAAPixel(&pipe, xDest + x, yDest + y);
+	}
+      }
+    }
+  } else {
+    pipeInit(&pipe, xDest, yDest, NULL, pixel,
+	     (Guchar)splashRound(state->fillAlpha * 255), srcAlpha, gFalse);
+    if (srcAlpha) {
+      for (y = 0; y < h; ++y) {
+	ap = src->getAlphaPtr() + (ySrc + y) * src->getWidth() + xSrc;
+	pipeSetXY(&pipe, xDest, yDest + y);
+	for (x = 0; x < w; ++x) {
+	  if (state->clip->test(xDest + x, yDest + y)) {
+	    src->getPixel(xSrc + x, ySrc + y, pixel);
+	    pipe.shape = *ap++;
+	    (this->*pipe.run)(&pipe);
+	    updateModX(xDest + x);
+	    updateModY(yDest + y);
+	  } else {
+	    pipeIncX(&pipe);
+	    ++ap;
+	  }
+	}
+      }
+    } else {
+      for (y = 0; y < h; ++y) {
+	pipeSetXY(&pipe, xDest, yDest + y);
+	for (x = 0; x < w; ++x) {
+	  if (state->clip->test(xDest + x, yDest + y)) {
+	    src->getPixel(xSrc + x, ySrc + y, pixel);
+	    (this->*pipe.run)(&pipe);
+	    updateModX(xDest + x);
+	    updateModY(yDest + y);
+	  } else {
+	    pipeIncX(&pipe);
+	  }
+	}
+      }
+    }
+  }
+}
+
+SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc,
+			      int xDest, int yDest, int w, int h,
+			      GBool noClip, GBool nonIsolated,
+			      GBool knockout, SplashCoord knockoutOpacity) {
+  SplashPipe pipe;
+  SplashColor pixel;
+  Guchar alpha;
+  Guchar *ap;
+  int x, y;
+
+  if (src->mode != bitmap->mode) {
+    return splashErrModeMismatch;
+  }
+
+  if (unlikely(!bitmap->data)) {
+    return splashErrZeroImage;
+  }
+
+  if(src->getSeparationList()->getLength() > bitmap->getSeparationList()->getLength()) {
+    for (x = bitmap->getSeparationList()->getLength(); x < src->getSeparationList()->getLength(); x++)
+      bitmap->getSeparationList()->append(((GfxSeparationColorSpace *)src->getSeparationList()->get(x))->copy());
+  }
+  if (src->alpha) {
+    pipeInit(&pipe, xDest, yDest, NULL, pixel,
+	     (Guchar)splashRound(state->fillAlpha * 255), gTrue, nonIsolated,
+	     knockout, (Guchar)splashRound(knockoutOpacity * 255));
+    if (noClip) {
+      for (y = 0; y < h; ++y) {
+	pipeSetXY(&pipe, xDest, yDest + y);
+	ap = src->getAlphaPtr() + (ySrc + y) * src->getWidth() + xSrc;
+	for (x = 0; x < w; ++x) {
+	  src->getPixel(xSrc + x, ySrc + y, pixel);
+	  alpha = *ap++;
+	  // this uses shape instead of alpha, which isn't technically
+	  // correct, but works out the same
+	  pipe.shape = alpha;
+	  (this->*pipe.run)(&pipe);
+	}
+      }
+      updateModX(xDest);
+      updateModX(xDest + w - 1);
+      updateModY(yDest);
+      updateModY(yDest + h - 1);
+    } else {
+      for (y = 0; y < h; ++y) {
+	pipeSetXY(&pipe, xDest, yDest + y);
+	ap = src->getAlphaPtr() + (ySrc + y) * src->getWidth() + xSrc;
+	for (x = 0; x < w; ++x) {
+	  src->getPixel(xSrc + x, ySrc + y, pixel);
+	  alpha = *ap++;
+	  if (state->clip->test(xDest + x, yDest + y)) {
+	    // this uses shape instead of alpha, which isn't technically
+	    // correct, but works out the same
+	    pipe.shape = alpha;
+	    (this->*pipe.run)(&pipe);
+	    updateModX(xDest + x);
+	    updateModY(yDest + y);
+	  } else {
+	    pipeIncX(&pipe);
+	  }
+	}
+      }
+    }
+  } else {
+    pipeInit(&pipe, xDest, yDest, NULL, pixel,
+	     (Guchar)splashRound(state->fillAlpha * 255), gFalse, nonIsolated);
+    if (noClip) {
+      for (y = 0; y < h; ++y) {
+	pipeSetXY(&pipe, xDest, yDest + y);
+	for (x = 0; x < w; ++x) {
+	  src->getPixel(xSrc + x, ySrc + y, pixel);
+	  (this->*pipe.run)(&pipe);
+	}
+      }
+      updateModX(xDest);
+      updateModX(xDest + w - 1);
+      updateModY(yDest);
+      updateModY(yDest + h - 1);
+    } else {
+      for (y = 0; y < h; ++y) {
+	pipeSetXY(&pipe, xDest, yDest + y);
+	for (x = 0; x < w; ++x) {
+	  src->getPixel(xSrc + x, ySrc + y, pixel);
+	  if (state->clip->test(xDest + x, yDest + y)) {
+	    (this->*pipe.run)(&pipe);
+	    updateModX(xDest + x);
+	    updateModY(yDest + y);
+	  } else {
+	    pipeIncX(&pipe);
+	  }
+	}
+      }
+    }
+  }
+
+  return splashOk;
+}
+
+void Splash::compositeBackground(SplashColorPtr color) {
+  SplashColorPtr p;
+  Guchar *q;
+  Guchar alpha, alpha1, c, color0, color1, color2;
+#ifdef SPLASH_CMYK
+  Guchar color3;
+  Guchar colorsp[SPOT_NCOMPS+4], cp;
+#endif
+  int x, y, mask;
+
+  if (unlikely(bitmap->alpha == NULL)) {
+    error(errInternal, -1, "bitmap->alpha is NULL in Splash::compositeBackground");
+    return;
+  }
+
+  switch (bitmap->mode) {
+  case splashModeMono1:
+    color0 = color[0];
+    for (y = 0; y < bitmap->height; ++y) {
+      p = &bitmap->data[y * bitmap->rowSize];
+      q = &bitmap->alpha[y * bitmap->width];
+      mask = 0x80;
+      for (x = 0; x < bitmap->width; ++x) {
+	alpha = *q++;
+	alpha1 = 255 - alpha;
+	c = (*p & mask) ? 0xff : 0x00;
+	c = div255(alpha1 * color0 + alpha * c);
+	if (c & 0x80) {
+	  *p |= mask;
+	} else {
+	  *p &= ~mask;
+	}
+	if (!(mask >>= 1)) {
+	  mask = 0x80;
+	  ++p;
+	}
+      }
+    }
+    break;
+  case splashModeMono8:
+    color0 = color[0];
+    for (y = 0; y < bitmap->height; ++y) {
+      p = &bitmap->data[y * bitmap->rowSize];
+      q = &bitmap->alpha[y * bitmap->width];
+      for (x = 0; x < bitmap->width; ++x) {
+	alpha = *q++;
+	alpha1 = 255 - alpha;
+	p[0] = div255(alpha1 * color0 + alpha * p[0]);
+	++p;
+      }
+    }
+    break;
+  case splashModeRGB8:
+  case splashModeBGR8:
+    color0 = color[0];
+    color1 = color[1];
+    color2 = color[2];
+    for (y = 0; y < bitmap->height; ++y) {
+      p = &bitmap->data[y * bitmap->rowSize];
+      q = &bitmap->alpha[y * bitmap->width];
+      for (x = 0; x < bitmap->width; ++x) {
+	alpha = *q++;
+	if (alpha == 0)
+	{
+	  p[0] = color0;
+	  p[1] = color1;
+	  p[2] = color2;
+	}
+	else if (alpha != 255)
+	{
+	  alpha1 = 255 - alpha;
+	  p[0] = div255(alpha1 * color0 + alpha * p[0]);
+	  p[1] = div255(alpha1 * color1 + alpha * p[1]);
+	  p[2] = div255(alpha1 * color2 + alpha * p[2]);
+	}
+	p += 3;
+      }
+    }
+    break;
+  case splashModeXBGR8:
+    color0 = color[0];
+    color1 = color[1];
+    color2 = color[2];
+    for (y = 0; y < bitmap->height; ++y) {
+      p = &bitmap->data[y * bitmap->rowSize];
+      q = &bitmap->alpha[y * bitmap->width];
+      for (x = 0; x < bitmap->width; ++x) {
+	alpha = *q++;
+	if (alpha == 0)
+	{
+	  p[0] = color0;
+	  p[1] = color1;
+	  p[2] = color2;
+	}
+	else if (alpha != 255)
+	{
+	  alpha1 = 255 - alpha;
+	  p[0] = div255(alpha1 * color0 + alpha * p[0]);
+	  p[1] = div255(alpha1 * color1 + alpha * p[1]);
+	  p[2] = div255(alpha1 * color2 + alpha * p[2]);
+	}
+	p[3] = 255;
+	p += 4;
+      }
+    }
+    break;
+#ifdef SPLASH_CMYK
+  case splashModeCMYK8:
+    color0 = color[0];
+    color1 = color[1];
+    color2 = color[2];
+    color3 = color[3];
+    for (y = 0; y < bitmap->height; ++y) {
+      p = &bitmap->data[y * bitmap->rowSize];
+      q = &bitmap->alpha[y * bitmap->width];
+      for (x = 0; x < bitmap->width; ++x) {
+	alpha = *q++;
+	if (alpha == 0)
+	{
+	  p[0] = color0;
+	  p[1] = color1;
+	  p[2] = color2;
+	  p[3] = color3;
+	}
+	else if (alpha != 255)
+	{
+	  alpha1 = 255 - alpha;
+	  p[0] = div255(alpha1 * color0 + alpha * p[0]);
+	  p[1] = div255(alpha1 * color1 + alpha * p[1]);
+	  p[2] = div255(alpha1 * color2 + alpha * p[2]);
+    p[3] = div255(alpha1 * color3 + alpha * p[3]);
+	}
+	p += 4;
+      }
+    }
+    break;
+  case splashModeDeviceN8:
+    for (cp = 0; cp < SPOT_NCOMPS+4; cp++)
+      colorsp[cp] = color[cp];
+    for (y = 0; y < bitmap->height; ++y) {
+      p = &bitmap->data[y * bitmap->rowSize];
+      q = &bitmap->alpha[y * bitmap->width];
+      for (x = 0; x < bitmap->width; ++x) {
+	alpha = *q++;
+	if (alpha == 0)
+	{
+    for (cp = 0; cp < SPOT_NCOMPS+4; cp++)
+      p[cp] = colorsp[cp];
+	}
+	else if (alpha != 255)
+	{
+	  alpha1 = 255 - alpha;
+    for (cp = 0; cp < SPOT_NCOMPS+4; cp++)
+      p[cp] = div255(alpha1 * colorsp[cp] + alpha * p[cp]);
+	}
+	p += (SPOT_NCOMPS+4);
+      }
+    }
+    break;
+#endif
+  }
+  memset(bitmap->alpha, 255, bitmap->width * bitmap->height);
+}
+
+GBool Splash::gouraudTriangleShadedFill(SplashGouraudColor *shading)
+{
+  double xdbl[3] = {0., 0., 0.};
+  double ydbl[3] = {0., 0., 0.};
+  int    x[3] = {0, 0, 0};
+  int    y[3] = {0, 0, 0};
+  double xt=0., xa=0., yt=0.;
+  double ca=0., ct=0.;
+
+  // triangle interpolation:
+  //
+  double scanLimitMapL[2] = {0., 0.};
+  double scanLimitMapR[2] = {0., 0.};
+  double scanColorMapL[2] = {0., 0.};
+  double scanColorMapR[2] = {0., 0.};
+  double scanColorMap[2] = {0., 0.};
+  int scanEdgeL[2] = { 0, 0 };
+  int scanEdgeR[2] = { 0, 0 };
+  GBool hasFurtherSegment = gFalse;
+
+  int scanLineOff = 0;
+  int bitmapOff = 0;
+  int scanLimitR = 0, scanLimitL = 0;
+
+  int bitmapWidth = bitmap->getWidth();
+  SplashClip* clip = getClip();
+  SplashBitmap *blitTarget = bitmap;
+  SplashColorPtr bitmapData = bitmap->getDataPtr();
+  int bitmapOffLimit = bitmap->getHeight() * bitmap->getRowSize();
+  SplashColorPtr bitmapAlpha = bitmap->getAlphaPtr();
+  SplashColorPtr cur = NULL;
+  SplashCoord* userToCanvasMatrix = getMatrix();
+  SplashColorMode bitmapMode = bitmap->getMode();
+  GBool hasAlpha = (bitmapAlpha != NULL);
+  int rowSize = bitmap->getRowSize();
+  int colorComps = 0;
+  switch (bitmapMode) {
+    case splashModeMono1:
+    break;
+    case splashModeMono8:
+      colorComps=1;
+    break;
+    case splashModeRGB8:
+      colorComps=3;
+    break;
+    case splashModeBGR8:
+      colorComps=3;
+    break;
+    case splashModeXBGR8:
+      colorComps=4;
+    break;
+#ifdef SPLASH_CMYK
+    case splashModeCMYK8:
+      colorComps=4;
+    break;
+    case splashModeDeviceN8:
+      colorComps=SPOT_NCOMPS+4;
+    break;
+#endif
+  }
+
+  SplashPipe pipe;
+  SplashColor cSrcVal;
+
+  pipeInit(&pipe, 0, 0, NULL, cSrcVal, (Guchar)splashRound(state->strokeAlpha * 255), gFalse, gFalse);
+
+  if (vectorAntialias) {
+    if (aaBuf == NULL)
+      return gFalse; // fall back to old behaviour
+    drawAAPixelInit();
+  }
+
+  // idea:
+  // 1. If pipe->noTransparency && !state->blendFunc
+  //  -> blit directly into the drawing surface!
+  //  -> disable alpha manually.
+  // 2. Otherwise:
+  // - blit also directly, but into an intermediate surface.
+  // Afterwards, blit the intermediate surface using the drawing pipeline.
+  // This is necessary because triangle elements can be on top of each
+  // other, so the complete shading needs to be drawn before opacity is
+  // applied.
+  // - the final step, is performed using a SplashPipe:
+  // - assign the actual color into cSrcVal: pipe uses cSrcVal by reference
+  // - invoke drawPixel(&pipe,X,Y,bNoClip);
+  GBool bDirectBlit = vectorAntialias ? gFalse : pipe.noTransparency && !state->blendFunc;
+  if (!bDirectBlit) {
+    blitTarget = new SplashBitmap(bitmap->getWidth(),
+                                  bitmap->getHeight(),
+                                  bitmap->getRowPad(),
+                                  bitmap->getMode(),
+                                  gTrue,
+                                  bitmap->getRowSize() >= 0);
+    bitmapData = blitTarget->getDataPtr();
+    bitmapAlpha = blitTarget->getAlphaPtr();
+
+    // initialisation seems to be necessary:
+    int S = bitmap->getWidth() * bitmap->getHeight();
+    for (int i = 0; i < S; ++i)
+      bitmapAlpha[i] = 0;
+    hasAlpha = gTrue;
+  }
+
+  if (shading->isParameterized()) {
+    double color[3];
+    double colorinterp;
+
+    for (int i = 0; i < shading->getNTriangles(); ++i) {
+      shading->getTriangle(i,
+                           xdbl + 0, ydbl + 0, color + 0,
+                           xdbl + 1, ydbl + 1, color + 1,
+                           xdbl + 2, ydbl + 2, color + 2);
+      for (int m = 0; m < 3; ++m) {
+        xt = xdbl[m] * (double)userToCanvasMatrix[0] + ydbl[m] * (double)userToCanvasMatrix[2] + (double)userToCanvasMatrix[4];
+        yt = xdbl[m] * (double)userToCanvasMatrix[1] + ydbl[m] * (double)userToCanvasMatrix[3] + (double)userToCanvasMatrix[5];
+        xdbl[m] = xt;
+        ydbl[m] = yt;
+        // we operate on scanlines which are integer offsets into the
+        // raster image. The double offsets are of no use here.
+        x[m] = splashRound(xt);
+        y[m] = splashRound(yt);
+      }
+      // sort according to y coordinate to simplify sweep through scanlines:
+      // INSERTION SORT.
+      if (y[0] > y[1]) {
+        Guswap(x[0], x[1]);
+        Guswap(y[0], y[1]);
+        Guswap(color[0], color[1]);
+      }
+      // first two are sorted.
+      assert(y[0] <= y[1]);
+      if (y[1] > y[2]) {
+        int tmpX = x[2];
+        int tmpY = y[2];
+        double tmpC = color[2];
+        x[2] = x[1]; y[2] = y[1]; color[2] = color[1];
+
+        if (y[0] > tmpY) {
+          x[1] = x[0]; y[1] = y[0]; color[1] = color[0];
+          x[0] = tmpX; y[0] = tmpY; color[0] = tmpC;
+        } else {
+          x[1] = tmpX; y[1] = tmpY; color[1] = tmpC;
+        }
+      }
+      // first three are sorted
+      assert(y[0] <= y[1]);
+      assert(y[1] <= y[2]);
+      /////
+
+      // this here is det( T ) == 0
+      // where T is the matrix to map to barycentric coordinates.
+      if ((x[0] - x[2]) * (y[1] - y[2]) - (x[1] - x[2]) * (y[0] - y[2]) == 0)
+        continue; // degenerate triangle.
+
+      // this here initialises the scanline generation.
+      // We start with low Y coordinates and sweep up to the large Y
+      // coordinates.
+      //
+      // scanEdgeL[m] in {0,1,2} m=0,1
+      // scanEdgeR[m] in {0,1,2} m=0,1
+      //
+      // are the two edges between which scanlines are (currently)
+      // sweeped. The values {0,1,2} are indices into 'x' and 'y'.
+      // scanEdgeL[0] = 0 means: the left scan edge has (x[0],y[0]) as vertex.
+      //
+      scanEdgeL[0] = 0;
+      scanEdgeR[0] = 0;
+      if (y[0] == y[1]) {
+        scanEdgeL[0] = 1;
+        scanEdgeL[1] = scanEdgeR[1] = 2;
+
+      } else {
+        scanEdgeL[1] = 1; scanEdgeR[1] = 2;
+      }
+      assert(y[scanEdgeL[0]] < y[scanEdgeL[1]]);
+      assert(y[scanEdgeR[0]] < y[scanEdgeR[1]]);
+
+      // Ok. Now prepare the linear maps which map the y coordinate of
+      // the current scanline to the corresponding LEFT and RIGHT x
+      // coordinate (which define the scanline).
+      scanLimitMapL[0] = double(x[scanEdgeL[1]] - x[scanEdgeL[0]]) / (y[scanEdgeL[1]] - y[scanEdgeL[0]]);
+      scanLimitMapL[1] = x[scanEdgeL[0]] - y[scanEdgeL[0]] * scanLimitMapL[0];
+      scanLimitMapR[0] = double(x[scanEdgeR[1]] - x[scanEdgeR[0]]) / (y[scanEdgeR[1]] - y[scanEdgeR[0]]);
+      scanLimitMapR[1] = x[scanEdgeR[0]] - y[scanEdgeR[0]] * scanLimitMapR[0];
+
+      xa = y[1] * scanLimitMapL[0] + scanLimitMapL[1];
+      xt = y[1] * scanLimitMapR[0] + scanLimitMapR[1];
+      if (xa > xt) {
+        // I have "left" is to the right of "right".
+        // Exchange sides!
+        Guswap(scanEdgeL[0], scanEdgeR[0]);
+        Guswap(scanEdgeL[1], scanEdgeR[1]);
+        Guswap(scanLimitMapL[0], scanLimitMapR[0]);
+        Guswap(scanLimitMapL[1], scanLimitMapR[1]);
+        // FIXME I'm sure there is a more efficient way to check this.
+      }
+
+      // Same game: we can linearly interpolate the color based on the
+      // current y coordinate (that's correct for triangle
+      // interpolation due to linearity. We could also have done it in
+      // barycentric coordinates, but that's slightly more involved)
+      scanColorMapL[0] = (color[scanEdgeL[1]] - color[scanEdgeL[0]]) / (y[scanEdgeL[1]] - y[scanEdgeL[0]]);
+      scanColorMapL[1] = color[scanEdgeL[0]] - y[scanEdgeL[0]] * scanColorMapL[0];
+      scanColorMapR[0] = (color[scanEdgeR[1]] - color[scanEdgeR[0]]) / (y[scanEdgeR[1]] - y[scanEdgeR[0]]);
+      scanColorMapR[1] = color[scanEdgeR[0]] - y[scanEdgeR[0]] * scanColorMapR[0];
+
+      hasFurtherSegment = (y[1] < y[2]);
+      scanLineOff = y[0] * rowSize;
+
+      for (int Y = y[0]; Y <= y[2]; ++Y, scanLineOff += rowSize) {
+        if (hasFurtherSegment && Y == y[1]) {
+          // SWEEP EVENT: we encountered the next segment.
+          //
+          // switch to next segment, either at left end or at right
+          // end:
+          if (scanEdgeL[1] == 1) {
+            scanEdgeL[0] = 1;
+            scanEdgeL[1] = 2;
+            scanLimitMapL[0] = double(x[scanEdgeL[1]] - x[scanEdgeL[0]]) / (y[scanEdgeL[1]] - y[scanEdgeL[0]]);
+            scanLimitMapL[1] = x[scanEdgeL[0]] - y[scanEdgeL[0]] * scanLimitMapL[0];
+
+            scanColorMapL[0] = (color[scanEdgeL[1]] - color[scanEdgeL[0]]) / (y[scanEdgeL[1]] - y[scanEdgeL[0]]);
+            scanColorMapL[1] = color[scanEdgeL[0]] - y[scanEdgeL[0]] * scanColorMapL[0];
+          } else if (scanEdgeR[1] == 1) {
+            scanEdgeR[0] = 1;
+            scanEdgeR[1] = 2;
+            scanLimitMapR[0] = double(x[scanEdgeR[1]] - x[scanEdgeR[0]]) / (y[scanEdgeR[1]] - y[scanEdgeR[0]]);
+            scanLimitMapR[1] = x[scanEdgeR[0]] - y[scanEdgeR[0]] * scanLimitMapR[0];
+
+            scanColorMapR[0] = (color[scanEdgeR[1]] - color[scanEdgeR[0]]) / (y[scanEdgeR[1]] - y[scanEdgeR[0]]);
+            scanColorMapR[1] = color[scanEdgeR[0]] - y[scanEdgeR[0]] * scanColorMapR[0];
+          }
+          assert( y[scanEdgeL[0]]  <  y[scanEdgeL[1]] );
+          assert( y[scanEdgeR[0]] <  y[scanEdgeR[1]] );
+          hasFurtherSegment = gFalse;
+        }
+
+        yt = Y;
+
+        xa = yt * scanLimitMapL[0] + scanLimitMapL[1];
+        xt = yt * scanLimitMapR[0] + scanLimitMapR[1];
+
+        ca = yt * scanColorMapL[0] + scanColorMapL[1];
+        ct = yt * scanColorMapR[0] + scanColorMapR[1];
+
+        scanLimitL = splashRound(xa);
+        scanLimitR = splashRound(xt);
+
+        // Ok. Now: init the color interpolation depending on the X
+        // coordinate inside of the current scanline:
+        scanColorMap[0] = (scanLimitR == scanLimitL) ? 0. : ((ct - ca) / (scanLimitR - scanLimitL));
+        scanColorMap[1] = ca - scanLimitL * scanColorMap[0];
+
+        // handled by clipping:
+        // assert( scanLimitL >= 0 && scanLimitR < bitmap->getWidth() );
+        assert(scanLimitL <= scanLimitR || abs(scanLimitL - scanLimitR) <= 2); // allow rounding inaccuracies
+        assert(scanLineOff == Y * rowSize);
+
+        colorinterp = scanColorMap[0] * scanLimitL + scanColorMap[1];
+
+        bitmapOff = scanLineOff + scanLimitL * colorComps;
+        if (likely(bitmapOff >= 0)) {
+	  for (int X = scanLimitL; X <= scanLimitR && bitmapOff + colorComps <= bitmapOffLimit; ++X, colorinterp += scanColorMap[0], bitmapOff += colorComps) {
+	    // FIXME : standard rectangular clipping can be done for a
+	    // complete scanline which is faster
+	    // --> see SplashClip and its methods
+	    if (!clip->test(X, Y))
+	      continue;
+
+	    assert(fabs(colorinterp - (scanColorMap[0] * X + scanColorMap[1])) < 1e-10);
+	    assert(bitmapOff == Y * rowSize + colorComps * X && scanLineOff == Y * rowSize);
+
+	    shading->getParameterizedColor(colorinterp, bitmapMode, &bitmapData[bitmapOff]);
+
+	    // make the shading visible.
+	    // Note that opacity is handled by the bDirectBlit stuff, see
+	    // above for comments and below for implementation.
+	    if (hasAlpha)
+	      bitmapAlpha[Y * bitmapWidth + X] = 255;
+	  }
+	}
+      }
+    }
+  } else {
+    if (!bDirectBlit) {
+      delete blitTarget;
+    }
+    return gFalse;
+  }
+
+  if (!bDirectBlit) {
+    // ok. Finalize the stuff by blitting the shading into the final
+    // geometry, this time respecting the rendering pipe.
+    int W = blitTarget->getWidth();
+    int H = blitTarget->getHeight();
+    cur = cSrcVal;
+
+    for (int X = 0; X < W; ++X) {
+      for (int Y = 0; Y < H; ++Y) {
+        if (!bitmapAlpha[Y * bitmapWidth + X])
+          continue; // draw only parts of the shading!
+        bitmapOff = Y * rowSize + colorComps * X;
+
+        for (int m = 0; m < colorComps; ++m)
+          cur[m] = bitmapData[bitmapOff + m];
+        if (vectorAntialias) {
+          drawAAPixel(&pipe, X, Y);
+        } else {
+          drawPixel(&pipe, X, Y, gTrue); // no clipping - has already been done.
+        }
+      }
+    }
+
+    delete blitTarget;
+    blitTarget = NULL;
+  }
+
+  return gTrue;
+}
+
+SplashError Splash::blitTransparent(SplashBitmap *src, int xSrc, int ySrc,
+				    int xDest, int yDest, int w, int h) {
+  SplashColorPtr p, sp;
+  Guchar *q;
+  int x, y, mask, srcMask;
+
+  if (src->mode != bitmap->mode) {
+    return splashErrModeMismatch;
+  }
+
+  if (unlikely(!bitmap->data)) {
+    return splashErrZeroImage;
+  }
+
+  switch (bitmap->mode) {
+  case splashModeMono1:
+    for (y = 0; y < h; ++y) {
+      p = &bitmap->data[(yDest + y) * bitmap->rowSize + (xDest >> 3)];
+      mask = 0x80 >> (xDest & 7);
+      sp = &src->data[(ySrc + y) * src->rowSize + (xSrc >> 3)];
+      srcMask = 0x80 >> (xSrc & 7);
+      for (x = 0; x < w; ++x) {
+	if (*sp & srcMask) {
+	  *p |= mask;
+	} else {
+	  *p &= ~mask;
+	}
+	if (!(mask >>= 1)) {
+	  mask = 0x80;
+	  ++p;
+	}
+	if (!(srcMask >>= 1)) {
+	  srcMask = 0x80;
+	  ++sp;
+	}
+      }
+    }
+    break;
+  case splashModeMono8:
+    for (y = 0; y < h; ++y) {
+      p = &bitmap->data[(yDest + y) * bitmap->rowSize + xDest];
+      sp = &src->data[(ySrc + y) * bitmap->rowSize + xSrc];
+      for (x = 0; x < w; ++x) {
+	*p++ = *sp++;
+      }
+    }
+    break;
+  case splashModeRGB8:
+  case splashModeBGR8:
+    for (y = 0; y < h; ++y) {
+      p = &bitmap->data[(yDest + y) * bitmap->rowSize + 3 * xDest];
+      sp = &src->data[(ySrc + y) * src->rowSize + 3 * xSrc];
+      for (x = 0; x < w; ++x) {
+	*p++ = *sp++;
+	*p++ = *sp++;
+	*p++ = *sp++;
+      }
+    }
+    break;
+  case splashModeXBGR8:
+    for (y = 0; y < h; ++y) {
+      p = &bitmap->data[(yDest + y) * bitmap->rowSize + 4 * xDest];
+      sp = &src->data[(ySrc + y) * src->rowSize + 4 * xSrc];
+      for (x = 0; x < w; ++x) {
+	*p++ = *sp++;
+	*p++ = *sp++;
+	*p++ = *sp++;
+	*p++ = 255;
+	sp++;
+      }
+    }
+    break;
+#ifdef SPLASH_CMYK
+  case splashModeCMYK8:
+    for (y = 0; y < h; ++y) {
+      p = &bitmap->data[(yDest + y) * bitmap->rowSize + 4 * xDest];
+      sp = &src->data[(ySrc + y) * src->rowSize + 4 * xSrc];
+      for (x = 0; x < w; ++x) {
+	*p++ = *sp++;
+	*p++ = *sp++;
+	*p++ = *sp++;
+	*p++ = *sp++;
+      }
+    }
+    break;
+  case splashModeDeviceN8:
+    for (y = 0; y < h; ++y) {
+      p = &bitmap->data[(yDest + y) * bitmap->rowSize + (SPOT_NCOMPS+4) * xDest];
+      sp = &src->data[(ySrc + y) * src->rowSize + (SPOT_NCOMPS+4) * xSrc];
+      for (x = 0; x < w; ++x) {
+        for (int cp=0; cp < SPOT_NCOMPS+4; cp++)
+          *p++ = *sp++;
+      }
+    }
+    break;
+#endif
+  }
+
+  if (bitmap->alpha) {
+    for (y = 0; y < h; ++y) {
+      q = &bitmap->alpha[(yDest + y) * bitmap->width + xDest];
+      memset(q, 0x00, w);
+    }
+  }
+
+  return splashOk;
+}
+
+SplashPath *Splash::makeStrokePath(SplashPath *path, SplashCoord w,
+				    GBool flatten) {
+SplashPath *pathIn, *dashPath, *pathOut;
+  SplashCoord d, dx, dy, wdx, wdy, dxNext, dyNext, wdxNext, wdyNext;
+  SplashCoord crossprod, dotprod, miter, m;
+  GBool first, last, closed, hasangle;
+  int subpathStart0, subpathStart1, seg, i0, i1, j0, j1, k0, k1;
+  int left0, left1, left2, right0, right1, right2, join0, join1, join2;
+  int leftFirst, rightFirst, firstPt;
+
+  pathOut = new SplashPath();
+
+  if (path->length == 0) {
+    return pathOut;
+  }
+
+  if (flatten) {
+    pathIn = flattenPath(path, state->matrix, state->flatness);
+    if (state->lineDashLength > 0) {
+      dashPath = makeDashedPath(pathIn);
+      delete pathIn;
+      pathIn = dashPath;
+      if (pathIn->length == 0) {
+	delete pathIn;
+	return pathOut;
+      }
+    }
+  } else {
+    pathIn = path;
+  }
+
+  subpathStart0 = subpathStart1 = 0; // make gcc happy
+  seg = 0; // make gcc happy
+  closed = gFalse; // make gcc happy
+  left0 = left1 = right0 = right1 = join0 = join1 = 0; // make gcc happy
+  leftFirst = rightFirst = firstPt = 0; // make gcc happy
+
+  i0 = 0;
+  for (i1 = i0;
+       !(pathIn->flags[i1] & splashPathLast) &&
+	 i1 + 1 < pathIn->length &&
+	 pathIn->pts[i1+1].x == pathIn->pts[i1].x &&
+	 pathIn->pts[i1+1].y == pathIn->pts[i1].y;
+       ++i1) ;
+
+  while (i1 < pathIn->length) {
+    if ((first = pathIn->flags[i0] & splashPathFirst)) {
+      subpathStart0 = i0;
+      subpathStart1 = i1;
+      seg = 0;
+      closed = pathIn->flags[i0] & splashPathClosed;
+    }
+    j0 = i1 + 1;
+    if (j0 < pathIn->length) {
+      for (j1 = j0;
+	   !(pathIn->flags[j1] & splashPathLast) &&
+	     j1 + 1 < pathIn->length &&
+	     pathIn->pts[j1+1].x == pathIn->pts[j1].x &&
+	     pathIn->pts[j1+1].y == pathIn->pts[j1].y;
+	   ++j1) ;
+    } else {
+      j1 = j0;
+    }
+    if (pathIn->flags[i1] & splashPathLast) {
+      if (first && state->lineCap == splashLineCapRound) {
+	// special case: zero-length subpath with round line caps -->
+	// draw a circle
+	pathOut->moveTo(pathIn->pts[i0].x + (SplashCoord)0.5 * w,
+			pathIn->pts[i0].y);
+	pathOut->curveTo(pathIn->pts[i0].x + (SplashCoord)0.5 * w,
+			 pathIn->pts[i0].y + bezierCircle2 * w,
+			 pathIn->pts[i0].x + bezierCircle2 * w,
+			 pathIn->pts[i0].y + (SplashCoord)0.5 * w,
+			 pathIn->pts[i0].x,
+			 pathIn->pts[i0].y + (SplashCoord)0.5 * w);
+	pathOut->curveTo(pathIn->pts[i0].x - bezierCircle2 * w,
+			 pathIn->pts[i0].y + (SplashCoord)0.5 * w,
+			 pathIn->pts[i0].x - (SplashCoord)0.5 * w,
+			 pathIn->pts[i0].y + bezierCircle2 * w,
+			 pathIn->pts[i0].x - (SplashCoord)0.5 * w,
+			 pathIn->pts[i0].y);
+	pathOut->curveTo(pathIn->pts[i0].x - (SplashCoord)0.5 * w,
+			 pathIn->pts[i0].y - bezierCircle2 * w,
+			 pathIn->pts[i0].x - bezierCircle2 * w,
+			 pathIn->pts[i0].y - (SplashCoord)0.5 * w,
+			 pathIn->pts[i0].x,
+			 pathIn->pts[i0].y - (SplashCoord)0.5 * w);
+	pathOut->curveTo(pathIn->pts[i0].x + bezierCircle2 * w,
+			 pathIn->pts[i0].y - (SplashCoord)0.5 * w,
+			 pathIn->pts[i0].x + (SplashCoord)0.5 * w,
+			 pathIn->pts[i0].y - bezierCircle2 * w,
+			 pathIn->pts[i0].x + (SplashCoord)0.5 * w,
+			 pathIn->pts[i0].y);
+	pathOut->close();
+      }
+      i0 = j0;
+      i1 = j1;
+      continue;
+    }
+    last = pathIn->flags[j1] & splashPathLast;
+    if (last) {
+      k0 = subpathStart1 + 1;
+    } else {
+      k0 = j1 + 1;
+    }
+    for (k1 = k0;
+	 !(pathIn->flags[k1] & splashPathLast) &&
+	   k1 + 1 < pathIn->length &&
+	   pathIn->pts[k1+1].x == pathIn->pts[k1].x &&
+	   pathIn->pts[k1+1].y == pathIn->pts[k1].y;
+	 ++k1) ;
+
+    // compute the deltas for segment (i1, j0)
+#ifdef USE_FIXEDPOINT
+    // the 1/d value can be small, which introduces significant
+    // inaccuracies in fixed point mode
+    d = splashDist(pathIn->pts[i1].x, pathIn->pts[i1].y,
+		   pathIn->pts[j0].x, pathIn->pts[j0].y);
+    dx = (pathIn->pts[j0].x - pathIn->pts[i1].x) / d;
+    dy = (pathIn->pts[j0].y - pathIn->pts[i1].y) / d;
+#else
+    d = (SplashCoord)1 / splashDist(pathIn->pts[i1].x, pathIn->pts[i1].y,
+				    pathIn->pts[j0].x, pathIn->pts[j0].y);
+    dx = d * (pathIn->pts[j0].x - pathIn->pts[i1].x);
+    dy = d * (pathIn->pts[j0].y - pathIn->pts[i1].y);
+#endif
+    wdx = (SplashCoord)0.5 * w * dx;
+    wdy = (SplashCoord)0.5 * w * dy;
+
+    // draw the start cap
+    pathOut->moveTo(pathIn->pts[i0].x - wdy, pathIn->pts[i0].y + wdx);
+    if (i0 == subpathStart0) {
+      firstPt = pathOut->length - 1;
+    }
+    if (first && !closed) {
+      switch (state->lineCap) {
+      case splashLineCapButt:
+	pathOut->lineTo(pathIn->pts[i0].x + wdy, pathIn->pts[i0].y - wdx);
+	break;
+      case splashLineCapRound:
+	pathOut->curveTo(pathIn->pts[i0].x - wdy - bezierCircle * wdx,
+			 pathIn->pts[i0].y + wdx - bezierCircle * wdy,
+			 pathIn->pts[i0].x - wdx - bezierCircle * wdy,
+			 pathIn->pts[i0].y - wdy + bezierCircle * wdx,
+			 pathIn->pts[i0].x - wdx,
+			 pathIn->pts[i0].y - wdy);
+	pathOut->curveTo(pathIn->pts[i0].x - wdx + bezierCircle * wdy,
+			 pathIn->pts[i0].y - wdy - bezierCircle * wdx,
+			 pathIn->pts[i0].x + wdy - bezierCircle * wdx,
+			 pathIn->pts[i0].y - wdx - bezierCircle * wdy,
+			 pathIn->pts[i0].x + wdy,
+			 pathIn->pts[i0].y - wdx);
+	break;
+      case splashLineCapProjecting:
+	pathOut->lineTo(pathIn->pts[i0].x - wdx - wdy,
+			pathIn->pts[i0].y + wdx - wdy);
+	pathOut->lineTo(pathIn->pts[i0].x - wdx + wdy,
+			pathIn->pts[i0].y - wdx - wdy);
+	pathOut->lineTo(pathIn->pts[i0].x + wdy,
+			pathIn->pts[i0].y - wdx);
+	break;
+      }
+    } else {
+      pathOut->lineTo(pathIn->pts[i0].x + wdy, pathIn->pts[i0].y - wdx);
+    }
+
+    // draw the left side of the segment rectangle
+    left2 = pathOut->length - 1;
+    pathOut->lineTo(pathIn->pts[j0].x + wdy, pathIn->pts[j0].y - wdx);
+
+    // draw the end cap
+    if (last && !closed) {
+      switch (state->lineCap) {
+      case splashLineCapButt:
+	pathOut->lineTo(pathIn->pts[j0].x - wdy, pathIn->pts[j0].y + wdx);
+	break;
+      case splashLineCapRound:
+	pathOut->curveTo(pathIn->pts[j0].x + wdy + bezierCircle * wdx,
+			 pathIn->pts[j0].y - wdx + bezierCircle * wdy,
+			 pathIn->pts[j0].x + wdx + bezierCircle * wdy,
+			 pathIn->pts[j0].y + wdy - bezierCircle * wdx,
+			 pathIn->pts[j0].x + wdx,
+			 pathIn->pts[j0].y + wdy);
+	pathOut->curveTo(pathIn->pts[j0].x + wdx - bezierCircle * wdy,
+			 pathIn->pts[j0].y + wdy + bezierCircle * wdx,
+			 pathIn->pts[j0].x - wdy + bezierCircle * wdx,
+			 pathIn->pts[j0].y + wdx + bezierCircle * wdy,
+			 pathIn->pts[j0].x - wdy,
+			 pathIn->pts[j0].y + wdx);
+	break;
+      case splashLineCapProjecting:
+	pathOut->lineTo(pathIn->pts[j0].x + wdy + wdx,
+			pathIn->pts[j0].y - wdx + wdy);
+	pathOut->lineTo(pathIn->pts[j0].x - wdy + wdx,
+			pathIn->pts[j0].y + wdx + wdy);
+	pathOut->lineTo(pathIn->pts[j0].x - wdy,
+			pathIn->pts[j0].y + wdx);
+	break;
+      }
+    } else {
+      pathOut->lineTo(pathIn->pts[j0].x - wdy, pathIn->pts[j0].y + wdx);
+    }
+
+    // draw the right side of the segment rectangle
+    // (NB: if stroke adjustment is enabled, the closepath operation MUST
+    // add a segment because this segment is used for a hint)
+    right2 = pathOut->length - 1;
+    pathOut->close(state->strokeAdjust);
+
+    // draw the join
+    join2 = pathOut->length;
+    if (!last || closed) {
+
+      // compute the deltas for segment (j1, k0)
+#ifdef USE_FIXEDPOINT
+      // the 1/d value can be small, which introduces significant
+      // inaccuracies in fixed point mode
+      d = splashDist(pathIn->pts[j1].x, pathIn->pts[j1].y,
+		     pathIn->pts[k0].x, pathIn->pts[k0].y);
+      dxNext = (pathIn->pts[k0].x - pathIn->pts[j1].x) / d;
+      dyNext = (pathIn->pts[k0].y - pathIn->pts[j1].y) / d;
+#else
+      d = (SplashCoord)1 / splashDist(pathIn->pts[j1].x, pathIn->pts[j1].y,
+				      pathIn->pts[k0].x, pathIn->pts[k0].y);
+      dxNext = d * (pathIn->pts[k0].x - pathIn->pts[j1].x);
+      dyNext = d * (pathIn->pts[k0].y - pathIn->pts[j1].y);
+#endif
+      wdxNext = (SplashCoord)0.5 * w * dxNext;
+      wdyNext = (SplashCoord)0.5 * w * dyNext;
+
+      // compute the join parameters
+      crossprod = dx * dyNext - dy * dxNext;
+      dotprod = -(dx * dxNext + dy * dyNext);
+      hasangle = crossprod != 0 || dx * dxNext < 0 || dy * dyNext < 0;
+      if (dotprod > 0.9999) {
+	// avoid a divide-by-zero -- set miter to something arbitrary
+	// such that sqrt(miter) will exceed miterLimit (and m is never
+	// used in that situation)
+	// (note: the comparison value (0.9999) has to be less than
+	// 1-epsilon, where epsilon is the smallest value
+	// representable in the fixed point format)
+	miter = (state->miterLimit + 1) * (state->miterLimit + 1);
+	m = 0;
+      } else {
+	miter = (SplashCoord)2 / ((SplashCoord)1 - dotprod);
+	if (miter < 1) {
+	  // this can happen because of floating point inaccuracies
+	  miter = 1;
+	}
+	m = splashSqrt(miter - 1);
+      }
+
+      // round join
+      if (hasangle && state->lineJoin == splashLineJoinRound) {
+	pathOut->moveTo(pathIn->pts[j0].x + (SplashCoord)0.5 * w,
+			pathIn->pts[j0].y);
+	pathOut->curveTo(pathIn->pts[j0].x + (SplashCoord)0.5 * w,
+			 pathIn->pts[j0].y + bezierCircle2 * w,
+			 pathIn->pts[j0].x + bezierCircle2 * w,
+			 pathIn->pts[j0].y + (SplashCoord)0.5 * w,
+			 pathIn->pts[j0].x,
+			 pathIn->pts[j0].y + (SplashCoord)0.5 * w);
+	pathOut->curveTo(pathIn->pts[j0].x - bezierCircle2 * w,
+			 pathIn->pts[j0].y + (SplashCoord)0.5 * w,
+			 pathIn->pts[j0].x - (SplashCoord)0.5 * w,
+			 pathIn->pts[j0].y + bezierCircle2 * w,
+			 pathIn->pts[j0].x - (SplashCoord)0.5 * w,
+			 pathIn->pts[j0].y);
+	pathOut->curveTo(pathIn->pts[j0].x - (SplashCoord)0.5 * w,
+			 pathIn->pts[j0].y - bezierCircle2 * w,
+			 pathIn->pts[j0].x - bezierCircle2 * w,
+			 pathIn->pts[j0].y - (SplashCoord)0.5 * w,
+			 pathIn->pts[j0].x,
+			 pathIn->pts[j0].y - (SplashCoord)0.5 * w);
+	pathOut->curveTo(pathIn->pts[j0].x + bezierCircle2 * w,
+			 pathIn->pts[j0].y - (SplashCoord)0.5 * w,
+			 pathIn->pts[j0].x + (SplashCoord)0.5 * w,
+			 pathIn->pts[j0].y - bezierCircle2 * w,
+			 pathIn->pts[j0].x + (SplashCoord)0.5 * w,
+			 pathIn->pts[j0].y);
+
+      } else if (hasangle) {
+	pathOut->moveTo(pathIn->pts[j0].x, pathIn->pts[j0].y);
+
+	// angle < 180
+	if (crossprod < 0) {
+	  pathOut->lineTo(pathIn->pts[j0].x - wdyNext,
+			  pathIn->pts[j0].y + wdxNext);
+	  // miter join inside limit
+	  if (state->lineJoin == splashLineJoinMiter &&
+	      splashSqrt(miter) <= state->miterLimit) {
+	    pathOut->lineTo(pathIn->pts[j0].x - wdy + wdx * m,
+			    pathIn->pts[j0].y + wdx + wdy * m);
+	    pathOut->lineTo(pathIn->pts[j0].x - wdy,
+			    pathIn->pts[j0].y + wdx);
+	  // bevel join or miter join outside limit
+	  } else {
+	    pathOut->lineTo(pathIn->pts[j0].x - wdy,
+			    pathIn->pts[j0].y + wdx);
+	  }
+
+	// angle >= 180
+	} else {
+	  pathOut->lineTo(pathIn->pts[j0].x + wdy,
+			  pathIn->pts[j0].y - wdx);
+	  // miter join inside limit
+	  if (state->lineJoin == splashLineJoinMiter &&
+	      splashSqrt(miter) <= state->miterLimit) {
+	    pathOut->lineTo(pathIn->pts[j0].x + wdy + wdx * m,
+			    pathIn->pts[j0].y - wdx + wdy * m);
+	    pathOut->lineTo(pathIn->pts[j0].x + wdyNext,
+			    pathIn->pts[j0].y - wdxNext);
+	  // bevel join or miter join outside limit
+	  } else {
+	    pathOut->lineTo(pathIn->pts[j0].x + wdyNext,
+			    pathIn->pts[j0].y - wdxNext);
+	  }
+	}
+      }
+
+      pathOut->close();
+    }
+
+    // add stroke adjustment hints
+    if (state->strokeAdjust) {
+      if (seg == 0 && !closed) {
+	if (state->lineCap == splashLineCapButt) {
+	  pathOut->addStrokeAdjustHint(firstPt, left2 + 1,
+				       firstPt, firstPt + 1);
+	  if (last) {
+	    pathOut->addStrokeAdjustHint(firstPt, left2 + 1,
+					 left2 + 1, left2 + 2);
+	  }
+	} else if (state->lineCap == splashLineCapProjecting) {
+	  if (last) {
+	    pathOut->addStrokeAdjustHint(firstPt + 1, left2 + 2,
+					 firstPt + 1, firstPt + 2);
+	    pathOut->addStrokeAdjustHint(firstPt + 1, left2 + 2,
+					 left2 + 2, left2 + 3);
+	  } else {
+	    pathOut->addStrokeAdjustHint(firstPt + 1, left2 + 1,
+					 firstPt + 1, firstPt + 2);
+	  }
+	}
+      }
+      if (seg >= 1) {
+	if (seg >= 2) {
+	  pathOut->addStrokeAdjustHint(left1, right1, left0 + 1, right0);
+	  pathOut->addStrokeAdjustHint(left1, right1, join0, left2);
+	} else {
+	  pathOut->addStrokeAdjustHint(left1, right1, firstPt, left2);
+	}
+	pathOut->addStrokeAdjustHint(left1, right1, right2 + 1, right2 + 1);
+      }
+      left0 = left1;
+      left1 = left2;
+      right0 = right1;
+      right1 = right2;
+      join0 = join1;
+      join1 = join2;
+      if (seg == 0) {
+	leftFirst = left2;
+	rightFirst = right2;
+      }
+      if (last) {
+	if (seg >= 2) {
+	  pathOut->addStrokeAdjustHint(left1, right1, left0 + 1, right0);
+	  pathOut->addStrokeAdjustHint(left1, right1,
+				       join0, pathOut->length - 1);
+	} else {
+	  pathOut->addStrokeAdjustHint(left1, right1,
+				       firstPt, pathOut->length - 1);
+	}
+	if (closed) {
+	  pathOut->addStrokeAdjustHint(left1, right1, firstPt, leftFirst);
+	  pathOut->addStrokeAdjustHint(left1, right1,
+				       rightFirst + 1, rightFirst + 1);
+	  pathOut->addStrokeAdjustHint(leftFirst, rightFirst,
+				       left1 + 1, right1);
+	  pathOut->addStrokeAdjustHint(leftFirst, rightFirst,
+				       join1, pathOut->length - 1);
+	}
+	if (!closed && seg > 0) {
+	  if (state->lineCap == splashLineCapButt) {
+	    pathOut->addStrokeAdjustHint(left1 - 1, left1 + 1,
+					 left1 + 1, left1 + 2);
+	  } else if (state->lineCap == splashLineCapProjecting) {
+	    pathOut->addStrokeAdjustHint(left1 - 1, left1 + 2,
+					 left1 + 2, left1 + 3);
+	  }
+	}
+      }
+    }
+
+    i0 = j0;
+    i1 = j1;
+    ++seg;
+  }
+
+  if (pathIn != path) {
+    delete pathIn;
+  }
+
+  return pathOut;
+}
+
+void Splash::dumpPath(SplashPath *path) {
+  int i;
+
+  for (i = 0; i < path->length; ++i) {
+    printf("  %3d: x=%8.2f y=%8.2f%s%s%s%s\n",
+	   i, (double)path->pts[i].x, (double)path->pts[i].y,
+	   (path->flags[i] & splashPathFirst) ? " first" : "",
+	   (path->flags[i] & splashPathLast) ? " last" : "",
+	   (path->flags[i] & splashPathClosed) ? " closed" : "",
+	   (path->flags[i] & splashPathCurve) ? " curve" : "");
+  }
+}
+
+void Splash::dumpXPath(SplashXPath *path) {
+  int i;
+
+  for (i = 0; i < path->length; ++i) {
+    printf("  %4d: x0=%8.2f y0=%8.2f x1=%8.2f y1=%8.2f %s%s%s\n",
+	   i, (double)path->segs[i].x0, (double)path->segs[i].y0,
+	   (double)path->segs[i].x1, (double)path->segs[i].y1,
+	   (path->segs[i].flags	& splashXPathHoriz) ? "H" : " ",
+	   (path->segs[i].flags	& splashXPathVert) ? "V" : " ",
+	   (path->segs[i].flags	& splashXPathFlip) ? "P" : " ");
+  }
+}
+
+SplashError Splash::shadedFill(SplashPath *path, GBool hasBBox,
+                               SplashPattern *pattern) {
+  SplashPipe pipe;
+  SplashXPath *xPath;
+  SplashXPathScanner *scanner;
+  int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y;
+  SplashClipResult clipRes;
+
+  if (vectorAntialias && aaBuf == NULL) { // should not happen, but to be secure
+    return splashErrGeneric;
+  }
+  if (path->length == 0) {
+    return splashErrEmptyPath;
+  }
+  xPath = new SplashXPath(path, state->matrix, state->flatness, gTrue);
+  if (vectorAntialias) {
+    xPath->aaScale();
+  }
+  xPath->sort();
+  yMinI = state->clip->getYMinI();
+  yMaxI = state->clip->getYMaxI();
+  if (vectorAntialias && !inShading) {
+    yMinI = yMinI * splashAASize;
+    yMaxI = (yMaxI + 1) * splashAASize - 1;
+  }
+  scanner = new SplashXPathScanner(xPath, gFalse, yMinI, yMaxI);
+
+  // get the min and max x and y values
+  if (vectorAntialias) {
+    scanner->getBBoxAA(&xMinI, &yMinI, &xMaxI, &yMaxI);
+  } else {
+    scanner->getBBox(&xMinI, &yMinI, &xMaxI, &yMaxI);
+  }
+
+  // check clipping
+  if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI)) != splashClipAllOutside) {
+    // limit the y range
+    if (yMinI < state->clip->getYMinI()) {
+      yMinI = state->clip->getYMinI();
+    }
+    if (yMaxI > state->clip->getYMaxI()) {
+      yMaxI = state->clip->getYMaxI();
+    }
+
+    pipeInit(&pipe, 0, yMinI, pattern, NULL, (Guchar)splashRound(state->fillAlpha * 255), vectorAntialias && !hasBBox, gFalse);
+
+    // draw the spans
+    if (vectorAntialias) {
+      for (y = yMinI; y <= yMaxI; ++y) {
+        scanner->renderAALine(aaBuf, &x0, &x1, y);
+        if (clipRes != splashClipAllInside) {
+          state->clip->clipAALine(aaBuf, &x0, &x1, y);
+        }
+#if splashAASize == 4
+        if (!hasBBox && y > yMinI && y < yMaxI) {
+          // correct shape on left side if clip is
+          // vertical through the middle of shading:
+          Guchar *p0, *p1, *p2, *p3;
+          Guchar c1, c2, c3, c4;
+          p0 = aaBuf->getDataPtr() + (x0 >> 1);
+          p1 = p0 + aaBuf->getRowSize();
+          p2 = p1 + aaBuf->getRowSize();
+          p3 = p2 + aaBuf->getRowSize();
+          if (x0 & 1) {
+           c1 = (*p0 & 0x0f); c2 =(*p1 & 0x0f); c3 = (*p2 & 0x0f) ; c4 = (*p3 & 0x0f);
+          } else {
+            c1 = (*p0 >> 4); c2 = (*p1 >> 4); c3 = (*p2 >> 4); c4 = (*p3 >> 4);
+          }
+          if ( (c1 & 0x03) == 0x03 && (c2 & 0x03) == 0x03 && (c3 & 0x03) == 0x03 && (c4 & 0x03) == 0x03
+            && c1 == c2 && c2 == c3 && c3 == c4 &&
+            pattern->testPosition(x0 - 1, y) )
+          {
+            Guchar shapeCorrection = (x0 & 1) ? 0x0f : 0xf0;
+            *p0 |= shapeCorrection;
+            *p1 |= shapeCorrection;
+            *p2 |= shapeCorrection;
+            *p3 |= shapeCorrection;
+          }
+          // correct shape on right side if clip is
+          // through the middle of shading:
+          p0 = aaBuf->getDataPtr() + (x1 >> 1);
+          p1 = p0 + aaBuf->getRowSize();
+          p2 = p1 + aaBuf->getRowSize();
+          p3 = p2 + aaBuf->getRowSize();
+          if (x1 & 1) {
+            c1 = (*p0 & 0x0f); c2 =(*p1 & 0x0f); c3 = (*p2 & 0x0f) ; c4 = (*p3 & 0x0f);
+          } else {
+            c1 = (*p0 >> 4); c2 = (*p1 >> 4); c3 = (*p2 >> 4); c4 = (*p3 >> 4);
+          }
+
+          if ( (c1 & 0xc) == 0x0c && (c2 & 0x0c) == 0x0c && (c3 & 0x0c) == 0x0c && (c4 & 0x0c) == 0x0c
+            && c1 == c2 && c2 == c3 && c3 == c4 &&
+            pattern->testPosition(x1 + 1, y) )
+          {
+            Guchar shapeCorrection = (x1 & 1) ? 0x0f : 0xf0;
+            *p0 |= shapeCorrection;
+            *p1 |= shapeCorrection;
+            *p2 |= shapeCorrection;
+            *p3 |= shapeCorrection;
+          }
+        }
+#endif
+        drawAALine(&pipe, x0, x1, y);
+      }
+    } else {
+      SplashClipResult clipRes2;
+      for (y = yMinI; y <= yMaxI; ++y) {
+        while (scanner->getNextSpan(y, &x0, &x1)) {
+          if (clipRes == splashClipAllInside) {
+            drawSpan(&pipe, x0, x1, y, gTrue);
+          } else {
+            // limit the x range
+            if (x0 < state->clip->getXMinI()) {
+              x0 = state->clip->getXMinI();
+            }
+            if (x1 > state->clip->getXMaxI()) {
+              x1 = state->clip->getXMaxI();
+            }
+            clipRes2 = state->clip->testSpan(x0, x1, y);
+            drawSpan(&pipe, x0, x1, y, clipRes2 == splashClipAllInside);
+          }
+        }
+      }
+    }
+  }
+  opClipRes = clipRes;
+
+  delete scanner;
+  delete xPath;
+  return splashOk;
+}
diff --git a/source/libs/poppler/poppler-src/splash/Splash.h b/source/libs/poppler/poppler-src/splash/Splash.h
new file mode 100644
index 0000000000000000000000000000000000000000..907e4c3b6ee4a0bf5f162f0e1dbe6b560ee35567
--- /dev/null
+++ b/source/libs/poppler/poppler-src/splash/Splash.h
@@ -0,0 +1,431 @@
+//========================================================================
+//
+// Splash.h
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005 Marco Pesenti Gritti <mpg@redhat.com>
+// Copyright (C) 2007, 2011 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2010-2013, 2015 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2010 Christian Feuers�nger <cfeuersaenger@googlemail.com>
+// Copyright (C) 2012, 2017 Adrian Johnson <ajohnson@redneon.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef SPLASH_H
+#define SPLASH_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include <stddef.h>
+#include "SplashTypes.h"
+#include "SplashClip.h"
+#include "SplashPattern.h"
+
+class SplashBitmap;
+struct SplashGlyphBitmap;
+class SplashState;
+class SplashScreen;
+class SplashPath;
+class SplashXPath;
+class SplashFont;
+struct SplashPipe;
+
+//------------------------------------------------------------------------
+
+// Retrieves the next line of pixels in an image mask.  Normally,
+// fills in *<line> and returns true.  If the image stream is
+// exhausted, returns false.
+typedef GBool (*SplashImageMaskSource)(void *data, SplashColorPtr pixel);
+
+// Retrieves the next line of pixels in an image.  Normally, fills in
+// *<line> and returns true.  If the image stream is exhausted,
+// returns false.
+typedef GBool (*SplashImageSource)(void *data, SplashColorPtr colorLine,
+				   Guchar *alphaLine);
+
+// Use ICCColorSpace to transform a bitmap
+typedef void (*SplashICCTransform)(void *data, SplashBitmap *bitmap);
+
+//------------------------------------------------------------------------
+
+enum SplashPipeResultColorCtrl {
+#ifdef SPLASH_CMYK
+  splashPipeResultColorNoAlphaBlendCMYK,
+  splashPipeResultColorNoAlphaBlendDeviceN,
+#endif
+  splashPipeResultColorNoAlphaBlendRGB,
+  splashPipeResultColorNoAlphaBlendMono,
+  splashPipeResultColorAlphaNoBlendMono,
+  splashPipeResultColorAlphaNoBlendRGB,
+#ifdef SPLASH_CMYK
+  splashPipeResultColorAlphaNoBlendCMYK,
+  splashPipeResultColorAlphaNoBlendDeviceN,
+#endif
+  splashPipeResultColorAlphaBlendMono,
+  splashPipeResultColorAlphaBlendRGB
+#ifdef SPLASH_CMYK
+  ,
+  splashPipeResultColorAlphaBlendCMYK,
+  splashPipeResultColorAlphaBlendDeviceN
+#endif
+};
+
+//------------------------------------------------------------------------
+// Splash
+//------------------------------------------------------------------------
+
+class Splash {
+public:
+
+  // Create a new rasterizer object.
+  Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA,
+	 SplashScreenParams *screenParams = NULL);
+  Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA,
+	 SplashScreen *screenA);
+
+  ~Splash();
+
+  //----- state read
+
+  SplashCoord *getMatrix();
+  SplashPattern *getStrokePattern();
+  SplashPattern *getFillPattern();
+  SplashScreen *getScreen();
+  SplashBlendFunc getBlendFunc();
+  SplashCoord getStrokeAlpha();
+  SplashCoord getFillAlpha();
+  SplashCoord getLineWidth();
+  int getLineCap();
+  int getLineJoin();
+  SplashCoord getMiterLimit();
+  SplashCoord getFlatness();
+  SplashCoord *getLineDash();
+  int getLineDashLength();
+  SplashCoord getLineDashPhase();
+  GBool getStrokeAdjust();
+  SplashClip *getClip();
+  SplashBitmap *getSoftMask();
+  GBool getInNonIsolatedGroup();
+
+  //----- state write
+
+  void setMatrix(SplashCoord *matrix);
+  void setStrokePattern(SplashPattern *strokeColor);
+  void setFillPattern(SplashPattern *fillColor);
+  void setScreen(SplashScreen *screen);
+  void setBlendFunc(SplashBlendFunc func);
+  void setStrokeAlpha(SplashCoord alpha);
+  void setFillAlpha(SplashCoord alpha);
+  void setPatternAlpha(SplashCoord strokeAlpha, SplashCoord fillAlpha);
+  void clearPatternAlpha();
+  void setFillOverprint(GBool fop);
+  void setStrokeOverprint(GBool sop);
+  void setOverprintMode(int opm);
+  void setLineWidth(SplashCoord lineWidth);
+  void setLineCap(int lineCap);
+  void setLineJoin(int lineJoin);
+  void setMiterLimit(SplashCoord miterLimit);
+  void setFlatness(SplashCoord flatness);
+  // the <lineDash> array will be copied
+  void setLineDash(SplashCoord *lineDash, int lineDashLength,
+		   SplashCoord lineDashPhase);
+  void setStrokeAdjust(GBool strokeAdjust);
+  // NB: uses transformed coordinates.
+  void clipResetToRect(SplashCoord x0, SplashCoord y0,
+		       SplashCoord x1, SplashCoord y1);
+  // NB: uses transformed coordinates.
+  SplashError clipToRect(SplashCoord x0, SplashCoord y0,
+			 SplashCoord x1, SplashCoord y1);
+  // NB: uses untransformed coordinates.
+  SplashError clipToPath(SplashPath *path, GBool eo);
+  void setSoftMask(SplashBitmap *softMask);
+  void setInNonIsolatedGroup(SplashBitmap *alpha0BitmapA,
+			     int alpha0XA, int alpha0YA);
+  void setTransfer(Guchar *red, Guchar *green, Guchar *blue, Guchar *gray);
+  void setOverprintMask(Guint overprintMask, GBool additive);
+
+  //----- state save/restore
+
+  void saveState();
+  SplashError restoreState();
+
+  //----- drawing operations
+
+  // Fill the bitmap with <color>.  This is not subject to clipping.
+  void clear(SplashColorPtr color, Guchar alpha = 0x00);
+
+  // Stroke a path using the current stroke pattern.
+  SplashError stroke(SplashPath *path);
+
+  // Fill a path using the current fill pattern.
+  SplashError fill(SplashPath *path, GBool eo);
+
+  // Fill a path, XORing with the current fill pattern.
+  SplashError xorFill(SplashPath *path, GBool eo);
+
+  // Draw a character, using the current fill pattern.
+  SplashError fillChar(SplashCoord x, SplashCoord y, int c, SplashFont *font);
+
+  // Draw a glyph, using the current fill pattern.  This function does
+  // not free any data, i.e., it ignores glyph->freeData.
+  void fillGlyph(SplashCoord x, SplashCoord y,
+			SplashGlyphBitmap *glyph);
+
+  // Draws an image mask using the fill color.  This will read <h>
+  // lines of <w> pixels from <src>, starting with the top line.  "1"
+  // pixels will be drawn with the current fill color; "0" pixels are
+  // transparent.  The matrix:
+  //    [ mat[0] mat[1] 0 ]
+  //    [ mat[2] mat[3] 0 ]
+  //    [ mat[4] mat[5] 1 ]
+  // maps a unit square to the desired destination for the image, in
+  // PostScript style:
+  //    [x' y' 1] = [x y 1] * mat
+  // Note that the Splash y axis points downward, and the image source
+  // is assumed to produce pixels in raster order, starting from the
+  // top line.
+  SplashError fillImageMask(SplashImageMaskSource src, void *srcData,
+			    int w, int h, SplashCoord *mat,
+			    GBool glyphMode);
+
+  // Draw an image.  This will read <h> lines of <w> pixels from
+  // <src>, starting with the top line.  These pixels are assumed to
+  // be in the source mode, <srcMode>.  If <srcAlpha> is true, the
+  // alpha values returned by <src> are used; otherwise they are
+  // ignored.  The following combinations of source and target modes
+  // are supported:
+  //    source       target
+  //    ------       ------
+  //    Mono1        Mono1
+  //    Mono8        Mono1   -- with dithering
+  //    Mono8        Mono8
+  //    RGB8         RGB8
+  //    BGR8         BGR8
+  //    CMYK8        CMYK8
+  // The matrix behaves as for fillImageMask.
+  SplashError drawImage(SplashImageSource src, SplashICCTransform tf, void *srcData,
+			SplashColorMode srcMode, GBool srcAlpha,
+			int w, int h, SplashCoord *mat, GBool interpolate,
+			GBool tilingPattern = gFalse);
+
+  // Composite a rectangular region from <src> onto this Splash
+  // object.
+  SplashError composite(SplashBitmap *src, int xSrc, int ySrc,
+			int xDest, int yDest, int w, int h,
+			GBool noClip, GBool nonIsolated,
+			GBool knockout = gFalse, SplashCoord knockoutOpacity = 1.0);
+
+  // Composite this Splash object onto a background color.  The
+  // background alpha is assumed to be 1.
+  void compositeBackground(SplashColorPtr color);
+
+  // Copy a rectangular region from <src> onto the bitmap belonging to
+  // this Splash object.  The destination alpha values are all set to
+  // zero.
+  SplashError blitTransparent(SplashBitmap *src, int xSrc, int ySrc,
+			      int xDest, int yDest, int w, int h);
+  void blitImage(SplashBitmap *src, GBool srcAlpha, int xDest, int yDest);
+
+  //----- misc
+
+  // Construct a path for a stroke, given the path to be stroked and
+  // the line width <w>.  All other stroke parameters are taken from
+  // the current state.  If <flatten> is true, this function will
+  // first flatten the path and handle the linedash.
+  SplashPath *makeStrokePath(SplashPath *path, SplashCoord w,
+			     GBool flatten = gTrue);
+
+  // Return the associated bitmap.
+  SplashBitmap *getBitmap() { return bitmap; }
+
+  // Set the minimum line width.
+  void setMinLineWidth(SplashCoord w) { minLineWidth = w; }
+
+  // Setter/Getter for thin line mode
+  void setThinLineMode(SplashThinLineMode thinLineModeA) { thinLineMode = thinLineModeA; }
+  SplashThinLineMode getThinLineMode() { return thinLineMode; }
+
+  // Get a bounding box which includes all modifications since the
+  // last call to clearModRegion.
+  void getModRegion(int *xMin, int *yMin, int *xMax, int *yMax)
+    { *xMin = modXMin; *yMin = modYMin; *xMax = modXMax; *yMax = modYMax; }
+
+  // Clear the modified region bounding box.
+  void clearModRegion();
+
+  // Get clipping status for the last drawing operation subject to
+  // clipping.
+  SplashClipResult getClipRes() { return opClipRes; }
+
+  // Toggle debug mode on or off.
+  void setDebugMode(GBool debugModeA) { debugMode = debugModeA; }
+
+#if 1 //~tmp: turn off anti-aliasing temporarily
+  void setInShading(GBool sh) { inShading = sh; }
+  GBool getVectorAntialias() { return vectorAntialias; }
+  void setVectorAntialias(GBool vaa) { vectorAntialias = vaa; }
+#endif
+
+  // Do shaded fills with dynamic patterns
+  SplashError shadedFill(SplashPath *path, GBool hasBBox,
+                         SplashPattern *pattern);
+  // Draw a gouraud triangle shading.
+  GBool gouraudTriangleShadedFill(SplashGouraudColor *shading);
+
+private:
+
+  void pipeInit(SplashPipe *pipe, int x, int y,
+		SplashPattern *pattern, SplashColorPtr cSrc,
+		Guchar aInput, GBool usesShape,
+		GBool nonIsolatedGroup,
+		GBool knockout = gFalse, Guchar knockoutOpacity = 255);
+  void pipeRun(SplashPipe *pipe);
+  void pipeRunSimpleMono1(SplashPipe *pipe);
+  void pipeRunSimpleMono8(SplashPipe *pipe);
+  void pipeRunSimpleRGB8(SplashPipe *pipe);
+  void pipeRunSimpleXBGR8(SplashPipe *pipe);
+  void pipeRunSimpleBGR8(SplashPipe *pipe);
+#ifdef SPLASH_CMYK
+  void pipeRunSimpleCMYK8(SplashPipe *pipe);
+  void pipeRunSimpleDeviceN8(SplashPipe *pipe);
+#endif
+  void pipeRunAAMono1(SplashPipe *pipe);
+  void pipeRunAAMono8(SplashPipe *pipe);
+  void pipeRunAARGB8(SplashPipe *pipe);
+  void pipeRunAAXBGR8(SplashPipe *pipe);
+  void pipeRunAABGR8(SplashPipe *pipe);
+#ifdef SPLASH_CMYK
+  void pipeRunAACMYK8(SplashPipe *pipe);
+  void pipeRunAADeviceN8(SplashPipe *pipe);
+#endif
+  void pipeSetXY(SplashPipe *pipe, int x, int y);
+  void pipeIncX(SplashPipe *pipe);
+  void drawPixel(SplashPipe *pipe, int x, int y, GBool noClip);
+  void drawAAPixelInit();
+  void drawAAPixel(SplashPipe *pipe, int x, int y);
+  void drawSpan(SplashPipe *pipe, int x0, int x1, int y, GBool noClip);
+  void drawAALine(SplashPipe *pipe, int x0, int x1, int y, GBool adjustLine = gFalse, Guchar lineOpacity = 0);
+  void transform(SplashCoord *matrix, SplashCoord xi, SplashCoord yi,
+		 SplashCoord *xo, SplashCoord *yo);
+  void updateModX(int x);
+  void updateModY(int y);
+  void strokeNarrow(SplashPath *path);
+  void strokeWide(SplashPath *path, SplashCoord w);
+  SplashPath *flattenPath(SplashPath *path, SplashCoord *matrix,
+			  SplashCoord flatness);
+  void flattenCurve(SplashCoord x0, SplashCoord y0,
+		    SplashCoord x1, SplashCoord y1,
+		    SplashCoord x2, SplashCoord y2,
+		    SplashCoord x3, SplashCoord y3,
+		    SplashCoord *matrix, SplashCoord flatness2,
+		    SplashPath *fPath);
+  SplashPath *makeDashedPath(SplashPath *xPath);
+  void getBBoxFP(SplashPath *path, SplashCoord *xMinA, SplashCoord *yMinA, SplashCoord *xMaxA, SplashCoord *yMaxA);
+  SplashError fillWithPattern(SplashPath *path, GBool eo,
+			      SplashPattern *pattern, SplashCoord alpha);
+  GBool pathAllOutside(SplashPath *path);
+  void fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph, GBool noclip);
+  void arbitraryTransformMask(SplashImageMaskSource src, void *srcData,
+			      int srcWidth, int srcHeight,
+			      SplashCoord *mat, GBool glyphMode);
+  SplashBitmap *scaleMask(SplashImageMaskSource src, void *srcData,
+			  int srcWidth, int srcHeight,
+			  int scaledWidth, int scaledHeight);
+  void scaleMaskYdXd(SplashImageMaskSource src, void *srcData,
+		     int srcWidth, int srcHeight,
+		     int scaledWidth, int scaledHeight,
+		     SplashBitmap *dest);
+  void scaleMaskYdXu(SplashImageMaskSource src, void *srcData,
+		     int srcWidth, int srcHeight,
+		     int scaledWidth, int scaledHeight,
+		     SplashBitmap *dest);
+  void scaleMaskYuXd(SplashImageMaskSource src, void *srcData,
+		     int srcWidth, int srcHeight,
+		     int scaledWidth, int scaledHeight,
+		     SplashBitmap *dest);
+  void scaleMaskYuXu(SplashImageMaskSource src, void *srcData,
+		     int srcWidth, int srcHeight,
+		     int scaledWidth, int scaledHeight,
+		     SplashBitmap *dest);
+  void blitMask(SplashBitmap *src, int xDest, int yDest,
+		SplashClipResult clipRes);
+  SplashError arbitraryTransformImage(SplashImageSource src, SplashICCTransform tf, void *srcData,
+			       SplashColorMode srcMode, int nComps,
+			       GBool srcAlpha,
+			       int srcWidth, int srcHeight,
+                               SplashCoord *mat, GBool interpolate, GBool tilingPattern = gFalse);
+  SplashBitmap *scaleImage(SplashImageSource src, void *srcData,
+			   SplashColorMode srcMode, int nComps,
+			   GBool srcAlpha, int srcWidth, int srcHeight,
+			   int scaledWidth, int scaledHeight, GBool interpolate, GBool tilingPattern = gFalse);
+  void scaleImageYdXd(SplashImageSource src, void *srcData,
+		      SplashColorMode srcMode, int nComps,
+		      GBool srcAlpha, int srcWidth, int srcHeight,
+		      int scaledWidth, int scaledHeight,
+		      SplashBitmap *dest);
+  void scaleImageYdXu(SplashImageSource src, void *srcData,
+		      SplashColorMode srcMode, int nComps,
+		      GBool srcAlpha, int srcWidth, int srcHeight,
+		      int scaledWidth, int scaledHeight,
+		      SplashBitmap *dest);
+  void scaleImageYuXd(SplashImageSource src, void *srcData,
+		      SplashColorMode srcMode, int nComps,
+		      GBool srcAlpha, int srcWidth, int srcHeight,
+		      int scaledWidth, int scaledHeight,
+		      SplashBitmap *dest);
+  void scaleImageYuXu(SplashImageSource src, void *srcData,
+		      SplashColorMode srcMode, int nComps,
+		      GBool srcAlpha, int srcWidth, int srcHeight,
+		      int scaledWidth, int scaledHeight,
+		      SplashBitmap *dest);
+  void scaleImageYuXuBilinear(SplashImageSource src, void *srcData,
+		      SplashColorMode srcMode, int nComps,
+		      GBool srcAlpha, int srcWidth, int srcHeight,
+		      int scaledWidth, int scaledHeight,
+		      SplashBitmap *dest);
+  void vertFlipImage(SplashBitmap *img, int width, int height,
+		     int nComps);
+  void blitImage(SplashBitmap *src, GBool srcAlpha, int xDest, int yDest,
+		 SplashClipResult clipRes);
+  void blitImageClipped(SplashBitmap *src, GBool srcAlpha,
+			int xSrc, int ySrc, int xDest, int yDest,
+			int w, int h);
+  void dumpPath(SplashPath *path);
+  void dumpXPath(SplashXPath *path);
+
+  static SplashPipeResultColorCtrl pipeResultColorNoAlphaBlend[];
+  static SplashPipeResultColorCtrl pipeResultColorAlphaNoBlend[];
+  static SplashPipeResultColorCtrl pipeResultColorAlphaBlend[];
+  static int pipeNonIsoGroupCorrection[];
+
+  SplashBitmap *bitmap;
+  SplashState *state;
+  SplashBitmap *aaBuf;
+  int aaBufY;
+  SplashBitmap *alpha0Bitmap;	// for non-isolated groups, this is the
+				//   bitmap containing the alpha0 values
+  int alpha0X, alpha0Y;		// offset within alpha0Bitmap
+  SplashCoord aaGamma[splashAASize * splashAASize + 1];
+  SplashCoord minLineWidth;
+  SplashThinLineMode thinLineMode;
+  int modXMin, modYMin, modXMax, modYMax;
+  SplashClipResult opClipRes;
+  GBool vectorAntialias;
+  GBool inShading;
+  GBool debugMode;
+};
+
+#endif
diff --git a/source/libs/poppler/poppler-src/splash/SplashBitmap.cc b/source/libs/poppler/poppler-src/splash/SplashBitmap.cc
new file mode 100644
index 0000000000000000000000000000000000000000..5acee7d0bd61e36c62cee2f1b5a1f962807b8333
--- /dev/null
+++ b/source/libs/poppler/poppler-src/splash/SplashBitmap.cc
@@ -0,0 +1,853 @@
+//========================================================================
+//
+// SplashBitmap.cc
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2006, 2009, 2010, 2012, 2015 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2007 Ilmari Heikkinen <ilmari.heikkinen@gmail.com>
+// Copyright (C) 2009 Shen Liang <shenzhuxi@gmail.com>
+// Copyright (C) 2009 Stefan Thomas <thomas@eload24.com>
+// Copyright (C) 2010, 2012, 2017 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2010 Harry Roberts <harry.roberts@midnight-labs.org>
+// Copyright (C) 2010 Christian Feuers�nger <cfeuersaenger@googlemail.com>
+// Copyright (C) 2010, 2015 William Bader <williambader@hotmail.com>
+// Copyright (C) 2011-2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2012 Anthony Wesley <awesley@smartnetworks.com.au>
+// Copyright (C) 2015 Adam Reichold <adamreichold@myopera.com>
+// Copyright (C) 2016 Kenji Uno <ku@digitaldolphins.jp>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include "goo/gmem.h"
+#include "SplashErrorCodes.h"
+#include "SplashBitmap.h"
+#include "poppler/Error.h"
+#include "goo/JpegWriter.h"
+#include "goo/PNGWriter.h"
+#include "goo/TiffWriter.h"
+#include "goo/ImgWriter.h"
+#include "goo/GooList.h"
+
+//------------------------------------------------------------------------
+// SplashBitmap
+//------------------------------------------------------------------------
+
+SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPadA,
+			   SplashColorMode modeA, GBool alphaA,
+			   GBool topDown, GooList *separationListA) {
+  width = widthA;
+  height = heightA;
+  mode = modeA;
+  rowPad = rowPadA;
+  switch (mode) {
+  case splashModeMono1:
+    if (width > 0) {
+      rowSize = (width + 7) >> 3;
+    } else {
+      rowSize = -1;
+    }
+    break;
+  case splashModeMono8:
+    if (width > 0) {
+      rowSize = width;
+    } else {
+      rowSize = -1;
+    }
+    break;
+  case splashModeRGB8:
+  case splashModeBGR8:
+    if (width > 0 && width <= INT_MAX / 3) {
+      rowSize = width * 3;
+    } else {
+      rowSize = -1;
+    }
+    break;
+  case splashModeXBGR8:
+    if (width > 0 && width <= INT_MAX / 4) {
+      rowSize = width * 4;
+    } else {
+      rowSize = -1;
+    }
+    break;
+#ifdef SPLASH_CMYK
+  case splashModeCMYK8:
+    if (width > 0 && width <= INT_MAX / 4) {
+      rowSize = width * 4;
+    } else {
+      rowSize = -1;
+    }
+    break;
+  case splashModeDeviceN8:
+    if (width > 0 && width <= INT_MAX / 4) {
+      rowSize = width * (SPOT_NCOMPS + 4);
+    } else {
+      rowSize = -1;
+    }
+    break;
+#endif
+  }
+  if (rowSize > 0) {
+    rowSize += rowPad - 1;
+    rowSize -= rowSize % rowPad;
+  }
+  data = (SplashColorPtr)gmallocn_checkoverflow(rowSize, height);
+  if (data != NULL) {
+    if (!topDown) {
+      data += (height - 1) * rowSize;
+      rowSize = -rowSize;
+    }
+    if (alphaA) {
+      alpha = (Guchar *)gmallocn(width, height);
+    } else {
+      alpha = NULL;
+    }
+  } else {
+    alpha = NULL;
+  }
+  separationList = new GooList();
+  if (separationListA != NULL)
+    for (int i = 0; i < separationListA->getLength(); i++)
+      separationList->append(((GfxSeparationColorSpace *) separationListA->get(i))->copy());
+}
+
+SplashBitmap *SplashBitmap::copy(SplashBitmap *src) {
+  SplashBitmap *result = new SplashBitmap(src->getWidth(), src->getHeight(), src->getRowPad(), 
+    src->getMode(), src->getAlphaPtr() != NULL, src->getRowSize() >= 0, src->getSeparationList());
+  Guchar *dataSource = src->getDataPtr();
+  Guchar *dataDest = result->getDataPtr();
+  int amount = src->getRowSize();
+  if (amount < 0) {
+    dataSource = dataSource + (src->getHeight() - 1) * amount;
+    dataDest = dataDest + (src->getHeight() - 1) * amount;
+    amount *= -src->getHeight();
+  } else {
+    amount *= src->getHeight();
+  }
+  memcpy(dataDest, dataSource, amount);
+  if (src->getAlphaPtr() != NULL) {
+    memcpy(result->getAlphaPtr(), src->getAlphaPtr(), src->getWidth() * src->getHeight());
+  }
+  return result;
+}
+
+SplashBitmap::~SplashBitmap() {
+  if (data) {
+    if (rowSize < 0) {
+      gfree(data + (height - 1) * rowSize);
+    } else {
+      gfree(data);
+    }
+  }
+  gfree(alpha);
+  deleteGooList(separationList, GfxSeparationColorSpace);
+}
+
+
+SplashError SplashBitmap::writePNMFile(char *fileName) {
+  FILE *f;
+  SplashError e;
+
+  if (!(f = fopen(fileName, "wb"))) {
+    return splashErrOpenFile;
+  }
+
+  e = this->writePNMFile(f);
+  
+  fclose(f);
+  return e;
+}
+
+
+SplashError SplashBitmap::writePNMFile(FILE *f) {
+  SplashColorPtr row, p;
+  int x, y;
+
+  switch (mode) {
+
+  case splashModeMono1:
+    fprintf(f, "P4\n%d %d\n", width, height);
+    row = data;
+    for (y = 0; y < height; ++y) {
+      p = row;
+      for (x = 0; x < width; x += 8) {
+	fputc(*p ^ 0xff, f);
+	++p;
+      }
+      row += rowSize;
+    }
+    break;
+
+  case splashModeMono8:
+    fprintf(f, "P5\n%d %d\n255\n", width, height);
+    row = data;
+    for (y = 0; y < height; ++y) {
+      fwrite(row, 1, width, f);
+      row += rowSize;
+    }
+    break;
+
+  case splashModeRGB8:
+    fprintf(f, "P6\n%d %d\n255\n", width, height);
+    row = data;
+    for (y = 0; y < height; ++y) {
+      fwrite(row, 1, 3 * width, f);
+      row += rowSize;
+    }
+    break;
+
+  case splashModeXBGR8:
+    fprintf(f, "P6\n%d %d\n255\n", width, height);
+    row = data;
+    for (y = 0; y < height; ++y) {
+      p = row;
+      for (x = 0; x < width; ++x) {
+	fputc(splashBGR8R(p), f);
+	fputc(splashBGR8G(p), f);
+	fputc(splashBGR8B(p), f);
+	p += 4;
+      }
+      row += rowSize;
+    }
+    break;
+
+
+  case splashModeBGR8:
+    fprintf(f, "P6\n%d %d\n255\n", width, height);
+    row = data;
+    for (y = 0; y < height; ++y) {
+      p = row;
+      for (x = 0; x < width; ++x) {
+	fputc(splashBGR8R(p), f);
+	fputc(splashBGR8G(p), f);
+	fputc(splashBGR8B(p), f);
+	p += 3;
+      }
+      row += rowSize;
+    }
+    break;
+
+#ifdef SPLASH_CMYK
+  case splashModeCMYK8:
+  case splashModeDeviceN8:
+    // PNM doesn't support CMYK
+    error(errInternal, -1, "unsupported SplashBitmap mode");
+    return splashErrGeneric;
+    break;
+#endif
+  }
+  return splashOk;
+}
+
+SplashError SplashBitmap::writeAlphaPGMFile(char *fileName) {
+  FILE *f;
+
+  if (!alpha) {
+    return splashErrModeMismatch;
+  }
+  if (!(f = fopen(fileName, "wb"))) {
+    return splashErrOpenFile;
+  }
+  fprintf(f, "P5\n%d %d\n255\n", width, height);
+  fwrite(alpha, 1, width * height, f);
+  fclose(f);
+  return splashOk;
+}
+
+void SplashBitmap::getPixel(int x, int y, SplashColorPtr pixel) {
+  SplashColorPtr p;
+
+  if (y < 0 || y >= height || x < 0 || x >= width || !data) {
+    return;
+  }
+  switch (mode) {
+  case splashModeMono1:
+    p = &data[y * rowSize + (x >> 3)];
+    pixel[0] = (p[0] & (0x80 >> (x & 7))) ? 0xff : 0x00;
+    break;
+  case splashModeMono8:
+    p = &data[y * rowSize + x];
+    pixel[0] = p[0];
+    break;
+  case splashModeRGB8:
+    p = &data[y * rowSize + 3 * x];
+    pixel[0] = p[0];
+    pixel[1] = p[1];
+    pixel[2] = p[2];
+    break;
+  case splashModeXBGR8:
+    p = &data[y * rowSize + 4 * x];
+    pixel[0] = p[2];
+    pixel[1] = p[1];
+    pixel[2] = p[0];
+    pixel[3] = p[3];
+    break;
+  case splashModeBGR8:
+    p = &data[y * rowSize + 3 * x];
+    pixel[0] = p[2];
+    pixel[1] = p[1];
+    pixel[2] = p[0];
+    break;
+#ifdef SPLASH_CMYK
+  case splashModeCMYK8:
+    p = &data[y * rowSize + 4 * x];
+    pixel[0] = p[0];
+    pixel[1] = p[1];
+    pixel[2] = p[2];
+    pixel[3] = p[3];
+    break;
+  case splashModeDeviceN8:
+    p = &data[y * rowSize + (SPOT_NCOMPS + 4) * x];
+    for (int cp = 0; cp < SPOT_NCOMPS + 4; cp++)
+      pixel[cp] = p[cp];
+    break;
+#endif
+  }
+}
+
+Guchar SplashBitmap::getAlpha(int x, int y) {
+  return alpha[y * width + x];
+}
+
+SplashColorPtr SplashBitmap::takeData() {
+  SplashColorPtr data2;
+
+  data2 = data;
+  data = NULL;
+  return data2;
+}
+
+SplashError SplashBitmap::writeImgFile(SplashImageFileFormat format, char *fileName, int hDPI, int vDPI, WriteImgParams* params) {
+  FILE *f;
+  SplashError e;
+
+  if (!(f = fopen(fileName, "wb"))) {
+    return splashErrOpenFile;
+  }
+
+  e = writeImgFile(format, f, hDPI, vDPI, params);
+
+  fclose(f);
+  return e;
+}
+
+void SplashBitmap::setJpegParams(ImgWriter *writer, WriteImgParams* params)
+{
+#ifdef ENABLE_LIBJPEG
+  if (params) {
+    static_cast<JpegWriter*>(writer)->setProgressive(params->jpegProgressive);
+    if (params->jpegQuality >= 0)
+      static_cast<JpegWriter*>(writer)->setQuality(params->jpegQuality);
+  }
+#endif
+}
+
+SplashError SplashBitmap::writeImgFile(SplashImageFileFormat format, FILE *f, int hDPI, int vDPI, WriteImgParams* params) {
+  ImgWriter *writer;
+	SplashError e;
+  
+  SplashColorMode imageWriterFormat = splashModeRGB8;
+
+  switch (format) {
+    #ifdef ENABLE_LIBPNG
+    case splashFormatPng:
+	  writer = new PNGWriter();
+      break;
+    #endif
+
+    #ifdef ENABLE_LIBJPEG
+    #ifdef SPLASH_CMYK
+    case splashFormatJpegCMYK:
+      writer = new JpegWriter(JpegWriter::CMYK);
+      setJpegParams(writer, params);
+      break;
+    #endif
+    case splashFormatJpeg:
+      writer = new JpegWriter();
+      setJpegParams(writer, params);
+      break;
+    #endif
+	
+    #ifdef ENABLE_LIBTIFF
+    case splashFormatTiff:
+      switch (mode) {
+      case splashModeMono1:
+        writer = new TiffWriter(TiffWriter::MONOCHROME);
+        imageWriterFormat = splashModeMono1;
+        break;
+      case splashModeMono8:
+        writer = new TiffWriter(TiffWriter::GRAY);
+        imageWriterFormat = splashModeMono8;
+        break;
+      case splashModeRGB8:
+      case splashModeBGR8:
+        writer = new TiffWriter(TiffWriter::RGB);
+        break;
+#ifdef SPLASH_CMYK
+      case splashModeCMYK8:
+      case splashModeDeviceN8:
+        writer = new TiffWriter(TiffWriter::CMYK);
+        break;
+#endif
+      default:
+        fprintf(stderr, "TiffWriter: Mode %d not supported\n", mode);
+        writer = new TiffWriter();
+      }
+      if (writer && params) {
+        ((TiffWriter *)writer)->setCompressionString(params->tiffCompression.getCString());
+      }
+      break;
+    #endif
+
+    default:
+      // Not the greatest error message, but users of this function should
+      // have already checked whether their desired format is compiled in.
+      error(errInternal, -1, "Support for this image type not compiled in");
+      return splashErrGeneric;
+  }
+
+	e = writeImgFile(writer, f, hDPI, vDPI, imageWriterFormat);
+	delete writer;
+	return e;
+}
+
+#include "poppler/GfxState_helpers.h"
+
+void SplashBitmap::getRGBLine(int yl, SplashColorPtr line) {
+  SplashColor col;
+  double c, m, y, k, c1, m1, y1, k1, r, g, b;
+
+  for (int x = 0; x < width; x++) {
+    getPixel(x, yl, col);
+    c = byteToDbl(col[0]);
+    m = byteToDbl(col[1]);
+    y = byteToDbl(col[2]);
+    k = byteToDbl(col[3]);
+#ifdef SPLASH_CMYK
+    if (separationList->getLength() > 0) {
+      for (int i = 0; i < separationList->getLength(); i++) {
+        if (col[i+4] > 0) {
+          GfxCMYK cmyk;
+          GfxColor input;
+          input.c[0] = byteToCol(col[i+4]);
+          GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)separationList->get(i);
+          sepCS->getCMYK(&input, &cmyk);
+          col[0] = colToByte(cmyk.c);
+          col[1] = colToByte(cmyk.m);
+          col[2] = colToByte(cmyk.y);
+          col[3] = colToByte(cmyk.k);
+          c += byteToDbl(col[0]);
+          m += byteToDbl(col[1]);
+          y += byteToDbl(col[2]);
+          k += byteToDbl(col[3]);
+        }
+      }
+      if (c > 1) c = 1;
+      if (m > 1) m = 1;
+      if (y > 1) y = 1;
+      if (k > 1) k = 1;
+    }
+#endif
+    c1 = 1 - c;
+    m1 = 1 - m;
+    y1 = 1 - y;
+    k1 = 1 - k;
+    cmykToRGBMatrixMultiplication(c, m, y, k, c1, m1, y1, k1, r, g, b);
+    *line++ = dblToByte(clip01(r));
+    *line++ = dblToByte(clip01(g));
+    *line++ = dblToByte(clip01(b));
+  }
+}
+
+void SplashBitmap::getXBGRLine(int yl, SplashColorPtr line, ConversionMode conversionMode) {
+  SplashColor col;
+  double c, m, y, k, c1, m1, y1, k1, r, g, b;
+
+  for (int x = 0; x < width; x++) {
+    getPixel(x, yl, col);
+    c = byteToDbl(col[0]);
+    m = byteToDbl(col[1]);
+    y = byteToDbl(col[2]);
+    k = byteToDbl(col[3]);
+#ifdef SPLASH_CMYK
+    if (separationList->getLength() > 0) {
+      for (int i = 0; i < separationList->getLength(); i++) {
+        if (col[i+4] > 0) {
+          GfxCMYK cmyk;
+          GfxColor input;
+          input.c[0] = byteToCol(col[i+4]);
+          GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)separationList->get(i);
+          sepCS->getCMYK(&input, &cmyk);
+          col[0] = colToByte(cmyk.c);
+          col[1] = colToByte(cmyk.m);
+          col[2] = colToByte(cmyk.y);
+          col[3] = colToByte(cmyk.k);
+          c += byteToDbl(col[0]);
+          m += byteToDbl(col[1]);
+          y += byteToDbl(col[2]);
+          k += byteToDbl(col[3]);
+        }
+      }
+      if (c > 1) c = 1;
+      if (m > 1) m = 1;
+      if (y > 1) y = 1;
+      if (k > 1) k = 1;
+    }
+#endif
+    c1 = 1 - c;
+    m1 = 1 - m;
+    y1 = 1 - y;
+    k1 = 1 - k;
+    cmykToRGBMatrixMultiplication(c, m, y, k, c1, m1, y1, k1, r, g, b);
+
+    if (conversionMode == conversionAlphaPremultiplied) {
+        const double a = getAlpha(x, yl) / 255.0;
+
+        *line++ = dblToByte(clip01(b * a));
+        *line++ = dblToByte(clip01(g * a));
+        *line++ = dblToByte(clip01(r * a));
+    } else {
+        *line++ = dblToByte(clip01(b));
+        *line++ = dblToByte(clip01(g));
+        *line++ = dblToByte(clip01(r));
+    }
+
+    if (conversionMode != conversionOpaque) {
+        *line++ = getAlpha(x, yl);
+    } else {
+        *line++ = 255;
+    }
+  }
+}
+
+static inline Guchar div255(int x) {
+  return (Guchar)((x + (x >> 8) + 0x80) >> 8);
+}
+
+GBool SplashBitmap::convertToXBGR(ConversionMode conversionMode) {
+  if (mode == splashModeXBGR8) {
+    if (conversionMode != conversionOpaque) {
+      // Copy the alpha channel into the fourth component so that XBGR becomes ABGR.
+      const SplashColorPtr dbegin = data;
+      const SplashColorPtr dend = data + rowSize * height;
+
+      Guchar *const abegin = alpha;
+      Guchar *const aend = alpha + width * height;
+
+      SplashColorPtr d = dbegin;
+      Guchar *a = abegin;
+
+      if (conversionMode == conversionAlphaPremultiplied) {
+          for (; d < dend && a < aend; d += 4, a += 1) {
+              d[0] = div255(d[0] * *a);
+              d[1] = div255(d[1] * *a);
+              d[2] = div255(d[2] * *a);
+              d[3] = *a;
+          }
+      } else {
+          for (d += 3; d < dend && a < aend; d += 4, a += 1) {
+              *d = *a;
+          }
+      }
+    }
+
+    return gTrue;
+  }
+  
+  int newrowSize = width * 4;
+  SplashColorPtr newdata = (SplashColorPtr)gmallocn_checkoverflow(newrowSize, height);
+  if (newdata != NULL) {
+    for (int y = 0; y < height; y++) {
+      unsigned char *row = newdata + y * newrowSize;
+      getXBGRLine(y, row, conversionMode);
+    }
+    if (rowSize < 0) {
+      gfree(data + (height - 1) * rowSize);
+    } else {
+      gfree(data);
+    }
+    data = newdata;
+    rowSize = newrowSize;
+    mode = splashModeXBGR8;
+  }
+  return newdata != NULL;
+}
+
+#ifdef SPLASH_CMYK
+void SplashBitmap::getCMYKLine(int yl, SplashColorPtr line) {
+  SplashColor col;
+
+  for (int x = 0; x < width; x++) {
+    getPixel(x, yl, col);
+    if (separationList->getLength() > 0) {
+      double c, m, y, k;
+      c = byteToDbl(col[0]);
+      m = byteToDbl(col[1]);
+      y = byteToDbl(col[2]);
+      k = byteToDbl(col[3]);
+      for (int i = 0; i < separationList->getLength(); i++) {
+        if (col[i+4] > 0) {
+          GfxCMYK cmyk;
+          GfxColor input;
+          input.c[0] = byteToCol(col[i+4]);
+          GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)separationList->get(i);
+          sepCS->getCMYK(&input, &cmyk);
+          col[0] = colToByte(cmyk.c);
+          col[1] = colToByte(cmyk.m);
+          col[2] = colToByte(cmyk.y);
+          col[3] = colToByte(cmyk.k);
+          c += byteToDbl(col[0]);
+          m += byteToDbl(col[1]);
+          y += byteToDbl(col[2]);
+          k += byteToDbl(col[3]);
+        }
+      }
+      col[0] = dblToByte(clip01(c));
+      col[1] = dblToByte(clip01(m));
+      col[2] = dblToByte(clip01(y));
+      col[3] = dblToByte(clip01(k));
+    }
+    *line++ = col[0];
+    *line++ = col[1];
+    *line++ = col[2];
+    *line++ = col[3];
+  }
+}
+#endif
+
+SplashError SplashBitmap::writeImgFile(ImgWriter *writer, FILE *f, int hDPI, int vDPI, SplashColorMode imageWriterFormat) {
+  if (mode != splashModeRGB8 && mode != splashModeMono8 && mode != splashModeMono1 && mode != splashModeXBGR8 && mode != splashModeBGR8
+#ifdef SPLASH_CMYK
+      && mode != splashModeCMYK8 && mode != splashModeDeviceN8
+#endif
+     ) {
+    error(errInternal, -1, "unsupported SplashBitmap mode");
+    return splashErrGeneric;
+  }
+
+  if (!writer->init(f, width, height, hDPI, vDPI)) {
+    return splashErrGeneric;
+  }
+
+  switch (mode) {
+#ifdef SPLASH_CMYK
+    case splashModeCMYK8:
+      if (writer->supportCMYK()) {
+        SplashColorPtr row;
+        unsigned char **row_pointers = new unsigned char*[height];
+        row = data;
+
+        for (int y = 0; y < height; ++y) {
+          row_pointers[y] = row;
+          row += rowSize;
+        }
+        if (!writer->writePointers(row_pointers, height)) {
+          delete[] row_pointers;
+          return splashErrGeneric;
+        }
+        delete[] row_pointers;
+      } else {
+        unsigned char *row = new unsigned char[3 * width];
+        for (int y = 0; y < height; y++) {
+          getRGBLine(y, row);
+          if (!writer->writeRow(&row)) {
+            delete[] row;
+            return splashErrGeneric;
+          }
+        }
+        delete[] row;
+      }
+    break;
+    case splashModeDeviceN8:
+      if (writer->supportCMYK()) {
+        unsigned char *row = new unsigned char[4 * width];
+        for (int y = 0; y < height; y++) {
+          getCMYKLine(y, row);
+          if (!writer->writeRow(&row)) {
+            delete[] row;
+            return splashErrGeneric;
+          }
+        }
+        delete[] row;
+      } else {
+        unsigned char *row = new unsigned char[3 * width];
+        for (int y = 0; y < height; y++) {
+          getRGBLine(y, row);
+          if (!writer->writeRow(&row)) {
+            delete[] row;
+            return splashErrGeneric;
+          }
+        }
+        delete[] row;
+      }
+    break;
+#endif
+    case splashModeRGB8:
+    {
+      SplashColorPtr row;
+      unsigned char **row_pointers = new unsigned char*[height];
+      row = data;
+
+      for (int y = 0; y < height; ++y) {
+        row_pointers[y] = row;
+        row += rowSize;
+      }
+      if (!writer->writePointers(row_pointers, height)) {
+        delete[] row_pointers;
+        return splashErrGeneric;
+      }
+      delete[] row_pointers;
+    }
+    break;
+    
+    case splashModeBGR8:
+    {
+      unsigned char *row = new unsigned char[3 * width];
+      for (int y = 0; y < height; y++) {
+        // Convert into a PNG row
+        for (int x = 0; x < width; x++) {
+          row[3*x] = data[y * rowSize + x * 3 + 2];
+          row[3*x+1] = data[y * rowSize + x * 3 + 1];
+          row[3*x+2] = data[y * rowSize + x * 3];
+        }
+
+        if (!writer->writeRow(&row)) {
+          delete[] row;
+          return splashErrGeneric;
+        }
+      }
+      delete[] row;
+    }
+    break;
+    
+    case splashModeXBGR8:
+    {
+      unsigned char *row = new unsigned char[3 * width];
+      for (int y = 0; y < height; y++) {
+        // Convert into a PNG row
+        for (int x = 0; x < width; x++) {
+          row[3*x] = data[y * rowSize + x * 4 + 2];
+          row[3*x+1] = data[y * rowSize + x * 4 + 1];
+          row[3*x+2] = data[y * rowSize + x * 4];
+        }
+
+        if (!writer->writeRow(&row)) {
+          delete[] row;
+          return splashErrGeneric;
+        }
+      }
+      delete[] row;
+    }
+    break;
+    
+    case splashModeMono8:
+    {
+      if (imageWriterFormat == splashModeMono8) {
+        SplashColorPtr row;
+        unsigned char **row_pointers = new unsigned char*[height];
+        row = data;
+
+        for (int y = 0; y < height; ++y) {
+          row_pointers[y] = row;
+          row += rowSize;
+        }
+        if (!writer->writePointers(row_pointers, height)) {
+          delete[] row_pointers;
+          return splashErrGeneric;
+        }
+        delete[] row_pointers;
+      } else if (imageWriterFormat == splashModeRGB8) {
+        unsigned char *row = new unsigned char[3 * width];
+        for (int y = 0; y < height; y++) {
+          // Convert into a PNG row
+          for (int x = 0; x < width; x++) {
+            row[3*x] = data[y * rowSize + x];
+            row[3*x+1] = data[y * rowSize + x];
+            row[3*x+2] = data[y * rowSize + x];
+          }
+
+          if (!writer->writeRow(&row)) {
+            delete[] row;
+            return splashErrGeneric;
+          }
+        }
+        delete[] row;
+      }
+      else {
+        // only splashModeMono8 or splashModeRGB8
+        return splashErrGeneric;
+      }
+    }
+    break;
+    
+    case splashModeMono1:
+    {
+      if (imageWriterFormat == splashModeMono1) {
+        SplashColorPtr row;
+        unsigned char **row_pointers = new unsigned char*[height];
+        row = data;
+
+        for (int y = 0; y < height; ++y) {
+          row_pointers[y] = row;
+          row += rowSize;
+        }
+        if (!writer->writePointers(row_pointers, height)) {
+          delete[] row_pointers;
+          return splashErrGeneric;
+        }
+        delete[] row_pointers;
+      } else if (imageWriterFormat == splashModeRGB8) {
+        unsigned char *row = new unsigned char[3 * width];
+        for (int y = 0; y < height; y++) {
+          // Convert into a PNG row
+          for (int x = 0; x < width; x++) {
+            getPixel(x, y, &row[3*x]);
+            row[3*x+1] = row[3*x];
+            row[3*x+2] = row[3*x];
+          }
+
+          if (!writer->writeRow(&row)) {
+            delete[] row;
+            return splashErrGeneric;
+          }
+        }
+        delete[] row;
+      }
+      else {
+        // only splashModeMono1 or splashModeRGB8
+        return splashErrGeneric;
+      }
+    }
+    break;
+    
+    default:
+    // can't happen
+    break;
+  }
+  
+  if (!writer->close()) {
+    return splashErrGeneric;
+  }
+
+  return splashOk;
+}
diff --git a/source/libs/poppler/poppler-src/splash/SplashBitmap.h b/source/libs/poppler/poppler-src/splash/SplashBitmap.h
new file mode 100644
index 0000000000000000000000000000000000000000..ccd3e7d955c3fd6f3342ac113fed5232cff1fadf
--- /dev/null
+++ b/source/libs/poppler/poppler-src/splash/SplashBitmap.h
@@ -0,0 +1,126 @@
+//========================================================================
+//
+// SplashBitmap.h
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2007 Ilmari Heikkinen <ilmari.heikkinen@gmail.com>
+// Copyright (C) 2009 Shen Liang <shenzhuxi@gmail.com>
+// Copyright (C) 2009, 2012 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2009 Stefan Thomas <thomas@eload24.com>
+// Copyright (C) 2010, 2017 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2010 Harry Roberts <harry.roberts@midnight-labs.org>
+// Copyright (C) 2010 Christian Feuers�nger <cfeuersaenger@googlemail.com>
+// Copyright (C) 2010 William Bader <williambader@hotmail.com>
+// Copyright (C) 2012 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2015 Adam Reichold <adamreichold@myopera.com>
+// Copyright (C) 2016 Kenji Uno <ku@digitaldolphins.jp>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef SPLASHBITMAP_H
+#define SPLASHBITMAP_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "SplashTypes.h"
+#include "poppler/GfxState.h"
+#include <stdio.h>
+
+class ImgWriter;
+
+//------------------------------------------------------------------------
+// SplashBitmap
+//------------------------------------------------------------------------
+
+class SplashBitmap {
+public:
+
+  // Create a new bitmap.  It will have <widthA> x <heightA> pixels in
+  // color mode <modeA>.  Rows will be padded out to a multiple of
+  // <rowPad> bytes.  If <topDown> is false, the bitmap will be stored
+  // upside-down, i.e., with the last row first in memory.
+  SplashBitmap(int widthA, int heightA, int rowPad,
+	       SplashColorMode modeA, GBool alphaA,
+	       GBool topDown = gTrue, GooList *separationList = NULL);
+  static SplashBitmap *copy(SplashBitmap *src);
+
+  ~SplashBitmap();
+
+  int getWidth() { return width; }
+  int getHeight() { return height; }
+  int getRowSize() { return rowSize; }
+  int getAlphaRowSize() { return width; }
+  int getRowPad() { return rowPad; }
+  SplashColorMode getMode() { return mode; }
+  SplashColorPtr getDataPtr() { return data; }
+  Guchar *getAlphaPtr() { return alpha; }
+  GooList *getSeparationList() { return separationList; }
+
+  SplashError writePNMFile(char *fileName);
+  SplashError writePNMFile(FILE *f);
+  SplashError writeAlphaPGMFile(char *fileName);
+
+  struct WriteImgParams
+  {
+    int jpegQuality = -1;
+    GBool jpegProgressive = gFalse;
+    GooString tiffCompression;
+  };
+
+  SplashError writeImgFile(SplashImageFileFormat format, char *fileName, int hDPI, int vDPI, WriteImgParams* params = nullptr);
+  SplashError writeImgFile(SplashImageFileFormat format, FILE *f, int hDPI, int vDPI, WriteImgParams* params = nullptr);
+  SplashError writeImgFile(ImgWriter *writer, FILE *f, int hDPI, int vDPI, SplashColorMode imageWriterFormat);
+
+  enum ConversionMode
+  {
+      conversionOpaque,
+      conversionAlpha,
+      conversionAlphaPremultiplied
+  };
+
+  GBool convertToXBGR(ConversionMode conversionMode = conversionOpaque);
+
+  void getPixel(int x, int y, SplashColorPtr pixel);
+  void getRGBLine(int y, SplashColorPtr line);
+  void getXBGRLine(int y, SplashColorPtr line, ConversionMode conversionMode = conversionOpaque);
+#ifdef SPLASH_CMYK
+  void getCMYKLine(int y, SplashColorPtr line);
+#endif
+  Guchar getAlpha(int x, int y);
+
+  // Caller takes ownership of the bitmap data.  The SplashBitmap
+  // object is no longer valid -- the next call should be to the
+  // destructor.
+  SplashColorPtr takeData();
+
+private:
+
+  int width, height;		// size of bitmap
+  int rowPad;
+  int rowSize;			// size of one row of data, in bytes
+				//   - negative for bottom-up bitmaps
+  SplashColorMode mode;		// color mode
+  SplashColorPtr data;		// pointer to row zero of the color data
+  Guchar *alpha;		// pointer to row zero of the alpha data
+				//   (always top-down)
+  GooList *separationList; // list of spot colorants and their mapping functions
+
+  friend class Splash;
+
+  void setJpegParams(ImgWriter *writer, WriteImgParams* params);
+};
+
+#endif
diff --git a/source/libs/poppler/poppler-src/splash/SplashClip.cc b/source/libs/poppler/poppler-src/splash/SplashClip.cc
new file mode 100644
index 0000000000000000000000000000000000000000..85c6b11473da8b8d1ec80f286253b2416cdfdd1b
--- /dev/null
+++ b/source/libs/poppler/poppler-src/splash/SplashClip.cc
@@ -0,0 +1,411 @@
+//========================================================================
+//
+// SplashClip.cc
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2010 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include "goo/gmem.h"
+#include "SplashErrorCodes.h"
+#include "SplashPath.h"
+#include "SplashXPath.h"
+#include "SplashXPathScanner.h"
+#include "SplashBitmap.h"
+#include "SplashClip.h"
+
+//------------------------------------------------------------------------
+// SplashClip.flags
+//------------------------------------------------------------------------
+
+#define splashClipEO       0x01	// use even-odd rule
+
+//------------------------------------------------------------------------
+// SplashClip
+//------------------------------------------------------------------------
+
+SplashClip::SplashClip(SplashCoord x0, SplashCoord y0,
+		       SplashCoord x1, SplashCoord y1,
+		       GBool antialiasA) {
+  antialias = antialiasA;
+  if (x0 < x1) {
+    xMin = x0;
+    xMax = x1;
+  } else {
+    xMin = x1;
+    xMax = x0;
+  }
+  if (y0 < y1) {
+    yMin = y0;
+    yMax = y1;
+  } else {
+    yMin = y1;
+    yMax = y0;
+  }
+  xMinI = splashFloor(xMin);
+  yMinI = splashFloor(yMin);
+  xMaxI = splashCeil(xMax) - 1;
+  yMaxI = splashCeil(yMax) - 1;
+  paths = NULL;
+  flags = NULL;
+  scanners = NULL;
+  length = size = 0;
+}
+
+SplashClip::SplashClip(SplashClip *clip) {
+  int yMinAA, yMaxAA;
+  int i;
+
+  antialias = clip->antialias;
+  xMin = clip->xMin;
+  yMin = clip->yMin;
+  xMax = clip->xMax;
+  yMax = clip->yMax;
+  xMinI = clip->xMinI;
+  yMinI = clip->yMinI;
+  xMaxI = clip->xMaxI;
+  yMaxI = clip->yMaxI;
+  length = clip->length;
+  size = clip->size;
+  paths = (SplashXPath **)gmallocn(size, sizeof(SplashXPath *));
+  flags = (Guchar *)gmallocn(size, sizeof(Guchar));
+  scanners = (SplashXPathScanner **)
+                 gmallocn(size, sizeof(SplashXPathScanner *));
+  for (i = 0; i < length; ++i) {
+    paths[i] = clip->paths[i]->copy();
+    flags[i] = clip->flags[i];
+    if (antialias) {
+      yMinAA = yMinI * splashAASize;
+      yMaxAA = (yMaxI + 1) * splashAASize - 1;
+    } else {
+      yMinAA = yMinI;
+      yMaxAA = yMaxI;
+    }
+    scanners[i] = new SplashXPathScanner(paths[i], flags[i] & splashClipEO,
+					 yMinAA, yMaxAA);
+  }
+}
+
+SplashClip::~SplashClip() {
+  int i;
+
+  for (i = 0; i < length; ++i) {
+    delete paths[i];
+    delete scanners[i];
+  }
+  gfree(paths);
+  gfree(flags);
+  gfree(scanners);
+}
+
+void SplashClip::grow(int nPaths) {
+  if (length + nPaths > size) {
+    if (size == 0) {
+      size = 32;
+    }
+    while (size < length + nPaths) {
+      size *= 2;
+    }
+    paths = (SplashXPath **)greallocn(paths, size, sizeof(SplashXPath *));
+    flags = (Guchar *)greallocn(flags, size, sizeof(Guchar));
+    scanners = (SplashXPathScanner **)
+                   greallocn(scanners, size, sizeof(SplashXPathScanner *));
+  }
+}
+
+void SplashClip::resetToRect(SplashCoord x0, SplashCoord y0,
+			     SplashCoord x1, SplashCoord y1) {
+  int i;
+
+  for (i = 0; i < length; ++i) {
+    delete paths[i];
+    delete scanners[i];
+  }
+  gfree(paths);
+  gfree(flags);
+  gfree(scanners);
+  paths = NULL;
+  flags = NULL;
+  scanners = NULL;
+  length = size = 0;
+
+  if (x0 < x1) {
+    xMin = x0;
+    xMax = x1;
+  } else {
+    xMin = x1;
+    xMax = x0;
+  }
+  if (y0 < y1) {
+    yMin = y0;
+    yMax = y1;
+  } else {
+    yMin = y1;
+    yMax = y0;
+  }
+  xMinI = splashFloor(xMin);
+  yMinI = splashFloor(yMin);
+  xMaxI = splashCeil(xMax) - 1;
+  yMaxI = splashCeil(yMax) - 1;
+}
+
+SplashError SplashClip::clipToRect(SplashCoord x0, SplashCoord y0,
+				   SplashCoord x1, SplashCoord y1) {
+  if (x0 < x1) {
+    if (x0 > xMin) {
+      xMin = x0;
+      xMinI = splashFloor(xMin);
+    }
+    if (x1 < xMax) {
+      xMax = x1;
+      xMaxI = splashCeil(xMax) - 1;
+    }
+  } else {
+    if (x1 > xMin) {
+      xMin = x1;
+      xMinI = splashFloor(xMin);
+    }
+    if (x0 < xMax) {
+      xMax = x0;
+      xMaxI = splashCeil(xMax) - 1;
+    }
+  }
+  if (y0 < y1) {
+    if (y0 > yMin) {
+      yMin = y0;
+      yMinI = splashFloor(yMin);
+    }
+    if (y1 < yMax) {
+      yMax = y1;
+      yMaxI = splashCeil(yMax) - 1;
+    }
+  } else {
+    if (y1 > yMin) {
+      yMin = y1;
+      yMinI = splashFloor(yMin);
+    }
+    if (y0 < yMax) {
+      yMax = y0;
+      yMaxI = splashCeil(yMax) - 1;
+    }
+  }
+  return splashOk;
+}
+
+SplashError SplashClip::clipToPath(SplashPath *path, SplashCoord *matrix,
+				   SplashCoord flatness, GBool eo) {
+  SplashXPath *xPath;
+  int yMinAA, yMaxAA;
+
+  xPath = new SplashXPath(path, matrix, flatness, gTrue);
+
+  // check for an empty path
+  if (xPath->length == 0) {
+    xMax = xMin - 1;
+    yMax = yMin - 1;
+    xMaxI = splashCeil(xMax) - 1;
+    yMaxI = splashCeil(yMax) - 1;
+    delete xPath;
+
+  // check for a rectangle
+  } else if (xPath->length == 4 &&
+	     ((xPath->segs[0].x0 == xPath->segs[0].x1 &&
+	       xPath->segs[0].x0 == xPath->segs[1].x0 &&
+	       xPath->segs[0].x0 == xPath->segs[3].x1 &&
+	       xPath->segs[2].x0 == xPath->segs[2].x1 &&
+	       xPath->segs[2].x0 == xPath->segs[1].x1 &&
+	       xPath->segs[2].x0 == xPath->segs[3].x0 &&
+	       xPath->segs[1].y0 == xPath->segs[1].y1 &&
+	       xPath->segs[1].y0 == xPath->segs[0].y1 &&
+	       xPath->segs[1].y0 == xPath->segs[2].y0 &&
+	       xPath->segs[3].y0 == xPath->segs[3].y1 &&
+	       xPath->segs[3].y0 == xPath->segs[0].y0 &&
+	       xPath->segs[3].y0 == xPath->segs[2].y1) ||
+	      (xPath->segs[0].y0 == xPath->segs[0].y1 &&
+	       xPath->segs[0].y0 == xPath->segs[1].y0 &&
+	       xPath->segs[0].y0 == xPath->segs[3].y1 &&
+	       xPath->segs[2].y0 == xPath->segs[2].y1 &&
+	       xPath->segs[2].y0 == xPath->segs[1].y1 &&
+	       xPath->segs[2].y0 == xPath->segs[3].y0 &&
+	       xPath->segs[1].x0 == xPath->segs[1].x1 &&
+	       xPath->segs[1].x0 == xPath->segs[0].x1 &&
+	       xPath->segs[1].x0 == xPath->segs[2].x0 &&
+	       xPath->segs[3].x0 == xPath->segs[3].x1 &&
+	       xPath->segs[3].x0 == xPath->segs[0].x0 &&
+	       xPath->segs[3].x0 == xPath->segs[2].x1))) {
+    clipToRect(xPath->segs[0].x0, xPath->segs[0].y0,
+	       xPath->segs[2].x0, xPath->segs[2].y0);
+    delete xPath;
+
+  } else {
+    grow(1);
+    if (antialias) {
+      xPath->aaScale();
+    }
+    xPath->sort();
+    paths[length] = xPath;
+    flags[length] = eo ? splashClipEO : 0;
+    if (antialias) {
+      yMinAA = yMinI * splashAASize;
+      yMaxAA = (yMaxI + 1) * splashAASize - 1;
+    } else {
+      yMinAA = yMinI;
+      yMaxAA = yMaxI;
+    }
+    scanners[length] = new SplashXPathScanner(xPath, eo, yMinAA, yMaxAA);
+    ++length;
+  }
+
+  return splashOk;
+}
+
+SplashClipResult SplashClip::testRect(int rectXMin, int rectYMin,
+				      int rectXMax, int rectYMax) {
+  // This tests the rectangle:
+  //     x = [rectXMin, rectXMax + 1)    (note: rect coords are ints)
+  //     y = [rectYMin, rectYMax + 1)
+  // against the clipping region:
+  //     x = [xMin, xMax)                (note: clipping coords are fp)
+  //     y = [yMin, yMax)
+  if ((SplashCoord)(rectXMax + 1) <= xMin || (SplashCoord)rectXMin >= xMax ||
+      (SplashCoord)(rectYMax + 1) <= yMin || (SplashCoord)rectYMin >= yMax) {
+    return splashClipAllOutside;
+  }
+  if ((SplashCoord)rectXMin >= xMin && (SplashCoord)(rectXMax + 1) <= xMax &&
+      (SplashCoord)rectYMin >= yMin && (SplashCoord)(rectYMax + 1) <= yMax &&
+      length == 0) {
+    return splashClipAllInside;
+  }
+  return splashClipPartial;
+}
+
+SplashClipResult SplashClip::testSpan(int spanXMin, int spanXMax, int spanY) {
+  int i;
+
+  // This tests the rectangle:
+  //     x = [spanXMin, spanXMax + 1)    (note: span coords are ints)
+  //     y = [spanY, spanY + 1)
+  // against the clipping region:
+  //     x = [xMin, xMax)                (note: clipping coords are fp)
+  //     y = [yMin, yMax)
+  if ((SplashCoord)(spanXMax + 1) <= xMin || (SplashCoord)spanXMin >= xMax ||
+      (SplashCoord)(spanY + 1) <= yMin || (SplashCoord)spanY >= yMax) {
+    return splashClipAllOutside;
+  }
+  if (!((SplashCoord)spanXMin >= xMin && (SplashCoord)(spanXMax + 1) <= xMax &&
+	(SplashCoord)spanY >= yMin && (SplashCoord)(spanY + 1) <= yMax)) {
+    return splashClipPartial;
+  }
+  if (antialias) {
+    for (i = 0; i < length; ++i) {
+      if (!scanners[i]->testSpan(spanXMin * splashAASize,
+				 spanXMax * splashAASize + (splashAASize - 1),
+				 spanY * splashAASize)) {
+	return splashClipPartial;
+      }
+    }
+  } else {
+    for (i = 0; i < length; ++i) {
+      if (!scanners[i]->testSpan(spanXMin, spanXMax, spanY)) {
+	return splashClipPartial;
+      }
+    }
+  }
+  return splashClipAllInside;
+}
+
+void SplashClip::clipAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y, GBool adjustVertLine) {
+  int xx0, xx1, xx, yy, i;
+  SplashColorPtr p;
+
+  // zero out pixels with x < xMin
+  xx0 = *x0 * splashAASize;
+  xx1 = splashFloor(xMin * splashAASize);
+  if (xx1 > aaBuf->getWidth()) {
+    xx1 = aaBuf->getWidth();
+  }
+  if (xx0 < xx1) {
+    xx0 &= ~7;
+    for (yy = 0; yy < splashAASize; ++yy) {
+      p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx0 >> 3);
+      for (xx = xx0; xx + 7 < xx1; xx += 8) {
+	*p++ = 0;
+      }
+      if (xx < xx1 && !adjustVertLine) {
+	*p &= 0xff >> (xx1 & 7);
+      }
+    }
+    *x0 = splashFloor(xMin);
+  }
+
+  // zero out pixels with x > xMax
+  xx0 = splashFloor(xMax * splashAASize) + 1;
+  if (xx0 < 0) {
+    xx0 = 0;
+  }
+  xx1 = (*x1 + 1) * splashAASize;
+  if (xx0 < xx1 && !adjustVertLine) {
+    for (yy = 0; yy < splashAASize; ++yy) {
+      p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx0 >> 3);
+      xx = xx0;
+      if (xx & 7) {
+	*p &= 0xff00 >> (xx & 7);
+	xx = (xx & ~7) + 8;
+	++p;
+      }
+      for (; xx < xx1; xx += 8) {
+	*p++ = 0;
+      }
+    }
+    *x1 = splashFloor(xMax);
+  }
+
+  // check the paths
+  for (i = 0; i < length; ++i) {
+    scanners[i]->clipAALine(aaBuf, x0, x1, y);
+  }
+  if (*x0 > *x1) {
+    *x0 = *x1;
+  }
+  if (*x0 < 0) {
+    *x0 = 0;
+  }
+  if ((*x0>>1) >= aaBuf->getRowSize()) {
+    xx0 = *x0;
+    *x0 = (aaBuf->getRowSize() - 1) << 1;
+    if (xx0 & 1) {
+      *x0 = *x0 + 1;
+    }
+  }
+  if (*x1 < *x0) {
+    *x1 = *x0;
+  }
+  if ((*x1>>1) >= aaBuf->getRowSize()) {
+    xx0 = *x1;
+    *x1 = (aaBuf->getRowSize() - 1) << 1;
+    if (xx0 & 1) {
+      *x1 = *x1 + 1;
+    }
+  }
+}
diff --git a/source/libs/poppler/poppler-src/splash/SplashClip.h b/source/libs/poppler/poppler-src/splash/SplashClip.h
new file mode 100644
index 0000000000000000000000000000000000000000..5c0fdba99a7de36fc51fcd34407f2d453e7fb143
--- /dev/null
+++ b/source/libs/poppler/poppler-src/splash/SplashClip.h
@@ -0,0 +1,152 @@
+//========================================================================
+//
+// SplashClip.h
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2010 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef SPLASHCLIP_H
+#define SPLASHCLIP_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "SplashTypes.h"
+#include "SplashMath.h"
+#include "SplashXPathScanner.h"
+
+class SplashPath;
+class SplashXPath;
+class SplashBitmap;
+
+//------------------------------------------------------------------------
+
+enum SplashClipResult {
+  splashClipAllInside,
+  splashClipAllOutside,
+  splashClipPartial
+};
+
+//------------------------------------------------------------------------
+// SplashClip
+//------------------------------------------------------------------------
+
+class SplashClip {
+public:
+
+  // Create a clip, for the given rectangle.
+  SplashClip(SplashCoord x0, SplashCoord y0,
+	     SplashCoord x1, SplashCoord y1,
+	     GBool antialiasA);
+
+  // Copy a clip.
+  SplashClip *copy() { return new SplashClip(this); }
+
+  ~SplashClip();
+
+  // Reset the clip to a rectangle.
+  void resetToRect(SplashCoord x0, SplashCoord y0,
+		   SplashCoord x1, SplashCoord y1);
+
+  // Intersect the clip with a rectangle.
+  SplashError clipToRect(SplashCoord x0, SplashCoord y0,
+			 SplashCoord x1, SplashCoord y1);
+
+  // Interesect the clip with <path>.
+  SplashError clipToPath(SplashPath *path, SplashCoord *matrix,
+			 SplashCoord flatness, GBool eo);
+
+  // Returns true if (<x>,<y>) is inside the clip.
+  GBool test(int x, int y)
+  {
+    int i;
+
+    // check the rectangle
+    if (x < xMinI || x > xMaxI || y < yMinI || y > yMaxI) {
+      return gFalse;
+    }
+
+    // check the paths
+    if (antialias) {
+      for (i = 0; i < length; ++i) {
+        if (!scanners[i]->test(x * splashAASize, y * splashAASize)) {
+	  return gFalse;
+        }
+      }
+    } else {
+      for (i = 0; i < length; ++i) {
+        if (!scanners[i]->test(x, y)) {
+	  return gFalse;
+        }
+      }
+    }
+
+    return gTrue;
+  }
+
+  // Tests a rectangle against the clipping region.  Returns one of:
+  //   - splashClipAllInside if the entire rectangle is inside the
+  //     clipping region, i.e., all pixels in the rectangle are
+  //     visible
+  //   - splashClipAllOutside if the entire rectangle is outside the
+  //     clipping region, i.e., all the pixels in the rectangle are
+  //     clipped
+  //   - splashClipPartial if the rectangle is part inside and part
+  //     outside the clipping region
+  SplashClipResult testRect(int rectXMin, int rectYMin,
+			    int rectXMax, int rectYMax);
+
+  // Similar to testRect, but tests a horizontal span.
+  SplashClipResult testSpan(int spanXMin, int spanXMax, int spanY);
+
+  // Clips an anti-aliased line by setting pixels to zero.  On entry,
+  // all non-zero pixels are between <x0> and <x1>.  This function
+  // will update <x0> and <x1>.
+  void clipAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y,
+    GBool adjustVertLine = gFalse);
+
+  // Get the rectangle part of the clip region.
+  SplashCoord getXMin() { return xMin; }
+  SplashCoord getXMax() { return xMax; }
+  SplashCoord getYMin() { return yMin; }
+  SplashCoord getYMax() { return yMax; }
+
+  // Get the rectangle part of the clip region, in integer coordinates.
+  int getXMinI() { return xMinI; }
+  int getXMaxI() { return xMaxI; }
+  int getYMinI() { return yMinI; }
+  int getYMaxI() { return yMaxI; }
+
+  // Get the number of arbitrary paths used by the clip region.
+  int getNumPaths() { return length; }
+
+protected:
+
+  SplashClip(SplashClip *clip);
+  void grow(int nPaths);
+
+  GBool antialias;
+  SplashCoord xMin, yMin, xMax, yMax;
+  int xMinI, yMinI, xMaxI, yMaxI;
+  SplashXPath **paths;
+  Guchar *flags;
+  SplashXPathScanner **scanners;
+  int length, size;
+};
+
+#endif
diff --git a/source/libs/poppler/poppler-src/splash/SplashErrorCodes.h b/source/libs/poppler/poppler-src/splash/SplashErrorCodes.h
new file mode 100644
index 0000000000000000000000000000000000000000..d1f81f85dd878c4a4c945e8a87b52d379091eff6
--- /dev/null
+++ b/source/libs/poppler/poppler-src/splash/SplashErrorCodes.h
@@ -0,0 +1,50 @@
+//========================================================================
+//
+// SplashErrorCodes.h
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2006, 2009 Albert Astals Cid <aacid@kde.org>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef SPLASHERRORCODES_H
+#define SPLASHERRORCODES_H
+
+//------------------------------------------------------------------------
+
+#define splashOk                 0	// no error
+
+#define splashErrNoCurPt         1	// no current point
+
+#define splashErrEmptyPath       2	// zero points in path
+
+#define splashErrBogusPath       3	// only one point in subpath
+
+#define splashErrNoSave	         4	// state stack is empty
+
+#define splashErrOpenFile        5	// couldn't open file
+
+#define splashErrNoGlyph         6	// couldn't get the requested glyph
+
+#define splashErrModeMismatch    7	// invalid combination of color modes
+
+#define splashErrSingularMatrix  8	// matrix is singular
+
+#define splashErrBadArg          9      // bad argument
+
+#define splashErrZeroImage     254      // image of 0x0
+
+#define splashErrGeneric       255
+
+#endif
diff --git a/source/libs/poppler/poppler-src/splash/SplashFTFont.cc b/source/libs/poppler/poppler-src/splash/SplashFTFont.cc
new file mode 100644
index 0000000000000000000000000000000000000000..91226da0421592bf23fbfed3d2412a2c64058b71
--- /dev/null
+++ b/source/libs/poppler/poppler-src/splash/SplashFTFont.cc
@@ -0,0 +1,510 @@
+//========================================================================
+//
+// SplashFTFont.cc
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2005, 2007-2011, 2014 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2006 Kristian Høgsberg <krh@bitplanet.net>
+// Copyright (C) 2009 Petr Gajdos <pgajdos@novell.com>
+// Copyright (C) 2010 Suzuki Toshiya <mpsuzuki@hiroshima-u.ac.jp>
+// Copyright (C) 2011 Andreas Hartmetz <ahartmetz@gmail.com>
+// Copyright (C) 2012 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2017 Adrian Johnson <ajohnson@redneon.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <ft2build.h>
+#include FT_OUTLINE_H
+#include FT_SIZES_H
+#include FT_GLYPH_H
+#include "goo/gmem.h"
+#include "SplashMath.h"
+#include "SplashGlyphBitmap.h"
+#include "SplashPath.h"
+#include "SplashFTFontEngine.h"
+#include "SplashFTFontFile.h"
+#include "SplashFTFont.h"
+
+//------------------------------------------------------------------------
+
+static int glyphPathMoveTo(const FT_Vector *pt, void *path);
+static int glyphPathLineTo(const FT_Vector *pt, void *path);
+static int glyphPathConicTo(const FT_Vector *ctrl, const FT_Vector *pt,
+			    void *path);
+static int glyphPathCubicTo(const FT_Vector *ctrl1, const FT_Vector *ctrl2,
+			    const FT_Vector *pt, void *path);
+
+//------------------------------------------------------------------------
+// SplashFTFont
+//------------------------------------------------------------------------
+
+SplashFTFont::SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA,
+			   SplashCoord *textMatA):
+  SplashFont(fontFileA, matA, textMatA, fontFileA->engine->aa), 
+  enableFreeTypeHinting(fontFileA->engine->enableFreeTypeHinting),
+  enableSlightHinting(fontFileA->engine->enableSlightHinting)
+{
+  FT_Face face;
+  int div;
+  int x, y;
+#ifdef USE_FIXEDPOINT
+  SplashCoord scale;
+#endif
+
+  face = fontFileA->face;
+  if (FT_New_Size(face, &sizeObj)) {
+    return;
+  }
+  face->size = sizeObj;
+  size = splashRound(splashDist(0, 0, mat[2], mat[3]));
+  if (size < 1) {
+    size = 1;
+  }
+  if (FT_Set_Pixel_Sizes(face, 0, size)) {
+    return;
+  }
+  // if the textMat values are too small, FreeType's fixed point
+  // arithmetic doesn't work so well
+  textScale = splashDist(0, 0, textMat[2], textMat[3]) / size;
+
+  div = face->bbox.xMax > 20000 ? 65536 : 1;
+
+#ifdef USE_FIXEDPOINT
+  scale = (SplashCoord)1 / (SplashCoord)face->units_per_EM;
+
+  // transform the four corners of the font bounding box -- the min
+  // and max values form the bounding box of the transformed font
+  x = (int)(mat[0] * (scale * (face->bbox.xMin / div)) +
+	    mat[2] * (scale * (face->bbox.yMin / div)));
+  xMin = xMax = x;
+  y = (int)(mat[1] * (scale * (face->bbox.xMin / div)) +
+	    mat[3] * (scale * (face->bbox.yMin / div)));
+  yMin = yMax = y;
+  x = (int)(mat[0] * (scale * (face->bbox.xMin / div)) +
+	    mat[2] * (scale * (face->bbox.yMax / div)));
+  if (x < xMin) {
+    xMin = x;
+  } else if (x > xMax) {
+    xMax = x;
+  }
+  y = (int)(mat[1] * (scale * (face->bbox.xMin / div)) +
+	    mat[3] * (scale * (face->bbox.yMax / div)));
+  if (y < yMin) {
+    yMin = y;
+  } else if (y > yMax) {
+    yMax = y;
+  }
+  x = (int)(mat[0] * (scale * (face->bbox.xMax / div)) +
+	    mat[2] * (scale * (face->bbox.yMin / div)));
+  if (x < xMin) {
+    xMin = x;
+  } else if (x > xMax) {
+    xMax = x;
+  }
+  y = (int)(mat[1] * (scale * (face->bbox.xMax / div)) +
+	    mat[3] * (scale * (face->bbox.yMin / div)));
+  if (y < yMin) {
+    yMin = y;
+  } else if (y > yMax) {
+    yMax = y;
+  }
+  x = (int)(mat[0] * (scale * (face->bbox.xMax / div)) +
+	    mat[2] * (scale * (face->bbox.yMax / div)));
+  if (x < xMin) {
+    xMin = x;
+  } else if (x > xMax) {
+    xMax = x;
+  }
+  y = (int)(mat[1] * (scale * (face->bbox.xMax / div)) +
+	    mat[3] * (scale * (face->bbox.yMax / div)));
+  if (y < yMin) {
+    yMin = y;
+  } else if (y > yMax) {
+    yMax = y;
+  }
+#else // USE_FIXEDPOINT
+  // transform the four corners of the font bounding box -- the min
+  // and max values form the bounding box of the transformed font
+  x = (int)((mat[0] * face->bbox.xMin + mat[2] * face->bbox.yMin) /
+	    (div * face->units_per_EM));
+  xMin = xMax = x;
+  y = (int)((mat[1] * face->bbox.xMin + mat[3] * face->bbox.yMin) /
+	    (div * face->units_per_EM));
+  yMin = yMax = y;
+  x = (int)((mat[0] * face->bbox.xMin + mat[2] * face->bbox.yMax) /
+	    (div * face->units_per_EM));
+  if (x < xMin) {
+    xMin = x;
+  } else if (x > xMax) {
+    xMax = x;
+  }
+  y = (int)((mat[1] * face->bbox.xMin + mat[3] * face->bbox.yMax) /
+	    (div * face->units_per_EM));
+  if (y < yMin) {
+    yMin = y;
+  } else if (y > yMax) {
+    yMax = y;
+  }
+  x = (int)((mat[0] * face->bbox.xMax + mat[2] * face->bbox.yMin) /
+	    (div * face->units_per_EM));
+  if (x < xMin) {
+    xMin = x;
+  } else if (x > xMax) {
+    xMax = x;
+  }
+  y = (int)((mat[1] * face->bbox.xMax + mat[3] * face->bbox.yMin) /
+	    (div * face->units_per_EM));
+  if (y < yMin) {
+    yMin = y;
+  } else if (y > yMax) {
+    yMax = y;
+  }
+  x = (int)((mat[0] * face->bbox.xMax + mat[2] * face->bbox.yMax) /
+	    (div * face->units_per_EM));
+  if (x < xMin) {
+    xMin = x;
+  } else if (x > xMax) {
+    xMax = x;
+  }
+  y = (int)((mat[1] * face->bbox.xMax + mat[3] * face->bbox.yMax) /
+	    (div * face->units_per_EM));
+  if (y < yMin) {
+    yMin = y;
+  } else if (y > yMax) {
+    yMax = y;
+  }
+#endif // USE_FIXEDPOINT
+  // This is a kludge: some buggy PDF generators embed fonts with
+  // zero bounding boxes.
+  if (xMax == xMin) {
+    xMin = 0;
+    xMax = size;
+  }
+  if (yMax == yMin) {
+    yMin = 0;
+    yMax = (int)((SplashCoord)1.2 * size);
+  }
+
+  // compute the transform matrix
+#ifdef USE_FIXEDPOINT
+  matrix.xx = (FT_Fixed)((mat[0] / size).get16Dot16());
+  matrix.yx = (FT_Fixed)((mat[1] / size).get16Dot16());
+  matrix.xy = (FT_Fixed)((mat[2] / size).get16Dot16());
+  matrix.yy = (FT_Fixed)((mat[3] / size).get16Dot16());
+  textMatrix.xx = (FT_Fixed)((textMat[0] / (textScale * size)).get16Dot16());
+  textMatrix.yx = (FT_Fixed)((textMat[1] / (textScale * size)).get16Dot16());
+  textMatrix.xy = (FT_Fixed)((textMat[2] / (textScale * size)).get16Dot16());
+  textMatrix.yy = (FT_Fixed)((textMat[3] / (textScale * size)).get16Dot16());
+#else
+  matrix.xx = (FT_Fixed)((mat[0] / size) * 65536);
+  matrix.yx = (FT_Fixed)((mat[1] / size) * 65536);
+  matrix.xy = (FT_Fixed)((mat[2] / size) * 65536);
+  matrix.yy = (FT_Fixed)((mat[3] / size) * 65536);
+  textMatrix.xx = (FT_Fixed)((textMat[0] / (textScale * size)) * 65536);
+  textMatrix.yx = (FT_Fixed)((textMat[1] / (textScale * size)) * 65536);
+  textMatrix.xy = (FT_Fixed)((textMat[2] / (textScale * size)) * 65536);
+  textMatrix.yy = (FT_Fixed)((textMat[3] / (textScale * size)) * 65536);
+#endif
+}
+
+SplashFTFont::~SplashFTFont() {
+}
+
+GBool SplashFTFont::getGlyph(int c, int xFrac, int yFrac,
+			     SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) {
+  return SplashFont::getGlyph(c, xFrac, 0, bitmap, x0, y0, clip, clipRes);
+}
+
+static FT_Int32 getFTLoadFlags(GBool type1, GBool trueType, GBool aa, GBool enableFreeTypeHinting, GBool enableSlightHinting)
+{
+  int ret = FT_LOAD_DEFAULT;
+  if (aa)
+    ret |= FT_LOAD_NO_BITMAP;
+  
+  if (enableFreeTypeHinting) {
+    if (enableSlightHinting) {
+      ret |= FT_LOAD_TARGET_LIGHT;
+    } else {
+      if (trueType) {
+	// FT2's autohinting doesn't always work very well (especially with
+	// font subsets), so turn it off if anti-aliasing is enabled; if
+	// anti-aliasing is disabled, this seems to be a tossup - some fonts
+	// look better with hinting, some without, so leave hinting on
+	if (aa) {
+	  ret |= FT_LOAD_NO_AUTOHINT;
+	}
+      } else if (type1) {
+	// Type 1 fonts seem to look better with 'light' hinting mode
+	ret |= FT_LOAD_TARGET_LIGHT;
+      }
+    }
+  } else {
+    ret |= FT_LOAD_NO_HINTING;
+  }
+  return ret;
+}
+
+GBool SplashFTFont::makeGlyph(int c, int xFrac, int yFrac,
+			      SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) {
+  SplashFTFontFile *ff;
+  FT_Vector offset;
+  FT_GlyphSlot slot;
+  FT_UInt gid;
+  int rowSize;
+  Guchar *p, *q;
+  int i;
+
+  ff = (SplashFTFontFile *)fontFile;
+
+  ff->face->size = sizeObj;
+  offset.x = (FT_Pos)(int)((SplashCoord)xFrac * splashFontFractionMul * 64);
+  offset.y = 0;
+  FT_Set_Transform(ff->face, &matrix, &offset);
+  slot = ff->face->glyph;
+
+  if (ff->codeToGID && c < ff->codeToGIDLen && c >= 0) {
+    gid = (FT_UInt)ff->codeToGID[c];
+  } else {
+    gid = (FT_UInt)c;
+  }
+
+  if (FT_Load_Glyph(ff->face, gid, getFTLoadFlags(ff->type1, ff->trueType, aa, enableFreeTypeHinting, enableSlightHinting))) {
+    return gFalse;
+  }
+
+  // prelimirary values based on FT_Outline_Get_CBox
+  // we add two pixels to each side to be in the safe side
+  FT_BBox cbox;
+  FT_Outline_Get_CBox(&ff->face->glyph->outline, &cbox);
+  bitmap->x = -(cbox.xMin / 64) + 2;
+  bitmap->y =  (cbox.yMax / 64) + 2;
+  bitmap->w = ((cbox.xMax - cbox.xMin) / 64) + 4;
+  bitmap->h = ((cbox.yMax - cbox.yMin) / 64) + 4;
+
+  *clipRes = clip->testRect(x0 - bitmap->x,
+                            y0 - bitmap->y,
+                            x0 - bitmap->x + bitmap->w,
+                            y0 - bitmap->y + bitmap->h);
+  if (*clipRes == splashClipAllOutside) {
+    bitmap->freeData = gFalse;
+    return gTrue;
+  }
+
+  if (FT_Render_Glyph(slot, aa ? ft_render_mode_normal
+		               : ft_render_mode_mono)) {
+    return gFalse;
+  }
+
+  if (slot->bitmap.width == 0 || slot->bitmap.rows == 0) {
+    // this can happen if (a) the glyph is really tiny or (b) the
+    // metrics in the TrueType file are broken
+    return gFalse;
+  }
+
+  bitmap->x = -slot->bitmap_left;
+  bitmap->y = slot->bitmap_top;
+  bitmap->w = slot->bitmap.width;
+  bitmap->h = slot->bitmap.rows;
+  bitmap->aa = aa;
+  if (aa) {
+    rowSize = bitmap->w;
+  } else {
+    rowSize = (bitmap->w + 7) >> 3;
+  }
+  bitmap->data = (Guchar *)gmallocn_checkoverflow(rowSize, bitmap->h);
+  if (!bitmap->data) {
+    return gFalse;
+  }
+  bitmap->freeData = gTrue;
+  for (i = 0, p = bitmap->data, q = slot->bitmap.buffer;
+       i < bitmap->h;
+       ++i, p += rowSize, q += slot->bitmap.pitch) {
+    memcpy(p, q, rowSize);
+  }
+
+  return gTrue;
+}
+
+double SplashFTFont::getGlyphAdvance(int c)
+{
+  SplashFTFontFile *ff;
+  FT_Vector offset;
+  FT_UInt gid;
+  FT_Matrix identityMatrix;
+
+  ff = (SplashFTFontFile *)fontFile;
+
+  // init the matrix
+  identityMatrix.xx = 65536; // 1 in 16.16 format
+  identityMatrix.xy = 0;
+  identityMatrix.yx = 0;
+  identityMatrix.yy = 65536; // 1 in 16.16 format
+
+  // init the offset
+  offset.x = 0;
+  offset.y = 0;
+
+  ff->face->size = sizeObj;
+  FT_Set_Transform(ff->face, &identityMatrix, &offset);
+
+  if (ff->codeToGID && c < ff->codeToGIDLen) {
+    gid = (FT_UInt)ff->codeToGID[c];
+  } else {
+    gid = (FT_UInt)c;
+  }
+
+  if (FT_Load_Glyph(ff->face, gid, getFTLoadFlags(ff->type1, ff->trueType, aa, enableFreeTypeHinting, enableSlightHinting))) {
+    return -1;
+  }
+
+  // 64.0 is 1 in 26.6 format
+  return ff->face->glyph->metrics.horiAdvance / 64.0 / size;
+}
+
+struct SplashFTFontPath {
+  SplashPath *path;
+  SplashCoord textScale;
+  GBool needClose;
+};
+
+SplashPath *SplashFTFont::getGlyphPath(int c) {
+  static FT_Outline_Funcs outlineFuncs = {
+#if FREETYPE_MINOR <= 1
+    (int (*)(FT_Vector *, void *))&glyphPathMoveTo,
+    (int (*)(FT_Vector *, void *))&glyphPathLineTo,
+    (int (*)(FT_Vector *, FT_Vector *, void *))&glyphPathConicTo,
+    (int (*)(FT_Vector *, FT_Vector *, FT_Vector *, void *))&glyphPathCubicTo,
+#else
+    &glyphPathMoveTo,
+    &glyphPathLineTo,
+    &glyphPathConicTo,
+    &glyphPathCubicTo,
+#endif
+    0, 0
+  };
+  SplashFTFontFile *ff;
+  SplashFTFontPath path;
+  FT_GlyphSlot slot;
+  FT_UInt gid;
+  FT_Glyph glyph;
+
+  ff = (SplashFTFontFile *)fontFile;
+  ff->face->size = sizeObj;
+  FT_Set_Transform(ff->face, &textMatrix, NULL);
+  slot = ff->face->glyph;
+  if (ff->codeToGID && c < ff->codeToGIDLen && c >= 0) {
+    gid = ff->codeToGID[c];
+  } else {
+    gid = (FT_UInt)c;
+  }
+  if (FT_Load_Glyph(ff->face, gid, getFTLoadFlags(ff->type1, ff->trueType, aa, enableFreeTypeHinting, enableSlightHinting))) {
+    return NULL;
+  }
+  if (FT_Get_Glyph(slot, &glyph)) {
+    return NULL;
+  }
+  if (FT_Outline_Check(&((FT_OutlineGlyph)glyph)->outline)) {
+    return NULL;
+  }
+  path.path = new SplashPath();
+  path.textScale = textScale;
+  path.needClose = gFalse;
+  FT_Outline_Decompose(&((FT_OutlineGlyph)glyph)->outline,
+		       &outlineFuncs, &path);
+  if (path.needClose) {
+    path.path->close();
+  }
+  FT_Done_Glyph(glyph);
+  return path.path;
+}
+
+static int glyphPathMoveTo(const FT_Vector *pt, void *path) {
+  SplashFTFontPath *p = (SplashFTFontPath *)path;
+
+  if (p->needClose) {
+    p->path->close();
+    p->needClose = gFalse;
+  }
+  p->path->moveTo((SplashCoord)pt->x * p->textScale / 64.0,
+		  (SplashCoord)pt->y * p->textScale / 64.0);
+  return 0;
+}
+
+static int glyphPathLineTo(const FT_Vector *pt, void *path) {
+  SplashFTFontPath *p = (SplashFTFontPath *)path;
+
+  p->path->lineTo((SplashCoord)pt->x * p->textScale / 64.0,
+		  (SplashCoord)pt->y * p->textScale / 64.0);
+  p->needClose = gTrue;
+  return 0;
+}
+
+static int glyphPathConicTo(const FT_Vector *ctrl, const FT_Vector *pt,
+			    void *path) {
+  SplashFTFontPath *p = (SplashFTFontPath *)path;
+  SplashCoord x0, y0, x1, y1, x2, y2, x3, y3, xc, yc;
+
+  if (!p->path->getCurPt(&x0, &y0)) {
+    return 0;
+  }
+  xc = (SplashCoord)ctrl->x * p->textScale / 64.0;
+  yc = (SplashCoord)ctrl->y * p->textScale / 64.0;
+  x3 = (SplashCoord)pt->x * p->textScale / 64.0;
+  y3 = (SplashCoord)pt->y * p->textScale / 64.0;
+
+  // A second-order Bezier curve is defined by two endpoints, p0 and
+  // p3, and one control point, pc:
+  //
+  //     p(t) = (1-t)^2*p0 + t*(1-t)*pc + t^2*p3
+  //
+  // A third-order Bezier curve is defined by the same two endpoints,
+  // p0 and p3, and two control points, p1 and p2:
+  //
+  //     p(t) = (1-t)^3*p0 + 3t*(1-t)^2*p1 + 3t^2*(1-t)*p2 + t^3*p3
+  //
+  // Applying some algebra, we can convert a second-order curve to a
+  // third-order curve:
+  //
+  //     p1 = (1/3) * (p0 + 2pc)
+  //     p2 = (1/3) * (2pc + p3)
+
+  x1 = (SplashCoord)(1.0 / 3.0) * (x0 + (SplashCoord)2 * xc);
+  y1 = (SplashCoord)(1.0 / 3.0) * (y0 + (SplashCoord)2 * yc);
+  x2 = (SplashCoord)(1.0 / 3.0) * ((SplashCoord)2 * xc + x3);
+  y2 = (SplashCoord)(1.0 / 3.0) * ((SplashCoord)2 * yc + y3);
+
+  p->path->curveTo(x1, y1, x2, y2, x3, y3);
+  p->needClose = gTrue;
+  return 0;
+}
+
+static int glyphPathCubicTo(const FT_Vector *ctrl1, const FT_Vector *ctrl2,
+			    const FT_Vector *pt, void *path) {
+  SplashFTFontPath *p = (SplashFTFontPath *)path;
+
+  p->path->curveTo((SplashCoord)ctrl1->x * p->textScale / 64.0,
+		   (SplashCoord)ctrl1->y * p->textScale / 64.0,
+		   (SplashCoord)ctrl2->x * p->textScale / 64.0,
+		   (SplashCoord)ctrl2->y * p->textScale / 64.0,
+		   (SplashCoord)pt->x * p->textScale / 64.0,
+		   (SplashCoord)pt->y * p->textScale / 64.0);
+  p->needClose = gTrue;
+  return 0;
+}
diff --git a/source/libs/poppler/poppler-src/splash/SplashFTFont.h b/source/libs/poppler/poppler-src/splash/SplashFTFont.h
new file mode 100644
index 0000000000000000000000000000000000000000..5f0d197669b47fd9e53d44534c3329f5c1e7731c
--- /dev/null
+++ b/source/libs/poppler/poppler-src/splash/SplashFTFont.h
@@ -0,0 +1,77 @@
+//========================================================================
+//
+// SplashFTFont.h
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2007-2009, 2011 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2009 Petr Gajdos <pgajdos@novell.com>
+// Copyright (C) 2011 Andreas Hartmetz <ahartmetz@gmail.com>
+// Copyright (C) 2017 Adrian Johnson <ajohnson@redneon.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef SPLASHFTFONT_H
+#define SPLASHFTFONT_H
+
+#include "poppler-config.h"
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include "SplashFont.h"
+
+class SplashFTFontFile;
+
+//------------------------------------------------------------------------
+// SplashFTFont
+//------------------------------------------------------------------------
+
+class SplashFTFont: public SplashFont {
+public:
+
+  SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA,
+	       SplashCoord *textMatA);
+
+  virtual ~SplashFTFont();
+
+  // Munge xFrac and yFrac before calling SplashFont::getGlyph.
+  GBool getGlyph(int c, int xFrac, int yFrac,
+		 SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) override;
+
+  // Rasterize a glyph.  The <xFrac> and <yFrac> values are the same
+  // as described for getGlyph.
+  GBool makeGlyph(int c, int xFrac, int yFrac,
+		  SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) override;
+
+  // Return the path for a glyph.
+  SplashPath *getGlyphPath(int c) override;
+
+  // Return the advance of a glyph. (in 0..1 range)
+  double getGlyphAdvance(int c) override;
+
+private:
+
+  FT_Size sizeObj;
+  FT_Matrix matrix;
+  FT_Matrix textMatrix;
+  SplashCoord textScale;
+  int size;
+  GBool enableFreeTypeHinting;
+  GBool enableSlightHinting;
+};
+
+#endif
diff --git a/source/libs/poppler/poppler-src/splash/SplashFTFontEngine.cc b/source/libs/poppler/poppler-src/splash/SplashFTFontEngine.cc
new file mode 100644
index 0000000000000000000000000000000000000000..9b20f4a17abfb096310c422ba90ca4dbef338118
--- /dev/null
+++ b/source/libs/poppler/poppler-src/splash/SplashFTFontEngine.cc
@@ -0,0 +1,177 @@
+//========================================================================
+//
+// SplashFTFontEngine.cc
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2006 Takashi Iwai <tiwai@suse.de>
+// Copyright (C) 2009, 2011, 2012 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2009 Petr Gajdos <pgajdos@novell.com>
+// Copyright (C) 2011 Andreas Hartmetz <ahartmetz@gmail.com>
+// Copyright (C) 2017 Adrian Johnson <ajohnson@redneon.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdio.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include "goo/gmem.h"
+#include "goo/GooString.h"
+#include "goo/gfile.h"
+#include "fofi/FoFiTrueType.h"
+#include "fofi/FoFiType1C.h"
+#include "SplashFTFontFile.h"
+#include "SplashFTFontEngine.h"
+
+#ifdef VMS
+#if (__VMS_VER < 70000000)
+extern "C" int unlink(char *filename);
+#endif
+#endif
+
+//------------------------------------------------------------------------
+// SplashFTFontEngine
+//------------------------------------------------------------------------
+
+SplashFTFontEngine::SplashFTFontEngine(GBool aaA, GBool enableFreeTypeHintingA,
+				       GBool enableSlightHintingA, FT_Library libA) {
+  FT_Int major, minor, patch;
+
+  aa = aaA;
+  enableFreeTypeHinting = enableFreeTypeHintingA;
+  enableSlightHinting = enableSlightHintingA;
+  lib = libA;
+
+  // as of FT 2.1.8, CID fonts are indexed by CID instead of GID
+  FT_Library_Version(lib, &major, &minor, &patch);
+  useCIDs = major > 2 ||
+            (major == 2 && (minor > 1 || (minor == 1 && patch > 7)));
+}
+
+SplashFTFontEngine *SplashFTFontEngine::init(GBool aaA, GBool enableFreeTypeHintingA,
+					     GBool enableSlightHintingA) {
+  FT_Library libA;
+
+  if (FT_Init_FreeType(&libA)) {
+    return NULL;
+  }
+  return new SplashFTFontEngine(aaA, enableFreeTypeHintingA, enableSlightHintingA, libA);
+}
+
+SplashFTFontEngine::~SplashFTFontEngine() {
+  FT_Done_FreeType(lib);
+}
+
+SplashFontFile *SplashFTFontEngine::loadType1Font(SplashFontFileID *idA,
+						  SplashFontSrc *src,
+						  const char **enc) {
+  return SplashFTFontFile::loadType1Font(this, idA, src, enc);
+}
+
+SplashFontFile *SplashFTFontEngine::loadType1CFont(SplashFontFileID *idA,
+						   SplashFontSrc *src,
+						   const char **enc) {
+  return SplashFTFontFile::loadType1Font(this, idA, src, enc);
+}
+
+SplashFontFile *SplashFTFontEngine::loadOpenTypeT1CFont(SplashFontFileID *idA,
+							SplashFontSrc *src,
+							const char **enc) {
+  return SplashFTFontFile::loadType1Font(this, idA, src, enc);
+}
+
+SplashFontFile *SplashFTFontEngine::loadCIDFont(SplashFontFileID *idA,
+						SplashFontSrc *src) {
+  FoFiType1C *ff;
+  int *cidToGIDMap;
+  int nCIDs;
+  SplashFontFile *ret;
+
+  // check for a CFF font
+  if (useCIDs) {
+    cidToGIDMap = NULL;
+    nCIDs = 0;
+  } else {
+    if (src->isFile) {
+      ff = FoFiType1C::load(src->fileName->getCString());
+    } else {
+      ff = FoFiType1C::make(src->buf, src->bufLen);
+    }
+    if (ff) {
+      cidToGIDMap = ff->getCIDToGIDMap(&nCIDs);
+      delete ff;
+    } else {
+      cidToGIDMap = NULL;
+      nCIDs = 0;
+    }
+  }
+  ret = SplashFTFontFile::loadCIDFont(this, idA, src, cidToGIDMap, nCIDs);
+  if (!ret) {
+    gfree(cidToGIDMap);
+  }
+  return ret;
+}
+
+SplashFontFile *SplashFTFontEngine::loadOpenTypeCFFFont(SplashFontFileID *idA,
+							SplashFontSrc *src,
+                                                        int *codeToGID,
+                                                        int codeToGIDLen) {
+  FoFiTrueType *ff;
+  int *cidToGIDMap;
+  int nCIDs;
+  SplashFontFile *ret;
+
+  cidToGIDMap = NULL;
+  nCIDs = 0;
+  if (!codeToGID) {
+    if (!useCIDs) {
+      if (src->isFile) {
+        ff = FoFiTrueType::load(src->fileName->getCString());
+      } else {
+        ff = FoFiTrueType::make(src->buf, src->bufLen);
+      }
+      if (ff) {
+        if (ff->isOpenTypeCFF()) {
+          cidToGIDMap = ff->getCIDToGIDMap(&nCIDs);
+        }
+        delete ff;
+      }
+    }
+  }
+  ret = SplashFTFontFile::loadCIDFont(this, idA, src,
+                                      codeToGID ? codeToGID : cidToGIDMap,
+                                      codeToGID ? codeToGIDLen : nCIDs);
+  if (!ret) {
+    gfree(cidToGIDMap);
+  }
+  return ret;
+}
+
+SplashFontFile *SplashFTFontEngine::loadTrueTypeFont(SplashFontFileID *idA,
+						     SplashFontSrc *src,
+						     int *codeToGID,
+						     int codeToGIDLen,
+						     int faceIndex) {
+  SplashFontFile *ret;
+  ret = SplashFTFontFile::loadTrueTypeFont(this, idA, src,
+					   codeToGID, codeToGIDLen,
+					   faceIndex);
+  return ret;
+}
diff --git a/source/libs/poppler/poppler-src/splash/SplashFTFontEngine.h b/source/libs/poppler/poppler-src/splash/SplashFTFontEngine.h
new file mode 100644
index 0000000000000000000000000000000000000000..899458bc5a77bc88825cb3f87dd1674936584a8a
--- /dev/null
+++ b/source/libs/poppler/poppler-src/splash/SplashFTFontEngine.h
@@ -0,0 +1,78 @@
+//========================================================================
+//
+// SplashFTFontEngine.h
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2006 Takashi Iwai <tiwai@suse.de>
+// Copyright (C) 2009 Petr Gajdos <pgajdos@novell.com>
+// Copyright (C) 2009 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2011 Andreas Hartmetz <ahartmetz@gmail.com>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2017 Adrian Johnson <ajohnson@redneon.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef SPLASHFTFONTENGINE_H
+#define SPLASHFTFONTENGINE_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include "goo/gtypes.h"
+
+class SplashFontFile;
+class SplashFontFileID;
+class SplashFontSrc;
+
+//------------------------------------------------------------------------
+// SplashFTFontEngine
+//------------------------------------------------------------------------
+
+class SplashFTFontEngine {
+public:
+
+  static SplashFTFontEngine *init(GBool aaA, GBool enableFreeTypeHintingA, GBool enableSlightHinting);
+
+  ~SplashFTFontEngine();
+
+  // Load fonts.
+  SplashFontFile *loadType1Font(SplashFontFileID *idA, SplashFontSrc *src,  const char **enc);
+  SplashFontFile *loadType1CFont(SplashFontFileID *idA, SplashFontSrc *src,  const char **enc);
+  SplashFontFile *loadOpenTypeT1CFont(SplashFontFileID *idA, SplashFontSrc *src,  const char **enc);
+  SplashFontFile *loadCIDFont(SplashFontFileID *idA, SplashFontSrc *src);
+  SplashFontFile *loadOpenTypeCFFFont(SplashFontFileID *idA, SplashFontSrc *src,
+                                      int *codeToGID, int codeToGIDLen);
+  SplashFontFile *loadTrueTypeFont(SplashFontFileID *idA, SplashFontSrc *src,
+				   int *codeToGID, int codeToGIDLen, int faceIndex = 0);
+  GBool getAA() { return aa; }
+  void setAA(GBool aaA) { aa = aaA; }
+
+private:
+
+  SplashFTFontEngine(GBool aaA, GBool enableFreeTypeHintingA, GBool enableSlightHintingA, FT_Library libA);
+
+  GBool aa;
+  GBool enableFreeTypeHinting;
+  GBool enableSlightHinting;
+  FT_Library lib;
+  GBool useCIDs;
+
+  friend class SplashFTFontFile;
+  friend class SplashFTFont;
+};
+
+#endif
diff --git a/source/libs/poppler/poppler-src/splash/SplashFTFontFile.cc b/source/libs/poppler/poppler-src/splash/SplashFTFontFile.cc
new file mode 100644
index 0000000000000000000000000000000000000000..3c070b70178852b7bf2858c97b5c6027057aab60
--- /dev/null
+++ b/source/libs/poppler/poppler-src/splash/SplashFTFontFile.cc
@@ -0,0 +1,149 @@
+//========================================================================
+//
+// SplashFTFontFile.cc
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2006 Takashi Iwai <tiwai@suse.de>
+// Copyright (C) 2014, 2017 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2017 Oliver Sander <oliver.sander@tu-dresden.de>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include "goo/gmem.h"
+#include "goo/GooString.h"
+#include "poppler/GfxFont.h"
+#include "SplashFTFontEngine.h"
+#include "SplashFTFont.h"
+#include "SplashFTFontFile.h"
+
+//------------------------------------------------------------------------
+// SplashFTFontFile
+//------------------------------------------------------------------------
+
+SplashFontFile *SplashFTFontFile::loadType1Font(SplashFTFontEngine *engineA,
+						SplashFontFileID *idA,
+						SplashFontSrc *src,
+						const char **encA) {
+  FT_Face faceA;
+  int *codeToGIDA;
+  const char *name;
+  int i;
+
+  if (src->isFile) {
+    if (FT_New_Face(engineA->lib, src->fileName->getCString(), 0, &faceA))
+      return NULL;
+  } else {
+    if (FT_New_Memory_Face(engineA->lib, (const FT_Byte *)src->buf, src->bufLen, 0, &faceA))
+      return NULL;
+  }
+  codeToGIDA = (int *)gmallocn(256, sizeof(int));
+  for (i = 0; i < 256; ++i) {
+    codeToGIDA[i] = 0;
+    if ((name = encA[i])) {
+      codeToGIDA[i] = (int)FT_Get_Name_Index(faceA, (char *)name);
+      if (codeToGIDA[i] == 0) {
+	name = GfxFont::getAlternateName(name);
+	if (name) {
+	  codeToGIDA[i] = FT_Get_Name_Index(faceA, (char *)name);
+	}
+      }
+    }
+  }
+
+  return new SplashFTFontFile(engineA, idA, src,
+			      faceA, codeToGIDA, 256, gFalse, gTrue);
+}
+
+SplashFontFile *SplashFTFontFile::loadCIDFont(SplashFTFontEngine *engineA,
+					      SplashFontFileID *idA,
+					      SplashFontSrc *src,
+					      int *codeToGIDA,
+					      int codeToGIDLenA) {
+  FT_Face faceA;
+
+  if (src->isFile) {
+    if (FT_New_Face(engineA->lib, src->fileName->getCString(), 0, &faceA))
+      return NULL;
+  } else {
+    if (FT_New_Memory_Face(engineA->lib, (const FT_Byte *)src->buf, src->bufLen, 0, &faceA))
+      return NULL;
+  }
+
+  return new SplashFTFontFile(engineA, idA, src,
+			      faceA, codeToGIDA, codeToGIDLenA, gFalse, gFalse);
+}
+
+SplashFontFile *SplashFTFontFile::loadTrueTypeFont(SplashFTFontEngine *engineA,
+						   SplashFontFileID *idA,
+						   SplashFontSrc *src,
+						   int *codeToGIDA,
+						   int codeToGIDLenA,
+						   int faceIndexA) {
+  FT_Face faceA;
+
+  if (src->isFile) {
+    if (FT_New_Face(engineA->lib, src->fileName->getCString(), faceIndexA, &faceA))
+      return NULL;
+  } else {
+    if (FT_New_Memory_Face(engineA->lib, (const FT_Byte *)src->buf, src->bufLen, faceIndexA, &faceA))
+      return NULL;
+  }
+
+  return new SplashFTFontFile(engineA, idA, src,
+			      faceA, codeToGIDA, codeToGIDLenA, gTrue, gFalse);
+}
+
+SplashFTFontFile::SplashFTFontFile(SplashFTFontEngine *engineA,
+				   SplashFontFileID *idA,
+				   SplashFontSrc *src,
+				   FT_Face faceA,
+				   int *codeToGIDA, int codeToGIDLenA,
+				   GBool trueTypeA, GBool type1A):
+  SplashFontFile(idA, src)
+{
+  engine = engineA;
+  face = faceA;
+  codeToGID = codeToGIDA;
+  codeToGIDLen = codeToGIDLenA;
+  trueType = trueTypeA;
+  type1 = type1A;
+}
+
+SplashFTFontFile::~SplashFTFontFile() {
+  if (face) {
+    FT_Done_Face(face);
+  }
+  if (codeToGID) {
+    gfree(codeToGID);
+  }
+}
+
+SplashFont *SplashFTFontFile::makeFont(SplashCoord *mat,
+				       SplashCoord *textMat) {
+  SplashFont *font;
+
+  font = new SplashFTFont(this, mat, textMat);
+  font->initCache();
+  return font;
+}
+
+int *SplashFTFontFile::getCodeToGID() {
+  return codeToGID;
+}
diff --git a/source/libs/poppler/poppler-src/splash/SplashFTFontFile.h b/source/libs/poppler/poppler-src/splash/SplashFTFontFile.h
new file mode 100644
index 0000000000000000000000000000000000000000..5931be3fe73d92c8c7e20320d126816024cc482d
--- /dev/null
+++ b/source/libs/poppler/poppler-src/splash/SplashFTFontFile.h
@@ -0,0 +1,87 @@
+//========================================================================
+//
+// SplashFTFontFile.h
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2006 Takashi Iwai <tiwai@suse.de>
+// Copyright (C) 2017 Oliver Sander <oliver.sander@tu-dresden.de>
+// Copyright (C) 2017 Adrian Johnson <ajohnson@redneon.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef SPLASHFTFONTFILE_H
+#define SPLASHFTFONTFILE_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include "SplashFontFile.h"
+
+class SplashFontFileID;
+class SplashFTFontEngine;
+
+//------------------------------------------------------------------------
+// SplashFTFontFile
+//------------------------------------------------------------------------
+
+class SplashFTFontFile: public SplashFontFile {
+public:
+
+  static SplashFontFile *loadType1Font(SplashFTFontEngine *engineA,
+				       SplashFontFileID *idA,
+				       SplashFontSrc *src, const char **encA);
+  static SplashFontFile *loadCIDFont(SplashFTFontEngine *engineA,
+					 SplashFontFileID *idA,
+					 SplashFontSrc *src,
+					 int *codeToCIDA, int codeToGIDLenA);
+  static SplashFontFile *loadTrueTypeFont(SplashFTFontEngine *engineA,
+					  SplashFontFileID *idA,
+					  SplashFontSrc *src,
+					  int *codeToGIDA,
+					  int codeToGIDLenA,
+					  int faceIndexA=0);
+
+  ~SplashFTFontFile();
+
+  // Create a new SplashFTFont, i.e., a scaled instance of this font
+  // file.
+  SplashFont *makeFont(SplashCoord *mat,
+		       SplashCoord *textMat) override;
+
+  // Provide access to the code-to-GID map
+  int* getCodeToGID();
+
+private:
+
+  SplashFTFontFile(SplashFTFontEngine *engineA,
+		   SplashFontFileID *idA,
+		   SplashFontSrc *src,
+		   FT_Face faceA,
+		   int *codeToGIDA, int codeToGIDLenA,
+		   GBool trueTypeA, GBool type1A);
+
+  SplashFTFontEngine *engine;
+  FT_Face face;
+  int *codeToGID;
+  int codeToGIDLen;
+  GBool trueType;
+  GBool type1;
+
+  friend class SplashFTFont;
+};
+
+#endif
diff --git a/source/libs/poppler/poppler-src/splash/SplashFont.cc b/source/libs/poppler/poppler-src/splash/SplashFont.cc
new file mode 100644
index 0000000000000000000000000000000000000000..3d6d6b2343e379c6c2ce8c9dd294a1c9ae7c0e13
--- /dev/null
+++ b/source/libs/poppler/poppler-src/splash/SplashFont.cc
@@ -0,0 +1,224 @@
+//========================================================================
+//
+// SplashFont.cc
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2007-2008, 2010, 2014 Albert Astals Cid <aacid@kde.org>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <limits.h>
+#include <string.h>
+#include "goo/gmem.h"
+#include "SplashMath.h"
+#include "SplashGlyphBitmap.h"
+#include "SplashFontFile.h"
+#include "SplashFont.h"
+
+//------------------------------------------------------------------------
+
+struct SplashFontCacheTag {
+  int c;
+  short xFrac, yFrac;		// x and y fractions
+  int mru;			// valid bit (0x80000000) and MRU index
+  int x, y, w, h;		// offset and size of glyph
+};
+
+//------------------------------------------------------------------------
+// SplashFont
+//------------------------------------------------------------------------
+
+SplashFont::SplashFont(SplashFontFile *fontFileA, SplashCoord *matA,
+		       SplashCoord *textMatA, GBool aaA) {
+  fontFile = fontFileA;
+  fontFile->incRefCnt();
+  mat[0] = matA[0];
+  mat[1] = matA[1];
+  mat[2] = matA[2];
+  mat[3] = matA[3];
+  textMat[0] = textMatA[0];
+  textMat[1] = textMatA[1];
+  textMat[2] = textMatA[2];
+  textMat[3] = textMatA[3];
+  aa = aaA;
+
+  cache = NULL;
+  cacheTags = NULL;
+
+  xMin = yMin = xMax = yMax = 0;
+}
+
+void SplashFont::initCache() {
+  int i;
+
+  // this should be (max - min + 1), but we add some padding to
+  // deal with rounding errors
+  glyphW = xMax - xMin + 3;
+  glyphH = yMax - yMin + 3;
+  if (glyphW > INT_MAX / glyphH) {
+    glyphSize = -1;
+  } else {
+    if (aa) {
+      glyphSize = glyphW * glyphH;
+    } else {
+      glyphSize = ((glyphW + 7) >> 3) * glyphH;
+    }
+  }
+
+  // set up the glyph pixmap cache
+  cacheAssoc = 8;
+  if (glyphSize <= 64) {
+    cacheSets = 32;
+  } else if (glyphSize <= 128) {
+    cacheSets = 16;
+  } else if (glyphSize <= 256) {
+    cacheSets = 8;
+  } else if (glyphSize <= 512) {
+    cacheSets = 4;
+  } else if (glyphSize <= 1024) {
+    cacheSets = 2;
+  } else {
+    cacheSets = 1;
+  }
+  cache = (Guchar *)gmallocn_checkoverflow(cacheSets* cacheAssoc, glyphSize);
+  if (cache != NULL) {
+    cacheTags = (SplashFontCacheTag *)gmallocn(cacheSets * cacheAssoc,
+					     sizeof(SplashFontCacheTag));
+    for (i = 0; i < cacheSets * cacheAssoc; ++i) {
+      cacheTags[i].mru = i & (cacheAssoc - 1);
+    }
+  } else {
+    cacheAssoc = 0;
+  }
+}
+
+SplashFont::~SplashFont() {
+  fontFile->decRefCnt();
+  if (cache) {
+    gfree(cache);
+  }
+  if (cacheTags) {
+    gfree(cacheTags);
+  }
+}
+
+GBool SplashFont::getGlyph(int c, int xFrac, int yFrac,
+			   SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) {
+  SplashGlyphBitmap bitmap2;
+  int size;
+  Guchar *p;
+  int i, j, k;
+
+  // no fractional coordinates for large glyphs or non-anti-aliased
+  // glyphs
+  if (!aa || glyphH > 50) {
+    xFrac = yFrac = 0;
+  }
+
+  // check the cache
+  i = (c & (cacheSets - 1)) * cacheAssoc;
+  for (j = 0; j < cacheAssoc; ++j) {
+    if ((cacheTags[i+j].mru & 0x80000000) &&
+	cacheTags[i+j].c == c &&
+	(int)cacheTags[i+j].xFrac == xFrac &&
+	(int)cacheTags[i+j].yFrac == yFrac) {
+      bitmap->x = cacheTags[i+j].x;
+      bitmap->y = cacheTags[i+j].y;
+      bitmap->w = cacheTags[i+j].w;
+      bitmap->h = cacheTags[i+j].h;
+      for (k = 0; k < cacheAssoc; ++k) {
+	if (k != j &&
+	    (cacheTags[i+k].mru & 0x7fffffff) <
+	      (cacheTags[i+j].mru & 0x7fffffff)) {
+	  ++cacheTags[i+k].mru;
+	}
+      }
+      cacheTags[i+j].mru = 0x80000000;
+      bitmap->aa = aa;
+      bitmap->data = cache + (i+j) * glyphSize;
+      bitmap->freeData = gFalse;
+
+      *clipRes = clip->testRect(x0 - bitmap->x,
+                                y0 - bitmap->y,
+                                x0 - bitmap->x + bitmap->w - 1,
+                                y0 - bitmap->y + bitmap->h - 1);
+
+      return gTrue;
+    }
+  }
+
+  // generate the glyph bitmap
+  if (!makeGlyph(c, xFrac, yFrac, &bitmap2, x0, y0, clip, clipRes)) {
+    return gFalse;
+  }
+
+  if (*clipRes == splashClipAllOutside)
+  {
+    bitmap->freeData = gFalse;
+    if (bitmap2.freeData) gfree(bitmap2.data);
+    return gTrue;
+  }
+
+  // if the glyph doesn't fit in the bounding box, return a temporary
+  // uncached bitmap
+  if (bitmap2.w > glyphW || bitmap2.h > glyphH) {
+    *bitmap = bitmap2;
+    return gTrue;
+  }
+
+  // insert glyph pixmap in cache
+  if (aa) {
+    size = bitmap2.w * bitmap2.h;
+  } else {
+    size = ((bitmap2.w + 7) >> 3) * bitmap2.h;
+  }
+  p = NULL; // make gcc happy
+  if (cacheAssoc == 0)
+  {
+    // we had problems on the malloc of the cache, so ignore it
+    *bitmap = bitmap2;
+  }
+  else
+  {
+    for (j = 0; j < cacheAssoc; ++j) {
+      if ((cacheTags[i+j].mru & 0x7fffffff) == cacheAssoc - 1) {
+        cacheTags[i+j].mru = 0x80000000;
+        cacheTags[i+j].c = c;
+        cacheTags[i+j].xFrac = (short)xFrac;
+        cacheTags[i+j].yFrac = (short)yFrac;
+        cacheTags[i+j].x = bitmap2.x;
+        cacheTags[i+j].y = bitmap2.y;
+        cacheTags[i+j].w = bitmap2.w;
+        cacheTags[i+j].h = bitmap2.h;
+        p = cache + (i+j) * glyphSize;
+        memcpy(p, bitmap2.data, size);
+      } else {
+        ++cacheTags[i+j].mru;
+      }
+    }
+    *bitmap = bitmap2;
+    bitmap->data = p;
+    bitmap->freeData = gFalse;
+    if (bitmap2.freeData) {
+      gfree(bitmap2.data);
+    }
+  }
+  return gTrue;
+}
diff --git a/source/libs/poppler/poppler-src/splash/SplashFont.h b/source/libs/poppler/poppler-src/splash/SplashFont.h
new file mode 100644
index 0000000000000000000000000000000000000000..78b00d2dcaf008bf9a874326a4b94adeb715dc5c
--- /dev/null
+++ b/source/libs/poppler/poppler-src/splash/SplashFont.h
@@ -0,0 +1,121 @@
+//========================================================================
+//
+// SplashFont.h
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2007-2008 Albert Astals Cid <aacid@kde.org>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef SPLASHFONT_H
+#define SPLASHFONT_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "goo/gtypes.h"
+#include "SplashTypes.h"
+#include "SplashClip.h"
+
+struct SplashGlyphBitmap;
+struct SplashFontCacheTag;
+class SplashFontFile;
+class SplashPath;
+
+//------------------------------------------------------------------------
+
+// Fractional positioning uses this many bits to the right of the
+// decimal points.
+#define splashFontFractionBits 2
+#define splashFontFraction     (1 << splashFontFractionBits)
+#define splashFontFractionMul \
+                       ((SplashCoord)1 / (SplashCoord)splashFontFraction)
+
+//------------------------------------------------------------------------
+// SplashFont
+//------------------------------------------------------------------------
+
+class SplashFont {
+public:
+
+  SplashFont(SplashFontFile *fontFileA, SplashCoord *matA,
+	     SplashCoord *textMatA, GBool aaA);
+
+  // This must be called after the constructor, so that the subclass
+  // constructor has a chance to compute the bbox.
+  void initCache();
+
+  virtual ~SplashFont();
+
+  SplashFontFile *getFontFile() { return fontFile; }
+
+  // Return true if <this> matches the specified font file and matrix.
+  GBool matches(SplashFontFile *fontFileA, SplashCoord *matA,
+		SplashCoord *textMatA) {
+    return fontFileA == fontFile &&
+           matA[0] == mat[0] && matA[1] == mat[1] &&
+           matA[2] == mat[2] && matA[3] == mat[3] &&
+           textMatA[0] == textMat[0] && textMatA[1] == textMat[1] &&
+           textMatA[2] == textMat[2] && textMatA[3] == textMat[3];
+  }
+
+  // Get a glyph - this does a cache lookup first, and if not found,
+  // creates a new bitmap and adds it to the cache.  The <xFrac> and
+  // <yFrac> values are splashFontFractionBits bits each, representing
+  // the numerators of fractions in [0, 1), where the denominator is
+  // splashFontFraction = 1 << splashFontFractionBits.  Subclasses
+  // should override this to zero out xFrac and/or yFrac if they don't
+  // support fractional coordinates.
+  virtual GBool getGlyph(int c, int xFrac, int yFrac,
+			 SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes);
+
+  // Rasterize a glyph.  The <xFrac> and <yFrac> values are the same
+  // as described for getGlyph.
+  virtual GBool makeGlyph(int c, int xFrac, int yFrac,
+			  SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) = 0;
+
+  // Return the path for a glyph.
+  virtual SplashPath *getGlyphPath(int c) = 0;
+
+  // Return the advance of a glyph. (in 0..1 range)
+  // < 0 means not known
+  virtual double getGlyphAdvance(int c) { return -1; }
+
+  // Return the font transform matrix.
+  SplashCoord *getMatrix() { return mat; }
+
+  // Return the glyph bounding box.
+  void getBBox(int *xMinA, int *yMinA, int *xMaxA, int *yMaxA)
+    { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; }
+
+protected:
+
+  SplashFontFile *fontFile;
+  SplashCoord mat[4];		// font transform matrix
+				//   (text space -> device space)
+  SplashCoord textMat[4];	// text transform matrix
+				//   (text space -> user space)
+  GBool aa;			// anti-aliasing
+  int xMin, yMin, xMax, yMax;	// glyph bounding box
+  Guchar *cache;		// glyph bitmap cache
+  SplashFontCacheTag *		// cache tags
+    cacheTags;
+  int glyphW, glyphH;		// size of glyph bitmaps
+  int glyphSize;		// size of glyph bitmaps, in bytes
+  int cacheSets;		// number of sets in cache
+  int cacheAssoc;		// cache associativity (glyphs per set)
+};
+
+#endif
diff --git a/source/libs/poppler/poppler-src/splash/SplashFontEngine.cc b/source/libs/poppler/poppler-src/splash/SplashFontEngine.cc
new file mode 100644
index 0000000000000000000000000000000000000000..62e5a0199bf7e43a54e226a1da93457a70a6bf2d
--- /dev/null
+++ b/source/libs/poppler/poppler-src/splash/SplashFontEngine.cc
@@ -0,0 +1,288 @@
+//========================================================================
+//
+// SplashFontEngine.cc
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2006 Takashi Iwai <tiwai@suse.de>
+// Copyright (C) 2009 Petr Gajdos <pgajdos@novell.com>
+// Copyright (C) 2009 Kovid Goyal <kovid@kovidgoyal.net>
+// Copyright (C) 2009 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2011 Andreas Hartmetz <ahartmetz@gmail.com>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2015 Dmytro Morgun <lztoad@gmail.com>
+// Copyright (C) 2017 Adrian Johnson <ajohnson@redneon.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#ifdef HAVE_UNISTD_H
+#  include <unistd.h>
+#endif
+#include "goo/gmem.h"
+#include "goo/GooString.h"
+#include "SplashMath.h"
+#include "SplashFTFontEngine.h"
+#include "SplashFontFile.h"
+#include "SplashFontFileID.h"
+#include "SplashFont.h"
+#include "SplashFontEngine.h"
+
+#ifdef VMS
+#if (__VMS_VER < 70000000)
+extern "C" int unlink(char *filename);
+#endif
+#endif
+
+#ifdef VMS
+#if (__VMS_VER < 70000000)
+extern "C" int unlink(char *filename);
+#endif
+#endif
+
+//------------------------------------------------------------------------
+// SplashFontEngine
+//------------------------------------------------------------------------
+
+SplashFontEngine::SplashFontEngine(
+				   GBool enableFreeType,
+				   GBool enableFreeTypeHinting,
+				   GBool enableSlightHinting,
+				   GBool aa) {
+  int i;
+
+  for (i = 0; i < splashFontCacheSize; ++i) {
+    fontCache[i] = NULL;
+  }
+
+  if (enableFreeType) {
+    ftEngine = SplashFTFontEngine::init(aa, enableFreeTypeHinting, enableSlightHinting);
+  } else {
+    ftEngine = NULL;
+  }
+}
+
+SplashFontEngine::~SplashFontEngine() {
+  int i;
+
+  for (i = 0; i < splashFontCacheSize; ++i) {
+    if (fontCache[i]) {
+      delete fontCache[i];
+    }
+  }
+
+  if (ftEngine) {
+    delete ftEngine;
+  }
+}
+
+SplashFontFile *SplashFontEngine::getFontFile(SplashFontFileID *id) {
+  SplashFontFile *fontFile;
+  int i;
+
+  for (i = 0; i < splashFontCacheSize; ++i) {
+    if (fontCache[i]) {
+      fontFile = fontCache[i]->getFontFile();
+      if (fontFile && fontFile->getID()->matches(id)) {
+	return fontFile;
+      }
+    }
+  }
+  return NULL;
+}
+
+SplashFontFile *SplashFontEngine::loadType1Font(SplashFontFileID *idA,
+						SplashFontSrc *src,
+						const char **enc) {
+  SplashFontFile *fontFile;
+
+  fontFile = NULL;
+  if (!fontFile && ftEngine) {
+    fontFile = ftEngine->loadType1Font(idA, src, enc);
+  }
+
+  // delete the (temporary) font file -- with Unix hard link
+  // semantics, this will remove the last link; otherwise it will
+  // return an error, leaving the file to be deleted later (if
+  // loadXYZFont failed, the file will always be deleted)
+  if (src->isFile)
+    src->unref();
+
+  return fontFile;
+}
+
+SplashFontFile *SplashFontEngine::loadType1CFont(SplashFontFileID *idA,
+						 SplashFontSrc *src,
+						 const char **enc) {
+  SplashFontFile *fontFile;
+
+  fontFile = NULL;
+  if (!fontFile && ftEngine) {
+    fontFile = ftEngine->loadType1CFont(idA, src, enc);
+  }
+
+  // delete the (temporary) font file -- with Unix hard link
+  // semantics, this will remove the last link; otherwise it will
+  // return an error, leaving the file to be deleted later (if
+  // loadXYZFont failed, the file will always be deleted)
+  if (src->isFile)
+    src->unref();
+
+  return fontFile;
+}
+
+SplashFontFile *SplashFontEngine::loadOpenTypeT1CFont(SplashFontFileID *idA,
+						      SplashFontSrc *src,
+						      const char **enc) {
+  SplashFontFile *fontFile;
+
+  fontFile = NULL;
+  if (!fontFile && ftEngine) {
+    fontFile = ftEngine->loadOpenTypeT1CFont(idA, src, enc);
+  }
+
+  // delete the (temporary) font file -- with Unix hard link
+  // semantics, this will remove the last link; otherwise it will
+  // return an error, leaving the file to be deleted later (if
+  // loadXYZFont failed, the file will always be deleted)
+  if (src->isFile)
+    src->unref();
+
+  return fontFile;
+}
+
+SplashFontFile *SplashFontEngine::loadCIDFont(SplashFontFileID *idA,
+					      SplashFontSrc *src) {
+  SplashFontFile *fontFile;
+
+  fontFile = NULL;
+  if (!fontFile && ftEngine) {
+    fontFile = ftEngine->loadCIDFont(idA, src);
+  }
+
+  // delete the (temporary) font file -- with Unix hard link
+  // semantics, this will remove the last link; otherwise it will
+  // return an error, leaving the file to be deleted later (if
+  // loadXYZFont failed, the file will always be deleted)
+  if (src->isFile)
+    src->unref();
+
+  return fontFile;
+}
+
+SplashFontFile *SplashFontEngine::loadOpenTypeCFFFont(SplashFontFileID *idA,
+						      SplashFontSrc *src,
+                                                      int *codeToGID,
+                                                      int codeToGIDLen) {
+  SplashFontFile *fontFile;
+
+  fontFile = NULL;
+  if (!fontFile && ftEngine) {
+    fontFile = ftEngine->loadOpenTypeCFFFont(idA, src, codeToGID, codeToGIDLen);
+  }
+
+  // delete the (temporary) font file -- with Unix hard link
+  // semantics, this will remove the last link; otherwise it will
+  // return an error, leaving the file to be deleted later (if
+  // loadXYZFont failed, the file will always be deleted)
+  if (src->isFile)
+    src->unref();
+
+  return fontFile;
+}
+
+SplashFontFile *SplashFontEngine::loadTrueTypeFont(SplashFontFileID *idA,
+						   SplashFontSrc *src,
+						   int *codeToGID,
+						   int codeToGIDLen,
+						   int faceIndex) {
+  SplashFontFile *fontFile;
+
+  fontFile = NULL;
+  if (!fontFile && ftEngine) {
+    fontFile = ftEngine->loadTrueTypeFont(idA, src,
+                                        codeToGID, codeToGIDLen, faceIndex);
+  }
+
+  if (!fontFile) {
+    gfree(codeToGID);
+  }
+
+  // delete the (temporary) font file -- with Unix hard link
+  // semantics, this will remove the last link; otherwise it will
+  // return an error, leaving the file to be deleted later (if
+  // loadXYZFont failed, the file will always be deleted)
+  if (src->isFile)
+    src->unref();
+
+  return fontFile;
+}
+
+GBool SplashFontEngine::getAA() {
+  return (ftEngine == NULL) ? gFalse : ftEngine->getAA();
+}
+
+void SplashFontEngine::setAA(GBool aa) {
+  if (ftEngine != NULL) {
+    ftEngine->setAA(aa);
+  }
+}
+
+SplashFont *SplashFontEngine::getFont(SplashFontFile *fontFile,
+				      SplashCoord *textMat,
+				      SplashCoord *ctm) {
+  SplashCoord mat[4];
+  SplashFont *font;
+  int i, j;
+
+  mat[0] = textMat[0] * ctm[0] + textMat[1] * ctm[2];
+  mat[1] = -(textMat[0] * ctm[1] + textMat[1] * ctm[3]);
+  mat[2] = textMat[2] * ctm[0] + textMat[3] * ctm[2];
+  mat[3] = -(textMat[2] * ctm[1] + textMat[3] * ctm[3]);
+  if (!splashCheckDet(mat[0], mat[1], mat[2], mat[3], 0.01)) {
+    // avoid a singular (or close-to-singular) matrix
+    mat[0] = 0.01;  mat[1] = 0;
+    mat[2] = 0;     mat[3] = 0.01;
+  }
+
+  font = fontCache[0];
+  if (font && font->matches(fontFile, mat, textMat)) {
+    return font;
+  }
+  for (i = 1; i < splashFontCacheSize; ++i) {
+    font = fontCache[i];
+    if (font && font->matches(fontFile, mat, textMat)) {
+      for (j = i; j > 0; --j) {
+	fontCache[j] = fontCache[j-1];
+      }
+      fontCache[0] = font;
+      return font;
+    }
+  }
+  font = fontFile->makeFont(mat, textMat);
+  if (fontCache[splashFontCacheSize - 1]) {
+    delete fontCache[splashFontCacheSize - 1];
+  }
+  for (j = splashFontCacheSize - 1; j > 0; --j) {
+    fontCache[j] = fontCache[j-1];
+  }
+  fontCache[0] = font;
+  return font;
+}
diff --git a/source/libs/poppler/poppler-src/splash/SplashFontEngine.h b/source/libs/poppler/poppler-src/splash/SplashFontEngine.h
new file mode 100644
index 0000000000000000000000000000000000000000..e3ee1ce600d4054f24fb99be40ab787dca9965a9
--- /dev/null
+++ b/source/libs/poppler/poppler-src/splash/SplashFontEngine.h
@@ -0,0 +1,99 @@
+//========================================================================
+//
+// SplashFontEngine.h
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2006 Takashi Iwai <tiwai@suse.de>
+// Copyright (C) 2009 Petr Gajdos <pgajdos@novell.com>
+// Copyright (C) 2009, 2011 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2011 Andreas Hartmetz <ahartmetz@gmail.com>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2017 Adrian Johnson <ajohnson@redneon.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef SPLASHFONTENGINE_H
+#define SPLASHFONTENGINE_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "goo/gtypes.h"
+#include "SplashTypes.h"
+
+class SplashT1FontEngine;
+class SplashFTFontEngine;
+class SplashDTFontEngine;
+class SplashDT4FontEngine;
+class SplashFontFile;
+class SplashFontFileID;
+class SplashFont;
+class SplashFontSrc;
+
+//------------------------------------------------------------------------
+
+#define splashFontCacheSize 16
+
+//------------------------------------------------------------------------
+// SplashFontEngine
+//------------------------------------------------------------------------
+
+class SplashFontEngine {
+public:
+
+  // Create a font engine.
+  SplashFontEngine(
+		   GBool enableFreeType,
+		   GBool enableFreeTypeHinting,
+		   GBool enableSlightHinting,
+		   GBool aa);
+
+  ~SplashFontEngine();
+
+  // Get a font file from the cache.  Returns NULL if there is no
+  // matching entry in the cache.
+  SplashFontFile *getFontFile(SplashFontFileID *id);
+
+  // Load fonts - these create new SplashFontFile objects.
+  SplashFontFile *loadType1Font(SplashFontFileID *idA, SplashFontSrc *src, const char **enc);
+  SplashFontFile *loadType1CFont(SplashFontFileID *idA, SplashFontSrc *src, const char **enc);
+  SplashFontFile *loadOpenTypeT1CFont(SplashFontFileID *idA, SplashFontSrc *src, const char **enc);
+  SplashFontFile *loadCIDFont(SplashFontFileID *idA, SplashFontSrc *src);
+  SplashFontFile *loadOpenTypeCFFFont(SplashFontFileID *idA, SplashFontSrc *src,
+                                      int *codeToGID, int codeToGIDLen);
+  SplashFontFile *loadTrueTypeFont(SplashFontFileID *idA, SplashFontSrc *src,
+				   int *codeToGID, int codeToGIDLen, int faceIndex = 0);
+
+  // Get a font - this does a cache lookup first, and if not found,
+  // creates a new SplashFont object and adds it to the cache.  The
+  // matrix, mat = textMat * ctm:
+  //    [ mat[0] mat[1] ]
+  //    [ mat[2] mat[3] ]
+  // specifies the font transform in PostScript style:
+  //    [x' y'] = [x y] * mat
+  // Note that the Splash y axis points downward.
+  SplashFont *getFont(SplashFontFile *fontFile,
+		      SplashCoord *textMat, SplashCoord *ctm);
+  GBool getAA();
+  void setAA(GBool aa);
+
+private:
+
+  SplashFont *fontCache[splashFontCacheSize];
+
+  SplashFTFontEngine *ftEngine;
+};
+
+#endif
diff --git a/source/libs/poppler/poppler-src/splash/SplashFontFile.cc b/source/libs/poppler/poppler-src/splash/SplashFontFile.cc
new file mode 100644
index 0000000000000000000000000000000000000000..68e8608b6a70a0e1d003862906111406ff233b50
--- /dev/null
+++ b/source/libs/poppler/poppler-src/splash/SplashFontFile.cc
@@ -0,0 +1,124 @@
+//========================================================================
+//
+// SplashFontFile.cc
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2006 Takashi Iwai <tiwai@suse.de>
+// Copyright (C) 2008 Albert Astals Cid <aacid@kde.org>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdio.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include "goo/gmem.h"
+#include "goo/GooString.h"
+#include "SplashFontFile.h"
+#include "SplashFontFileID.h"
+
+#ifdef VMS
+#if (__VMS_VER < 70000000)
+extern "C" int unlink(char *filename);
+#endif
+#endif
+
+//------------------------------------------------------------------------
+// SplashFontFile
+//------------------------------------------------------------------------
+
+SplashFontFile::SplashFontFile(SplashFontFileID *idA, SplashFontSrc *srcA) {
+  id = idA;
+  src = srcA;
+  src->ref();
+  refCnt = 0;
+  doAdjustMatrix = gFalse;
+}
+
+SplashFontFile::~SplashFontFile() {
+  src->unref();
+  delete id;
+}
+
+void SplashFontFile::incRefCnt() {
+  ++refCnt;
+}
+
+void SplashFontFile::decRefCnt() {
+  if (!--refCnt) {
+    delete this;
+  }
+}
+
+//
+
+SplashFontSrc::SplashFontSrc() {
+  isFile = gFalse;
+  deleteSrc = gFalse;
+  fileName = NULL;
+  buf = NULL;
+  refcnt = 1;
+}
+
+SplashFontSrc::~SplashFontSrc() {
+  if (deleteSrc) {
+    if (isFile) {
+      if (fileName)
+	unlink(fileName->getCString());
+    } else {
+      if (buf)
+	gfree(buf);
+    }
+  }
+
+  if (isFile && fileName)
+    delete fileName;
+}
+
+void SplashFontSrc::ref() {
+  refcnt++;
+}
+
+void SplashFontSrc::unref() {
+  if (! --refcnt)
+    delete this;
+}
+
+void SplashFontSrc::setFile(GooString *file, GBool del)
+{
+  isFile = gTrue;
+  fileName = file->copy();
+  deleteSrc = del;
+}
+
+void SplashFontSrc::setFile(const char *file, GBool del)
+{
+  isFile = gTrue;
+  fileName = new GooString(file);
+  deleteSrc = del;
+}
+
+void SplashFontSrc::setBuf(char *bufA, int bufLenA, GBool del)
+{
+  isFile = gFalse;
+  buf = bufA;
+  bufLen = bufLenA;
+  deleteSrc = del;
+}
diff --git a/source/libs/poppler/poppler-src/splash/SplashFontFile.h b/source/libs/poppler/poppler-src/splash/SplashFontFile.h
new file mode 100644
index 0000000000000000000000000000000000000000..ec87504b9bc593d602b68828f92d28154e8f73e4
--- /dev/null
+++ b/source/libs/poppler/poppler-src/splash/SplashFontFile.h
@@ -0,0 +1,95 @@
+//========================================================================
+//
+// SplashFontFile.h
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2006 Takashi Iwai <tiwai@suse.de>
+// Copyright (C) 2008, 2010 Albert Astals Cid <aacid@kde.org>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef SPLASHFONTFILE_H
+#define SPLASHFONTFILE_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "goo/gtypes.h"
+#include "SplashTypes.h"
+
+class GooString;
+class SplashFontEngine;
+class SplashFont;
+class SplashFontFileID;
+
+//------------------------------------------------------------------------
+// SplashFontFile
+//------------------------------------------------------------------------
+
+class SplashFontSrc {
+public:
+  SplashFontSrc();
+
+  void setFile(GooString *file, GBool del);
+  void setFile(const char *file, GBool del);
+  void setBuf(char *bufA, int buflenA, GBool del);
+
+  void ref();
+  void unref();
+
+  GBool isFile;
+  GooString *fileName;
+  char *buf;
+  int bufLen;
+
+private:
+  ~SplashFontSrc();
+  int refcnt;
+  GBool deleteSrc;
+};
+
+class SplashFontFile {
+public:
+
+  virtual ~SplashFontFile();
+
+  // Create a new SplashFont, i.e., a scaled instance of this font
+  // file.
+  virtual SplashFont *makeFont(SplashCoord *mat, SplashCoord *textMat) = 0;
+
+  // Get the font file ID.
+  SplashFontFileID *getID() { return id; }
+
+  // Increment the reference count.
+  void incRefCnt();
+
+  // Decrement the reference count.  If the new value is zero, delete
+  // the SplashFontFile object.
+  void decRefCnt();
+
+  GBool doAdjustMatrix;
+
+protected:
+
+  SplashFontFile(SplashFontFileID *idA, SplashFontSrc *srcA);
+
+  SplashFontFileID *id;
+  SplashFontSrc *src;
+  int refCnt;
+
+  friend class SplashFontEngine;
+};
+
+#endif
diff --git a/source/libs/poppler/poppler-src/splash/SplashFontFileID.cc b/source/libs/poppler/poppler-src/splash/SplashFontFileID.cc
new file mode 100644
index 0000000000000000000000000000000000000000..a66dabf61e3173b9543f935182905fba2ded796d
--- /dev/null
+++ b/source/libs/poppler/poppler-src/splash/SplashFontFileID.cc
@@ -0,0 +1,23 @@
+//========================================================================
+//
+// SplashFontFileID.cc
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include "SplashFontFileID.h"
+
+//------------------------------------------------------------------------
+// SplashFontFileID
+//------------------------------------------------------------------------
+
+SplashFontFileID::SplashFontFileID() {
+}
+
+SplashFontFileID::~SplashFontFileID() {
+}
diff --git a/source/libs/poppler/poppler-src/splash/SplashFontFileID.h b/source/libs/poppler/poppler-src/splash/SplashFontFileID.h
new file mode 100644
index 0000000000000000000000000000000000000000..cfd89ebb56aa4492f5ab9094fb7a3c5a3aa4b987
--- /dev/null
+++ b/source/libs/poppler/poppler-src/splash/SplashFontFileID.h
@@ -0,0 +1,28 @@
+//========================================================================
+//
+// SplashFontFileID.h
+//
+//========================================================================
+
+#ifndef SPLASHFONTFILEID_H
+#define SPLASHFONTFILEID_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "goo/gtypes.h"
+
+//------------------------------------------------------------------------
+// SplashFontFileID
+//------------------------------------------------------------------------
+
+class SplashFontFileID {
+public:
+
+  SplashFontFileID();
+  virtual ~SplashFontFileID();
+  virtual GBool matches(SplashFontFileID *id) = 0;
+};
+
+#endif
diff --git a/source/libs/poppler/poppler-src/splash/SplashGlyphBitmap.h b/source/libs/poppler/poppler-src/splash/SplashGlyphBitmap.h
new file mode 100644
index 0000000000000000000000000000000000000000..c062c106e6a42b5d48290d90f46aa826d528193b
--- /dev/null
+++ b/source/libs/poppler/poppler-src/splash/SplashGlyphBitmap.h
@@ -0,0 +1,24 @@
+//========================================================================
+//
+// SplashGlyphBitmap.h
+//
+//========================================================================
+
+#ifndef SPLASHGLYPHBITMAP_H
+#define SPLASHGLYPHBITMAP_H
+
+#include "goo/gtypes.h"
+
+//------------------------------------------------------------------------
+// SplashGlyphBitmap
+//------------------------------------------------------------------------
+
+struct SplashGlyphBitmap {
+  int x, y, w, h;		// offset and size of glyph
+  GBool aa;			// anti-aliased: true means 8-bit alpha
+				//   bitmap; false means 1-bit
+  Guchar *data;			// bitmap data
+  GBool freeData;		// true if data memory should be freed
+};
+
+#endif
diff --git a/source/libs/poppler/poppler-src/splash/SplashMath.h b/source/libs/poppler/poppler-src/splash/SplashMath.h
new file mode 100644
index 0000000000000000000000000000000000000000..36793ea3fcd42156c57029a4564a49740445b01d
--- /dev/null
+++ b/source/libs/poppler/poppler-src/splash/SplashMath.h
@@ -0,0 +1,246 @@
+//========================================================================
+//
+// SplashMath.h
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2009-2011 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2017 Adrian Johnson <ajohnson@redneon.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef SPLASHMATH_H
+#define SPLASHMATH_H
+
+#include "poppler-config.h"
+
+#ifdef USE_FIXEDPOINT
+#include "goo/FixedPoint.h"
+#else
+#include <math.h>
+#endif
+#include "SplashTypes.h"
+
+static inline SplashCoord splashAbs(SplashCoord x) {
+#if defined(USE_FIXEDPOINT)
+  return FixedPoint::abs(x);
+#elif defined(USE_FLOAT)
+  return fabsf(x);
+#else
+  return fabs(x);
+#endif
+}
+
+static inline int splashFloor(SplashCoord x) {
+#if defined(USE_FIXEDPOINT)
+    return FixedPoint::floor(x);
+#elif defined(USE_FLOAT)
+    return (int)floorf(x);
+#elif defined(__GNUC__) && defined(__i386__)
+    // floor() and (int)() are implemented separately, which results
+    // in changing the FPCW multiple times - so we optimize it with
+    // some inline assembly
+    Gushort oldCW, newCW, t;
+    int result;
+
+    __asm__ volatile("fldl   %4\n"
+		   "fnstcw %0\n"
+		   "movw   %0, %3\n"
+		   "andw   $0xf3ff, %3\n"
+		   "orw    $0x0400, %3\n"
+		   "movw   %3, %1\n"       // round down
+		   "fldcw  %1\n"
+		   "fistpl %2\n"
+		   "fldcw  %0\n"
+		   : "=m" (oldCW), "=m" (newCW), "=m" (result), "=r" (t)
+		   : "m" (x));
+    return result;
+#elif defined(_WIN32) && defined(_M_IX86)
+    // floor() and (int)() are implemented separately, which results
+    // in changing the FPCW multiple times - so we optimize it with
+    // some inline assembly
+    Gushort oldCW, newCW;
+    int result;
+
+    __asm fld QWORD PTR x
+    __asm fnstcw WORD PTR oldCW
+    __asm mov ax, WORD PTR oldCW
+    __asm and ax, 0xf3ff
+    __asm or ax, 0x0400
+    __asm mov WORD PTR newCW, ax     // round down
+    __asm fldcw WORD PTR newCW
+    __asm fistp DWORD PTR result
+    __asm fldcw WORD PTR oldCW
+    return result;
+#else
+    if (x > 0) return (int)x;
+    else return (int)floor(x);
+#endif
+}
+
+static inline int splashCeil(SplashCoord x) {
+#if defined(USE_FIXEDPOINT)
+  return FixedPoint::ceil(x);
+#elif defined(USE_FLOAT)
+  return (int)ceilf(x);
+#elif defined(__GNUC__) && defined(__i386__)
+  // ceil() and (int)() are implemented separately, which results
+  // in changing the FPCW multiple times - so we optimize it with
+  // some inline assembly
+  Gushort oldCW, newCW, t;
+  int result;
+
+  __asm__ volatile("fldl   %4\n"
+		   "fnstcw %0\n"
+		   "movw   %0, %3\n"
+		   "andw   $0xf3ff, %3\n"
+		   "orw    $0x0800, %3\n"
+		   "movw   %3, %1\n"       // round up
+		   "fldcw  %1\n"
+		   "fistpl %2\n"
+		   "fldcw  %0\n"
+		   : "=m" (oldCW), "=m" (newCW), "=m" (result), "=r" (t)
+		   : "m" (x));
+  return result;
+#elif defined(_WIN32) && defined(_M_IX86)
+  // ceil() and (int)() are implemented separately, which results
+  // in changing the FPCW multiple times - so we optimize it with
+  // some inline assembly
+  Gushort oldCW, newCW;
+  int result;
+
+  __asm fld QWORD PTR x
+  __asm fnstcw WORD PTR oldCW
+  __asm mov ax, WORD PTR oldCW
+  __asm and ax, 0xf3ff
+  __asm or ax, 0x0800
+  __asm mov WORD PTR newCW, ax     // round up
+  __asm fldcw WORD PTR newCW
+  __asm fistp DWORD PTR result
+  __asm fldcw WORD PTR oldCW
+  return result;
+#else
+  return (int)ceil(x);
+#endif
+}
+
+static inline int splashRound(SplashCoord x) {
+#if defined(USE_FIXEDPOINT)
+  return FixedPoint::round(x);
+#elif defined(__GNUC__) && defined(__i386__)
+  // this could use round-to-nearest mode and avoid the "+0.5",
+  // but that produces slightly different results (because i+0.5
+  // sometimes rounds up and sometimes down using the even rule)
+  Gushort oldCW, newCW, t;
+  int result;
+
+  x += 0.5;
+  __asm__ volatile("fldl   %4\n"
+		   "fnstcw %0\n"
+		   "movw   %0, %3\n"
+		   "andw   $0xf3ff, %3\n"
+		   "orw    $0x0400, %3\n"
+		   "movw   %3, %1\n"       // round down
+		   "fldcw  %1\n"
+		   "fistpl %2\n"
+		   "fldcw  %0\n"
+		   : "=m" (oldCW), "=m" (newCW), "=m" (result), "=r" (t)
+		   : "m" (x));
+  return result;
+#elif defined(_WIN32) && defined(_M_IX86)
+  // this could use round-to-nearest mode and avoid the "+0.5",
+  // but that produces slightly different results (because i+0.5
+  // sometimes rounds up and sometimes down using the even rule)
+  Gushort oldCW, newCW;
+  int result;
+
+  x += 0.5;
+  __asm fld QWORD PTR x
+  __asm fnstcw WORD PTR oldCW
+  __asm mov ax, WORD PTR oldCW
+  __asm and ax, 0xf3ff
+  __asm or ax, 0x0400
+  __asm mov WORD PTR newCW, ax     // round down
+  __asm fldcw WORD PTR newCW
+  __asm fistp DWORD PTR result
+  __asm fldcw WORD PTR oldCW
+  return result;
+#else
+  return (int)splashFloor(x + 0.5);
+#endif
+}
+
+static inline SplashCoord splashAvg(SplashCoord x, SplashCoord y) {
+#ifdef USE_FIXEDPOINT
+  return FixedPoint::avg(x, y);
+#else
+  return 0.5 * (x + y);
+#endif
+}
+ 
+static inline SplashCoord splashSqrt(SplashCoord x) {
+#if defined(USE_FIXEDPOINT)
+  return FixedPoint::sqrt(x);
+#elif defined(USE_FLOAT)
+  return sqrtf(x);
+#else
+  return sqrt(x);
+#endif
+}
+
+static inline SplashCoord splashPow(SplashCoord x, SplashCoord y) {
+#if defined(USE_FIXEDPOINT)
+  return FixedPoint::pow(x, y);
+#elif defined(USE_FLOAT)
+  return powf(x, y);
+#else
+  return pow(x, y);
+#endif
+}
+
+static inline SplashCoord splashDist(SplashCoord x0, SplashCoord y0,
+				     SplashCoord x1, SplashCoord y1) {
+  SplashCoord dx, dy;
+  dx = x1 - x0;
+  dy = y1 - y0;
+#ifdef USE_FIXEDPOINT
+  // this handles the situation where dx*dx or dy*dy is too large to
+  // fit in the 16.16 fixed point format
+  SplashCoord dxa, dya, d;
+  dxa = splashAbs(dx);
+  dya = splashAbs(dy);
+  if (dxa == 0 && dya == 0) {
+    return 0;
+  } else if (dxa > dya) {
+    d = dya / dxa;
+    return dxa * FixedPoint::sqrt(d*d + 1);
+  } else {
+    d = dxa / dya;
+    return dya * FixedPoint::sqrt(d*d + 1);
+  }
+#else
+  return splashSqrt(dx * dx + dy * dy);
+#endif
+}
+
+static inline GBool splashCheckDet(SplashCoord m11, SplashCoord m12,
+				   SplashCoord m21, SplashCoord m22,
+				   SplashCoord epsilon) {
+#ifdef USE_FIXEDPOINT
+  return FixedPoint::checkDet(m11, m12, m21, m22, epsilon);
+#else
+  return fabs(m11 * m22 - m12 * m21) >= epsilon;
+#endif
+}
+
+#endif
diff --git a/source/libs/poppler/poppler-src/splash/SplashPath.cc b/source/libs/poppler/poppler-src/splash/SplashPath.cc
new file mode 100644
index 0000000000000000000000000000000000000000..bc4ccd524a49c1003098110ec1eea93c7e79451d
--- /dev/null
+++ b/source/libs/poppler/poppler-src/splash/SplashPath.cc
@@ -0,0 +1,185 @@
+//========================================================================
+//
+// SplashPath.cc
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <string.h>
+#include "goo/gmem.h"
+#include "SplashErrorCodes.h"
+#include "SplashPath.h"
+
+//------------------------------------------------------------------------
+// SplashPath
+//------------------------------------------------------------------------
+
+// A path can be in three possible states:
+//
+// 1. no current point -- zero or more finished subpaths
+//    [curSubpath == length]
+//
+// 2. one point in subpath
+//    [curSubpath == length - 1]
+//
+// 3. open subpath with two or more points
+//    [curSubpath < length - 1]
+
+SplashPath::SplashPath() {
+  pts = NULL;
+  flags = NULL;
+  length = size = 0;
+  curSubpath = 0;
+  hints = NULL;
+  hintsLength = hintsSize = 0;
+}
+
+SplashPath::SplashPath(SplashPath *path) {
+  length = path->length;
+  size = path->size;
+  pts = (SplashPathPoint *)gmallocn(size, sizeof(SplashPathPoint));
+  flags = (Guchar *)gmallocn(size, sizeof(Guchar));
+  memcpy(pts, path->pts, length * sizeof(SplashPathPoint));
+  memcpy(flags, path->flags, length * sizeof(Guchar));
+  curSubpath = path->curSubpath;
+  if (path->hints) {
+    hintsLength = hintsSize = path->hintsLength;
+    hints = (SplashPathHint *)gmallocn(hintsSize, sizeof(SplashPathHint));
+    memcpy(hints, path->hints, hintsLength * sizeof(SplashPathHint));
+  } else {
+    hints = NULL;
+  }
+}
+
+SplashPath::~SplashPath() {
+  gfree(pts);
+  gfree(flags);
+  gfree(hints);
+}
+
+// Add space for <nPts> more points.
+void SplashPath::grow(int nPts) {
+  if (length + nPts > size) {
+    if (size == 0) {
+      size = 32;
+    }
+    while (size < length + nPts) {
+      size *= 2;
+    }
+    pts = (SplashPathPoint *)greallocn(pts, size, sizeof(SplashPathPoint));
+    flags = (Guchar *)greallocn(flags, size, sizeof(Guchar));
+  }
+}
+
+void SplashPath::append(SplashPath *path) {
+  int i;
+
+  curSubpath = length + path->curSubpath;
+  grow(path->length);
+  for (i = 0; i < path->length; ++i) {
+    pts[length] = path->pts[i];
+    flags[length] = path->flags[i];
+    ++length;
+  }
+}
+
+SplashError SplashPath::moveTo(SplashCoord x, SplashCoord y) {
+  if (onePointSubpath()) {
+    return splashErrBogusPath;
+  }
+  grow(1);
+  pts[length].x = x;
+  pts[length].y = y;
+  flags[length] = splashPathFirst | splashPathLast;
+  curSubpath = length++;
+  return splashOk;
+}
+
+SplashError SplashPath::lineTo(SplashCoord x, SplashCoord y) {
+  if (noCurrentPoint()) {
+    return splashErrNoCurPt;
+  }
+  flags[length-1] &= ~splashPathLast;
+  grow(1);
+  pts[length].x = x;
+  pts[length].y = y;
+  flags[length] = splashPathLast;
+  ++length;
+  return splashOk;
+}
+
+SplashError SplashPath::curveTo(SplashCoord x1, SplashCoord y1,
+				SplashCoord x2, SplashCoord y2,
+				SplashCoord x3, SplashCoord y3) {
+  if (noCurrentPoint()) {
+    return splashErrNoCurPt;
+  }
+  flags[length-1] &= ~splashPathLast;
+  grow(3);
+  pts[length].x = x1;
+  pts[length].y = y1;
+  flags[length] = splashPathCurve;
+  ++length;
+  pts[length].x = x2;
+  pts[length].y = y2;
+  flags[length] = splashPathCurve;
+  ++length;
+  pts[length].x = x3;
+  pts[length].y = y3;
+  flags[length] = splashPathLast;
+  ++length;
+  return splashOk;
+}
+
+SplashError SplashPath::close(GBool force) {
+  if (noCurrentPoint()) {
+    return splashErrNoCurPt;
+  }
+  if (force ||
+      curSubpath == length - 1 ||
+      pts[length - 1].x != pts[curSubpath].x ||
+      pts[length - 1].y != pts[curSubpath].y) {
+    lineTo(pts[curSubpath].x, pts[curSubpath].y);
+  }
+  flags[curSubpath] |= splashPathClosed;
+  flags[length - 1] |= splashPathClosed;
+  curSubpath = length;
+  return splashOk;
+}
+
+void SplashPath::addStrokeAdjustHint(int ctrl0, int ctrl1,
+				     int firstPt, int lastPt) {
+  if (hintsLength == hintsSize) {
+    hintsSize = hintsLength ? 2 * hintsLength : 8;
+    hints = (SplashPathHint *)greallocn(hints, hintsSize,
+					sizeof(SplashPathHint));
+  }
+  hints[hintsLength].ctrl0 = ctrl0;
+  hints[hintsLength].ctrl1 = ctrl1;
+  hints[hintsLength].firstPt = firstPt;
+  hints[hintsLength].lastPt = lastPt;
+  ++hintsLength;
+}
+
+void SplashPath::offset(SplashCoord dx, SplashCoord dy) {
+  int i;
+
+  for (i = 0; i < length; ++i) {
+    pts[i].x += dx;
+    pts[i].y += dy;
+  }
+}
+
+GBool SplashPath::getCurPt(SplashCoord *x, SplashCoord *y) {
+  if (noCurrentPoint()) {
+    return gFalse;
+  }
+  *x = pts[length - 1].x;
+  *y = pts[length - 1].y;
+  return gTrue;
+}
diff --git a/source/libs/poppler/poppler-src/splash/SplashPath.h b/source/libs/poppler/poppler-src/splash/SplashPath.h
new file mode 100644
index 0000000000000000000000000000000000000000..81273c613e57bc432d78d0ea26e69585ee521fbc
--- /dev/null
+++ b/source/libs/poppler/poppler-src/splash/SplashPath.h
@@ -0,0 +1,123 @@
+//========================================================================
+//
+// SplashPath.h
+//
+//========================================================================
+
+#ifndef SPLASHPATH_H
+#define SPLASHPATH_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "SplashTypes.h"
+
+//------------------------------------------------------------------------
+// SplashPathPoint
+//------------------------------------------------------------------------
+
+struct SplashPathPoint {
+  SplashCoord x, y;
+};
+
+//------------------------------------------------------------------------
+// SplashPath.flags
+//------------------------------------------------------------------------
+
+// first point on each subpath sets this flag
+#define splashPathFirst         0x01
+
+// last point on each subpath sets this flag
+#define splashPathLast          0x02
+
+// if the subpath is closed, its first and last points must be
+// identical, and must set this flag
+#define splashPathClosed        0x04
+
+// curve control points set this flag
+#define splashPathCurve         0x08
+
+//------------------------------------------------------------------------
+// SplashPathHint
+//------------------------------------------------------------------------
+
+struct SplashPathHint {
+  int ctrl0, ctrl1;
+  int firstPt, lastPt;
+};
+
+//------------------------------------------------------------------------
+// SplashPath
+//------------------------------------------------------------------------
+
+class SplashPath {
+public:
+
+  // Create an empty path.
+  SplashPath();
+
+  // Copy a path.
+  SplashPath *copy() { return new SplashPath(this); }
+
+  ~SplashPath();
+
+  // Append <path> to <this>.
+  void append(SplashPath *path);
+
+  // Start a new subpath.
+  SplashError moveTo(SplashCoord x, SplashCoord y);
+
+  // Add a line segment to the last subpath.
+  SplashError lineTo(SplashCoord x, SplashCoord y);
+
+  // Add a third-order (cubic) Bezier curve segment to the last
+  // subpath.
+  SplashError curveTo(SplashCoord x1, SplashCoord y1,
+		      SplashCoord x2, SplashCoord y2,
+		      SplashCoord x3, SplashCoord y3);
+
+  // Close the last subpath, adding a line segment if necessary.  If
+  // <force> is true, this adds a line segment even if the current
+  // point is equal to the first point in the subpath.
+  SplashError close(GBool force = gFalse);
+
+  // Add a stroke adjustment hint.  The controlling segments are
+  // <ctrl0> and <ctrl1> (where segments are identified by their first
+  // point), and the points to be adjusted are <firstPt> .. <lastPt>.
+  void addStrokeAdjustHint(int ctrl0, int ctrl1, int firstPt, int lastPt);
+
+  // Add (<dx>, <dy>) to every point on this path.
+  void offset(SplashCoord dx, SplashCoord dy);
+
+  // Get the points on the path.
+  int getLength() { return length; }
+  void getPoint(int i, double *x, double *y, Guchar *f)
+    { *x = pts[i].x; *y = pts[i].y; *f = flags[i]; }
+
+  // Get the current point.
+  GBool getCurPt(SplashCoord *x, SplashCoord *y);
+
+protected:
+
+  SplashPath(SplashPath *path);
+  void grow(int nPts);
+  GBool noCurrentPoint() { return curSubpath == length; }
+  GBool onePointSubpath() { return curSubpath == length - 1; }
+  GBool openSubpath() { return curSubpath < length - 1; }
+
+  SplashPathPoint *pts;		// array of points
+  Guchar *flags;		// array of flags
+  int length, size;		// length/size of the pts and flags arrays
+  int curSubpath;		// index of first point in last subpath
+
+  SplashPathHint *hints;	// list of hints
+  int hintsLength, hintsSize;
+
+  friend class SplashXPath;
+  friend class Splash;
+  // this is a temporary hack, until we read FreeType paths directly
+  friend class ArthurOutputDev;
+};
+
+#endif
diff --git a/source/libs/poppler/poppler-src/splash/SplashPattern.cc b/source/libs/poppler/poppler-src/splash/SplashPattern.cc
new file mode 100644
index 0000000000000000000000000000000000000000..28ca4995882a51f4e92674983c855a9c0e412ec3
--- /dev/null
+++ b/source/libs/poppler/poppler-src/splash/SplashPattern.cc
@@ -0,0 +1,55 @@
+//========================================================================
+//
+// SplashPattern.cc
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2010, 2011 Thomas Freitag <Thomas.Freitag@alfa.de>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include "SplashMath.h"
+#include "SplashScreen.h"
+#include "SplashPattern.h"
+
+//------------------------------------------------------------------------
+// SplashPattern
+//------------------------------------------------------------------------
+
+SplashPattern::SplashPattern() {
+}
+
+SplashPattern::~SplashPattern() {
+}
+
+//------------------------------------------------------------------------
+// SplashSolidColor
+//------------------------------------------------------------------------
+
+SplashSolidColor::SplashSolidColor(SplashColorPtr colorA) {
+  splashColorCopy(color, colorA);
+}
+
+SplashSolidColor::~SplashSolidColor() {
+}
+
+GBool SplashSolidColor::getColor(int x, int y, SplashColorPtr c) {
+  splashColorCopy(c, color);
+  return gTrue;
+}
diff --git a/source/libs/poppler/poppler-src/splash/SplashPattern.h b/source/libs/poppler/poppler-src/splash/SplashPattern.h
new file mode 100644
index 0000000000000000000000000000000000000000..1e2881c812e748b254729959ea875ca4a8a502c8
--- /dev/null
+++ b/source/libs/poppler/poppler-src/splash/SplashPattern.h
@@ -0,0 +1,104 @@
+//========================================================================
+//
+// SplashPattern.h
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2010, 2011, 2014 Thomas Freitag <Thomas.Freitag@alfa.de>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef SPLASHPATTERN_H
+#define SPLASHPATTERN_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "SplashTypes.h"
+
+class SplashScreen;
+
+//------------------------------------------------------------------------
+// SplashPattern
+//------------------------------------------------------------------------
+
+class SplashPattern {
+public:
+
+  SplashPattern();
+
+  virtual SplashPattern *copy() = 0;
+
+  virtual ~SplashPattern();
+
+  // Return the color value for a specific pixel.
+  virtual GBool getColor(int x, int y, SplashColorPtr c) = 0;
+
+  // Test if x,y-position is inside pattern.
+  virtual GBool testPosition(int x, int y) = 0;
+
+  // Returns true if this pattern object will return the same color
+  // value for all pixels.
+  virtual GBool isStatic() = 0;
+
+  // Returns true if this pattern colorspace is CMYK.
+  virtual GBool isCMYK() = 0;
+private:
+};
+
+//------------------------------------------------------------------------
+// SplashSolidColor
+//------------------------------------------------------------------------
+
+class SplashSolidColor: public SplashPattern {
+public:
+
+  SplashSolidColor(SplashColorPtr colorA);
+
+  SplashPattern *copy() override { return new SplashSolidColor(color); }
+
+  ~SplashSolidColor();
+
+  GBool getColor(int x, int y, SplashColorPtr c) override;
+
+  GBool testPosition(int x, int y) override { return gFalse; }
+
+  GBool isStatic() override { return gTrue; }
+
+  GBool isCMYK() override { return gFalse; }
+
+private:
+
+  SplashColor color;
+};
+
+//------------------------------------------------------------------------
+// SplashGouraudColor (needed for gouraudTriangleShadedFill)
+//------------------------------------------------------------------------
+
+class SplashGouraudColor: public SplashPattern {
+public:
+
+  virtual GBool isParameterized() = 0;
+
+  virtual int getNTriangles() = 0;
+
+  virtual  void getTriangle(int i, double *x0, double *y0, double *color0,
+                            double *x1, double *y1, double *color1,
+                            double *x2, double *y2, double *color2) = 0;
+
+  virtual void getParameterizedColor(double t, SplashColorMode mode, SplashColorPtr c) = 0;
+};
+
+#endif
diff --git a/source/libs/poppler/poppler-src/splash/SplashScreen.cc b/source/libs/poppler/poppler-src/splash/SplashScreen.cc
new file mode 100644
index 0000000000000000000000000000000000000000..28b1e7997e266ccefc94be6c4a22ab2dabb76c8b
--- /dev/null
+++ b/source/libs/poppler/poppler-src/splash/SplashScreen.cc
@@ -0,0 +1,390 @@
+//========================================================================
+//
+// SplashScreen.cc
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2009, 2016 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <algorithm>
+#include "goo/gmem.h"
+#include "goo/grandom.h"
+#include "goo/GooLikely.h"
+#include "SplashMath.h"
+#include "SplashScreen.h"
+
+static SplashScreenParams defaultParams = {
+  splashScreenDispersed,	// type
+  2,				// size
+  2,				// dotRadius
+  1.0,				// gamma
+  0.0,				// blackThreshold
+  1.0				// whiteThreshold
+};
+
+//------------------------------------------------------------------------
+
+struct SplashScreenPoint {
+  int x, y;
+  int dist;
+};
+
+
+struct cmpDistancesFunctor {
+  bool operator()(const SplashScreenPoint &p0, const SplashScreenPoint &p1) {
+    return p0.dist < p1.dist;
+  }
+};
+
+//------------------------------------------------------------------------
+// SplashScreen
+//------------------------------------------------------------------------
+
+// If <clustered> is true, this generates a 45 degree screen using a
+// circular dot spot function.  DPI = resolution / ((size / 2) *
+// sqrt(2)).  If <clustered> is false, this generates an optimal
+// threshold matrix using recursive tesselation.  Gamma correction
+// (gamma = 1 / 1.33) is also computed here.
+SplashScreen::SplashScreen(SplashScreenParams *params) {
+
+  if (!params) {
+    params = &defaultParams;
+  }
+  
+  screenParams = params;
+  mat = NULL;
+  size = 0;
+  maxVal = 0;
+  minVal = 0;
+}
+
+void SplashScreen::createMatrix()
+{
+  Guchar u;
+  int black, white, i;
+  
+  SplashScreenParams *params = screenParams;
+
+  // size must be a power of 2, and at least 2
+  for (size = 2, log2Size = 1; size < params->size; size <<= 1, ++log2Size) ;
+
+  switch (params->type) {
+
+  case splashScreenDispersed:
+    mat = (Guchar *)gmallocn(size * size, sizeof(Guchar));
+    buildDispersedMatrix(size/2, size/2, 1, size/2, 1);
+    break;
+
+  case splashScreenClustered:
+    mat = (Guchar *)gmallocn(size * size, sizeof(Guchar));
+    buildClusteredMatrix();
+    break;
+
+  case splashScreenStochasticClustered:
+    // size must be at least 2*r
+    while (size < (params->dotRadius << 1)) {
+      size <<= 1;
+      ++log2Size;
+    }
+    mat = (Guchar *)gmallocn(size * size, sizeof(Guchar));
+    buildSCDMatrix(params->dotRadius);
+    break;
+  }
+  
+  sizeM1 = size - 1;
+
+  // do gamma correction and compute minVal/maxVal
+  minVal = 255;
+  maxVal = 0;
+  black = splashRound((SplashCoord)255.0 * params->blackThreshold);
+  if (black < 1) {
+    black = 1;
+  }
+  int whiteAux = splashRound((SplashCoord)255.0 * params->whiteThreshold);
+  if (whiteAux > 255) {
+    white = 255;
+  } else {
+    white = whiteAux;
+  }
+   for (i = 0; i < size * size; ++i) {
+    u = splashRound((SplashCoord)255.0 *
+		    splashPow((SplashCoord)mat[i] / 255.0, params->gamma));
+    if (u < black) {
+      u = (Guchar)black;
+    } else if (u >= white) {
+      u = (Guchar)white;
+    }
+    mat[i] = u;
+    if (u < minVal) {
+      minVal = u;
+    } else if (u > maxVal) {
+      maxVal = u;
+    }
+  }
+}
+
+void SplashScreen::buildDispersedMatrix(int i, int j, int val,
+					int delta, int offset) {
+  if (delta == 0) {
+    // map values in [1, size^2] --> [1, 255]
+    mat[(i << log2Size) + j] = 1 + (254 * (val - 1)) / (size * size - 1);
+  } else {
+    buildDispersedMatrix(i, j,
+			 val, delta / 2, 4*offset);
+    buildDispersedMatrix((i + delta) % size, (j + delta) % size,
+			 val + offset, delta / 2, 4*offset);
+    buildDispersedMatrix((i + delta) % size, j,
+			 val + 2*offset, delta / 2, 4*offset);
+    buildDispersedMatrix((i + 2*delta) % size, (j + delta) % size,
+			 val + 3*offset, delta / 2, 4*offset);
+  }
+}
+
+void SplashScreen::buildClusteredMatrix() {
+  SplashCoord *dist;
+  SplashCoord u, v, d;
+  Guchar val;
+  int size2, x, y, x1, y1, i;
+
+  size2 = size >> 1;
+
+  // initialize the threshold matrix
+  for (y = 0; y < size; ++y) {
+    for (x = 0; x < size; ++x) {
+      mat[(y << log2Size) + x] = 0;
+    }
+  }
+
+  // build the distance matrix
+  dist = (SplashCoord *)gmallocn(size * size2, sizeof(SplashCoord));
+  for (y = 0; y < size2; ++y) {
+    for (x = 0; x < size2; ++x) {
+      if (x + y < size2 - 1) {
+	u = (SplashCoord)x + 0.5 - 0;
+	v = (SplashCoord)y + 0.5 - 0;
+      } else {
+	u = (SplashCoord)x + 0.5 - (SplashCoord)size2;
+	v = (SplashCoord)y + 0.5 - (SplashCoord)size2;
+      }
+      dist[y * size2 + x] = u*u + v*v;
+    }
+  }
+  for (y = 0; y < size2; ++y) {
+    for (x = 0; x < size2; ++x) {
+      if (x < y) {
+	u = (SplashCoord)x + 0.5 - 0;
+	v = (SplashCoord)y + 0.5 - (SplashCoord)size2;
+      } else {
+	u = (SplashCoord)x + 0.5 - (SplashCoord)size2;
+	v = (SplashCoord)y + 0.5 - 0;
+      }
+      dist[(size2 + y) * size2 + x] = u*u + v*v;
+    }
+  }
+
+  // build the threshold matrix
+  x1 = y1 = 0; // make gcc happy
+  for (i = 0; i < size * size2; ++i) {
+    d = -1;
+    for (y = 0; y < size; ++y) {
+      for (x = 0; x < size2; ++x) {
+	if (mat[(y << log2Size) + x] == 0 &&
+	    dist[y * size2 + x] > d) {
+	  x1 = x;
+	  y1 = y;
+	  d = dist[y1 * size2 + x1];
+	}
+      }
+    }
+    // map values in [0, 2*size*size2-1] --> [1, 255]
+    val = 1 + (254 * (2*i)) / (2*size*size2 - 1);
+    mat[(y1 << log2Size) + x1] = val;
+    val = 1 + (254 * (2*i+1)) / (2*size*size2 - 1);
+    if (y1 < size2) {
+      mat[((y1 + size2) << log2Size) + x1 + size2] = val;
+    } else {
+      mat[((y1 - size2) << log2Size) + x1 + size2] = val;
+    }
+  }
+
+  gfree(dist);
+}
+
+// Compute the distance between two points on a toroid.
+int SplashScreen::distance(int x0, int y0, int x1, int y1) {
+  int dx0, dx1, dx, dy0, dy1, dy;
+
+  dx0 = abs(x0 - x1);
+  dx1 = size - dx0;
+  dx = dx0 < dx1 ? dx0 : dx1;
+  dy0 = abs(y0 - y1);
+  dy1 = size - dy0;
+  dy = dy0 < dy1 ? dy0 : dy1;
+  return dx * dx + dy * dy;
+}
+
+// Algorithm taken from:
+// Victor Ostromoukhov and Roger D. Hersch, "Stochastic Clustered-Dot
+// Dithering" in Color Imaging: Device-Independent Color, Color
+// Hardcopy, and Graphic Arts IV, SPIE Vol. 3648, pp. 496-505, 1999.
+void SplashScreen::buildSCDMatrix(int r) {
+  SplashScreenPoint *dots, *pts;
+  int dotsLen, dotsSize;
+  char *tmpl;
+  char *grid;
+  int *region, *dist;
+  int x, y, xx, yy, x0, x1, y0, y1, i, j, d, iMin, dMin, n;
+
+  // generate the random space-filling curve
+  pts = (SplashScreenPoint *)gmallocn(size * size, sizeof(SplashScreenPoint));
+  i = 0;
+  for (y = 0; y < size; ++y) {
+    for (x = 0; x < size; ++x) {
+      pts[i].x = x;
+      pts[i].y = y;
+      ++i;
+    }
+  }
+  for (i = 0; i < size * size; ++i) {
+    j = i + (int)((double)(size * size - i) * grandom_double());
+    x = pts[i].x;
+    y = pts[i].y;
+    pts[i].x = pts[j].x;
+    pts[i].y = pts[j].y;
+    pts[j].x = x;
+    pts[j].y = y;
+  }
+
+  // construct the circle template
+  tmpl = (char *)gmallocn((r+1)*(r+1), sizeof(char));
+  for (y = 0; y <= r; ++y) {
+    for (x = 0; x <= r; ++x) {
+      tmpl[y*(r+1) + x] = (x * y <= r * r) ? 1 : 0;
+    }
+  }
+
+  // mark all grid cells as free
+  grid = (char *)gmallocn(size * size, sizeof(char));
+  for (y = 0; y < size; ++y) {
+    for (x = 0; x < size; ++x) {
+      grid[(y << log2Size) + x] = 0;
+    }
+  }
+
+  // walk the space-filling curve, adding dots
+  dotsLen = 0;
+  dotsSize = 32;
+  dots = (SplashScreenPoint *)gmallocn(dotsSize, sizeof(SplashScreenPoint));
+  for (i = 0; i < size * size; ++i) {
+    x = pts[i].x;
+    y = pts[i].y;
+    if (!grid[(y << log2Size) + x]) {
+      if (dotsLen == dotsSize) {
+	dotsSize *= 2;
+	dots = (SplashScreenPoint *)greallocn(dots, dotsSize,
+					      sizeof(SplashScreenPoint));
+      }
+      dots[dotsLen++] = pts[i];
+      for (yy = 0; yy <= r; ++yy) {
+	y0 = (y + yy) % size;
+	y1 = (y - yy + size) % size;
+	for (xx = 0; xx <= r; ++xx) {
+	  if (tmpl[yy*(r+1) + xx]) {
+	    x0 = (x + xx) % size;
+	    x1 = (x - xx + size) % size;
+	    grid[(y0 << log2Size) + x0] = 1;
+	    grid[(y0 << log2Size) + x1] = 1;
+	    grid[(y1 << log2Size) + x0] = 1;
+	    grid[(y1 << log2Size) + x1] = 1;
+	  }
+	}
+      }
+    }
+  }
+
+  gfree(tmpl);
+  gfree(grid);
+
+  // assign each cell to a dot, compute distance to center of dot
+  region = (int *)gmallocn(size * size, sizeof(int));
+  dist = (int *)gmallocn(size * size, sizeof(int));
+  for (y = 0; y < size; ++y) {
+    for (x = 0; x < size; ++x) {
+      iMin = 0;
+      dMin = distance(dots[0].x, dots[0].y, x, y);
+      for (i = 1; i < dotsLen; ++i) {
+	d = distance(dots[i].x, dots[i].y, x, y);
+	if (d < dMin) {
+	  iMin = i;
+	  dMin = d;
+	}
+      }
+      region[(y << log2Size) + x] = iMin;
+      dist[(y << log2Size) + x] = dMin;
+    }
+  }
+
+  // compute threshold values
+  for (i = 0; i < dotsLen; ++i) {
+    n = 0;
+    for (y = 0; y < size; ++y) {
+      for (x = 0; x < size; ++x) {
+	if (region[(y << log2Size) + x] == i) {
+	  pts[n].x = x;
+	  pts[n].y = y;
+	  pts[n].dist = distance(dots[i].x, dots[i].y, x, y);
+	  ++n;
+	}
+      }
+    }
+    std::sort(pts, pts + n, cmpDistancesFunctor());
+    for (j = 0; j < n; ++j) {
+      // map values in [0 .. n-1] --> [255 .. 1]
+      mat[(pts[j].y << log2Size) + pts[j].x] = 255 - (254 * j) / (n - 1);
+    }
+  }
+
+  gfree(pts);
+  gfree(region);
+  gfree(dist);
+
+  gfree(dots);
+}
+
+SplashScreen::SplashScreen(SplashScreen *screen) {
+  screenParams = screen->screenParams;
+  size = screen->size;
+  sizeM1 = screen->sizeM1;
+  log2Size = screen->log2Size;
+  mat = (Guchar *)gmallocn(size * size, sizeof(Guchar));
+  if (likely(mat != NULL)) {
+    memcpy(mat, screen->mat, size * size * sizeof(Guchar));
+  }
+  minVal = screen->minVal;
+  maxVal = screen->maxVal;
+}
+
+SplashScreen::~SplashScreen() {
+  gfree(mat);
+}
diff --git a/source/libs/poppler/poppler-src/splash/SplashScreen.h b/source/libs/poppler/poppler-src/splash/SplashScreen.h
new file mode 100644
index 0000000000000000000000000000000000000000..a7fc45591489ec686439af872671582c8fffda16
--- /dev/null
+++ b/source/libs/poppler/poppler-src/splash/SplashScreen.h
@@ -0,0 +1,80 @@
+//========================================================================
+//
+// SplashScreen.h
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2009 Albert Astals Cid <aacid@kde.org>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef SPLASHSCREEN_H
+#define SPLASHSCREEN_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "SplashTypes.h"
+
+#include <stdlib.h>
+
+//------------------------------------------------------------------------
+// SplashScreen
+//------------------------------------------------------------------------
+
+class SplashScreen {
+public:
+
+  SplashScreen(SplashScreenParams *params);
+  SplashScreen(SplashScreen *screen);
+  ~SplashScreen();
+
+  SplashScreen *copy() { return new SplashScreen(this); }
+
+  // Return the computed pixel value (0=black, 1=white) for the gray
+  // level <value> at (<x>, <y>).
+  int test(int x, int y, Guchar value) {
+    int xx, yy;
+    if (mat == NULL) createMatrix();
+    xx = x & sizeM1;
+    yy = y & sizeM1;
+    return value < mat[(yy << log2Size) + xx] ? 0 : 1;
+  }
+
+  // Returns true if value is above the white threshold or below the
+  // black threshold, i.e., if the corresponding halftone will be
+  // solid white or black.
+  GBool isStatic(Guchar value) { if (mat == NULL) createMatrix(); return value < minVal || value >= maxVal; }
+
+private:
+  void createMatrix();
+
+  void buildDispersedMatrix(int i, int j, int val,
+			    int delta, int offset);
+  void buildClusteredMatrix();
+  int distance(int x0, int y0, int x1, int y1);
+  void buildSCDMatrix(int r);
+
+  SplashScreenParams *screenParams;	// params to create the other members
+  Guchar *mat;			// threshold matrix
+  int size;			// size of the threshold matrix
+  int sizeM1;			// size - 1
+  int log2Size;			// log2(size)
+  Guchar minVal;		// any pixel value below minVal generates
+				//   solid black
+  Guchar maxVal;		// any pixel value above maxVal generates
+				//   solid white
+};
+
+#endif
diff --git a/source/libs/poppler/poppler-src/splash/SplashState.cc b/source/libs/poppler/poppler-src/splash/SplashState.cc
new file mode 100644
index 0000000000000000000000000000000000000000..abd940842ae2c06ac82ab4c80c0c98d01257f702
--- /dev/null
+++ b/source/libs/poppler/poppler-src/splash/SplashState.cc
@@ -0,0 +1,273 @@
+//========================================================================
+//
+// SplashState.cc
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2009, 2011, 2012, 2015 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2017 Adrian Johnson <ajohnson@redneon.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <string.h>
+#include "goo/gmem.h"
+#include "SplashPattern.h"
+#include "SplashScreen.h"
+#include "SplashClip.h"
+#include "SplashBitmap.h"
+#include "SplashState.h"
+
+//------------------------------------------------------------------------
+// SplashState
+//------------------------------------------------------------------------
+
+// number of components in each color mode
+int splashColorModeNComps[] = {
+  1, 1, 3, 3, 4
+#ifdef SPLASH_CMYK
+  , 4, 4 + SPOT_NCOMPS
+#endif
+};
+
+SplashState::SplashState(int width, int height, GBool vectorAntialias,
+			 SplashScreenParams *screenParams) {
+  SplashColor color;
+  int i;
+
+  matrix[0] = 1;  matrix[1] = 0;
+  matrix[2] = 0;  matrix[3] = 1;
+  matrix[4] = 0;  matrix[5] = 0;
+  memset(&color, 0, sizeof(SplashColor));
+  strokePattern = new SplashSolidColor(color);
+  fillPattern = new SplashSolidColor(color);
+  screen = new SplashScreen(screenParams);
+  blendFunc = NULL;
+  strokeAlpha = 1;
+  fillAlpha = 1;
+  multiplyPatternAlpha = gFalse;
+  patternStrokeAlpha = 1;
+  patternFillAlpha = 1;
+  lineWidth = 0;
+  lineCap = splashLineCapButt;
+  lineJoin = splashLineJoinMiter;
+  miterLimit = 10;
+  flatness = 1;
+  lineDash = NULL;
+  lineDashLength = 0;
+  lineDashPhase = 0;
+  strokeAdjust = gFalse;
+  clip = new SplashClip(0, 0, width - 0.001, height - 0.001, vectorAntialias);
+  softMask = NULL;
+  deleteSoftMask = gFalse;
+  inNonIsolatedGroup = gFalse;
+  fillOverprint = gFalse;
+  strokeOverprint = gFalse;
+  overprintMode = 0;	  
+  for (i = 0; i < 256; ++i) {
+    rgbTransferR[i] = (Guchar)i;
+    rgbTransferG[i] = (Guchar)i;
+    rgbTransferB[i] = (Guchar)i;
+    grayTransfer[i] = (Guchar)i;
+#ifdef SPLASH_CMYK
+    cmykTransferC[i] = (Guchar)i;
+    cmykTransferM[i] = (Guchar)i;
+    cmykTransferY[i] = (Guchar)i;
+    cmykTransferK[i] = (Guchar)i;
+    for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+      deviceNTransfer[cp][i] = (Guchar)i;
+#endif
+  }
+  overprintMask = 0xffffffff;
+  overprintAdditive = gFalse;
+  next = NULL;
+}
+
+SplashState::SplashState(int width, int height, GBool vectorAntialias,
+			 SplashScreen *screenA) {
+  SplashColor color;
+  int i;
+
+  matrix[0] = 1;  matrix[1] = 0;
+  matrix[2] = 0;  matrix[3] = 1;
+  matrix[4] = 0;  matrix[5] = 0;
+  memset(&color, 0, sizeof(SplashColor));
+  strokePattern = new SplashSolidColor(color);
+  fillPattern = new SplashSolidColor(color);
+  screen = screenA->copy();
+  blendFunc = NULL;
+  strokeAlpha = 1;
+  fillAlpha = 1;
+  multiplyPatternAlpha = gFalse;
+  patternStrokeAlpha = 1;
+  patternFillAlpha = 1;
+  lineWidth = 0;
+  lineCap = splashLineCapButt;
+  lineJoin = splashLineJoinMiter;
+  miterLimit = 10;
+  flatness = 1;
+  lineDash = NULL;
+  lineDashLength = 0;
+  lineDashPhase = 0;
+  strokeAdjust = gFalse;
+  clip = new SplashClip(0, 0, width - 0.001, height - 0.001, vectorAntialias);
+  softMask = NULL;
+  deleteSoftMask = gFalse;
+  inNonIsolatedGroup = gFalse;
+  fillOverprint = gFalse;
+  strokeOverprint = gFalse;
+  overprintMode = 0;	  
+  for (i = 0; i < 256; ++i) {
+    rgbTransferR[i] = (Guchar)i;
+    rgbTransferG[i] = (Guchar)i;
+    rgbTransferB[i] = (Guchar)i;
+    grayTransfer[i] = (Guchar)i;
+#ifdef SPLASH_CMYK
+    cmykTransferC[i] = (Guchar)i;
+    cmykTransferM[i] = (Guchar)i;
+    cmykTransferY[i] = (Guchar)i;
+    cmykTransferK[i] = (Guchar)i;
+    for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+      deviceNTransfer[cp][i] = (Guchar)i;
+#endif
+  }
+  overprintMask = 0xffffffff;
+  overprintAdditive = gFalse;
+  next = NULL;
+}
+
+SplashState::SplashState(SplashState *state) {
+  memcpy(matrix, state->matrix, 6 * sizeof(SplashCoord));
+  strokePattern = state->strokePattern->copy();
+  fillPattern = state->fillPattern->copy();
+  screen = state->screen->copy();
+  blendFunc = state->blendFunc;
+  strokeAlpha = state->strokeAlpha;
+  fillAlpha = state->fillAlpha;
+  multiplyPatternAlpha = state->multiplyPatternAlpha;
+  patternStrokeAlpha = state->patternStrokeAlpha;
+  patternFillAlpha = state->patternFillAlpha;
+  lineWidth = state->lineWidth;
+  lineCap = state->lineCap;
+  lineJoin = state->lineJoin;
+  miterLimit = state->miterLimit;
+  flatness = state->flatness;
+  if (state->lineDash) {
+    lineDashLength = state->lineDashLength;
+    lineDash = (SplashCoord *)gmallocn(lineDashLength, sizeof(SplashCoord));
+    memcpy(lineDash, state->lineDash, lineDashLength * sizeof(SplashCoord));
+  } else {
+    lineDash = NULL;
+    lineDashLength = 0;
+  }
+  lineDashPhase = state->lineDashPhase;
+  strokeAdjust = state->strokeAdjust;
+  clip = state->clip->copy();
+  softMask = state->softMask;
+  deleteSoftMask = gFalse;
+  inNonIsolatedGroup = state->inNonIsolatedGroup;
+  fillOverprint = state->fillOverprint;
+  strokeOverprint = state->strokeOverprint;
+  overprintMode = state->overprintMode;	  
+  memcpy(rgbTransferR, state->rgbTransferR, 256);
+  memcpy(rgbTransferG, state->rgbTransferG, 256);
+  memcpy(rgbTransferB, state->rgbTransferB, 256);
+  memcpy(grayTransfer, state->grayTransfer, 256);
+#ifdef SPLASH_CMYK
+  memcpy(cmykTransferC, state->cmykTransferC, 256);
+  memcpy(cmykTransferM, state->cmykTransferM, 256);
+  memcpy(cmykTransferY, state->cmykTransferY, 256);
+  memcpy(cmykTransferK, state->cmykTransferK, 256);
+  for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+    memcpy(deviceNTransfer[cp], state->deviceNTransfer[cp], 256);
+#endif
+  overprintMask = state->overprintMask;
+  overprintAdditive = state->overprintAdditive;
+  next = NULL;
+}
+
+SplashState::~SplashState() {
+  delete strokePattern;
+  delete fillPattern;
+  delete screen;
+  gfree(lineDash);
+  delete clip;
+  if (deleteSoftMask && softMask) {
+    delete softMask;
+  }
+}
+
+void SplashState::setStrokePattern(SplashPattern *strokePatternA) {
+  delete strokePattern;
+  strokePattern = strokePatternA;
+}
+
+void SplashState::setFillPattern(SplashPattern *fillPatternA) {
+  delete fillPattern;
+  fillPattern = fillPatternA;
+}
+
+void SplashState::setScreen(SplashScreen *screenA) {
+  delete screen;
+  screen = screenA;
+}
+
+void SplashState::setLineDash(SplashCoord *lineDashA, int lineDashLengthA,
+			      SplashCoord lineDashPhaseA) {
+  gfree(lineDash);
+  lineDashLength = lineDashLengthA;
+  if (lineDashLength > 0) {
+    lineDash = (SplashCoord *)gmallocn(lineDashLength, sizeof(SplashCoord));
+    memcpy(lineDash, lineDashA, lineDashLength * sizeof(SplashCoord));
+  } else {
+    lineDash = NULL;
+  }
+  lineDashPhase = lineDashPhaseA;
+}
+
+void SplashState::setSoftMask(SplashBitmap *softMaskA) {
+  if (deleteSoftMask) {
+    delete softMask;
+  }
+  softMask = softMaskA;
+  deleteSoftMask = gTrue;
+}
+
+void SplashState::setTransfer(Guchar *red, Guchar *green, Guchar *blue,
+			      Guchar *gray) {
+#ifdef SPLASH_CMYK
+  int i;
+
+  for (i = 0; i < 256; ++i) {
+    cmykTransferC[i] = 255 - rgbTransferR[255 - i];
+    cmykTransferM[i] = 255 - rgbTransferG[255 - i];
+    cmykTransferY[i] = 255 - rgbTransferB[255 - i];
+    cmykTransferK[i] = 255 - grayTransfer[255 - i];
+  }
+  for (i = 0; i < 256; ++i) {
+    deviceNTransfer[0][i] = 255 - rgbTransferR[255 - i];
+    deviceNTransfer[1][i] = 255 - rgbTransferG[255 - i];
+    deviceNTransfer[2][i] = 255 - rgbTransferB[255 - i];
+    deviceNTransfer[3][i] = 255 - grayTransfer[255 - i];
+  }
+#endif
+  memcpy(rgbTransferR, red, 256);
+  memcpy(rgbTransferG, green, 256);
+  memcpy(rgbTransferB, blue, 256);
+  memcpy(grayTransfer, gray, 256);
+}
diff --git a/source/libs/poppler/poppler-src/splash/SplashState.h b/source/libs/poppler/poppler-src/splash/SplashState.h
new file mode 100644
index 0000000000000000000000000000000000000000..32270382037b34a59e94984d3ed5138f2687dd38
--- /dev/null
+++ b/source/libs/poppler/poppler-src/splash/SplashState.h
@@ -0,0 +1,143 @@
+//========================================================================
+//
+// SplashState.h
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2011, 2012, 2015 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2017 Adrian Johnson <ajohnson@redneon.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef SPLASHSTATE_H
+#define SPLASHSTATE_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "SplashTypes.h"
+
+class SplashPattern;
+class SplashScreen;
+class SplashClip;
+class SplashBitmap;
+
+//------------------------------------------------------------------------
+// line cap values
+//------------------------------------------------------------------------
+
+#define splashLineCapButt       0
+#define splashLineCapRound      1
+#define splashLineCapProjecting 2
+
+//------------------------------------------------------------------------
+// line join values
+//------------------------------------------------------------------------
+
+#define splashLineJoinMiter     0
+#define splashLineJoinRound     1
+#define splashLineJoinBevel     2
+
+//------------------------------------------------------------------------
+// SplashState
+//------------------------------------------------------------------------
+
+class SplashState {
+public:
+
+  // Create a new state object, initialized with default settings.
+  SplashState(int width, int height, GBool vectorAntialias,
+	      SplashScreenParams *screenParams);
+  SplashState(int width, int height, GBool vectorAntialias,
+	      SplashScreen *screenA);
+
+  // Copy a state object.
+  SplashState *copy() { return new SplashState(this); }
+
+  ~SplashState();
+
+  // Set the stroke pattern.  This does not copy <strokePatternA>.
+  void setStrokePattern(SplashPattern *strokePatternA);
+
+  // Set the fill pattern.  This does not copy <fillPatternA>.
+  void setFillPattern(SplashPattern *fillPatternA);
+
+  // Set the screen.  This does not copy <screenA>.
+  void setScreen(SplashScreen *screenA);
+
+  // Set the line dash pattern.  This copies the <lineDashA> array.
+  void setLineDash(SplashCoord *lineDashA, int lineDashLengthA,
+		   SplashCoord lineDashPhaseA);
+
+  // Set the soft mask bitmap.
+  void setSoftMask(SplashBitmap *softMaskA);
+
+  // Set the overprint parametes.
+  void setFillOverprint(GBool fillOverprintA) { fillOverprint = fillOverprintA; }
+  void setStrokeOverprint(GBool strokeOverprintA) { strokeOverprint = strokeOverprintA; }
+  void setOverprintMode(int overprintModeA) { overprintMode = overprintModeA; }
+
+  // Set the transfer function.
+  void setTransfer(Guchar *red, Guchar *green, Guchar *blue, Guchar *gray);
+
+private:
+
+  SplashState(SplashState *state);
+
+  SplashCoord matrix[6];
+  SplashPattern *strokePattern;
+  SplashPattern *fillPattern;
+  SplashScreen *screen;
+  SplashBlendFunc blendFunc;
+  SplashCoord strokeAlpha;
+  SplashCoord fillAlpha;
+  GBool multiplyPatternAlpha;
+  SplashCoord patternStrokeAlpha;
+  SplashCoord patternFillAlpha;
+  SplashCoord lineWidth;
+  int lineCap;
+  int lineJoin;
+  SplashCoord miterLimit;
+  SplashCoord flatness;
+  SplashCoord *lineDash;
+  int lineDashLength;
+  SplashCoord lineDashPhase;
+  GBool strokeAdjust;
+  SplashClip *clip;
+  SplashBitmap *softMask;
+  GBool deleteSoftMask;
+  GBool inNonIsolatedGroup;
+  GBool fillOverprint;
+  GBool strokeOverprint;
+  int overprintMode;
+  Guchar rgbTransferR[256],
+         rgbTransferG[256],
+         rgbTransferB[256];
+  Guchar grayTransfer[256];
+#ifdef SPLASH_CMYK
+  Guchar cmykTransferC[256],
+         cmykTransferM[256],
+         cmykTransferY[256],
+         cmykTransferK[256];
+  Guchar deviceNTransfer[SPOT_NCOMPS+4][256];
+#endif
+  Guint overprintMask;
+  GBool overprintAdditive;
+
+  SplashState *next;		// used by Splash class
+
+  friend class Splash;
+};
+
+#endif
diff --git a/source/libs/poppler/poppler-src/splash/SplashXPath.cc b/source/libs/poppler/poppler-src/splash/SplashXPath.cc
new file mode 100644
index 0000000000000000000000000000000000000000..9c5c8813a2cd543038fc2987f5d35a58fa06d959
--- /dev/null
+++ b/source/libs/poppler/poppler-src/splash/SplashXPath.cc
@@ -0,0 +1,473 @@
+//========================================================================
+//
+// SplashXPath.cc
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2010 Paweł Wiejacha <pawel.wiejacha@gmail.com>
+// Copyright (C) 2010, 2011 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2017 Adrian Johnson <ajohnson@redneon.com>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <algorithm>
+#include "goo/gmem.h"
+#include "SplashMath.h"
+#include "SplashPath.h"
+#include "SplashXPath.h"
+
+//------------------------------------------------------------------------
+
+struct SplashXPathPoint {
+  SplashCoord x, y;
+};
+
+struct SplashXPathAdjust {
+  int firstPt, lastPt;		// range of points
+  GBool vert;			// vertical or horizontal hint
+  SplashCoord x0a, x0b,		// hint boundaries
+              xma, xmb,
+              x1a, x1b;
+  SplashCoord x0, x1, xm;	// adjusted coordinates
+};
+
+//------------------------------------------------------------------------
+
+// Transform a point from user space to device space.
+inline void SplashXPath::transform(SplashCoord *matrix,
+				   SplashCoord xi, SplashCoord yi,
+				   SplashCoord *xo, SplashCoord *yo) {
+  //                          [ m[0] m[1] 0 ]
+  // [xo yo 1] = [xi yi 1] *  [ m[2] m[3] 0 ]
+  //                          [ m[4] m[5] 1 ]
+  *xo = xi * matrix[0] + yi * matrix[2] + matrix[4];
+  *yo = xi * matrix[1] + yi * matrix[3] + matrix[5];
+}
+
+//------------------------------------------------------------------------
+// SplashXPath
+//------------------------------------------------------------------------
+
+SplashXPath::SplashXPath(SplashPath *path, SplashCoord *matrix,
+			 SplashCoord flatness, GBool closeSubpaths,
+			 GBool adjustLines, int linePosI) {
+  SplashPathHint *hint;
+  SplashXPathPoint *pts;
+  SplashXPathAdjust *adjusts, *adjust;
+  SplashCoord x0, y0, x1, y1, x2, y2, x3, y3, xsp, ysp;
+  SplashCoord adj0, adj1;
+  int curSubpath, i, j;
+
+  // transform the points
+  pts = (SplashXPathPoint *)gmallocn(path->length, sizeof(SplashXPathPoint));
+  for (i = 0; i < path->length; ++i) {
+    transform(matrix, path->pts[i].x, path->pts[i].y, &pts[i].x, &pts[i].y);
+  }
+
+  // set up the stroke adjustment hints
+  if (path->hints) {
+    adjusts = (SplashXPathAdjust *)gmallocn(path->hintsLength,
+					    sizeof(SplashXPathAdjust));
+    for (i = 0; i < path->hintsLength; ++i) {
+      hint = &path->hints[i];
+      if (hint->ctrl0 + 1 >= path->length || hint->ctrl1 + 1 >= path->length) {
+	gfree(adjusts);
+	adjusts = NULL;
+	break;
+      }
+      x0 = pts[hint->ctrl0    ].x;    y0 = pts[hint->ctrl0    ].y;
+      x1 = pts[hint->ctrl0 + 1].x;    y1 = pts[hint->ctrl0 + 1].y;
+      x2 = pts[hint->ctrl1    ].x;    y2 = pts[hint->ctrl1    ].y;
+      x3 = pts[hint->ctrl1 + 1].x;    y3 = pts[hint->ctrl1 + 1].y;
+      if (x0 == x1 && x2 == x3) {
+	adjusts[i].vert = gTrue;
+	adj0 = x0;
+	adj1 = x2;
+      } else if (y0 == y1 && y2 == y3) {
+	adjusts[i].vert = gFalse;
+	adj0 = y0;
+	adj1 = y2;
+      } else {
+	gfree(adjusts);
+	adjusts = NULL;
+	break;
+      }
+      if (adj0 > adj1) {
+	x0 = adj0;
+	adj0 = adj1;
+	adj1 = x0;
+      }
+      adjusts[i].x0a = adj0 - 0.01;
+      adjusts[i].x0b = adj0 + 0.01;
+      adjusts[i].xma = (SplashCoord)0.5 * (adj0 + adj1) - 0.01;
+      adjusts[i].xmb = (SplashCoord)0.5 * (adj0 + adj1) + 0.01;
+      adjusts[i].x1a = adj1 - 0.01;
+      adjusts[i].x1b = adj1 + 0.01;
+      // rounding both edge coordinates can result in lines of
+      // different widths (e.g., adj=10.1, adj1=11.3 --> x0=10, x1=11;
+      // adj0=10.4, adj1=11.6 --> x0=10, x1=12), but it has the
+      // benefit of making adjacent strokes/fills line up without any
+      // gaps between them
+      x0 = splashRound(adj0);
+      x1 = splashRound(adj1);
+      if (x1 == x0) {
+        if (adjustLines) {
+          // the adjustment moves thin lines (clip rectangle with
+          // empty width or height) out of clip area, here we need
+          // a special adjustment:
+          x0 = linePosI;
+          x1 = x0 + 1;
+        } else {
+          x1 = x1 + 1;
+        }
+      }
+      adjusts[i].x0 = (SplashCoord)x0;
+      adjusts[i].x1 = (SplashCoord)x1 - 0.01;
+      adjusts[i].xm = (SplashCoord)0.5 * (adjusts[i].x0 + adjusts[i].x1);
+      adjusts[i].firstPt = hint->firstPt;
+      adjusts[i].lastPt = hint->lastPt;
+    }
+
+  } else {
+    adjusts = NULL;
+  }
+
+  // perform stroke adjustment
+  if (adjusts) {
+    for (i = 0, adjust = adjusts; i < path->hintsLength; ++i, ++adjust) {
+      for (j = adjust->firstPt; j <= adjust->lastPt; ++j) {
+	strokeAdjust(adjust, &pts[j].x, &pts[j].y);
+      }
+    }
+    gfree(adjusts);
+  }
+
+  segs = NULL;
+  length = size = 0;
+
+  x0 = y0 = xsp = ysp = 0; // make gcc happy
+  adj0 = adj1 = 0; // make gcc happy
+  curSubpath = 0;
+  i = 0;
+  while (i < path->length) {
+
+    // first point in subpath - skip it
+    if (path->flags[i] & splashPathFirst) {
+      x0 = pts[i].x;
+      y0 = pts[i].y;
+      xsp = x0;
+      ysp = y0;
+      curSubpath = i;
+      ++i;
+
+    } else {
+
+      // curve segment
+      if (path->flags[i] & splashPathCurve) {
+	x1 = pts[i].x;
+	y1 = pts[i].y;
+	x2 = pts[i+1].x;
+	y2 = pts[i+1].y;
+	x3 = pts[i+2].x;
+	y3 = pts[i+2].y;
+	addCurve(x0, y0, x1, y1, x2, y2, x3, y3,
+		 flatness,
+		 (path->flags[i-1] & splashPathFirst),
+		 (path->flags[i+2] & splashPathLast),
+		 !closeSubpaths &&
+		   (path->flags[i-1] & splashPathFirst) &&
+		   !(path->flags[i-1] & splashPathClosed),
+		 !closeSubpaths &&
+		   (path->flags[i+2] & splashPathLast) &&
+		   !(path->flags[i+2] & splashPathClosed));
+	x0 = x3;
+	y0 = y3;
+	i += 3;
+
+      // line segment
+      } else {
+	x1 = pts[i].x;
+	y1 = pts[i].y;
+	addSegment(x0, y0, x1, y1);
+	x0 = x1;
+	y0 = y1;
+	++i;
+      }
+
+      // close a subpath
+      if (closeSubpaths &&
+	  (path->flags[i-1] & splashPathLast) &&
+	  (pts[i-1].x != pts[curSubpath].x ||
+	   pts[i-1].y != pts[curSubpath].y)) {
+	addSegment(x0, y0, xsp, ysp);
+      }
+    }
+  }
+
+  gfree(pts);
+}
+
+// Apply the stroke adjust hints to point <pt>: (*<xp>, *<yp>).
+void SplashXPath::strokeAdjust(SplashXPathAdjust *adjust,
+			       SplashCoord *xp, SplashCoord *yp) {
+  SplashCoord x, y;
+
+  if (adjust->vert) {
+    x = *xp;
+    if (x > adjust->x0a && x < adjust->x0b) {
+      *xp = adjust->x0;
+    } else if (x > adjust->xma && x < adjust->xmb) {
+      *xp = adjust->xm;
+    } else if (x > adjust->x1a && x < adjust->x1b) {
+      *xp = adjust->x1;
+    }
+  } else {
+    y = *yp;
+    if (y > adjust->x0a && y < adjust->x0b) {
+      *yp = adjust->x0;
+    } else if (y > adjust->xma && y < adjust->xmb) {
+      *yp = adjust->xm;
+    } else if (y > adjust->x1a && y < adjust->x1b) {
+      *yp = adjust->x1;
+    }
+  }
+}
+
+SplashXPath::SplashXPath(SplashXPath *xPath) {
+  length = xPath->length;
+  size = xPath->size;
+  segs = (SplashXPathSeg *)gmallocn(size, sizeof(SplashXPathSeg));
+  memcpy(segs, xPath->segs, length * sizeof(SplashXPathSeg));
+}
+
+SplashXPath::~SplashXPath() {
+  gfree(segs);
+}
+
+// Add space for <nSegs> more segments
+void SplashXPath::grow(int nSegs) {
+  if (length + nSegs > size) {
+    if (size == 0) {
+      size = 32;
+    }
+    while (size < length + nSegs) {
+      size *= 2;
+    }
+    segs = (SplashXPathSeg *)greallocn(segs, size, sizeof(SplashXPathSeg));
+  }
+}
+
+void SplashXPath::addCurve(SplashCoord x0, SplashCoord y0,
+			   SplashCoord x1, SplashCoord y1,
+			   SplashCoord x2, SplashCoord y2,
+			   SplashCoord x3, SplashCoord y3,
+			   SplashCoord flatness,
+			   GBool first, GBool last, GBool end0, GBool end1) {
+  SplashCoord *cx = new SplashCoord[(splashMaxCurveSplits + 1) * 3];
+  SplashCoord *cy = new SplashCoord[(splashMaxCurveSplits + 1) * 3];
+  int *cNext = new int[splashMaxCurveSplits + 1];
+  SplashCoord xl0, xl1, xl2, xr0, xr1, xr2, xr3, xx1, xx2, xh;
+  SplashCoord yl0, yl1, yl2, yr0, yr1, yr2, yr3, yy1, yy2, yh;
+  SplashCoord dx, dy, mx, my, d1, d2, flatness2;
+  int p1, p2, p3;
+
+#ifdef USE_FIXEDPOINT
+  flatness2 = flatness;
+#else
+  flatness2 = flatness * flatness;
+#endif
+
+  // initial segment
+  p1 = 0;
+  p2 = splashMaxCurveSplits;
+
+  *(cx + p1 * 3 + 0) = x0;
+  *(cx + p1 * 3 + 1) = x1;
+  *(cx + p1 * 3 + 2) = x2;
+  *(cx + p2 * 3 + 0) = x3;
+
+  *(cy + p1 * 3 + 0) = y0;
+  *(cy + p1 * 3 + 1) = y1;
+  *(cy + p1 * 3 + 2) = y2;
+  *(cy + p2 * 3 + 0) = y3;
+
+  *(cNext + p1) = p2;
+
+  while (p1 < splashMaxCurveSplits) {
+
+    // get the next segment
+    xl0 = *(cx + p1 * 3 + 0);
+    xx1 = *(cx + p1 * 3 + 1);
+    xx2 = *(cx + p1 * 3 + 2);
+
+    yl0 = *(cy + p1 * 3 + 0);
+    yy1 = *(cy + p1 * 3 + 1);
+    yy2 = *(cy + p1 * 3 + 2);
+
+    p2 = *(cNext + p1);
+
+    xr3 = *(cx + p2 * 3 + 0);
+    yr3 = *(cy + p2 * 3 + 0);
+
+    // compute the distances from the control points to the
+    // midpoint of the straight line (this is a bit of a hack, but
+    // it's much faster than computing the actual distances to the
+    // line)
+    mx = (xl0 + xr3) * 0.5;
+    my = (yl0 + yr3) * 0.5;
+#ifdef USE_FIXEDPOINT
+    d1 = splashDist(xx1, yy1, mx, my);
+    d2 = splashDist(xx2, yy2, mx, my);
+#else
+    dx = xx1 - mx;
+    dy = yy1 - my;
+    d1 = dx*dx + dy*dy;
+    dx = xx2 - mx;
+    dy = yy2 - my;
+    d2 = dx*dx + dy*dy;
+#endif    
+
+    // if the curve is flat enough, or no more subdivisions are
+    // allowed, add the straight line segment
+    if (p2 - p1 == 1 || (d1 <= flatness2 && d2 <= flatness2)) {
+      addSegment(xl0, yl0, xr3, yr3);
+      p1 = p2;
+
+    // otherwise, subdivide the curve
+    } else {
+      xl1 = (xl0 + xx1) * 0.5;
+      yl1 = (yl0 + yy1) * 0.5;
+      xh = (xx1 + xx2) * 0.5;
+      yh = (yy1 + yy2) * 0.5;
+      xl2 = (xl1 + xh) * 0.5;
+      yl2 = (yl1 + yh) * 0.5;
+      xr2 = (xx2 + xr3) * 0.5;
+      yr2 = (yy2 + yr3) * 0.5;
+      xr1 = (xh + xr2) * 0.5;
+      yr1 = (yh + yr2) * 0.5;
+      xr0 = (xl2 + xr1) * 0.5;
+      yr0 = (yl2 + yr1) * 0.5;
+      // add the new subdivision points
+      p3 = (p1 + p2) / 2;
+
+      *(cx + p1 * 3 + 1) = xl1;
+      *(cx + p1 * 3 + 2) = xl2;
+
+      *(cy + p1 * 3 + 1) = yl1;
+      *(cy + p1 * 3 + 2) = yl2;
+
+      *(cNext + p1) = p3;
+
+      *(cx + p3 * 3 + 0) = xr0;
+      *(cx + p3 * 3 + 1) = xr1;
+      *(cx + p3 * 3 + 2) = xr2;
+
+      *(cy + p3 * 3 + 0) = yr0;
+      *(cy + p3 * 3 + 1) = yr1;
+      *(cy + p3 * 3 + 2) = yr2;
+
+      *(cNext + p3) = p2;
+    }
+  }
+
+  delete [] cx;
+  delete [] cy;
+  delete [] cNext;
+}
+
+void SplashXPath::addSegment(SplashCoord x0, SplashCoord y0,
+			     SplashCoord x1, SplashCoord y1) {
+  grow(1);
+  segs[length].x0 = x0;
+  segs[length].y0 = y0;
+  segs[length].x1 = x1;
+  segs[length].y1 = y1;
+  segs[length].flags = 0;
+  if (y1 == y0) {
+    segs[length].dxdy = segs[length].dydx = 0;
+    segs[length].flags |= splashXPathHoriz;
+    if (x1 == x0) {
+      segs[length].flags |= splashXPathVert;
+    }
+  } else if (x1 == x0) {
+    segs[length].dxdy = segs[length].dydx = 0;
+    segs[length].flags |= splashXPathVert;
+  } else {
+#ifdef USE_FIXEDPOINT
+    if (FixedPoint::divCheck(x1 - x0, y1 - y0, &segs[length].dxdy)) {
+      segs[length].dydx = (SplashCoord)1 / segs[length].dxdy;
+    } else {
+      segs[length].dxdy = segs[length].dydx = 0;
+      if (splashAbs(x1 - x0) > splashAbs(y1 - y0)) {
+	segs[length].flags |= splashXPathHoriz;
+      } else {
+	segs[length].flags |= splashXPathVert;
+      }
+    }
+#else
+    segs[length].dxdy = (x1 - x0) / (y1 - y0);
+    segs[length].dydx = (SplashCoord)1 / segs[length].dxdy;
+#endif
+  }
+  if (y0 > y1) {
+    segs[length].flags |= splashXPathFlip;
+  }
+  ++length;
+}
+
+struct cmpXPathSegsFunctor {
+  bool operator()(const SplashXPathSeg &seg0, const SplashXPathSeg &seg1) {
+    SplashCoord x0, y0, x1, y1;
+
+    if (seg0.flags & splashXPathFlip) {
+      x0 = seg0.x1;
+      y0 = seg0.y1;
+    } else {
+      x0 = seg0.x0;
+      y0 = seg0.y0;
+    }
+    if (seg1.flags & splashXPathFlip) {
+      x1 = seg1.x1;
+      y1 = seg1.y1;
+    } else {
+      x1 = seg1.x0;
+      y1 = seg1.y0;
+    }
+    return (y0 != y1) ? (y0 < y1) : (x0 < x1);
+  }
+};
+
+void SplashXPath::aaScale() {
+  SplashXPathSeg *seg;
+  int i;
+
+  for (i = 0, seg = segs; i < length; ++i, ++seg) {
+    seg->x0 *= splashAASize;
+    seg->y0 *= splashAASize;
+    seg->x1 *= splashAASize;
+    seg->y1 *= splashAASize;
+  }
+}
+
+void SplashXPath::sort() {
+  std::sort(segs, segs + length, cmpXPathSegsFunctor());
+}
diff --git a/source/libs/poppler/poppler-src/splash/SplashXPath.h b/source/libs/poppler/poppler-src/splash/SplashXPath.h
new file mode 100644
index 0000000000000000000000000000000000000000..1c7040daa2309edab11ebfd4d7af8c283ebe5c2b
--- /dev/null
+++ b/source/libs/poppler/poppler-src/splash/SplashXPath.h
@@ -0,0 +1,107 @@
+//========================================================================
+//
+// SplashXPath.h
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef SPLASHXPATH_H
+#define SPLASHXPATH_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "SplashTypes.h"
+
+class SplashPath;
+struct SplashXPathAdjust;
+
+//------------------------------------------------------------------------
+
+#define splashMaxCurveSplits (1 << 10)
+
+//------------------------------------------------------------------------
+// SplashXPathSeg
+//------------------------------------------------------------------------
+
+struct SplashXPathSeg {
+  SplashCoord x0, y0;		// first endpoint
+  SplashCoord x1, y1;		// second endpoint
+  SplashCoord dxdy;		// slope: delta-x / delta-y
+  SplashCoord dydx;		// slope: delta-y / delta-x
+  Guint flags;
+};
+
+#define splashXPathHoriz   0x01 // segment is vertical (y0 == y1)
+				//   (dxdy is undef)
+#define splashXPathVert    0x02 // segment is horizontal (x0 == x1)
+				//   (dydx is undef)
+#define splashXPathFlip	   0x04	// y0 > y1
+
+//------------------------------------------------------------------------
+// SplashXPath
+//------------------------------------------------------------------------
+
+class SplashXPath {
+public:
+
+  // Expands (converts to segments) and flattens (converts curves to
+  // lines) <path>.  Transforms all points from user space to device
+  // space, via <matrix>.  If <closeSubpaths> is true, closes all open
+  // subpaths.
+  SplashXPath(SplashPath *path, SplashCoord *matrix,
+	      SplashCoord flatness, GBool closeSubpaths,
+	      GBool adjustLines = gFalse, int linePosI = 0);
+
+  // Copy an expanded path.
+  SplashXPath *copy() { return new SplashXPath(this); }
+
+  ~SplashXPath();
+
+  // Multiply all coordinates by splashAASize, in preparation for
+  // anti-aliased rendering.
+  void aaScale();
+
+  // Sort by upper coordinate (lower y), in y-major order.
+  void sort();
+
+protected:
+
+  SplashXPath(SplashXPath *xPath);
+  void transform(SplashCoord *matrix, SplashCoord xi, SplashCoord yi,
+		 SplashCoord *xo, SplashCoord *yo);
+  void strokeAdjust(SplashXPathAdjust *adjust,
+		    SplashCoord *xp, SplashCoord *yp);
+  void grow(int nSegs);
+  void addCurve(SplashCoord x0, SplashCoord y0,
+		SplashCoord x1, SplashCoord y1,
+		SplashCoord x2, SplashCoord y2,
+		SplashCoord x3, SplashCoord y3,
+		SplashCoord flatness,
+		GBool first, GBool last, GBool end0, GBool end1);
+  void addSegment(SplashCoord x0, SplashCoord y0,
+		  SplashCoord x1, SplashCoord y1);
+
+  SplashXPathSeg *segs;
+  int length, size;		// length and size of segs array
+
+  friend class SplashXPathScanner;
+  friend class SplashClip;
+  friend class Splash;
+};
+
+#endif
diff --git a/source/libs/poppler/poppler-src/splash/SplashXPathScanner.cc b/source/libs/poppler/poppler-src/splash/SplashXPathScanner.cc
new file mode 100644
index 0000000000000000000000000000000000000000..ac47881cb4f395c80f282f4caf4a8c03329bfaa6
--- /dev/null
+++ b/source/libs/poppler/poppler-src/splash/SplashXPathScanner.cc
@@ -0,0 +1,544 @@
+//========================================================================
+//
+// SplashXPathScanner.cc
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2008, 2010, 2014 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2010 Paweł Wiejacha <pawel.wiejacha@gmail.com>
+// Copyright (C) 2013, 2014 Thomas Freitag <Thomas.Freitag@alfa.de>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include <config.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <algorithm>
+#include "goo/gmem.h"
+#include "SplashMath.h"
+#include "SplashXPath.h"
+#include "SplashBitmap.h"
+#include "SplashXPathScanner.h"
+
+//------------------------------------------------------------------------
+
+struct SplashIntersect {
+  int y;
+  int x0, x1;			// intersection of segment with [y, y+1)
+  int count;			// EO/NZWN counter increment
+};
+
+struct cmpIntersectFunctor {
+  bool operator()(const SplashIntersect &i0, const SplashIntersect &i1) {
+    return (i0.y != i1.y) ? (i0.y < i1.y) : (i0.x0 < i1.x0);
+  }
+};
+
+//------------------------------------------------------------------------
+// SplashXPathScanner
+//------------------------------------------------------------------------
+
+SplashXPathScanner::SplashXPathScanner(SplashXPath *xPathA, GBool eoA,
+				       int clipYMin, int clipYMax) {
+  SplashXPathSeg *seg;
+  SplashCoord xMinFP, yMinFP, xMaxFP, yMaxFP;
+  int i;
+
+  xPath = xPathA;
+  eo = eoA;
+  partialClip = gFalse;
+
+  // compute the bbox
+  if (xPath->length == 0) {
+    xMin = yMin = 1;
+    xMax = yMax = 0;
+  } else {
+    seg = &xPath->segs[0];
+    if (seg->x0 <= seg->x1) {
+      xMinFP = seg->x0;
+      xMaxFP = seg->x1;
+    } else {
+      xMinFP = seg->x1;
+      xMaxFP = seg->x0;
+    }
+    if (seg->flags & splashXPathFlip) {
+      yMinFP = seg->y1;
+      yMaxFP = seg->y0;
+    } else {
+      yMinFP = seg->y0;
+      yMaxFP = seg->y1;
+    }
+    for (i = 1; i < xPath->length; ++i) {
+      seg = &xPath->segs[i];
+      if (seg->x0 < xMinFP) {
+	xMinFP = seg->x0;
+      } else if (seg->x0 > xMaxFP) {
+	xMaxFP = seg->x0;
+      }
+      if (seg->x1 < xMinFP) {
+	xMinFP = seg->x1;
+      } else if (seg->x1 > xMaxFP) {
+	xMaxFP = seg->x1;
+      }
+      if (seg->flags & splashXPathFlip) {
+	if (seg->y0 > yMaxFP) {
+	  yMaxFP = seg->y0;
+	}
+      } else {
+	if (seg->y1 > yMaxFP) {
+	  yMaxFP = seg->y1;
+	}
+      }
+    }
+    xMin = splashFloor(xMinFP);
+    xMax = splashFloor(xMaxFP);
+    yMin = splashFloor(yMinFP);
+    yMax = splashFloor(yMaxFP);
+    if (clipYMin > yMin) {
+      yMin = clipYMin;
+      partialClip = gTrue;
+    }
+    if (clipYMax < yMax) {
+      yMax = clipYMax;
+      partialClip = gTrue;
+    }
+  }
+
+  allInter = NULL;
+  inter = NULL;
+  computeIntersections();
+  interY = yMin - 1;
+}
+
+SplashXPathScanner::~SplashXPathScanner() {
+  gfree(inter);
+  gfree(allInter);
+}
+
+void SplashXPathScanner::getBBoxAA(int *xMinA, int *yMinA,
+				   int *xMaxA, int *yMaxA) {
+  *xMinA = xMin / splashAASize;
+  *yMinA = yMin / splashAASize;
+  *xMaxA = xMax / splashAASize;
+  *yMaxA = yMax / splashAASize;
+}
+
+void SplashXPathScanner::getSpanBounds(int y, int *spanXMin, int *spanXMax) {
+  int interBegin, interEnd, xx, i;
+
+  if (y < yMin || y > yMax) {
+    interBegin = interEnd = 0;
+  } else {
+    interBegin = inter[y - yMin];
+    interEnd = inter[y - yMin + 1];
+  }
+  if (interBegin < interEnd) {
+    *spanXMin = allInter[interBegin].x0;
+    xx = allInter[interBegin].x1;
+    for (i = interBegin + 1; i < interEnd; ++i) {
+      if (allInter[i].x1 > xx) {
+	xx = allInter[i].x1;
+      }
+    }
+    *spanXMax = xx;
+  } else {
+    *spanXMin = xMax + 1;
+    *spanXMax = xMax;
+  }
+}
+
+GBool SplashXPathScanner::test(int x, int y) {
+  int interBegin, interEnd, count, i;
+
+  if (y < yMin || y > yMax) {
+    return gFalse;
+  }
+  interBegin = inter[y - yMin];
+  interEnd = inter[y - yMin + 1];
+  count = 0;
+  for (i = interBegin; i < interEnd && allInter[i].x0 <= x; ++i) {
+    if (x <= allInter[i].x1) {
+      return gTrue;
+    }
+    count += allInter[i].count;
+  }
+  return eo ? (count & 1) : (count != 0);
+}
+
+GBool SplashXPathScanner::testSpan(int x0, int x1, int y) {
+  int interBegin, interEnd, count, xx1, i;
+
+  if (y < yMin || y > yMax) {
+    return gFalse;
+  }
+  interBegin = inter[y - yMin];
+  interEnd = inter[y - yMin + 1];
+  count = 0;
+  for (i = interBegin; i < interEnd && allInter[i].x1 < x0; ++i) {
+    count += allInter[i].count;
+  }
+
+  // invariant: the subspan [x0,xx1] is inside the path
+  xx1 = x0 - 1;
+  while (xx1 < x1) {
+    if (i >= interEnd) {
+      return gFalse;
+    }
+    if (allInter[i].x0 > xx1 + 1 &&
+	!(eo ? (count & 1) : (count != 0))) {
+      return gFalse;
+    }
+    if (allInter[i].x1 > xx1) {
+      xx1 = allInter[i].x1;
+    }
+    count += allInter[i].count;
+    ++i;
+  }
+
+  return gTrue;
+}
+
+GBool SplashXPathScanner::getNextSpan(int y, int *x0, int *x1) {
+  int interEnd, xx0, xx1;
+
+  if (y < yMin || y > yMax) {
+    return gFalse;
+  }
+  if (interY != y) {
+    interY = y;
+    interIdx = inter[y - yMin];
+    interCount = 0;
+  }
+  interEnd = inter[y - yMin + 1];
+  if (interIdx >= interEnd) {
+    return gFalse;
+  }
+  xx0 = allInter[interIdx].x0;
+  xx1 = allInter[interIdx].x1;
+  interCount += allInter[interIdx].count;
+  ++interIdx;
+  while (interIdx < interEnd &&
+	 (allInter[interIdx].x0 <= xx1 ||
+	  (eo ? (interCount & 1) : (interCount != 0)))) {
+    if (allInter[interIdx].x1 > xx1) {
+      xx1 = allInter[interIdx].x1;
+    }
+    interCount += allInter[interIdx].count;
+    ++interIdx;
+  }
+  *x0 = xx0;
+  *x1 = xx1;
+  return gTrue;
+}
+
+void SplashXPathScanner::computeIntersections() {
+  SplashXPathSeg *seg;
+  SplashCoord segXMin, segXMax, segYMin, segYMax, xx0, xx1;
+  int x, y, y0, y1, i;
+
+  if (yMin > yMax) {
+    return;
+  }
+
+  // build the list of all intersections
+  allInterLen = 0;
+  allInterSize = 16;
+  allInter = (SplashIntersect *)gmallocn(allInterSize,
+					 sizeof(SplashIntersect));
+  for (i = 0; i < xPath->length; ++i) {
+    seg = &xPath->segs[i];
+    if (seg->flags & splashXPathFlip) {
+      segYMin = seg->y1;
+      segYMax = seg->y0;
+    } else {
+      segYMin = seg->y0;
+      segYMax = seg->y1;
+    }
+    if (seg->flags & splashXPathHoriz) {
+      y = splashFloor(seg->y0);
+      if (y >= yMin && y <= yMax) {
+	if (!addIntersection(segYMin, segYMax, seg->flags,
+			y, splashFloor(seg->x0), splashFloor(seg->x1)))
+          break;
+      }
+    } else if (seg->flags & splashXPathVert) {
+      y0 = splashFloor(segYMin);
+      if (y0 < yMin) {
+	y0 = yMin;
+      }
+      y1 = splashFloor(segYMax);
+      if (y1 > yMax) {
+	y1 = yMax;
+      }
+      x = splashFloor(seg->x0);
+      for (y = y0; y <= y1; ++y) {
+	if (!addIntersection(segYMin, segYMax, seg->flags, y, x, x))
+          break;
+      }
+    } else {
+      if (seg->x0 < seg->x1) {
+	segXMin = seg->x0;
+	segXMax = seg->x1;
+      } else {
+	segXMin = seg->x1;
+	segXMax = seg->x0;
+      }
+      y0 = splashFloor(segYMin);
+      if (y0 < yMin) {
+	y0 = yMin;
+      }
+      y1 = splashFloor(segYMax);
+      if (y1 > yMax) {
+	y1 = yMax;
+      }
+      // this loop could just add seg->dxdy to xx1 on each iteration,
+      // but that introduces numerical accuracy problems
+      xx1 = seg->x0 + ((SplashCoord)y0 - seg->y0) * seg->dxdy;
+      for (y = y0; y <= y1; ++y) {
+	xx0 = xx1;
+	xx1 = seg->x0 + ((SplashCoord)(y + 1) - seg->y0) * seg->dxdy;
+	// the segment may not actually extend to the top and/or bottom edges
+	if (xx0 < segXMin) {
+	  xx0 = segXMin;
+	} else if (xx0 > segXMax) {
+	  xx0 = segXMax;
+	}
+	if (xx1 < segXMin) {
+	  xx1 = segXMin;
+	} else if (xx1 > segXMax) {
+	  xx1 = segXMax;
+	}
+	if (!addIntersection(segYMin, segYMax, seg->flags, y,
+			splashFloor(xx0), splashFloor(xx1)))
+          break;
+      }
+    }
+  }
+  std::sort(allInter, allInter + allInterLen, cmpIntersectFunctor());
+
+  // build the list of y pointers
+  inter = (int *)gmallocn(yMax - yMin + 2, sizeof(int));
+  i = 0;
+  for (y = yMin; y <= yMax; ++y) {
+    inter[y - yMin] = i;
+    while (i < allInterLen && allInter[i].y <= y) {
+      ++i;
+    }
+  }
+  inter[yMax - yMin + 1] = i;
+}
+
+GBool SplashXPathScanner::addIntersection(double segYMin, double segYMax,
+					 Guint segFlags,
+					 int y, int x0, int x1) {
+  if (allInterLen == allInterSize) {
+    unsigned int newInterSize = ((unsigned int) allInterSize * 2 > INT_MAX / sizeof(SplashIntersect)) ? allInterSize + 32768 : allInterSize * 2;
+    if (newInterSize >= INT_MAX / sizeof(SplashIntersect)) {
+      error(errInternal, -1, "Bogus memory allocation size in SplashXPathScanner::addIntersection {0:d}", newInterSize);
+      return gFalse;
+    }
+    allInterSize = newInterSize;
+    allInter = (SplashIntersect *)greallocn(allInter, newInterSize,
+					    sizeof(SplashIntersect));
+  }
+  allInter[allInterLen].y = y;
+  if (x0 < x1) {
+    allInter[allInterLen].x0 = x0;
+    allInter[allInterLen].x1 = x1;
+  } else {
+    allInter[allInterLen].x0 = x1;
+    allInter[allInterLen].x1 = x0;
+  }
+  if (segYMin <= y &&
+      (SplashCoord)y < segYMax &&
+      !(segFlags & splashXPathHoriz)) {
+    allInter[allInterLen].count = eo ? 1
+                                     : (segFlags & splashXPathFlip) ? 1 : -1;
+  } else {
+    allInter[allInterLen].count = 0;
+  }
+  ++allInterLen;
+  return gTrue;
+}
+
+void SplashXPathScanner::renderAALine(SplashBitmap *aaBuf,
+				      int *x0, int *x1, int y, GBool adjustVertLine) {
+  int xx0, xx1, xx, xxMin, xxMax, yy, interEnd;
+  Guchar mask;
+  SplashColorPtr p;
+
+  memset(aaBuf->getDataPtr(), 0, aaBuf->getRowSize() * aaBuf->getHeight());
+  xxMin = aaBuf->getWidth();
+  xxMax = -1;
+  if (yMin <= yMax) {
+    if (splashAASize * y < yMin) {
+      interIdx = inter[0];
+    } else if (splashAASize * y > yMax) {
+      interIdx = inter[yMax - yMin + 1];
+    } else {
+      interIdx = inter[splashAASize * y - yMin];
+    }
+    for (yy = 0; yy < splashAASize; ++yy) {
+      if (splashAASize * y + yy < yMin) {
+	interEnd = inter[0];
+      } else if (splashAASize * y + yy > yMax) {
+	interEnd = inter[yMax - yMin + 1];
+      } else {
+	interEnd = inter[splashAASize * y + yy - yMin + 1];
+      }
+      interCount = 0;
+      while (interIdx < interEnd) {
+	xx0 = allInter[interIdx].x0;
+	xx1 = allInter[interIdx].x1;
+	interCount += allInter[interIdx].count;
+	++interIdx;
+	while (interIdx < interEnd &&
+	       (allInter[interIdx].x0 <= xx1 ||
+		(eo ? (interCount & 1) : (interCount != 0)))) {
+	  if (allInter[interIdx].x1 > xx1) {
+	    xx1 = allInter[interIdx].x1;
+	  }
+	  interCount += allInter[interIdx].count;
+	  ++interIdx;
+	}
+	if (xx0 < 0) {
+	  xx0 = 0;
+	}
+	++xx1;
+	if (xx1 > aaBuf->getWidth()) {
+	  xx1 = aaBuf->getWidth();
+	}
+	// set [xx0, xx1) to 1
+	if (xx0 < xx1) {
+	  xx = xx0;
+	  p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx >> 3);
+	  if (xx & 7) {
+	    mask = adjustVertLine ? 0xff : 0xff >> (xx & 7);
+	    if (!adjustVertLine && (xx & ~7) == (xx1 & ~7)) {
+	      mask &= (Guchar)(0xff00 >> (xx1 & 7));
+	    }
+	    *p++ |= mask;
+	    xx = (xx & ~7) + 8;
+	  }
+	  for (; xx + 7 < xx1; xx += 8) {
+	    *p++ |= 0xff;
+	  }
+	  if (xx < xx1) {
+	    *p |= adjustVertLine ? 0xff : (Guchar)(0xff00 >> (xx1 & 7));
+	  }
+	}
+	if (xx0 < xxMin) {
+	  xxMin = xx0;
+	}
+	if (xx1 > xxMax) {
+	  xxMax = xx1;
+	}
+      }
+    }
+  }
+  if (xxMin > xxMax) {
+    xxMin = xxMax;
+  }
+  *x0 = xxMin / splashAASize;
+  *x1 = (xxMax - 1) / splashAASize;
+}
+
+void SplashXPathScanner::clipAALine(SplashBitmap *aaBuf,
+				    int *x0, int *x1, int y) {
+  int xx0, xx1, xx, yy, interEnd;
+  Guchar mask;
+  SplashColorPtr p;
+
+  for (yy = 0; yy < splashAASize; ++yy) {
+    xx = *x0 * splashAASize;
+    if (yMin <= yMax) {
+      if (splashAASize * y + yy < yMin) {
+	interIdx = interEnd = inter[0];
+      } else if (splashAASize * y + yy > yMax) {
+	interIdx = interEnd = inter[yMax - yMin + 1];
+      } else {
+	interIdx = inter[splashAASize * y + yy - yMin];
+	if (splashAASize * y + yy > yMax) {
+	  interEnd = inter[yMax - yMin + 1];
+	} else {
+	  interEnd = inter[splashAASize * y + yy - yMin + 1];
+	}
+      }
+      interCount = 0;
+      while (interIdx < interEnd && xx < (*x1 + 1) * splashAASize) {
+	xx0 = allInter[interIdx].x0;
+	xx1 = allInter[interIdx].x1;
+	interCount += allInter[interIdx].count;
+	++interIdx;
+	while (interIdx < interEnd &&
+	       (allInter[interIdx].x0 <= xx1 ||
+		(eo ? (interCount & 1) : (interCount != 0)))) {
+	  if (allInter[interIdx].x1 > xx1) {
+	    xx1 = allInter[interIdx].x1;
+	  }
+	  interCount += allInter[interIdx].count;
+	  ++interIdx;
+	}
+	if (xx0 > aaBuf->getWidth()) {
+	  xx0 = aaBuf->getWidth();
+	}
+	// set [xx, xx0) to 0
+	if (xx < xx0) {
+	  p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx >> 3);
+	  if (xx & 7) {
+	    mask = (Guchar)(0xff00 >> (xx & 7));
+	    if ((xx & ~7) == (xx0 & ~7)) {
+	      mask |= 0xff >> (xx0 & 7);
+	    }
+	    *p++ &= mask;
+	    xx = (xx & ~7) + 8;
+	  }
+	  for (; xx + 7 < xx0; xx += 8) {
+	    *p++ = 0x00;
+	  }
+	  if (xx < xx0) {
+	    *p &= 0xff >> (xx0 & 7);
+	  }
+	}
+	if (xx1 >= xx) {
+	  xx = xx1 + 1;
+	}
+      }
+    }
+    xx0 = (*x1 + 1) * splashAASize;
+    if (xx0 > aaBuf->getWidth()) xx0 = aaBuf->getWidth();
+    // set [xx, xx0) to 0
+    if (xx < xx0 && xx >= 0) {
+      p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx >> 3);
+      if (xx & 7) {
+	mask = (Guchar)(0xff00 >> (xx & 7));
+	if ((xx & ~7) == (xx0 & ~7)) {
+	  mask &= 0xff >> (xx0 & 7);
+	}
+	*p++ &= mask;
+	xx = (xx & ~7) + 8;
+      }
+      for (; xx + 7 < xx0; xx += 8) {
+	*p++ = 0x00;
+      }
+      if (xx < xx0) {
+	*p &= 0xff >> (xx0 & 7);
+      }
+    }
+  }
+}
diff --git a/source/libs/poppler/poppler-src/splash/SplashXPathScanner.h b/source/libs/poppler/poppler-src/splash/SplashXPathScanner.h
new file mode 100644
index 0000000000000000000000000000000000000000..cc295cb68fede84c6a8e038103534a68b55b42a6
--- /dev/null
+++ b/source/libs/poppler/poppler-src/splash/SplashXPathScanner.h
@@ -0,0 +1,108 @@
+//========================================================================
+//
+// SplashXPathScanner.h
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2013, 2014 Thomas Freitag <Thomas.Freitag@alfa.de>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#ifndef SPLASHXPATHSCANNER_H
+#define SPLASHXPATHSCANNER_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "SplashTypes.h"
+
+class SplashXPath;
+class SplashBitmap;
+struct SplashIntersect;
+
+//------------------------------------------------------------------------
+// SplashXPathScanner
+//------------------------------------------------------------------------
+
+class SplashXPathScanner {
+public:
+
+  // Create a new SplashXPathScanner object.  <xPathA> must be sorted.
+  SplashXPathScanner(SplashXPath *xPathA, GBool eoA,
+		     int clipYMin, int clipYMax);
+
+  ~SplashXPathScanner();
+
+  // Return the path's bounding box.
+  void getBBox(int *xMinA, int *yMinA, int *xMaxA, int *yMaxA)
+    { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; }
+
+  // Return the path's bounding box.
+  void getBBoxAA(int *xMinA, int *yMinA, int *xMaxA, int *yMaxA);
+
+  // Returns true if at least part of the path was outside the
+  // clipYMin/clipYMax bounds passed to the constructor.
+  GBool hasPartialClip() { return partialClip; }
+
+  // Return the min/max x values for the span at <y>.
+  void getSpanBounds(int y, int *spanXMin, int *spanXMax);
+
+  // Returns true if (<x>,<y>) is inside the path.
+  GBool test(int x, int y);
+
+  // Returns true if the entire span ([<x0>,<x1>], <y>) is inside the
+  // path.
+  GBool testSpan(int x0, int x1, int y);
+
+  // Returns the next span inside the path at <y>.  If <y> is
+  // different than the previous call to getNextSpan, this returns the
+  // first span at <y>; otherwise it returns the next span (relative
+  // to the previous call to getNextSpan).  Returns false if there are
+  // no more spans at <y>.
+  GBool getNextSpan(int y, int *x0, int *x1);
+
+  // Renders one anti-aliased line into <aaBuf>.  Returns the min and
+  // max x coordinates with non-zero pixels in <x0> and <x1>.
+  void renderAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y,
+    GBool adjustVertLine = gFalse);
+
+  // Clips an anti-aliased line by setting pixels to zero.  On entry,
+  // all non-zero pixels are between <x0> and <x1>.  This function
+  // will update <x0> and <x1>.
+  void clipAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y);
+
+private:
+
+  void computeIntersections();
+  GBool addIntersection(double segYMin, double segYMax,
+		       Guint segFlags,
+		       int y, int x0, int x1);
+
+  SplashXPath *xPath;
+  GBool eo;
+  int xMin, yMin, xMax, yMax;
+  GBool partialClip;
+
+  SplashIntersect *allInter;	// array of intersections
+  int allInterLen;		// number of intersections in <allInter>
+  int allInterSize;		// size of the <allInter> array
+  int *inter;			// indexes into <allInter> for each y value
+  int interY;			// current y value - used by getNextSpan
+  int interIdx;			// current index into <inter> - used by
+				//   getNextSpan 
+  int interCount;		// current EO/NZWN counter - used by
+				//   getNextSpan
+};
+
+#endif
diff --git a/source/libs/poppler/version.ac b/source/libs/poppler/version.ac
index e9a7275a68b639e57abc82d9bf901a137042ee15..3a85dc6053c06dfdbf86006cc3206e340c701665 100644
--- a/source/libs/poppler/version.ac
+++ b/source/libs/poppler/version.ac
@@ -1,5 +1,6 @@
-dnl
-dnl   Copyright (C) 2011-2015 Peter Breitenlohner <tex-live@tug.org>
+dnl $Id: version.ac 46257 2018-01-09 18:53:05Z karl $
+dnl   Copyright 2018 Karl Berry <tex-live@tug.org>
+dnl   Copyright 2011-2015 Peter Breitenlohner <tex-live@tug.org>
 dnl
 dnl   This file is free software; the copyright holder
 dnl   gives unlimited permission to copy and/or distribute it,
diff --git a/source/m4/ChangeLog b/source/m4/ChangeLog
index 8843714b1013f725b12c61adb36462f3545f0391..a33660429fc6a1d5dbeb2f1a6b7f44ba8e6d9266 100644
--- a/source/m4/ChangeLog
+++ b/source/m4/ChangeLog
@@ -1,3 +1,8 @@
+2018-01-08  Karl Berry  <karl@freefriends.org>
+
+	* ax_cxx_compile_stdcxx.m4: move from dvisvgm; original from
+	https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html#ax_cxx_compile_stdcxx
+
 2017-12-08  Norbert Preining  <preining@logic.at>
 
 	* kpse-icu-flags.m4 (KPSE_ICU_SYSTEM_FLAGS): also check for PKG_CONFIG.
diff --git a/source/m4/ax_cxx_compile_stdcxx.m4 b/source/m4/ax_cxx_compile_stdcxx.m4
new file mode 100644
index 0000000000000000000000000000000000000000..5032bba8091d5d1074f4509b4c47b38a66389c6b
--- /dev/null
+++ b/source/m4/ax_cxx_compile_stdcxx.m4
@@ -0,0 +1,982 @@
+# ===========================================================================
+#  https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional])
+#
+# DESCRIPTION
+#
+#   Check for baseline language coverage in the compiler for the specified
+#   version of the C++ standard.  If necessary, add switches to CXX and
+#   CXXCPP to enable support.  VERSION may be '11' (for the C++11 standard)
+#   or '14' (for the C++14 standard).
+#
+#   The second argument, if specified, indicates whether you insist on an
+#   extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
+#   -std=c++11).  If neither is specified, you get whatever works, with
+#   preference for an extended mode.
+#
+#   The third argument, if specified 'mandatory' or if left unspecified,
+#   indicates that baseline support for the specified C++ standard is
+#   required and that the macro should error out if no mode with that
+#   support is found.  If specified 'optional', then configuration proceeds
+#   regardless, after defining HAVE_CXX${VERSION} if and only if a
+#   supporting mode is found.
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
+#   Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
+#   Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
+#   Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
+#   Copyright (c) 2015 Paul Norman <penorman@mac.com>
+#   Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
+#   Copyright (c) 2016 Krzesimir Nowak <qdlacz@gmail.com>
+#
+#   Copying and distribution of this file, with or without modification, are
+#   permitted in any medium without royalty provided the copyright notice
+#   and this notice are preserved.  This file is offered as-is, without any
+#   warranty.
+
+#serial 7
+
+dnl  This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
+dnl  (serial version number 13).
+
+AX_REQUIRE_DEFINED([AC_MSG_WARN])
+AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
+  m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"],
+        [$1], [14], [ax_cxx_compile_alternatives="14 1y"],
+        [$1], [17], [ax_cxx_compile_alternatives="17 1z"],
+        [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl
+  m4_if([$2], [], [],
+        [$2], [ext], [],
+        [$2], [noext], [],
+        [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl
+  m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true],
+        [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true],
+        [$3], [optional], [ax_cxx_compile_cxx$1_required=false],
+        [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])])
+  AC_LANG_PUSH([C++])dnl
+  ac_success=no
+  AC_CACHE_CHECK(whether $CXX supports C++$1 features by default,
+  ax_cv_cxx_compile_cxx$1,
+  [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
+    [ax_cv_cxx_compile_cxx$1=yes],
+    [ax_cv_cxx_compile_cxx$1=no])])
+  if test x$ax_cv_cxx_compile_cxx$1 = xyes; then
+    ac_success=yes
+  fi
+
+  m4_if([$2], [noext], [], [dnl
+  if test x$ac_success = xno; then
+    for alternative in ${ax_cxx_compile_alternatives}; do
+      switch="-std=gnu++${alternative}"
+      cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
+      AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
+                     $cachevar,
+        [ac_save_CXX="$CXX"
+         CXX="$CXX $switch"
+         AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
+          [eval $cachevar=yes],
+          [eval $cachevar=no])
+         CXX="$ac_save_CXX"])
+      if eval test x\$$cachevar = xyes; then
+        CXX="$CXX $switch"
+        if test -n "$CXXCPP" ; then
+          CXXCPP="$CXXCPP $switch"
+        fi
+        ac_success=yes
+        break
+      fi
+    done
+  fi])
+
+  m4_if([$2], [ext], [], [dnl
+  if test x$ac_success = xno; then
+    dnl HP's aCC needs +std=c++11 according to:
+    dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
+    dnl Cray's crayCC needs "-h std=c++11"
+    for alternative in ${ax_cxx_compile_alternatives}; do
+      for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do
+        cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
+        AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
+                       $cachevar,
+          [ac_save_CXX="$CXX"
+           CXX="$CXX $switch"
+           AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
+            [eval $cachevar=yes],
+            [eval $cachevar=no])
+           CXX="$ac_save_CXX"])
+        if eval test x\$$cachevar = xyes; then
+          CXX="$CXX $switch"
+          if test -n "$CXXCPP" ; then
+            CXXCPP="$CXXCPP $switch"
+          fi
+          ac_success=yes
+          break
+        fi
+      done
+      if test x$ac_success = xyes; then
+        break
+      fi
+    done
+  fi])
+  AC_LANG_POP([C++])
+  if test x$ax_cxx_compile_cxx$1_required = xtrue; then
+    if test x$ac_success = xno; then
+      AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.])
+    fi
+  fi
+  if test x$ac_success = xno; then
+    HAVE_CXX$1=0
+    AC_MSG_NOTICE([No compiler with C++$1 support was found])
+  else
+    HAVE_CXX$1=1
+    AC_DEFINE(HAVE_CXX$1,1,
+              [define if the compiler supports basic C++$1 syntax])
+  fi
+  AC_SUBST(HAVE_CXX$1)
+  m4_if([$1], [17], [AC_MSG_WARN([C++17 is not yet standardized, so the checks may change in incompatible ways anytime])])
+])
+
+
+dnl  Test body for checking C++11 support
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11],
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
+)
+
+
+dnl  Test body for checking C++14 support
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
+)
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17],
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_17
+)
+
+dnl  Tests for new features in C++11
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[
+
+// If the compiler admits that it is not ready for C++11, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus < 201103L
+
+#error "This is not a C++11 compiler"
+
+#else
+
+namespace cxx11
+{
+
+  namespace test_static_assert
+  {
+
+    template <typename T>
+    struct check
+    {
+      static_assert(sizeof(int) <= sizeof(T), "not big enough");
+    };
+
+  }
+
+  namespace test_final_override
+  {
+
+    struct Base
+    {
+      virtual void f() {}
+    };
+
+    struct Derived : public Base
+    {
+      virtual void f() override {}
+    };
+
+  }
+
+  namespace test_double_right_angle_brackets
+  {
+
+    template < typename T >
+    struct check {};
+
+    typedef check<void> single_type;
+    typedef check<check<void>> double_type;
+    typedef check<check<check<void>>> triple_type;
+    typedef check<check<check<check<void>>>> quadruple_type;
+
+  }
+
+  namespace test_decltype
+  {
+
+    int
+    f()
+    {
+      int a = 1;
+      decltype(a) b = 2;
+      return a + b;
+    }
+
+  }
+
+  namespace test_type_deduction
+  {
+
+    template < typename T1, typename T2 >
+    struct is_same
+    {
+      static const bool value = false;
+    };
+
+    template < typename T >
+    struct is_same<T, T>
+    {
+      static const bool value = true;
+    };
+
+    template < typename T1, typename T2 >
+    auto
+    add(T1 a1, T2 a2) -> decltype(a1 + a2)
+    {
+      return a1 + a2;
+    }
+
+    int
+    test(const int c, volatile int v)
+    {
+      static_assert(is_same<int, decltype(0)>::value == true, "");
+      static_assert(is_same<int, decltype(c)>::value == false, "");
+      static_assert(is_same<int, decltype(v)>::value == false, "");
+      auto ac = c;
+      auto av = v;
+      auto sumi = ac + av + 'x';
+      auto sumf = ac + av + 1.0;
+      static_assert(is_same<int, decltype(ac)>::value == true, "");
+      static_assert(is_same<int, decltype(av)>::value == true, "");
+      static_assert(is_same<int, decltype(sumi)>::value == true, "");
+      static_assert(is_same<int, decltype(sumf)>::value == false, "");
+      static_assert(is_same<int, decltype(add(c, v))>::value == true, "");
+      return (sumf > 0.0) ? sumi : add(c, v);
+    }
+
+  }
+
+  namespace test_noexcept
+  {
+
+    int f() { return 0; }
+    int g() noexcept { return 0; }
+
+    static_assert(noexcept(f()) == false, "");
+    static_assert(noexcept(g()) == true, "");
+
+  }
+
+  namespace test_constexpr
+  {
+
+    template < typename CharT >
+    unsigned long constexpr
+    strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
+    {
+      return *s ? strlen_c_r(s + 1, acc + 1) : acc;
+    }
+
+    template < typename CharT >
+    unsigned long constexpr
+    strlen_c(const CharT *const s) noexcept
+    {
+      return strlen_c_r(s, 0UL);
+    }
+
+    static_assert(strlen_c("") == 0UL, "");
+    static_assert(strlen_c("1") == 1UL, "");
+    static_assert(strlen_c("example") == 7UL, "");
+    static_assert(strlen_c("another\0example") == 7UL, "");
+
+  }
+
+  namespace test_rvalue_references
+  {
+
+    template < int N >
+    struct answer
+    {
+      static constexpr int value = N;
+    };
+
+    answer<1> f(int&)       { return answer<1>(); }
+    answer<2> f(const int&) { return answer<2>(); }
+    answer<3> f(int&&)      { return answer<3>(); }
+
+    void
+    test()
+    {
+      int i = 0;
+      const int c = 0;
+      static_assert(decltype(f(i))::value == 1, "");
+      static_assert(decltype(f(c))::value == 2, "");
+      static_assert(decltype(f(0))::value == 3, "");
+    }
+
+  }
+
+  namespace test_uniform_initialization
+  {
+
+    struct test
+    {
+      static const int zero {};
+      static const int one {1};
+    };
+
+    static_assert(test::zero == 0, "");
+    static_assert(test::one == 1, "");
+
+  }
+
+  namespace test_lambdas
+  {
+
+    void
+    test1()
+    {
+      auto lambda1 = [](){};
+      auto lambda2 = lambda1;
+      lambda1();
+      lambda2();
+    }
+
+    int
+    test2()
+    {
+      auto a = [](int i, int j){ return i + j; }(1, 2);
+      auto b = []() -> int { return '0'; }();
+      auto c = [=](){ return a + b; }();
+      auto d = [&](){ return c; }();
+      auto e = [a, &b](int x) mutable {
+        const auto identity = [](int y){ return y; };
+        for (auto i = 0; i < a; ++i)
+          a += b--;
+        return x + identity(a + b);
+      }(0);
+      return a + b + c + d + e;
+    }
+
+    int
+    test3()
+    {
+      const auto nullary = [](){ return 0; };
+      const auto unary = [](int x){ return x; };
+      using nullary_t = decltype(nullary);
+      using unary_t = decltype(unary);
+      const auto higher1st = [](nullary_t f){ return f(); };
+      const auto higher2nd = [unary](nullary_t f1){
+        return [unary, f1](unary_t f2){ return f2(unary(f1())); };
+      };
+      return higher1st(nullary) + higher2nd(nullary)(unary);
+    }
+
+  }
+
+  namespace test_variadic_templates
+  {
+
+    template <int...>
+    struct sum;
+
+    template <int N0, int... N1toN>
+    struct sum<N0, N1toN...>
+    {
+      static constexpr auto value = N0 + sum<N1toN...>::value;
+    };
+
+    template <>
+    struct sum<>
+    {
+      static constexpr auto value = 0;
+    };
+
+    static_assert(sum<>::value == 0, "");
+    static_assert(sum<1>::value == 1, "");
+    static_assert(sum<23>::value == 23, "");
+    static_assert(sum<1, 2>::value == 3, "");
+    static_assert(sum<5, 5, 11>::value == 21, "");
+    static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
+
+  }
+
+  // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
+  // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
+  // because of this.
+  namespace test_template_alias_sfinae
+  {
+
+    struct foo {};
+
+    template<typename T>
+    using member = typename T::member_type;
+
+    template<typename T>
+    void func(...) {}
+
+    template<typename T>
+    void func(member<T>*) {}
+
+    void test();
+
+    void test() { func<foo>(0); }
+
+  }
+
+}  // namespace cxx11
+
+#endif  // __cplusplus >= 201103L
+
+]])
+
+
+dnl  Tests for new features in C++14
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[
+
+// If the compiler admits that it is not ready for C++14, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus < 201402L
+
+#error "This is not a C++14 compiler"
+
+#else
+
+namespace cxx14
+{
+
+  namespace test_polymorphic_lambdas
+  {
+
+    int
+    test()
+    {
+      const auto lambda = [](auto&&... args){
+        const auto istiny = [](auto x){
+          return (sizeof(x) == 1UL) ? 1 : 0;
+        };
+        const int aretiny[] = { istiny(args)... };
+        return aretiny[0];
+      };
+      return lambda(1, 1L, 1.0f, '1');
+    }
+
+  }
+
+  namespace test_binary_literals
+  {
+
+    constexpr auto ivii = 0b0000000000101010;
+    static_assert(ivii == 42, "wrong value");
+
+  }
+
+  namespace test_generalized_constexpr
+  {
+
+    template < typename CharT >
+    constexpr unsigned long
+    strlen_c(const CharT *const s) noexcept
+    {
+      auto length = 0UL;
+      for (auto p = s; *p; ++p)
+        ++length;
+      return length;
+    }
+
+    static_assert(strlen_c("") == 0UL, "");
+    static_assert(strlen_c("x") == 1UL, "");
+    static_assert(strlen_c("test") == 4UL, "");
+    static_assert(strlen_c("another\0test") == 7UL, "");
+
+  }
+
+  namespace test_lambda_init_capture
+  {
+
+    int
+    test()
+    {
+      auto x = 0;
+      const auto lambda1 = [a = x](int b){ return a + b; };
+      const auto lambda2 = [a = lambda1(x)](){ return a; };
+      return lambda2();
+    }
+
+  }
+
+  namespace test_digit_separators
+  {
+
+    constexpr auto ten_million = 100'000'000;
+    static_assert(ten_million == 100000000, "");
+
+  }
+
+  namespace test_return_type_deduction
+  {
+
+    auto f(int& x) { return x; }
+    decltype(auto) g(int& x) { return x; }
+
+    template < typename T1, typename T2 >
+    struct is_same
+    {
+      static constexpr auto value = false;
+    };
+
+    template < typename T >
+    struct is_same<T, T>
+    {
+      static constexpr auto value = true;
+    };
+
+    int
+    test()
+    {
+      auto x = 0;
+      static_assert(is_same<int, decltype(f(x))>::value, "");
+      static_assert(is_same<int&, decltype(g(x))>::value, "");
+      return x;
+    }
+
+  }
+
+}  // namespace cxx14
+
+#endif  // __cplusplus >= 201402L
+
+]])
+
+
+dnl  Tests for new features in C++17
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[
+
+// If the compiler admits that it is not ready for C++17, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus <= 201402L
+
+#error "This is not a C++17 compiler"
+
+#else
+
+#if defined(__clang__)
+  #define REALLY_CLANG
+#else
+  #if defined(__GNUC__)
+    #define REALLY_GCC
+  #endif
+#endif
+
+#include <initializer_list>
+#include <utility>
+#include <type_traits>
+
+namespace cxx17
+{
+
+#if !defined(REALLY_CLANG)
+  namespace test_constexpr_lambdas
+  {
+
+    // TODO: test it with clang++ from git
+
+    constexpr int foo = [](){return 42;}();
+
+  }
+#endif // !defined(REALLY_CLANG)
+
+  namespace test::nested_namespace::definitions
+  {
+
+  }
+
+  namespace test_fold_expression
+  {
+
+    template<typename... Args>
+    int multiply(Args... args)
+    {
+      return (args * ... * 1);
+    }
+
+    template<typename... Args>
+    bool all(Args... args)
+    {
+      return (args && ...);
+    }
+
+  }
+
+  namespace test_extended_static_assert
+  {
+
+    static_assert (true);
+
+  }
+
+  namespace test_auto_brace_init_list
+  {
+
+    auto foo = {5};
+    auto bar {5};
+
+    static_assert(std::is_same<std::initializer_list<int>, decltype(foo)>::value);
+    static_assert(std::is_same<int, decltype(bar)>::value);
+  }
+
+  namespace test_typename_in_template_template_parameter
+  {
+
+    template<template<typename> typename X> struct D;
+
+  }
+
+  namespace test_fallthrough_nodiscard_maybe_unused_attributes
+  {
+
+    int f1()
+    {
+      return 42;
+    }
+
+    [[nodiscard]] int f2()
+    {
+      [[maybe_unused]] auto unused = f1();
+
+      switch (f1())
+      {
+      case 17:
+        f1();
+        [[fallthrough]];
+      case 42:
+        f1();
+      }
+      return f1();
+    }
+
+  }
+
+  namespace test_extended_aggregate_initialization
+  {
+
+    struct base1
+    {
+      int b1, b2 = 42;
+    };
+
+    struct base2
+    {
+      base2() {
+        b3 = 42;
+      }
+      int b3;
+    };
+
+    struct derived : base1, base2
+    {
+        int d;
+    };
+
+    derived d1 {{1, 2}, {}, 4};  // full initialization
+    derived d2 {{}, {}, 4};      // value-initialized bases
+
+  }
+
+  namespace test_general_range_based_for_loop
+  {
+
+    struct iter
+    {
+      int i;
+
+      int& operator* ()
+      {
+        return i;
+      }
+
+      const int& operator* () const
+      {
+        return i;
+      }
+
+      iter& operator++()
+      {
+        ++i;
+        return *this;
+      }
+    };
+
+    struct sentinel
+    {
+      int i;
+    };
+
+    bool operator== (const iter& i, const sentinel& s)
+    {
+      return i.i == s.i;
+    }
+
+    bool operator!= (const iter& i, const sentinel& s)
+    {
+      return !(i == s);
+    }
+
+    struct range
+    {
+      iter begin() const
+      {
+        return {0};
+      }
+
+      sentinel end() const
+      {
+        return {5};
+      }
+    };
+
+    void f()
+    {
+      range r {};
+
+      for (auto i : r)
+      {
+        [[maybe_unused]] auto v = i;
+      }
+    }
+
+  }
+
+  namespace test_lambda_capture_asterisk_this_by_value
+  {
+
+    struct t
+    {
+      int i;
+      int foo()
+      {
+        return [*this]()
+        {
+          return i;
+        }();
+      }
+    };
+
+  }
+
+  namespace test_enum_class_construction
+  {
+
+    enum class byte : unsigned char
+    {};
+
+    byte foo {42};
+
+  }
+
+  namespace test_constexpr_if
+  {
+
+    template <bool cond>
+    int f ()
+    {
+      if constexpr(cond)
+      {
+        return 13;
+      }
+      else
+      {
+        return 42;
+      }
+    }
+
+  }
+
+  namespace test_selection_statement_with_initializer
+  {
+
+    int f()
+    {
+      return 13;
+    }
+
+    int f2()
+    {
+      if (auto i = f(); i > 0)
+      {
+        return 3;
+      }
+
+      switch (auto i = f(); i + 4)
+      {
+      case 17:
+        return 2;
+
+      default:
+        return 1;
+      }
+    }
+
+  }
+
+#if !defined(REALLY_CLANG)
+  namespace test_template_argument_deduction_for_class_templates
+  {
+
+    // TODO: test it with clang++ from git
+
+    template <typename T1, typename T2>
+    struct pair
+    {
+      pair (T1 p1, T2 p2)
+        : m1 {p1},
+          m2 {p2}
+      {}
+
+      T1 m1;
+      T2 m2;
+    };
+
+    void f()
+    {
+      [[maybe_unused]] auto p = pair{13, 42u};
+    }
+
+  }
+#endif // !defined(REALLY_CLANG)
+
+  namespace test_non_type_auto_template_parameters
+  {
+
+    template <auto n>
+    struct B
+    {};
+
+    B<5> b1;
+    B<'a'> b2;
+
+  }
+
+#if !defined(REALLY_CLANG)
+  namespace test_structured_bindings
+  {
+
+    // TODO: test it with clang++ from git
+
+    int arr[2] = { 1, 2 };
+    std::pair<int, int> pr = { 1, 2 };
+
+    auto f1() -> int(&)[2]
+    {
+      return arr;
+    }
+
+    auto f2() -> std::pair<int, int>&
+    {
+      return pr;
+    }
+
+    struct S
+    {
+      int x1 : 2;
+      volatile double y1;
+    };
+
+    S f3()
+    {
+      return {};
+    }
+
+    auto [ x1, y1 ] = f1();
+    auto& [ xr1, yr1 ] = f1();
+    auto [ x2, y2 ] = f2();
+    auto& [ xr2, yr2 ] = f2();
+    const auto [ x3, y3 ] = f3();
+
+  }
+#endif // !defined(REALLY_CLANG)
+
+#if !defined(REALLY_CLANG)
+  namespace test_exception_spec_type_system
+  {
+
+    // TODO: test it with clang++ from git
+
+    struct Good {};
+    struct Bad {};
+
+    void g1() noexcept;
+    void g2();
+
+    template<typename T>
+    Bad
+    f(T*, T*);
+
+    template<typename T1, typename T2>
+    Good
+    f(T1*, T2*);
+
+    static_assert (std::is_same_v<Good, decltype(f(g1, g2))>);
+
+  }
+#endif // !defined(REALLY_CLANG)
+
+  namespace test_inline_variables
+  {
+
+    template<class T> void f(T)
+    {}
+
+    template<class T> inline T g(T)
+    {
+      return T{};
+    }
+
+    template<> inline void f<>(int)
+    {}
+
+    template<> int g<>(int)
+    {
+      return 5;
+    }
+
+  }
+
+}  // namespace cxx17
+
+#endif  // __cplusplus <= 201402L
+
+]])
diff --git a/source/texk/kpathsea/ChangeLog b/source/texk/kpathsea/ChangeLog
index 1511b4a06210786b79dd78668a33c8a2f3a36728..a57bcff546756e6445294c709d0ffaee34c26ab2 100644
--- a/source/texk/kpathsea/ChangeLog
+++ b/source/texk/kpathsea/ChangeLog
@@ -1,3 +1,10 @@
+2018-01-05  Karl Berry  <karl@freefriends.org>
+
+	* pathsearch.c (dir_list_search, dir_list_search_list): save the
+	next element to continue the loop, in case the
+	current element floats. Report from Douglas McKenna,
+	tex-k mail 4 Jan 2018 10:16:18.
+
 2017-12-27  Akira Kakuto  <kakuto@fuk.kindai.ac.jp>
 
 	* xbasename.c, xdirname.c: Remove IS_KANJI test for UNC names,
diff --git a/source/texk/kpathsea/doc/kpathsea.info b/source/texk/kpathsea/doc/kpathsea.info
index 7b7c6f91e08f3fe87e3fb8a7cec08d80dc710e8b..98c5bd794e17535460506edbec38d463f7f4766e 100644
--- a/source/texk/kpathsea/doc/kpathsea.info
+++ b/source/texk/kpathsea/doc/kpathsea.info
@@ -1,4 +1,4 @@
-This is kpathsea.info, produced by makeinfo version 6.1 from
+This is kpathsea.info, produced by makeinfo version 6.5 from
 kpathsea.texi.
 
 This file documents the Kpathsea library for path searching.
diff --git a/source/texk/kpathsea/pathsearch.c b/source/texk/kpathsea/pathsearch.c
index 0f59ac5ed95c20507fa8e37e40d594e0b4f966ef..4f57c116191c565cb2d3fb2fabc8826790a2fd6c 100644
--- a/source/texk/kpathsea/pathsearch.c
+++ b/source/texk/kpathsea/pathsearch.c
@@ -1,6 +1,6 @@
 /* pathsearch.c: look up a filename in a path.
 
-   Copyright 1993, 1994, 1995, 1997, 2007, 2009-2012 Karl Berry.
+   Copyright 1993, 1994, 1995, 1997, 2007, 2009-2012, 2018 Karl Berry.
    Copyright 1997-2005 Olaf Weber.
 
    This library is free software; you can redistribute it and/or
@@ -117,6 +117,7 @@ dir_list_search (kpathsea kpse, str_llist_type *dirs,  const_string name,
                     boolean search_all)
 {
   str_llist_elt_type *elt;
+  str_llist_elt_type *next_elt;
   str_list_type ret;
   unsigned name_len = strlen (name);
   unsigned allocated = INIT_ALLOC;
@@ -124,11 +125,13 @@ dir_list_search (kpathsea kpse, str_llist_type *dirs,  const_string name,
 
   ret = str_list_init ();
 
-  for (elt = *dirs; elt; elt = STR_LLIST_NEXT (*elt))
+  for (elt = *dirs; elt; elt = next_elt)
     {
       const_string dir = STR_LLIST (*elt);
       unsigned dir_len = strlen (dir);
 
+      next_elt = STR_LLIST_NEXT (*elt); /* in case elt floats */
+
       while (dir_len + name_len + 1 > allocated)
         {
           allocated += allocated;
@@ -165,22 +168,26 @@ dir_list_search (kpathsea kpse, str_llist_type *dirs,  const_string name,
 }
 
 /* Note: NAMES[i] is not modified.  */
+
 static str_list_type
 dir_list_search_list (kpathsea kpse, str_llist_type *dirs, string* names,
                       boolean search_all)
 {
   str_llist_elt_type *elt;
+  str_llist_elt_type *next_elt;
   str_list_type ret;
   unsigned allocated = INIT_ALLOC;
   string potential = XTALLOC(allocated, char);
 
   ret = str_list_init ();
 
-  for (elt = *dirs; elt; elt = STR_LLIST_NEXT(*elt)) {
+  for (elt = *dirs; elt; elt = next_elt) {
       const_string dir = STR_LLIST (*elt);
       unsigned dir_len = strlen (dir);
       int i;
 
+      next_elt = STR_LLIST_NEXT (*elt); /* in case elt floats */
+
       for (i = 0; names[i]; i++) {
           const_string name = names[i];
           unsigned name_len;
diff --git a/source/texk/web2c/Makefile.in b/source/texk/web2c/Makefile.in
index a40e85c595c6bd2b557214b369f88c822b843ebc..fbcf7ce1c0e7b9fea37e21e8daf010e7942ab30e 100644
--- a/source/texk/web2c/Makefile.in
+++ b/source/texk/web2c/Makefile.in
@@ -336,6 +336,7 @@ TESTS = tangle.test $(am__EXEEXT_41) ctiedir/ctie.test \
 subdir = .
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/web2c-disable.m4 \
+	$(top_srcdir)/../../m4/ax_cxx_compile_stdcxx.m4 \
 	$(top_srcdir)/../../m4/kpse-asm.m4 \
 	$(top_srcdir)/../../m4/kpse-cairo-flags.m4 \
 	$(top_srcdir)/../../m4/kpse-common.m4 \
@@ -1934,6 +1935,7 @@ GREP = @GREP@
 HARFBUZZ_DEPEND = @HARFBUZZ_DEPEND@
 HARFBUZZ_INCLUDES = @HARFBUZZ_INCLUDES@
 HARFBUZZ_LIBS = @HARFBUZZ_LIBS@
+HAVE_CXX11 = @HAVE_CXX11@
 ICU_CONFIG = @ICU_CONFIG@
 ICU_DEPEND = @ICU_DEPEND@
 ICU_INCLUDES = @ICU_INCLUDES@
diff --git a/source/texk/web2c/aclocal.m4 b/source/texk/web2c/aclocal.m4
index 4dcb26da29c50493ff807c027e3a8b2587ad7e4d..9d9e1cb8c4bbb3fdae38198d78b462d8a36c360b 100644
--- a/source/texk/web2c/aclocal.m4
+++ b/source/texk/web2c/aclocal.m4
@@ -20,6 +20,44 @@ You have another version of autoconf.  It may work, but is not guaranteed to.
 If you have problems, you may need to regenerate the build system entirely.
 To do so, use the procedure documented by the package, typically 'autoreconf'.])])
 
+# ===========================================================================
+#    http://www.gnu.org/software/autoconf-archive/ax_require_defined.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_REQUIRE_DEFINED(MACRO)
+#
+# DESCRIPTION
+#
+#   AX_REQUIRE_DEFINED is a simple helper for making sure other macros have
+#   been defined and thus are available for use.  This avoids random issues
+#   where a macro isn't expanded.  Instead the configure script emits a
+#   non-fatal:
+#
+#     ./configure: line 1673: AX_CFLAGS_WARN_ALL: command not found
+#
+#   It's like AC_REQUIRE except it doesn't expand the required macro.
+#
+#   Here's an example:
+#
+#     AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG])
+#
+# LICENSE
+#
+#   Copyright (c) 2014 Mike Frysinger <vapier@gentoo.org>
+#
+#   Copying and distribution of this file, with or without modification, are
+#   permitted in any medium without royalty provided the copyright notice
+#   and this notice are preserved. This file is offered as-is, without any
+#   warranty.
+
+#serial 1
+
+AC_DEFUN([AX_REQUIRE_DEFINED], [dnl
+  m4_ifndef([$1], [m4_fatal([macro ]$1[ is not defined; is a m4 file missing?])])
+])dnl AX_REQUIRE_DEFINED
+
 # Copyright (C) 2002-2014 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
@@ -1224,6 +1262,7 @@ AC_SUBST([am__untar])
 ]) # _AM_PROG_TAR
 
 m4_include([m4/web2c-disable.m4])
+m4_include([../../m4/ax_cxx_compile_stdcxx.m4])
 m4_include([../../m4/kpse-asm.m4])
 m4_include([../../m4/kpse-cairo-flags.m4])
 m4_include([../../m4/kpse-common.m4])
diff --git a/source/texk/web2c/c-auto.in b/source/texk/web2c/c-auto.in
index ce18d89e49b125d6a9b8607ff30c81c9e20e9ca2..81d750ea7b837bc1f8795fdab26b46d8c14346dc 100644
--- a/source/texk/web2c/c-auto.in
+++ b/source/texk/web2c/c-auto.in
@@ -55,6 +55,9 @@
 /* Define to 1 if you have the `atoi' function. */
 #undef HAVE_ATOI
 
+/* define if the compiler supports basic C++11 syntax */
+#undef HAVE_CXX11
+
 /* Define to 1 if you have the declaration of `isascii', and to 0 if you
    don't. */
 #undef HAVE_DECL_ISASCII
diff --git a/source/texk/web2c/configure b/source/texk/web2c/configure
index e43e116ac335f3b874ab8695983f99bae7698974..6f05c10053506aea18d207354f4b6f04a3d02f6b 100755
--- a/source/texk/web2c/configure
+++ b/source/texk/web2c/configure
@@ -823,6 +823,7 @@ MINGW32_TRUE
 WIN32_FALSE
 WIN32_TRUE
 KPSEWHICH
+HAVE_CXX11
 CXXLD
 WARNING_OBJCXXFLAGS
 am__fastdepOBJCXX_FALSE
@@ -18987,6 +18988,999 @@ fi
 
 
 
+if test "x$enable_xetex" = xyes \
+   || test "x$enable_luatex" = xyes \
+   || test "x$enable_luajittex" = xyes \
+   || test "x$enable_luatex53" = xyes; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: LuaTeX enabled" >&5
+$as_echo "$as_me: LuaTeX enabled" >&requiring C++11 support;}
+    ax_cxx_compile_alternatives="11 0x"    ax_cxx_compile_cxx11_required=true
+  ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+  ac_success=no
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features by default" >&5
+$as_echo_n "checking whether $CXX supports C++11 features by default... " >&6; }
+if ${ax_cv_cxx_compile_cxx11+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+
+// If the compiler admits that it is not ready for C++11, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus < 201103L
+
+#error "This is not a C++11 compiler"
+
+#else
+
+namespace cxx11
+{
+
+  namespace test_static_assert
+  {
+
+    template <typename T>
+    struct check
+    {
+      static_assert(sizeof(int) <= sizeof(T), "not big enough");
+    };
+
+  }
+
+  namespace test_final_override
+  {
+
+    struct Base
+    {
+      virtual void f() {}
+    };
+
+    struct Derived : public Base
+    {
+      virtual void f() override {}
+    };
+
+  }
+
+  namespace test_double_right_angle_brackets
+  {
+
+    template < typename T >
+    struct check {};
+
+    typedef check<void> single_type;
+    typedef check<check<void>> double_type;
+    typedef check<check<check<void>>> triple_type;
+    typedef check<check<check<check<void>>>> quadruple_type;
+
+  }
+
+  namespace test_decltype
+  {
+
+    int
+    f()
+    {
+      int a = 1;
+      decltype(a) b = 2;
+      return a + b;
+    }
+
+  }
+
+  namespace test_type_deduction
+  {
+
+    template < typename T1, typename T2 >
+    struct is_same
+    {
+      static const bool value = false;
+    };
+
+    template < typename T >
+    struct is_same<T, T>
+    {
+      static const bool value = true;
+    };
+
+    template < typename T1, typename T2 >
+    auto
+    add(T1 a1, T2 a2) -> decltype(a1 + a2)
+    {
+      return a1 + a2;
+    }
+
+    int
+    test(const int c, volatile int v)
+    {
+      static_assert(is_same<int, decltype(0)>::value == true, "");
+      static_assert(is_same<int, decltype(c)>::value == false, "");
+      static_assert(is_same<int, decltype(v)>::value == false, "");
+      auto ac = c;
+      auto av = v;
+      auto sumi = ac + av + 'x';
+      auto sumf = ac + av + 1.0;
+      static_assert(is_same<int, decltype(ac)>::value == true, "");
+      static_assert(is_same<int, decltype(av)>::value == true, "");
+      static_assert(is_same<int, decltype(sumi)>::value == true, "");
+      static_assert(is_same<int, decltype(sumf)>::value == false, "");
+      static_assert(is_same<int, decltype(add(c, v))>::value == true, "");
+      return (sumf > 0.0) ? sumi : add(c, v);
+    }
+
+  }
+
+  namespace test_noexcept
+  {
+
+    int f() { return 0; }
+    int g() noexcept { return 0; }
+
+    static_assert(noexcept(f()) == false, "");
+    static_assert(noexcept(g()) == true, "");
+
+  }
+
+  namespace test_constexpr
+  {
+
+    template < typename CharT >
+    unsigned long constexpr
+    strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
+    {
+      return *s ? strlen_c_r(s + 1, acc + 1) : acc;
+    }
+
+    template < typename CharT >
+    unsigned long constexpr
+    strlen_c(const CharT *const s) noexcept
+    {
+      return strlen_c_r(s, 0UL);
+    }
+
+    static_assert(strlen_c("") == 0UL, "");
+    static_assert(strlen_c("1") == 1UL, "");
+    static_assert(strlen_c("example") == 7UL, "");
+    static_assert(strlen_c("another\0example") == 7UL, "");
+
+  }
+
+  namespace test_rvalue_references
+  {
+
+    template < int N >
+    struct answer
+    {
+      static constexpr int value = N;
+    };
+
+    answer<1> f(int&)       { return answer<1>(); }
+    answer<2> f(const int&) { return answer<2>(); }
+    answer<3> f(int&&)      { return answer<3>(); }
+
+    void
+    test()
+    {
+      int i = 0;
+      const int c = 0;
+      static_assert(decltype(f(i))::value == 1, "");
+      static_assert(decltype(f(c))::value == 2, "");
+      static_assert(decltype(f(0))::value == 3, "");
+    }
+
+  }
+
+  namespace test_uniform_initialization
+  {
+
+    struct test
+    {
+      static const int zero {};
+      static const int one {1};
+    };
+
+    static_assert(test::zero == 0, "");
+    static_assert(test::one == 1, "");
+
+  }
+
+  namespace test_lambdas
+  {
+
+    void
+    test1()
+    {
+      auto lambda1 = [](){};
+      auto lambda2 = lambda1;
+      lambda1();
+      lambda2();
+    }
+
+    int
+    test2()
+    {
+      auto a = [](int i, int j){ return i + j; }(1, 2);
+      auto b = []() -> int { return '0'; }();
+      auto c = [=](){ return a + b; }();
+      auto d = [&](){ return c; }();
+      auto e = [a, &b](int x) mutable {
+        const auto identity = [](int y){ return y; };
+        for (auto i = 0; i < a; ++i)
+          a += b--;
+        return x + identity(a + b);
+      }(0);
+      return a + b + c + d + e;
+    }
+
+    int
+    test3()
+    {
+      const auto nullary = [](){ return 0; };
+      const auto unary = [](int x){ return x; };
+      using nullary_t = decltype(nullary);
+      using unary_t = decltype(unary);
+      const auto higher1st = [](nullary_t f){ return f(); };
+      const auto higher2nd = [unary](nullary_t f1){
+        return [unary, f1](unary_t f2){ return f2(unary(f1())); };
+      };
+      return higher1st(nullary) + higher2nd(nullary)(unary);
+    }
+
+  }
+
+  namespace test_variadic_templates
+  {
+
+    template <int...>
+    struct sum;
+
+    template <int N0, int... N1toN>
+    struct sum<N0, N1toN...>
+    {
+      static constexpr auto value = N0 + sum<N1toN...>::value;
+    };
+
+    template <>
+    struct sum<>
+    {
+      static constexpr auto value = 0;
+    };
+
+    static_assert(sum<>::value == 0, "");
+    static_assert(sum<1>::value == 1, "");
+    static_assert(sum<23>::value == 23, "");
+    static_assert(sum<1, 2>::value == 3, "");
+    static_assert(sum<5, 5, 11>::value == 21, "");
+    static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
+
+  }
+
+  // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
+  // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
+  // because of this.
+  namespace test_template_alias_sfinae
+  {
+
+    struct foo {};
+
+    template<typename T>
+    using member = typename T::member_type;
+
+    template<typename T>
+    void func(...) {}
+
+    template<typename T>
+    void func(member<T>*) {}
+
+    void test();
+
+    void test() { func<foo>(0); }
+
+  }
+
+}  // namespace cxx11
+
+#endif  // __cplusplus >= 201103L
+
+
+
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  ax_cv_cxx_compile_cxx11=yes
+else
+  ax_cv_cxx_compile_cxx11=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_cxx_compile_cxx11" >&5
+$as_echo "$ax_cv_cxx_compile_cxx11" >&6; }
+  if test x$ax_cv_cxx_compile_cxx11 = xyes; then
+    ac_success=yes
+  fi
+
+    if test x$ac_success = xno; then
+    for alternative in ${ax_cxx_compile_alternatives}; do
+      switch="-std=gnu++${alternative}"
+      cachevar=`$as_echo "ax_cv_cxx_compile_cxx11_$switch" | $as_tr_sh`
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features with $switch" >&5
+$as_echo_n "checking whether $CXX supports C++11 features with $switch... " >&6; }
+if eval \${$cachevar+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_CXX="$CXX"
+         CXX="$CXX $switch"
+         cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+
+// If the compiler admits that it is not ready for C++11, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus < 201103L
+
+#error "This is not a C++11 compiler"
+
+#else
+
+namespace cxx11
+{
+
+  namespace test_static_assert
+  {
+
+    template <typename T>
+    struct check
+    {
+      static_assert(sizeof(int) <= sizeof(T), "not big enough");
+    };
+
+  }
+
+  namespace test_final_override
+  {
+
+    struct Base
+    {
+      virtual void f() {}
+    };
+
+    struct Derived : public Base
+    {
+      virtual void f() override {}
+    };
+
+  }
+
+  namespace test_double_right_angle_brackets
+  {
+
+    template < typename T >
+    struct check {};
+
+    typedef check<void> single_type;
+    typedef check<check<void>> double_type;
+    typedef check<check<check<void>>> triple_type;
+    typedef check<check<check<check<void>>>> quadruple_type;
+
+  }
+
+  namespace test_decltype
+  {
+
+    int
+    f()
+    {
+      int a = 1;
+      decltype(a) b = 2;
+      return a + b;
+    }
+
+  }
+
+  namespace test_type_deduction
+  {
+
+    template < typename T1, typename T2 >
+    struct is_same
+    {
+      static const bool value = false;
+    };
+
+    template < typename T >
+    struct is_same<T, T>
+    {
+      static const bool value = true;
+    };
+
+    template < typename T1, typename T2 >
+    auto
+    add(T1 a1, T2 a2) -> decltype(a1 + a2)
+    {
+      return a1 + a2;
+    }
+
+    int
+    test(const int c, volatile int v)
+    {
+      static_assert(is_same<int, decltype(0)>::value == true, "");
+      static_assert(is_same<int, decltype(c)>::value == false, "");
+      static_assert(is_same<int, decltype(v)>::value == false, "");
+      auto ac = c;
+      auto av = v;
+      auto sumi = ac + av + 'x';
+      auto sumf = ac + av + 1.0;
+      static_assert(is_same<int, decltype(ac)>::value == true, "");
+      static_assert(is_same<int, decltype(av)>::value == true, "");
+      static_assert(is_same<int, decltype(sumi)>::value == true, "");
+      static_assert(is_same<int, decltype(sumf)>::value == false, "");
+      static_assert(is_same<int, decltype(add(c, v))>::value == true, "");
+      return (sumf > 0.0) ? sumi : add(c, v);
+    }
+
+  }
+
+  namespace test_noexcept
+  {
+
+    int f() { return 0; }
+    int g() noexcept { return 0; }
+
+    static_assert(noexcept(f()) == false, "");
+    static_assert(noexcept(g()) == true, "");
+
+  }
+
+  namespace test_constexpr
+  {
+
+    template < typename CharT >
+    unsigned long constexpr
+    strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
+    {
+      return *s ? strlen_c_r(s + 1, acc + 1) : acc;
+    }
+
+    template < typename CharT >
+    unsigned long constexpr
+    strlen_c(const CharT *const s) noexcept
+    {
+      return strlen_c_r(s, 0UL);
+    }
+
+    static_assert(strlen_c("") == 0UL, "");
+    static_assert(strlen_c("1") == 1UL, "");
+    static_assert(strlen_c("example") == 7UL, "");
+    static_assert(strlen_c("another\0example") == 7UL, "");
+
+  }
+
+  namespace test_rvalue_references
+  {
+
+    template < int N >
+    struct answer
+    {
+      static constexpr int value = N;
+    };
+
+    answer<1> f(int&)       { return answer<1>(); }
+    answer<2> f(const int&) { return answer<2>(); }
+    answer<3> f(int&&)      { return answer<3>(); }
+
+    void
+    test()
+    {
+      int i = 0;
+      const int c = 0;
+      static_assert(decltype(f(i))::value == 1, "");
+      static_assert(decltype(f(c))::value == 2, "");
+      static_assert(decltype(f(0))::value == 3, "");
+    }
+
+  }
+
+  namespace test_uniform_initialization
+  {
+
+    struct test
+    {
+      static const int zero {};
+      static const int one {1};
+    };
+
+    static_assert(test::zero == 0, "");
+    static_assert(test::one == 1, "");
+
+  }
+
+  namespace test_lambdas
+  {
+
+    void
+    test1()
+    {
+      auto lambda1 = [](){};
+      auto lambda2 = lambda1;
+      lambda1();
+      lambda2();
+    }
+
+    int
+    test2()
+    {
+      auto a = [](int i, int j){ return i + j; }(1, 2);
+      auto b = []() -> int { return '0'; }();
+      auto c = [=](){ return a + b; }();
+      auto d = [&](){ return c; }();
+      auto e = [a, &b](int x) mutable {
+        const auto identity = [](int y){ return y; };
+        for (auto i = 0; i < a; ++i)
+          a += b--;
+        return x + identity(a + b);
+      }(0);
+      return a + b + c + d + e;
+    }
+
+    int
+    test3()
+    {
+      const auto nullary = [](){ return 0; };
+      const auto unary = [](int x){ return x; };
+      using nullary_t = decltype(nullary);
+      using unary_t = decltype(unary);
+      const auto higher1st = [](nullary_t f){ return f(); };
+      const auto higher2nd = [unary](nullary_t f1){
+        return [unary, f1](unary_t f2){ return f2(unary(f1())); };
+      };
+      return higher1st(nullary) + higher2nd(nullary)(unary);
+    }
+
+  }
+
+  namespace test_variadic_templates
+  {
+
+    template <int...>
+    struct sum;
+
+    template <int N0, int... N1toN>
+    struct sum<N0, N1toN...>
+    {
+      static constexpr auto value = N0 + sum<N1toN...>::value;
+    };
+
+    template <>
+    struct sum<>
+    {
+      static constexpr auto value = 0;
+    };
+
+    static_assert(sum<>::value == 0, "");
+    static_assert(sum<1>::value == 1, "");
+    static_assert(sum<23>::value == 23, "");
+    static_assert(sum<1, 2>::value == 3, "");
+    static_assert(sum<5, 5, 11>::value == 21, "");
+    static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
+
+  }
+
+  // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
+  // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
+  // because of this.
+  namespace test_template_alias_sfinae
+  {
+
+    struct foo {};
+
+    template<typename T>
+    using member = typename T::member_type;
+
+    template<typename T>
+    void func(...) {}
+
+    template<typename T>
+    void func(member<T>*) {}
+
+    void test();
+
+    void test() { func<foo>(0); }
+
+  }
+
+}  // namespace cxx11
+
+#endif  // __cplusplus >= 201103L
+
+
+
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  eval $cachevar=yes
+else
+  eval $cachevar=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+         CXX="$ac_save_CXX"
+fi
+eval ac_res=\$$cachevar
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+      if eval test x\$$cachevar = xyes; then
+        CXX="$CXX $switch"
+        if test -n "$CXXCPP" ; then
+          CXXCPP="$CXXCPP $switch"
+        fi
+        ac_success=yes
+        break
+      fi
+    done
+  fi
+
+    if test x$ac_success = xno; then
+                for alternative in ${ax_cxx_compile_alternatives}; do
+      for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do
+        cachevar=`$as_echo "ax_cv_cxx_compile_cxx11_$switch" | $as_tr_sh`
+        { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features with $switch" >&5
+$as_echo_n "checking whether $CXX supports C++11 features with $switch... " >&6; }
+if eval \${$cachevar+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_CXX="$CXX"
+           CXX="$CXX $switch"
+           cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+
+// If the compiler admits that it is not ready for C++11, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus < 201103L
+
+#error "This is not a C++11 compiler"
+
+#else
+
+namespace cxx11
+{
+
+  namespace test_static_assert
+  {
+
+    template <typename T>
+    struct check
+    {
+      static_assert(sizeof(int) <= sizeof(T), "not big enough");
+    };
+
+  }
+
+  namespace test_final_override
+  {
+
+    struct Base
+    {
+      virtual void f() {}
+    };
+
+    struct Derived : public Base
+    {
+      virtual void f() override {}
+    };
+
+  }
+
+  namespace test_double_right_angle_brackets
+  {
+
+    template < typename T >
+    struct check {};
+
+    typedef check<void> single_type;
+    typedef check<check<void>> double_type;
+    typedef check<check<check<void>>> triple_type;
+    typedef check<check<check<check<void>>>> quadruple_type;
+
+  }
+
+  namespace test_decltype
+  {
+
+    int
+    f()
+    {
+      int a = 1;
+      decltype(a) b = 2;
+      return a + b;
+    }
+
+  }
+
+  namespace test_type_deduction
+  {
+
+    template < typename T1, typename T2 >
+    struct is_same
+    {
+      static const bool value = false;
+    };
+
+    template < typename T >
+    struct is_same<T, T>
+    {
+      static const bool value = true;
+    };
+
+    template < typename T1, typename T2 >
+    auto
+    add(T1 a1, T2 a2) -> decltype(a1 + a2)
+    {
+      return a1 + a2;
+    }
+
+    int
+    test(const int c, volatile int v)
+    {
+      static_assert(is_same<int, decltype(0)>::value == true, "");
+      static_assert(is_same<int, decltype(c)>::value == false, "");
+      static_assert(is_same<int, decltype(v)>::value == false, "");
+      auto ac = c;
+      auto av = v;
+      auto sumi = ac + av + 'x';
+      auto sumf = ac + av + 1.0;
+      static_assert(is_same<int, decltype(ac)>::value == true, "");
+      static_assert(is_same<int, decltype(av)>::value == true, "");
+      static_assert(is_same<int, decltype(sumi)>::value == true, "");
+      static_assert(is_same<int, decltype(sumf)>::value == false, "");
+      static_assert(is_same<int, decltype(add(c, v))>::value == true, "");
+      return (sumf > 0.0) ? sumi : add(c, v);
+    }
+
+  }
+
+  namespace test_noexcept
+  {
+
+    int f() { return 0; }
+    int g() noexcept { return 0; }
+
+    static_assert(noexcept(f()) == false, "");
+    static_assert(noexcept(g()) == true, "");
+
+  }
+
+  namespace test_constexpr
+  {
+
+    template < typename CharT >
+    unsigned long constexpr
+    strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
+    {
+      return *s ? strlen_c_r(s + 1, acc + 1) : acc;
+    }
+
+    template < typename CharT >
+    unsigned long constexpr
+    strlen_c(const CharT *const s) noexcept
+    {
+      return strlen_c_r(s, 0UL);
+    }
+
+    static_assert(strlen_c("") == 0UL, "");
+    static_assert(strlen_c("1") == 1UL, "");
+    static_assert(strlen_c("example") == 7UL, "");
+    static_assert(strlen_c("another\0example") == 7UL, "");
+
+  }
+
+  namespace test_rvalue_references
+  {
+
+    template < int N >
+    struct answer
+    {
+      static constexpr int value = N;
+    };
+
+    answer<1> f(int&)       { return answer<1>(); }
+    answer<2> f(const int&) { return answer<2>(); }
+    answer<3> f(int&&)      { return answer<3>(); }
+
+    void
+    test()
+    {
+      int i = 0;
+      const int c = 0;
+      static_assert(decltype(f(i))::value == 1, "");
+      static_assert(decltype(f(c))::value == 2, "");
+      static_assert(decltype(f(0))::value == 3, "");
+    }
+
+  }
+
+  namespace test_uniform_initialization
+  {
+
+    struct test
+    {
+      static const int zero {};
+      static const int one {1};
+    };
+
+    static_assert(test::zero == 0, "");
+    static_assert(test::one == 1, "");
+
+  }
+
+  namespace test_lambdas
+  {
+
+    void
+    test1()
+    {
+      auto lambda1 = [](){};
+      auto lambda2 = lambda1;
+      lambda1();
+      lambda2();
+    }
+
+    int
+    test2()
+    {
+      auto a = [](int i, int j){ return i + j; }(1, 2);
+      auto b = []() -> int { return '0'; }();
+      auto c = [=](){ return a + b; }();
+      auto d = [&](){ return c; }();
+      auto e = [a, &b](int x) mutable {
+        const auto identity = [](int y){ return y; };
+        for (auto i = 0; i < a; ++i)
+          a += b--;
+        return x + identity(a + b);
+      }(0);
+      return a + b + c + d + e;
+    }
+
+    int
+    test3()
+    {
+      const auto nullary = [](){ return 0; };
+      const auto unary = [](int x){ return x; };
+      using nullary_t = decltype(nullary);
+      using unary_t = decltype(unary);
+      const auto higher1st = [](nullary_t f){ return f(); };
+      const auto higher2nd = [unary](nullary_t f1){
+        return [unary, f1](unary_t f2){ return f2(unary(f1())); };
+      };
+      return higher1st(nullary) + higher2nd(nullary)(unary);
+    }
+
+  }
+
+  namespace test_variadic_templates
+  {
+
+    template <int...>
+    struct sum;
+
+    template <int N0, int... N1toN>
+    struct sum<N0, N1toN...>
+    {
+      static constexpr auto value = N0 + sum<N1toN...>::value;
+    };
+
+    template <>
+    struct sum<>
+    {
+      static constexpr auto value = 0;
+    };
+
+    static_assert(sum<>::value == 0, "");
+    static_assert(sum<1>::value == 1, "");
+    static_assert(sum<23>::value == 23, "");
+    static_assert(sum<1, 2>::value == 3, "");
+    static_assert(sum<5, 5, 11>::value == 21, "");
+    static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
+
+  }
+
+  // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
+  // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
+  // because of this.
+  namespace test_template_alias_sfinae
+  {
+
+    struct foo {};
+
+    template<typename T>
+    using member = typename T::member_type;
+
+    template<typename T>
+    void func(...) {}
+
+    template<typename T>
+    void func(member<T>*) {}
+
+    void test();
+
+    void test() { func<foo>(0); }
+
+  }
+
+}  // namespace cxx11
+
+#endif  // __cplusplus >= 201103L
+
+
+
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  eval $cachevar=yes
+else
+  eval $cachevar=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+           CXX="$ac_save_CXX"
+fi
+eval ac_res=\$$cachevar
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+        if eval test x\$$cachevar = xyes; then
+          CXX="$CXX $switch"
+          if test -n "$CXXCPP" ; then
+            CXXCPP="$CXXCPP $switch"
+          fi
+          ac_success=yes
+          break
+        fi
+      done
+      if test x$ac_success = xyes; then
+        break
+      fi
+    done
+  fi
+  ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+  if test x$ax_cxx_compile_cxx11_required = xtrue; then
+    if test x$ac_success = xno; then
+      as_fn_error $? "*** A compiler with support for C++11 language features is required." "$LINENO" 5
+    fi
+  fi
+  if test x$ac_success = xno; then
+    HAVE_CXX11=0
+    { $as_echo "$as_me:${as_lineno-$LINENO}: No compiler with C++11 support was found" >&5
+$as_echo "$as_me: No compiler with C++11 support was found" >&6;}
+  else
+    HAVE_CXX11=1
+
+$as_echo "#define HAVE_CXX11 1" >>confdefs.h
+
+  fi
+
+
+
+fi
+
 if test "x$enable_texlive_build" = xyes; then :
   banner_pre='TeX Live'
 else
diff --git a/source/texk/web2c/configure.ac b/source/texk/web2c/configure.ac
index c6cd65893fe7e032bb59c70a589c39fb1ae36f2c..e65b3e6c098e6c574b256a4255721545ea93f5d5 100644
--- a/source/texk/web2c/configure.ac
+++ b/source/texk/web2c/configure.ac
@@ -1,6 +1,8 @@
+dnl $Id: configure.ac 46257 2018-01-09 18:53:05Z karl $
 dnl Process this file with Autoconf to produce a configure script for Web2c.
 dnl
-dnl   Copyright (C) 2009-2015 Peter Breitenlohner <tex-live@tug.org>
+dnl   Copyright 2018 Karl Berry <tex-live@tug.org>
+dnl   Copyright 2009-2015 Peter Breitenlohner <tex-live@tug.org>
 dnl
 dnl   This file is free software; the copyright holder
 dnl   gives unlimited permission to copy and/or distribute it,
@@ -15,9 +17,7 @@ dnl   more than 256 fonts.
 dnl - NONASCII: necessary for the character translation feature.
 dnl - REGFIX: modern compilers mostly ignore register declarations, anyway.
 dnl The code for these things remains (where applicable), so you can
-dnl get these features if you are willing to hack the sources. If not,
-dnl it'll take a good argument to convince me to invest the time to make
-dnl them configurable.
+dnl get these features if you are willing to hack the sources.
 dnl
 m4_include([../../version.ac])[] dnl define tex_live_version
 AC_INIT([Web2C], tex_live_version(), [tex-k@tug.org])
@@ -46,6 +46,15 @@ dnl Include additional code for web2c.
 KPSE_WEB2C_PREPARE
 m4_include([ac/web2c.ac])
 
+dnl LuaTeX requires C++11 because poppler does :(.
+if test "x$enable_xetex" = xyes \
+   || test "x$enable_luatex" = xyes \
+   || test "x$enable_luajittex" = xyes \
+   || test "x$enable_luatex53" = xyes; then
+  AC_MSG_NOTICE(LuaTeX enabled, requiring C++11 support)
+  AX_CXX_COMPILE_STDCXX([11])
+fi
+
 AS_IF([test "x$enable_texlive_build" = xyes],
       [banner_pre='TeX Live'],
       [banner_pre='Web2C'])
diff --git a/source/texk/web2c/doc/Makefile.in b/source/texk/web2c/doc/Makefile.in
index 26ad32df1de89dd484210c4ab8fa8805ab572721..e781f9c0b063c272c0db4b68497c33d23b6b27c5 100644
--- a/source/texk/web2c/doc/Makefile.in
+++ b/source/texk/web2c/doc/Makefile.in
@@ -90,6 +90,7 @@ host_triplet = @host@
 subdir = doc
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/web2c-disable.m4 \
+	$(top_srcdir)/../../m4/ax_cxx_compile_stdcxx.m4 \
 	$(top_srcdir)/../../m4/kpse-asm.m4 \
 	$(top_srcdir)/../../m4/kpse-cairo-flags.m4 \
 	$(top_srcdir)/../../m4/kpse-common.m4 \
@@ -283,6 +284,7 @@ GREP = @GREP@
 HARFBUZZ_DEPEND = @HARFBUZZ_DEPEND@
 HARFBUZZ_INCLUDES = @HARFBUZZ_INCLUDES@
 HARFBUZZ_LIBS = @HARFBUZZ_LIBS@
+HAVE_CXX11 = @HAVE_CXX11@
 ICU_CONFIG = @ICU_CONFIG@
 ICU_DEPEND = @ICU_DEPEND@
 ICU_INCLUDES = @ICU_INCLUDES@
diff --git a/source/texk/web2c/lib/Makefile.in b/source/texk/web2c/lib/Makefile.in
index ea962fecfa17ec145ef624838b846efd4291a688..f4dca2c18edbc07548a577b4c93a8cf15a2db9d6 100644
--- a/source/texk/web2c/lib/Makefile.in
+++ b/source/texk/web2c/lib/Makefile.in
@@ -92,6 +92,7 @@ host_triplet = @host@
 subdir = lib
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/web2c-disable.m4 \
+	$(top_srcdir)/../../m4/ax_cxx_compile_stdcxx.m4 \
 	$(top_srcdir)/../../m4/kpse-asm.m4 \
 	$(top_srcdir)/../../m4/kpse-cairo-flags.m4 \
 	$(top_srcdir)/../../m4/kpse-common.m4 \
@@ -279,6 +280,7 @@ GREP = @GREP@
 HARFBUZZ_DEPEND = @HARFBUZZ_DEPEND@
 HARFBUZZ_INCLUDES = @HARFBUZZ_INCLUDES@
 HARFBUZZ_LIBS = @HARFBUZZ_LIBS@
+HAVE_CXX11 = @HAVE_CXX11@
 ICU_CONFIG = @ICU_CONFIG@
 ICU_DEPEND = @ICU_DEPEND@
 ICU_INCLUDES = @ICU_INCLUDES@
diff --git a/source/texk/web2c/luatexdir/NEWS b/source/texk/web2c/luatexdir/NEWS
index 9afef8d6ab8808733657b2ca5d4697f8bf09ad41..eacbe3cd34d8f603dba4bbc2620cdaf2d08887ff 100644
--- a/source/texk/web2c/luatexdir/NEWS
+++ b/source/texk/web2c/luatexdir/NEWS
@@ -1,16 +1,6 @@
 
 This file is in the public domain.
 
-
-==============================================================
-LuaTeX Release 1.06.3  was released 2018.01.08
-==============================================================
-
-Transition release, from lua52-only code base to "mix" -- 
-lua52 & lua53 code base.
-
-
-
 ==============================================================
 LuaTeX Release 1.0.4  was released 2017033109
 ==============================================================
diff --git a/source/texk/web2c/man/Makefile.in b/source/texk/web2c/man/Makefile.in
index cd3823eb383fd6ac2d009aa29b5f38517ffbd230..588395fbebc3990a732aec372a3b5b73689e9c9b 100644
--- a/source/texk/web2c/man/Makefile.in
+++ b/source/texk/web2c/man/Makefile.in
@@ -107,6 +107,7 @@ host_triplet = @host@
 subdir = man
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/web2c-disable.m4 \
+	$(top_srcdir)/../../m4/ax_cxx_compile_stdcxx.m4 \
 	$(top_srcdir)/../../m4/kpse-asm.m4 \
 	$(top_srcdir)/../../m4/kpse-cairo-flags.m4 \
 	$(top_srcdir)/../../m4/kpse-common.m4 \
@@ -261,6 +262,7 @@ GREP = @GREP@
 HARFBUZZ_DEPEND = @HARFBUZZ_DEPEND@
 HARFBUZZ_INCLUDES = @HARFBUZZ_INCLUDES@
 HARFBUZZ_LIBS = @HARFBUZZ_LIBS@
+HAVE_CXX11 = @HAVE_CXX11@
 ICU_CONFIG = @ICU_CONFIG@
 ICU_DEPEND = @ICU_DEPEND@
 ICU_INCLUDES = @ICU_INCLUDES@
diff --git a/source/texk/web2c/omegafonts/Makefile.in b/source/texk/web2c/omegafonts/Makefile.in
index e369d0ded4d7caaa85d33076febab40b2886ebb9..4c03b3a9227ce0ca8e8a9c81565ef9180bd96fcd 100644
--- a/source/texk/web2c/omegafonts/Makefile.in
+++ b/source/texk/web2c/omegafonts/Makefile.in
@@ -95,6 +95,7 @@ EXTRA_PROGRAMS = omfonts$(EXEEXT)
 subdir = omegafonts
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/web2c-disable.m4 \
+	$(top_srcdir)/../../m4/ax_cxx_compile_stdcxx.m4 \
 	$(top_srcdir)/../../m4/kpse-asm.m4 \
 	$(top_srcdir)/../../m4/kpse-cairo-flags.m4 \
 	$(top_srcdir)/../../m4/kpse-common.m4 \
@@ -505,6 +506,7 @@ GREP = @GREP@
 HARFBUZZ_DEPEND = @HARFBUZZ_DEPEND@
 HARFBUZZ_INCLUDES = @HARFBUZZ_INCLUDES@
 HARFBUZZ_LIBS = @HARFBUZZ_LIBS@
+HAVE_CXX11 = @HAVE_CXX11@
 ICU_CONFIG = @ICU_CONFIG@
 ICU_DEPEND = @ICU_DEPEND@
 ICU_INCLUDES = @ICU_INCLUDES@
diff --git a/source/texk/web2c/otps/Makefile.in b/source/texk/web2c/otps/Makefile.in
index fcb8085b0545ae0be9a6abaaac75c1b7dcb1f852..f9dc26db66fd7bae844702fa6085fac85af3d1b2 100644
--- a/source/texk/web2c/otps/Makefile.in
+++ b/source/texk/web2c/otps/Makefile.in
@@ -95,6 +95,7 @@ EXTRA_PROGRAMS = $(am__EXEEXT_1)
 subdir = otps
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/web2c-disable.m4 \
+	$(top_srcdir)/../../m4/ax_cxx_compile_stdcxx.m4 \
 	$(top_srcdir)/../../m4/kpse-asm.m4 \
 	$(top_srcdir)/../../m4/kpse-cairo-flags.m4 \
 	$(top_srcdir)/../../m4/kpse-common.m4 \
@@ -545,6 +546,7 @@ GREP = @GREP@
 HARFBUZZ_DEPEND = @HARFBUZZ_DEPEND@
 HARFBUZZ_INCLUDES = @HARFBUZZ_INCLUDES@
 HARFBUZZ_LIBS = @HARFBUZZ_LIBS@
+HAVE_CXX11 = @HAVE_CXX11@
 ICU_CONFIG = @ICU_CONFIG@
 ICU_DEPEND = @ICU_DEPEND@
 ICU_INCLUDES = @ICU_INCLUDES@
diff --git a/source/texk/web2c/otps/win32/Makefile.in b/source/texk/web2c/otps/win32/Makefile.in
index 846384909d1e062601eed73dfc69f8e32b5c309a..de340f943c7c622294603a5ca520fa57cfe7aa09 100644
--- a/source/texk/web2c/otps/win32/Makefile.in
+++ b/source/texk/web2c/otps/win32/Makefile.in
@@ -92,6 +92,7 @@ bin_PROGRAMS = mkocp$(EXEEXT) mkofm$(EXEEXT)
 subdir = otps/win32
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/web2c-disable.m4 \
+	$(top_srcdir)/../../m4/ax_cxx_compile_stdcxx.m4 \
 	$(top_srcdir)/../../m4/kpse-asm.m4 \
 	$(top_srcdir)/../../m4/kpse-cairo-flags.m4 \
 	$(top_srcdir)/../../m4/kpse-common.m4 \
@@ -267,6 +268,7 @@ GREP = @GREP@
 HARFBUZZ_DEPEND = @HARFBUZZ_DEPEND@
 HARFBUZZ_INCLUDES = @HARFBUZZ_INCLUDES@
 HARFBUZZ_LIBS = @HARFBUZZ_LIBS@
+HAVE_CXX11 = @HAVE_CXX11@
 ICU_CONFIG = @ICU_CONFIG@
 ICU_DEPEND = @ICU_DEPEND@
 ICU_INCLUDES = @ICU_INCLUDES@
diff --git a/source/texk/web2c/window/Makefile.in b/source/texk/web2c/window/Makefile.in
index 725182562f74ed4dbd023e61b551c5fa5aeafe43..6948342d06edb0ebf430ff5b589bc79064e8482b 100644
--- a/source/texk/web2c/window/Makefile.in
+++ b/source/texk/web2c/window/Makefile.in
@@ -92,6 +92,7 @@ host_triplet = @host@
 subdir = window
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/web2c-disable.m4 \
+	$(top_srcdir)/../../m4/ax_cxx_compile_stdcxx.m4 \
 	$(top_srcdir)/../../m4/kpse-asm.m4 \
 	$(top_srcdir)/../../m4/kpse-cairo-flags.m4 \
 	$(top_srcdir)/../../m4/kpse-common.m4 \
@@ -277,6 +278,7 @@ GREP = @GREP@
 HARFBUZZ_DEPEND = @HARFBUZZ_DEPEND@
 HARFBUZZ_INCLUDES = @HARFBUZZ_INCLUDES@
 HARFBUZZ_LIBS = @HARFBUZZ_LIBS@
+HAVE_CXX11 = @HAVE_CXX11@
 ICU_CONFIG = @ICU_CONFIG@
 ICU_DEPEND = @ICU_DEPEND@
 ICU_INCLUDES = @ICU_INCLUDES@
diff --git a/source/utils/README b/source/utils/README
index c81340454db20a7f4e2e6b9582529ff1eac84560..0f470d1004dd9dc29e16594a2f9c377a2d021c49 100644
--- a/source/utils/README
+++ b/source/utils/README
@@ -1,4 +1,4 @@
-$Id: README 46169 2017-12-30 22:19:20Z kakuto $
+$Id: README 46254 2018-01-09 03:41:12Z kakuto $
 Public domain.  Originally written 2005 by Karl Berry.
 
 Extra utilities we (optionally) compile for TeX Live.
@@ -17,7 +17,7 @@ devnag - from devanagari package installed in texmf-dist.
 
 lacheck - maintained here, by us
 
-m-tx 0.62 - checked 10feb16
+m-tx 0.63 - checked 09jan18
   http://ctan.org/pkg/m-tx/
 
 pmx 2.7.6 - checked 09dec16