pdftex[845] branches/stable/source/src: sync with tl 57745, for

commits+karl at tug.org commits+karl at tug.org
Mon Feb 15 20:17:21 CET 2021


Revision: 845
          http://tug.org/svn/pdftex?view=revision&revision=845
Author:   karl
Date:     2021-02-15 20:17:20 +0100 (Mon, 15 Feb 2021)
Log Message:
-----------
sync with tl 57745, for \tracingstacklevels etc.

Modified Paths:
--------------
    branches/stable/source/src/Makefile.in
    branches/stable/source/src/build-aux/config.guess
    branches/stable/source/src/build-aux/config.sub
    branches/stable/source/src/configure
    branches/stable/source/src/doc/ChangeLog
    branches/stable/source/src/doc/Makefile.in
    branches/stable/source/src/doc/tlbuild.info
    branches/stable/source/src/doc/tlbuild.texi
    branches/stable/source/src/libs/Makefile.in
    branches/stable/source/src/libs/README
    branches/stable/source/src/libs/configure
    branches/stable/source/src/libs/xpdf/ChangeLog
    branches/stable/source/src/libs/xpdf/Makefile.am
    branches/stable/source/src/libs/xpdf/Makefile.in
    branches/stable/source/src/libs/xpdf/TLpatches/ChangeLog
    branches/stable/source/src/libs/xpdf/TLpatches/TL-Changes
    branches/stable/source/src/libs/xpdf/TLpatches/patch-bunched
    branches/stable/source/src/libs/xpdf/configure
    branches/stable/source/src/libs/xpdf/version.ac
    branches/stable/source/src/libs/xpdf/xpdf-src/ANNOUNCE
    branches/stable/source/src/libs/xpdf/xpdf-src/CHANGES
    branches/stable/source/src/libs/xpdf/xpdf-src/INSTALL
    branches/stable/source/src/libs/xpdf/xpdf-src/README
    branches/stable/source/src/libs/xpdf/xpdf-src/cmake-config.txt
    branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdfdetach.1
    branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdfdetach.cat
    branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdffonts.1
    branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdffonts.cat
    branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdfimages.1
    branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdfimages.cat
    branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdfinfo.1
    branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdfinfo.cat
    branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftohtml.1
    branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftohtml.cat
    branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftopng.1
    branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftopng.cat
    branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftoppm.1
    branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftoppm.cat
    branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftops.1
    branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftops.cat
    branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftotext.1
    branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftotext.cat
    branches/stable/source/src/libs/xpdf/xpdf-src/doc/xpdf.1
    branches/stable/source/src/libs/xpdf/xpdf-src/doc/xpdf.cat
    branches/stable/source/src/libs/xpdf/xpdf-src/doc/xpdfrc.5
    branches/stable/source/src/libs/xpdf/xpdf-src/doc/xpdfrc.cat
    branches/stable/source/src/libs/xpdf/xpdf-src/fofi/FoFiIdentifier.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/fofi/FoFiTrueType.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/fofi/FoFiType1.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/fofi/FoFiType1C.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/fofi/FoFiType1C.h
    branches/stable/source/src/libs/xpdf/xpdf-src/goo/CMakeLists.txt
    branches/stable/source/src/libs/xpdf/xpdf-src/goo/FixedPoint.h
    branches/stable/source/src/libs/xpdf/xpdf-src/goo/gfile.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/goo/gfile.h
    branches/stable/source/src/libs/xpdf/xpdf-src/goo/gmem.h
    branches/stable/source/src/libs/xpdf/xpdf-src/splash/Splash.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/splash/Splash.h
    branches/stable/source/src/libs/xpdf/xpdf-src/splash/SplashBitmap.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/splash/SplashBitmap.h
    branches/stable/source/src/libs/xpdf/xpdf-src/splash/SplashFont.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/splash/SplashFontEngine.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/splash/SplashFontEngine.h
    branches/stable/source/src/libs/xpdf/xpdf-src/splash/SplashXPath.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/AcroForm.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/AcroForm.h
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Annot.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/CMakeLists.txt
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Catalog.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Catalog.h
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/CharCodeToUnicode.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/CharCodeToUnicode.h
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Gfx.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Gfx.h
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/GfxFont.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/GfxFont.h
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/GfxState.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/GfxState.h
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/GlobalParams.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/GlobalParams.h
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/HTMLGen.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/ImageOutputDev.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/ImageOutputDev.h
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/JBIG2Stream.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/JBIG2Stream.h
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/JPXStream.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/JPXStream.h
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Lexer.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Object.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/OptionalContent.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/OutputDev.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/OutputDev.h
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/PDFCore.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/PDFCore.h
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/PDFDoc.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/PDFDoc.h
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/PSOutputDev.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/PSOutputDev.h
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Page.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Page.h
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/PreScanOutputDev.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/PreScanOutputDev.h
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/SplashOutputDev.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/SplashOutputDev.h
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Stream.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Stream.h
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/TextOutputDev.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/TextOutputDev.h
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/TextString.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/TextString.h
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/WebFont.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/XRef.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/XRef.h
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Zoox.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Zoox.h
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/config.h
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/pdfdetach.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/pdffonts.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/pdfimages.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/pdfinfo.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/pdftohtml.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/pdftopng.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/pdftoppm.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/pdftops.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/pdftotext.cc
    branches/stable/source/src/m4/ChangeLog
    branches/stable/source/src/m4/kpse-pkgs.m4
    branches/stable/source/src/m4/kpse-setup.m4
    branches/stable/source/src/texk/Makefile.in
    branches/stable/source/src/texk/README
    branches/stable/source/src/texk/configure
    branches/stable/source/src/texk/kpathsea/texmf.cnf
    branches/stable/source/src/texk/web2c/ChangeLog
    branches/stable/source/src/texk/web2c/Makefile.am
    branches/stable/source/src/texk/web2c/Makefile.in
    branches/stable/source/src/texk/web2c/NEWS
    branches/stable/source/src/texk/web2c/am/texmf.am
    branches/stable/source/src/texk/web2c/ctangleboot.cin
    branches/stable/source/src/texk/web2c/cwebboot.cin
    branches/stable/source/src/texk/web2c/cwebdir/ChangeLog
    branches/stable/source/src/texk/web2c/cwebdir/Makefile
    branches/stable/source/src/texk/web2c/cwebdir/README
    branches/stable/source/src/texk/web2c/cwebdir/comm-amiga.ch
    branches/stable/source/src/texk/web2c/cwebdir/comm-bs.ch
    branches/stable/source/src/texk/web2c/cwebdir/comm-mac.ch
    branches/stable/source/src/texk/web2c/cwebdir/comm-os2.ch
    branches/stable/source/src/texk/web2c/cwebdir/comm-pc.ch
    branches/stable/source/src/texk/web2c/cwebdir/comm-ql.ch
    branches/stable/source/src/texk/web2c/cwebdir/comm-vms.ch
    branches/stable/source/src/texk/web2c/cwebdir/comm-w2c.ch
    branches/stable/source/src/texk/web2c/cwebdir/comm-w2c.h
    branches/stable/source/src/texk/web2c/cwebdir/comm-w32.ch
    branches/stable/source/src/texk/web2c/cwebdir/common.c
    branches/stable/source/src/texk/web2c/cwebdir/common.h
    branches/stable/source/src/texk/web2c/cwebdir/common.w
    branches/stable/source/src/texk/web2c/cwebdir/ctang-bs.ch
    branches/stable/source/src/texk/web2c/cwebdir/ctang-man.ch
    branches/stable/source/src/texk/web2c/cwebdir/ctang-pc.ch
    branches/stable/source/src/texk/web2c/cwebdir/ctang-ql.ch
    branches/stable/source/src/texk/web2c/cwebdir/ctang-vms.ch
    branches/stable/source/src/texk/web2c/cwebdir/ctang-w2c.ch
    branches/stable/source/src/texk/web2c/cwebdir/ctang-w32.ch
    branches/stable/source/src/texk/web2c/cwebdir/ctangle.c
    branches/stable/source/src/texk/web2c/cwebdir/ctangle.w
    branches/stable/source/src/texk/web2c/cwebdir/ctwill-mini.ch
    branches/stable/source/src/texk/web2c/cwebdir/ctwill-w2c.ch
    branches/stable/source/src/texk/web2c/cwebdir/ctwill.bux
    branches/stable/source/src/texk/web2c/cwebdir/cweav-bs.ch
    branches/stable/source/src/texk/web2c/cwebdir/cweav-man.ch
    branches/stable/source/src/texk/web2c/cwebdir/cweav-pc.ch
    branches/stable/source/src/texk/web2c/cwebdir/cweav-ql.ch
    branches/stable/source/src/texk/web2c/cwebdir/cweav-vms.ch
    branches/stable/source/src/texk/web2c/cwebdir/cweav-w2c.ch
    branches/stable/source/src/texk/web2c/cwebdir/cweav-w32.ch
    branches/stable/source/src/texk/web2c/cwebdir/cweave.w
    branches/stable/source/src/texk/web2c/cwebdir/cweb.1
    branches/stable/source/src/texk/web2c/cwebdir/cwebmac.tex
    branches/stable/source/src/texk/web2c/cwebdir/cwebman-w2c.ch
    branches/stable/source/src/texk/web2c/cwebdir/cwebman.tex
    branches/stable/source/src/texk/web2c/cwebdir/examples/wmerge.w
    branches/stable/source/src/texk/web2c/cwebdir/po/cweb-tl.pot
    branches/stable/source/src/texk/web2c/cwebdir/po/cweb.pot
    branches/stable/source/src/texk/web2c/cwebdir/po/de/cweb-tl.po
    branches/stable/source/src/texk/web2c/cwebdir/po/de/cweb.po
    branches/stable/source/src/texk/web2c/cwebdir/po/de/web2c-help.po
    branches/stable/source/src/texk/web2c/cwebdir/po/it/cweb.po
    branches/stable/source/src/texk/web2c/cwebdir/po/web2c-help.pot
    branches/stable/source/src/texk/web2c/cwebdir/system.bux
    branches/stable/source/src/texk/web2c/cwebdir/texinputs/pdfctwimac.tex
    branches/stable/source/src/texk/web2c/etexdir/ChangeLog
    branches/stable/source/src/texk/web2c/etexdir/am/etex.am
    branches/stable/source/src/texk/web2c/etexdir/etex.ch
    branches/stable/source/src/texk/web2c/etexdir/etexextra.h
    branches/stable/source/src/texk/web2c/etexdir/etrip/etrip.diffs
    branches/stable/source/src/texk/web2c/etexdir/etrip/etrip.tex
    branches/stable/source/src/texk/web2c/etexdir/tex.ch0
    branches/stable/source/src/texk/web2c/etexdir/tex.ech
    branches/stable/source/src/texk/web2c/lib/texmfmp.c
    branches/stable/source/src/texk/web2c/pdftexdir/ChangeLog
    branches/stable/source/src/texk/web2c/pdftexdir/am/pdftex.am
    branches/stable/source/src/texk/web2c/pdftexdir/pdftex.web
    branches/stable/source/src/texk/web2c/pdftexdir/pdftexextra.h
    branches/stable/source/src/texk/web2c/pdftexdir/tex.ch0
    branches/stable/source/src/texk/web2c/pdftexdir/tounicode.c
    branches/stable/source/src/texk/web2c/synctexdir/synctex-ep-mem.ch1
    branches/stable/source/src/texk/web2c/synctexdir/synctex-p-mem.ch1
    branches/stable/source/src/texk/web2c/tangle.ch
    branches/stable/source/src/texk/web2c/tangle.web
    branches/stable/source/src/texk/web2c/tangleboot.pin
    branches/stable/source/src/texk/web2c/tex.ch
    branches/stable/source/src/texk/web2c/triptrap-sh
    branches/stable/source/src/utils/Makefile.in
    branches/stable/source/src/utils/README
    branches/stable/source/src/utils/configure

Added Paths:
-----------
    branches/stable/source/src/libs/xpdf/xpdf-src/goo/Trace.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/goo/Trace.h
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/ShadingImage.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/ShadingImage.h
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/XFAScanner.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/XFAScanner.h
    branches/stable/source/src/texk/web2c/enctexdir/
    branches/stable/source/src/texk/web2c/enctexdir/enctex-pdftex.ch
    branches/stable/source/src/texk/web2c/enctexdir/enctex-tex.ch
    branches/stable/source/src/texk/web2c/enctexdir/enctex1.ch
    branches/stable/source/src/texk/web2c/enctexdir/enctex2.ch
    branches/stable/source/src/texk/web2c/tests/tracinglostchars.tex
    branches/stable/source/src/texk/web2c/tests/tracingstacklevel2.tex
    branches/stable/source/src/texk/web2c/tests/tracingstacklevels.tex
    branches/stable/source/src/texk/web2c/tracingstacklevels.ch

Removed Paths:
-------------
    branches/stable/source/src/doc/tlbuild.cp
    branches/stable/source/src/doc/tlbuild.cps
    branches/stable/source/src/doc/tlbuild.pdf
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Form.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Form.h
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/XFAForm.cc
    branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/XFAForm.h
    branches/stable/source/src/texk/web2c/cwebdir/texinputs/p+cwebmac.tex
    branches/stable/source/src/texk/web2c/enctex.ch

Modified: branches/stable/source/src/Makefile.in
===================================================================
--- branches/stable/source/src/Makefile.in	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/Makefile.in	2021-02-15 19:17:20 UTC (rev 845)
@@ -134,6 +134,7 @@
 	$(top_srcdir)/utils/xindy/ac/withenable.ac \
 	$(top_srcdir)/utils/xindy/ac/xindy.ac \
 	$(top_srcdir)/utils/xindy/ac/clisp.ac \
+	$(top_srcdir)/utils/xml2pmx/ac/withenable.ac \
 	$(top_srcdir)/utils/xpdfopen/ac/withenable.ac \
 	$(top_srcdir)/texk/web2c/ac/withenable.ac \
 	$(top_srcdir)/texk/web2c/ac/web2c.ac \

Modified: branches/stable/source/src/build-aux/config.guess
===================================================================
--- branches/stable/source/src/build-aux/config.guess	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/build-aux/config.guess	2021-02-15 19:17:20 UTC (rev 845)
@@ -2,7 +2,7 @@
 # Attempt to guess a canonical system name.
 #   Copyright 1992-2021 Free Software Foundation, Inc.
 
-timestamp='2021-01-01'
+timestamp='2021-01-25'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -188,10 +188,9 @@
 	#
 	# Note: NetBSD doesn't particularly care about the vendor
 	# portion of the name.  We always set it to "unknown".
-	sysctl="sysctl -n hw.machine_arch"
 	UNAME_MACHINE_ARCH=$( (uname -p 2>/dev/null || \
-	    "/sbin/$sysctl" 2>/dev/null || \
-	    "/usr/sbin/$sysctl" 2>/dev/null || \
+	    /sbin/sysctl -n hw.machine_arch 2>/dev/null || \
+	    /usr/sbin/sysctl -n hw.machine_arch 2>/dev/null || \
 	    echo unknown))
 	case "$UNAME_MACHINE_ARCH" in
 	    aarch64eb) machine=aarch64_be-unknown ;;
@@ -1483,8 +1482,8 @@
     i*86:rdos:*:*)
 	echo "$UNAME_MACHINE"-pc-rdos
 	exit ;;
-    i*86:AROS:*:*)
-	echo "$UNAME_MACHINE"-pc-aros
+    *:AROS:*:*)
+	echo "$UNAME_MACHINE"-unknown-aros
 	exit ;;
     x86_64:VMkernel:*:*)
 	echo "$UNAME_MACHINE"-unknown-esx

Modified: branches/stable/source/src/build-aux/config.sub
===================================================================
--- branches/stable/source/src/build-aux/config.sub	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/build-aux/config.sub	2021-02-15 19:17:20 UTC (rev 845)
@@ -2,7 +2,7 @@
 # Configuration validation subroutine script.
 #   Copyright 1992-2021 Free Software Foundation, Inc.
 
-timestamp='2021-01-07'
+timestamp='2021-01-08'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -1683,12 +1683,15 @@
 
 # Now, validate our (potentially fixed-up) OS.
 case $os in
-	# Sometimes we do "kernel-abi", so those need to count as OSes.
+	# Sometimes we do "kernel-libc", so those need to count as OSes.
 	musl* | newlib* | uclibc*)
 		;;
-	# Likewise for "kernel-libc"
+	# Likewise for "kernel-abi"
 	eabi* | gnueabi*)
 		;;
+	# VxWorks passes extra cpu info in the 4th filed.
+	simlinux | simwindows | spe)
+		;;
 	# Now accept the basic system types.
 	# The portable systems comes first.
 	# Each alternative MUST end in a * to match a version number.
@@ -1751,6 +1754,8 @@
 		;;
 	kfreebsd*-gnu* | kopensolaris*-gnu*)
 		;;
+	vxworks-simlinux | vxworks-simwindows | vxworks-spe)
+		;;
 	nto-qnx*)
 		;;
 	os2-emx)

Modified: branches/stable/source/src/configure
===================================================================
--- branches/stable/source/src/configure	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/configure	2021-02-15 19:17:20 UTC (rev 845)
@@ -800,6 +800,7 @@
 enable_xindy_rules
 enable_xindy_docs
 with_clisp_runtime
+enable_xml2pmx
 enable_xpdfopen
 enable_web2c
 with_banner_add
@@ -1607,6 +1608,7 @@
   --enable-xindy          build the xindy package
   --enable-xindy-rules      build and install make-rules package
   --enable-xindy-docs       build and install documentation
+  --disable-xml2pmx       do not build the xml2pmx package
   --disable-xpdfopen      do not build the xpdfopen package
   --disable-web2c         do not build the web2c (TeX & Co.) package
   --enable-auto-core        cause TeX&MF to dump core, given a certain
@@ -4455,6 +4457,24 @@
 fi ;;
 esac
 
+## utils/xml2pmx/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory utils/xml2pmx/
+## configure options and TL libraries required for xml2pmx
+# Check whether --enable-xml2pmx was given.
+if test "${enable_xml2pmx+set}" = set; then :
+  enableval=$enable_xml2pmx;
+fi
+case $enable_xml2pmx in #(
+  yes|no) :
+     ;; #(
+  *) :
+
+   enable_xml2pmx=$enable_all_pkgs
+     { $as_echo "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-xml2pmx=$enable_xml2pmx'" >&5
+$as_echo "$as_me: Assuming \`--enable-xml2pmx=$enable_xml2pmx'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-xml2pmx=$enable_xml2pmx'"
+    ;;
+esac
+
 ## utils/xpdfopen/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory utils/xpdfopen/
 ## configure options and TL libraries required for xpdfopen
 # Check whether --enable-xpdfopen was given.
@@ -21088,10 +21108,14 @@
 if test -x $srcdir/texk/ptexenc/configure; then
   test "x$with_system_ptexenc" != xyes && test "x$need_ptexenc" = xyes && MAKE_SUBDIRS="texk/ptexenc $MAKE_SUBDIRS"
   CONF_SUBDIRS="texk/ptexenc $CONF_SUBDIRS"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/texk/ptexenc/configure' >&5
 fi
 if test -x $srcdir/texk/kpathsea/configure; then
   test "x$with_system_kpathsea" != xyes && test "x$need_kpathsea" = xyes && MAKE_SUBDIRS="texk/kpathsea $MAKE_SUBDIRS"
   CONF_SUBDIRS="texk/kpathsea $CONF_SUBDIRS"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/texk/kpathsea/configure' >&5
 fi
 
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAKE_SUBDIRS" >&5

Modified: branches/stable/source/src/doc/ChangeLog
===================================================================
--- branches/stable/source/src/doc/ChangeLog	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/doc/ChangeLog	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,3 +1,8 @@
+2021-02-09  Karl Berry  <karl at freefriends.org>
+
+	* tlbuild.texi (Adding a new program module): emphasize requirement
+	for configure, etc., to be committed.
+
 2020-11-28  Karl Berry  <karl at freefriends.org>
 
 	* tlbuild.texi (Adding a new program module): more explicit

Modified: branches/stable/source/src/doc/Makefile.in
===================================================================
--- branches/stable/source/src/doc/Makefile.in	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/doc/Makefile.in	2021-02-15 19:17:20 UTC (rev 845)
@@ -134,6 +134,7 @@
 	$(top_srcdir)/utils/xindy/ac/withenable.ac \
 	$(top_srcdir)/utils/xindy/ac/xindy.ac \
 	$(top_srcdir)/utils/xindy/ac/clisp.ac \
+	$(top_srcdir)/utils/xml2pmx/ac/withenable.ac \
 	$(top_srcdir)/utils/xpdfopen/ac/withenable.ac \
 	$(top_srcdir)/texk/web2c/ac/withenable.ac \
 	$(top_srcdir)/texk/web2c/ac/web2c.ac \

Deleted: branches/stable/source/src/doc/tlbuild.cp
===================================================================
--- branches/stable/source/src/doc/tlbuild.cp	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/doc/tlbuild.cp	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,372 +0,0 @@
-\entry{introduction}{1}{introduction}
-\entry{build system, design of}{2}{build system, design of}
-\entry{Autoconf}{2}{Autoconf}
-\entry{Automake}{2}{Automake}
-\entry{Libtool}{2}{Libtool}
-\entry{tests, running}{2}{tests, running}
-\entry{kpse-pkgs.m4}{2}{\code {kpse-pkgs.m4}}
-\entry{prerequisites for building}{3}{prerequisites for building}
-\entry{requirements for building}{3}{requirements for building}
-\entry{compilers, C and C++11}{3}{compilers, C and C++11}
-\entry{GNU make, required}{3}{GNU \code {make}, required}
-\entry{gmake, required}{3}{\code {gmake}, required}
-\entry{FreeType}{3}{FreeType}
-\entry{C++11, required}{3}{C++11, required}
-\entry{perl, required by web2c, etc.}{3}{\code {perl}, required by \code {web2c}, etc.}
-\entry{X11 development, required by X clients}{3}{X11 development, required by X clients}
-\entry{fontconfig library, required by xetex}{3}{\code {fontconfig} library, required by \code {xetex}}
-\entry{ApplicationServices Mac framework, required by xetex}{3}{\code {ApplicationServices} Mac framework, required by \code {xetex}}
-\entry{Cocoa Mac framework, required by xetex}{3}{\code {Cocoa} Mac framework, required by \code {xetex}}
-\entry{clisp, required by xindy}{3}{\code {clisp}, required by \code {xindy}}
-\entry{libsigsegv, required by xindy}{3}{\code {libsigsegv}, required by \code {xindy}}
-\entry{building}{4}{building}
-\entry{overall build process}{4}{overall build process}
-\entry{Build script}{4}{\code {Build \r {script}}}
-\entry{source directory building, not supported}{4}{source directory building, not supported}
-\entry{build directory, required}{4}{build directory, required}
-\entry{build iteration}{4}{build iteration}
-\entry{iteration through sources, by configure and make}{4}{iteration through sources, by \code {configure} and \code {make}}
-\entry{build problems}{4}{build problems}
-\entry{problems with build}{4}{problems with build}
-\entry{failure to build}{4}{failure to build}
-\entry{--no-clean Build option}{4}{\code {--no-clean Build \r {option}}}
-\entry{building in parallel}{4}{building in parallel}
-\entry{parallel build}{4}{parallel build}
-\entry{cache for configure}{4}{cache for \code {configure}}
-\entry{dependencies, with several output files}{4}{dependencies, with several output files}
-\entry{-j make option}{4}{\code {-j make \r {option}}}
-\entry{cache file, for configure}{4}{cache file, for \code {configure}}
-\entry{-C configure option}{4}{\code {-C configure \r {option}}}
-\entry{building a distribution}{4}{building a distribution}
-\entry{distribution tarball, making}{4}{distribution tarball, making}
-\entry{dist and distcheck targets for make}{4}{\code {dist} and \code {distcheck} targets for \code {make}}
-\entry{build one package}{5}{build one package}
-\entry{one package, building}{5}{one package, building}
-\entry{--disable-all-packages}{5}{\code {--disable-all-packages}}
-\entry{build on demand}{5}{build on demand}
-\entry{size of source tree}{6}{size of source tree}
-\entry{--enable-missing to ignore dependencies}{6}{\code {--enable-missing \r {to ignore dependencies}}}
-\entry{CC=c-compiler}{6}{\code {CC=\var {c-compiler}}}
-\entry{CXX=c++-compiler}{6}{\code {CXX=\var {c++-compiler}}}
-\entry{OBJCXX=objc-compiler}{6}{\code {OBJCXX=\var {objc-compiler}}}
-\entry{gcc, default compilers}{6}{\code {gcc\r {, default compilers}}}
-\entry{build one engine}{6}{build one engine}
-\entry{one engine, building}{6}{one engine, building}
-\entry{engine, building one}{6}{engine, building one}
-\entry{cross compilation}{6}{cross compilation}
-\entry{native cross compilation}{6}{native cross compilation}
-\entry{cross compilation configuring}{7}{cross compilation configuring}
-\entry{configuring, for cross compilation}{7}{configuring, for cross compilation}
-\entry{--host=host}{7}{\code {--host=\var {host}}}
-\entry{--build=host}{7}{\code {--build=\var {host}}}
-\entry{mingw32}{7}{\code {mingw32}}
-\entry{BUILDCC, BUILDCFLAGS, ...}{7}{\code {BUILDCC\r {,} BUILDCFLAGS\r {, \dots {}}}}
-\entry{cross compilation problems}{7}{cross compilation problems}
-\entry{squeeze}{8}{\code {squeeze}}
-\entry{web2c program}{8}{\code {web2c \r {program}}}
-\entry{freetype cross compiling}{8}{\code {freetype} cross compiling}
-\entry{CC_BUILD}{8}{\code {CC_BUILD}}
-\entry{ICU cross compiling}{8}{ICU cross compiling}
-\entry{tangle}{8}{\code {tangle}}
-\entry{ctangle}{8}{\code {ctangle}}
-\entry{otangle}{8}{\code {otangle}}
-\entry{tie}{8}{\code {tie}}
-\entry{xindy cross compiling impossible}{8}{\code {xindy} cross compiling impossible}
-\entry{installing}{9}{installing}
-\entry{support files, separate from build}{9}{support files, separate from build}
-\entry{texlive.tlpdb,  database}{9}{\code {texlive.tlpdb\r {, \TL {} database}}}
-\entry{install-tl,  installer}{9}{\code {install-tl\r {, \TL {} installer}}}
-\entry{plain.tex, not in source tree}{9}{\code {plain.tex\r {, not in source tree}}}
-\entry{installation directories}{9}{installation directories}
-\entry{directories, for installation}{9}{directories, for installation}
-\entry{paths, for installation}{9}{paths, for installation}
-\entry{linked scripts}{9}{linked scripts}
-\entry{scripts, linked and not maintained}{9}{scripts, linked and not maintained}
-\entry{symlinks, used for scripts}{9}{symlinks, used for scripts}
-\entry{wrapper binary for scripts on Windows}{9}{wrapper binary for scripts on Windows}
-\entry{Windows, invoking scripts on}{9}{Windows, invoking scripts on}
-\entry{asymptote}{10}{\code {asymptote}}
-\entry{biber}{10}{\code {biber}}
-\entry{xindy}{10}{\code {xindy}}
-\entry{xz}{10}{\code {xz}}
-\entry{wget}{10}{\code {wget}}
-\entry{distro, building for}{10}{distro, building for}
-\entry{operating system distribution, building for}{10}{operating system distribution, building for}
-\entry{system distribution, building for}{10}{system distribution, building for}
-\entry{GNU/Linux distro}{10}{GNU/Linux distro}
-\entry{BSD distro}{10}{BSD distro}
-\entry{shared libraries, using vs. avoiding}{10}{shared libraries, using vs.\: avoiding}
-\entry{Preining, Norbert}{11}{Preining, Norbert}
-\entry{adapting  for distros}{11}{adapting \TL {} for distros}
-\entry{layout of sources}{12}{layout of sources}
-\entry{source tree}{12}{source tree}
-\entry{tools, for building}{12}{tools, for building}
-\entry{GNU tools, needed for building}{12}{GNU tools, needed for building}
-\entry{infrastructure, tools needed for}{12}{infrastructure, tools needed for}
-\entry{reautoconf}{12}{\code {reautoconf}}
-\entry{--enable-maintainer-mode}{12}{\code {--enable-maintainer-mode}}
-\entry{Subversion repository}{12}{Subversion repository}
-\entry{timestamps, in repository}{12}{timestamps, in repository}
-\entry{use-commit-times, Subversion}{12}{\code {use-commit-times\r {, Subversion}}}
-\entry{touching files to avoid rerunning}{12}{touching files to avoid rerunning}
-\entry{make -t}{12}{\code {make -t}}
-\entry{directories, top-level}{12}{directories, top-level}
-\entry{top-level directories}{12}{top-level directories}
-\entry{am/ top-level directory}{12}{\file {am/} top-level directory}
-\entry{m4/ top-level directory}{12}{\file {m4/} top-level directory}
-\entry{build-aux/ top-level directory}{13}{\file {build-aux/} top-level directory}
-\entry{config.guess, config.sub, ...}{13}{\code {config.guess\r {,} config.sub, \dots {}}}
-\entry{Gnulib, used for common files}{13}{Gnulib, used for common files}
-\entry{Work/ top-level directory}{13}{\file {Work/} top-level directory}
-\entry{inst/ top-level directory}{13}{\file {inst/} top-level directory}
-\entry{autoconf macros}{13}{autoconf macros}
-\entry{general setup macros}{13}{general setup macros}
-\entry{setup macros, general}{13}{setup macros, general}
-\entry{macros, general setup}{13}{macros, general setup}
-\entry{KPSE_BASIC}{13}{\code {KPSE_BASIC}}
-\entry{KPSE_COMMON}{13}{\code {KPSE_COMMON}}
-\entry{macros, for programs}{14}{macros, for programs}
-\entry{KPSE_CHECK_LATEX}{14}{\code {KPSE_CHECK_LATEX}}
-\entry{KPSE_CHECK_PDFLATEX}{14}{\code {KPSE_CHECK_PDFLATEX}}
-\entry{KPSE_CHECK_PERL}{14}{\code {KPSE_CHECK_PERL}}
-\entry{KPSE_PROG_LEX}{14}{\code {KPSE_PROG_LEX}}
-\entry{macros, for compilers}{14}{macros, for compilers}
-\entry{KPSE_COMPILER_WARNINGS}{14}{\code {KPSE_COMPILER_WARNINGS}}
-\entry{WARNING_C[XX]FLAGS}{14}{\code {WARNING_C[XX]FLAGS}}
-\entry{kpse_cv_warning_cflags}{14}{\code {kpse_cv_warning_cflags}}
-\entry{KPSE_COMPILER_VISIBILITY}{14}{\code {KPSE_COMPILER_VISIBILITY}}
-\entry{kpse_cv_visibility_c[xx]flags}{14}{\code {kpse_cv_visibility_c[xx]flags}}
-\entry{KPSE_CXX_HACK}{14}{\code {KPSE_CXX_HACK}}
-\entry{static linking for C++}{14}{static linking for C++}
-\entry{linking C++ libraries statically}{14}{linking C++ libraries statically}
-\entry{--enable-cxx-runtime-hack}{14}{\code {--enable-cxx-runtime-hack}}
-\entry{libstc++, statically linking}{14}{\code {libstc++\r {, statically linking}}}
-\entry{kpse_cv_cxx_hack}{14}{\code {kpse_cv_cxx_hack}}
-\entry{macros, for libraries}{14}{macros, for libraries}
-\entry{KPSE_LARGEFILE}{14}{\code {KPSE_LARGEFILE}}
-\entry{macros, for library and header flags}{15}{macros, for library and header flags}
-\entry{flags, macros for library and header}{15}{flags, macros for library and header}
-\entry{KPSE_LIB_FLAGS}{15}{\code {KPSE_\var {LIB}_FLAGS}}
-\entry{KPSE_LIBPNG_FLAGS}{15}{\code {KPSE_LIBPNG_FLAGS}}
-\entry{KPSE_ADD_FLAGS}{15}{\code {KPSE_ADD_FLAGS}}
-\entry{KPSE_RESTORE_FLAGS}{15}{\code {KPSE_RESTORE_FLAGS}}
-\entry{macros, for Windows}{15}{macros, for Windows}
-\entry{Windows, macros for}{15}{Windows, macros for}
-\entry{KPSE_CHECK_WIN32}{16}{\code {KPSE_CHECK_WIN32}}
-\entry{kpse_cv_have_win32}{16}{\code {kpse_cv_have_win32}}
-\entry{KPSE_COND_WIN32}{16}{\code {KPSE_COND_WIN32}}
-\entry{WIN32, Automake conditional}{16}{\code {WIN32\r {, Automake conditional}}}
-\entry{KPSE_COND_MINGW32}{16}{\code {KPSE_COND_MINGW32}}
-\entry{MINGW32, Automake conditional}{16}{\code {MINGW32\r {, Automake conditional}}}
-\entry{KPSE_COND_WIN32_WRAP}{16}{\code {KPSE_COND_WIN32_WRAP}}
-\entry{WIN32_WRAP, Automake conditional}{16}{\code {WIN32_WRAP\r {, Automake conditional}}}
-\entry{runscript.exe}{16}{\code {runscript.exe}}
-\entry{KPSE_WIN32_CALL}{16}{\code {KPSE_WIN32_CALL}}
-\entry{callexe.c}{16}{\code {callexe.c}}
-\entry{library modules}{16}{library modules}
-\entry{modules, for libraries}{16}{modules, for libraries}
-\entry{png library}{16}{\code {png \r {library}}}
-\entry{libpng library}{16}{\code {libpng \r {library}}}
-\entry{KPSE_TRY_LIB}{16}{\code {KPSE_TRY_LIB}}
-\entry{KPSE_TRY_LIBXX}{17}{\code {KPSE_TRY_LIBXX}}
-\entry{proxy build system}{17}{proxy build system}
-\entry{kpse-libpng-flags.m4}{17}{\code {kpse-libpng-flags.m4}}
-\entry{KPSE_LIBPNG_FLAGS}{17}{\code {KPSE_LIBPNG_FLAGS}}
-\entry{zlib library}{17}{\code {zlib \r {library}}}
-\entry{kpse-zlib-flags.m4}{17}{\code {kpse-zlib-flags.m4}}
-\entry{freetype library}{17}{\code {freetype \r {library}}}
-\entry{wrapper build system}{17}{wrapper build system}
-\entry{freetype-config}{17}{\code {freetype-config}}
-\entry{kpathsea library}{17}{\code {kpathsea \r {library}}}
-\entry{--with-system-kpathsea}{17}{\code {--with-system-kpathsea}}
-\entry{kpathsea.ac}{17}{\code {kpathsea.ac}}
-\entry{mktex.ac}{17}{\code {mktex.ac}}
-\entry{--enable-mktextfm-default}{17}{\code {--enable-mktextfm-default}}
-\entry{mktextfm}{17}{\code {mktextfm}}
-\entry{program modules}{18}{program modules}
-\entry{modules, for programs}{18}{modules, for programs}
-\entry{t1utils package}{18}{\code {t1utils \r {package}}}
-\entry{xindy}{18}{\code {xindy}}
-\entry{xdvik}{18}{\code {xdvik}}
-\entry{squeeze/configure.ac}{18}{\code {squeeze/configure.ac}}
-\entry{cross compilation, with host binary}{18}{cross compilation, with host binary}
-\entry{--with-xdvi-x-toolkit}{18}{\code {--with-xdvi-x-toolkit}}
-\entry{asymptote}{19}{\code {asymptote}}
-\entry{xasy}{19}{\code {xasy}}
-\entry{OpenGL, required for Asymptote}{19}{OpenGL, required for Asymptote}
-\entry{extending }{19}{extending \TL {}}
-\entry{adding to }{19}{adding to \TL {}}
-\entry{adding a new program}{19}{adding a new program}
-\entry{program module, adding}{19}{program module, adding}
-\entry{kpse_texk_pkgs}{19}{\code {kpse_texk_pkgs}}
-\entry{kpse_utils_pkgs}{19}{\code {kpse_utils_pkgs}}
-\entry{withenable.ac, for new modules}{19}{\code {withenable.ac\r {, for new modules}}}
-\entry{KPSE_ENABLE_PROG}{19}{\code {KPSE_ENABLE_PROG}}
-\entry{adding a new generic library}{20}{adding a new generic library}
-\entry{generic library module, adding}{20}{generic library module, adding}
-\entry{library module, generic, adding}{20}{library module, generic, adding}
-\entry{kpse_libs_pkgs}{20}{\code {kpse_libs_pkgs}}
-\entry{KPSE_WITH_LIB}{20}{\code {KPSE_WITH_LIB}}
-\entry{KPSE_TRY_LIB}{20}{\code {KPSE_TRY_LIB}}
-\entry{KPSE_TRY_LIBXX}{20}{\code {KPSE_TRY_LIBXX}}
-\entry{KPSE_LIB_FLAGS}{20}{\code {KPSE_\var {LIB}_FLAGS}}
-\entry{--with-system-lib}{21}{\code {--with-system-\var {lib}}}
-\entry{KPSE_LIB_SYSTEM_FLAGS}{21}{\code {KPSE_\var {LIB}_SYSTEM_FLAGS}}
-\entry{KPSE_ALL_SYSTEM_FLAGS}{21}{\code {KPSE_ALL_SYSTEM_FLAGS}}
-\entry{adding a new TeX{}-specific library}{21}{adding a new \TeX {}-specific library}
-\entry{TeX{}-specific library module, adding}{21}{\TeX {}-specific library module, adding}
-\entry{library module, TeX{}-specific, adding}{21}{library module, \TeX {}-specific, adding}
-\entry{kpse_texlibs_pkgs}{21}{\code {kpse_texlibs_pkgs}}
-\entry{KPSE_WITH_TEXLIB}{21}{\code {KPSE_WITH_TEXLIB}}
-\entry{configure options}{22}{\code {configure} options}
-\entry{environment variables, for configure}{22}{environment variables, for \code {configure}}
-\entry{global configure options}{22}{global \code {configure} options}
-\entry{configure options, global}{22}{\code {configure} options, global}
-\entry{--disable-native-texlive-build}{22}{\code {--disable-native-texlive-build}}
-\entry{--enable-texlive-build}{22}{\code {--enable-texlive-build}}
-\entry{--prefix configure option}{22}{\code {--prefix configure \r {option}}}
-\entry{--bindir configure option}{22}{\code {--bindir configure \r {option}}}
-\entry{DESTDIR}{22}{\code {DESTDIR}}
-\entry{--disable-largefile}{22}{\code {--disable-largefile}}
-\entry{large file support}{22}{large file support}
-\entry{LFS (large file support)}{22}{LFS (large file support)}
-\entry{size of PDF and PS files}{22}{size of PDF and PS files}
-\entry{PDF files, size of}{22}{PDF files, size of}
-\entry{PostScript files, size of}{22}{PostScript files, size of}
-\entry{--disable-missing}{23}{\code {--disable-missing}}
-\entry{--enable-compiler-warnings=level}{23}{\code {--enable-compiler-warnings=\var {level}}}
-\entry{--enable-maintainer-mode}{23}{\code {--enable-maintainer-mode}}
-\entry{--enable-multiplatform}{23}{\code {--enable-multiplatform}}
-\entry{exec_prefix}{23}{\code {exec_prefix}}
-\entry{--bindir configure option}{23}{\code {--bindir configure \r {option}}}
-\entry{--libdir configure option}{23}{\code {--libdir configure \r {option}}}
-\entry{--enable-shared}{23}{\code {--enable-shared}}
-\entry{--enable-silent-rules}{23}{\code {--enable-silent-rules}}
-\entry{make rules, verbose vs. silent}{23}{\code {make} rules, verbose vs.\: silent}
-\entry{--without-ln-s}{23}{\code {--without-ln-s}}
-\entry{--without-x}{24}{\code {--without-x}}
-\entry{program-specific configure options}{24}{program-specific \code {configure} options}
-\entry{configure options, program-specific}{24}{\code {configure} options, program-specific}
-\entry{--enable-prog}{24}{\code {--enable-\var {prog}}}
-\entry{--disable-prog}{24}{\code {--disable-\var {prog}}}
-\entry{--disable-all-pkgs}{24}{\code {--disable-all-pkgs}}
-\entry{configure options, for web2c}{24}{\code {configure} options, for \code {web2c}}
-\entry{--with-banner-add=str}{24}{\code {--with-banner-add=\var {str}}}
-\entry{--with-editor=cmd}{24}{\code {--with-editor=\var {cmd}}}
-\entry{--with-fontconfig-includes=dir}{24}{\code {--with-fontconfig-includes=\var {dir}}}
-\entry{--with-fontconfig-libdir=dir}{24}{\code {--with-fontconfig-libdir=\var {dir}}}
-\entry{X toolkit}{24}{X toolkit}
-\entry{libXt}{24}{\code {libXt}}
-\entry{Xlib}{24}{\code {Xlib}}
-\entry{--disable-dump-share}{24}{\code {--disable-dump-share}}
-\entry{LittleEndian architectures}{24}{LittleEndian architectures}
-\entry{--disable-ipc}{24}{\code {--disable-ipc}}
-\entry{interprocess communication}{24}{interprocess communication}
-\entry{--disable-mf-nowin}{24}{\code {--disable-mf-nowin}}
-\entry{mf-nowin}{24}{\code {mf-nowin}}
-\entry{--disable-tex}{24}{\code {--disable-tex}}
-\entry{--enable-etex}{24}{\code {--enable-etex}}
-\entry{web2c.ac}{24}{\code {web2c.ac}}
-\entry{--disable-web-progs}{24}{\code {--disable-web-progs}}
-\entry{--enable-auto-core}{25}{\code {--enable-auto-core}}
-\entry{preloaded binaries}{25}{preloaded binaries}
-\entry{--enable-libtool-hack}{25}{\code {--enable-libtool-hack}}
-\entry{libtool, hack for avoiding excessive linking}{25}{\code {libtool\r {, hack for avoiding excessive linking}}}
-\entry{libfontconfig, hack for avoiding linking dependencies}{25}{\code {libfontconfig\r {, hack for avoiding linking dependencies}}}
-\entry{libexpat, dependency of libfontconfig}{25}{\code {libexpat\r {, dependency of \code {libfontconfig}}}}
-\entry{--enable-*win for Metafont window support}{25}{\code {--enable-*win \r {for Metafont window support}}}
-\entry{--enable-tex-synctex}{25}{\code {--enable-tex-synctex}}
-\entry{--disable-etex-synctex}{25}{\code {--disable-etex-synctex}}
-\entry{synctex}{25}{synctex}
-\entry{--disable-synctex}{25}{\code {--disable-synctex}}
-\entry{synctex}{25}{synctex}
-\entry{configure options, for bibtex-x}{25}{\code {configure} options, for \code {bibtex-x}}
-\entry{bibtex8}{25}{\code {bibtex8}}
-\entry{bibtexu}{25}{\code {bibtexu}}
-\entry{bibtex-x}{25}{\code {bibtex-x}}
-\entry{--disable-bibtex8}{25}{\code {--disable-bibtex8}}
-\entry{--disable-bibtexu}{25}{\code {--disable-bibtexu}}
-\entry{configure options, for dvipdfm-x}{25}{\code {configure} options, for \code {dvipdfm-x}}
-\entry{dvipdfm-x}{25}{\code {dvipdfm-x}}
-\entry{dvipdfmx}{25}{\code {dvipdfmx}}
-\entry{xdvipdfmx}{25}{\code {xdvipdfmx}}
-\entry{--disable-dvipdfmx}{25}{\code {--disable-dvipdfmx}}
-\entry{--disable-xdvipdfmx}{25}{\code {--disable-xdvipdfmx}}
-\entry{configure options, for dvisvgm}{25}{\code {configure} options, for \file {dvisvgm}}
-\entry{dvisvgm}{25}{\code {dvisvgm}}
-\entry{--with-system-libgs}{25}{\code {--with-system-libgs}}
-\entry{--without-libgs}{25}{\code {--without-libgs}}
-\entry{--with-libgs-includes, -libdir}{25}{\code {--with-libgs-includes\r {,} -libdir}}
-\entry{configure options, for texk/texlive}{26}{\code {configure} options, for \file {texk/texlive}}
-\entry{--disable-linked-scripts}{26}{\code {--disable-linked-scripts}}
-\entry{configure options, for xdvik}{26}{\code {configure} options, for \file {xdvik}}
-\entry{xdvik}{26}{\code {xdvik}}
-\entry{--with-gs=filename}{26}{\code {--with-gs=\var {filename}}}
-\entry{Ghostscript location for Xdvik}{26}{Ghostscript location for Xdvik}
-\entry{--with-xdvi-x-toolkit=kit}{26}{\code {--with-xdvi-x-toolkit=\var {kit}}}
-\entry{motif}{26}{\code {motif}}
-\entry{xaw}{26}{\code {xaw}}
-\entry{--enable-xi2-scrolling}{26}{\code {--enable-xi2-scrolling}}
-\entry{XInput}{26}{\code {XInput}}
-\entry{scrolling, smooth}{26}{\code {scrolling, smooth}}
-\entry{configure options, for xindy}{26}{\code {configure} options, for \file {xindy}}
-\entry{xindy}{26}{\code {xindy}}
-\entry{--enable-xindy-rules}{26}{\code {--enable-xindy-rules}}
-\entry{--enable-xindy-docs}{26}{\code {--enable-xindy-docs}}
-\entry{--with-clisp-runtime=filename}{26}{\code {--with-clisp-runtime=\var {filename}}}
-\entry{lisp.run, lisp.exe}{26}{\code {lisp.run\r {,} lisp.exe}}
-\entry{CLISP}{26}{CLISP}
-\entry{library-specific configure options}{26}{library-specific \code {configure} options}
-\entry{configure options, library-specific}{26}{\code {configure} options, library-specific}
-\entry{--with-system-lib}{26}{\code {--with-system-\var {lib}}}
-\entry{--with-lib-includes=dir, -libdir}{26}{\code {--with-\var {lib}-includes=\var {dir}\r {,} -libdir}}
-\entry{configure options, for kpathsea}{26}{\code {configure} options, for \code {kpathsea}}
-\entry{configure options, for system poppler}{27}{\code {configure} options, for system \code {poppler}}
-\entry{poppler}{27}{\code {poppler}}
-\entry{xpdf as library}{27}{\code {xpdf \r {as library}}}
-\entry{--with-system-poppler}{27}{\code {--with-system-poppler}}
-\entry{--with-system-xpdf}{27}{\code {--with-system-xpdf}}
-\entry{variables for configure}{27}{variables for \code {configure}}
-\entry{configure variables}{27}{\code {configure} variables}
-\entry{CC}{27}{\code {CC}}
-\entry{CXX}{27}{\code {CXX}}
-\entry{CPPFLAGS}{27}{\code {CPPFLAGS}}
-\entry{CLISP}{27}{\code {CLISP}}
-\entry{clisp}{27}{\code {clisp}}
-\entry{FT2_CONFIG}{27}{\code {FT2_CONFIG}}
-\entry{ICU_CONFIG}{27}{\code {ICU_CONFIG}}
-\entry{PKG_CONFIG}{27}{\code {PKG_CONFIG}}
-\entry{freetype-config}{27}{\code {freetype-config}}
-\entry{icu-config}{27}{\code {icu-config}}
-\entry{libfreetype}{27}{\code {libfreetype}}
-\entry{ICU libraries}{27}{ICU libraries}
-\entry{KPSEWHICH}{27}{\code {KPSEWHICH}}
-\entry{kpsewhich}{27}{\code {kpsewhich}}
-\entry{MAKE}{28}{\code {MAKE}}
-\entry{SED}{28}{\code {SED}}
-\entry{PERL}{28}{\code {PERL}}
-\entry{LATEX}{28}{\code {LATEX}}
-\entry{PDFLATEX}{28}{\code {PDFLATEX}}
-\entry{coding conventions}{29}{coding conventions}
-\entry{conventions, coding}{29}{conventions, coding}
-\entry{declarations and definitions, in source code}{29}{declarations and definitions, in source code}
-\entry{source code declarations}{29}{source code declarations}
-\entry{ANSI C}{29}{ANSI C}
-\entry{declarations before statements, avoiding}{29}{declarations before statements, avoiding}
-\entry{C, ANSI, required}{29}{C, ANSI, required}
-\entry{C99, avoided}{29}{C99, avoided}
-\entry{chktex}{29}{\code {chktex}}
-\entry{stpcpy}{29}{\code {stpcpy}}
-\entry{static functions}{29}{\code {static} functions}
-\entry{extern functions}{29}{\code {extern} functions}
-\entry{variable declarations, in source code}{29}{variable declarations, in source code}
-\entry{const}{30}{\code {const}}
-\entry{X11 headers, and const}{30}{X11 headers, and \code {const}}
-\entry{libfreetype, and const}{30}{\code {libfreetype}, and \code {const}}
-\entry{warning, discards qualifiers}{30}{warning, discards qualifiers}
-\entry{discards qualifiers warning}{30}{discards qualifiers warning}
-\entry{type cast from const, avoiding}{30}{type cast from const, avoiding}
-\entry{continuous integration}{31}{continuous integration}
-\entry{Travis-CI}{31}{Travis-CI}
-\entry{git-svn}{31}{\code {git-svn}}
-\entry{travis.yml}{32}{\code {travis.yml}}

Deleted: branches/stable/source/src/doc/tlbuild.cps
===================================================================
--- branches/stable/source/src/doc/tlbuild.cps	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/doc/tlbuild.cps	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,381 +0,0 @@
-\initial {-}
-\entry {\code {--bindir configure \r {option}}}{22, 23}
-\entry {\code {--build=\var {host}}}{7}
-\entry {\code {--disable-all-packages}}{5}
-\entry {\code {--disable-all-pkgs}}{24}
-\entry {\code {--disable-bibtex8}}{25}
-\entry {\code {--disable-bibtexu}}{25}
-\entry {\code {--disable-dump-share}}{24}
-\entry {\code {--disable-dvipdfmx}}{25}
-\entry {\code {--disable-etex-synctex}}{25}
-\entry {\code {--disable-ipc}}{24}
-\entry {\code {--disable-largefile}}{22}
-\entry {\code {--disable-linked-scripts}}{26}
-\entry {\code {--disable-mf-nowin}}{24}
-\entry {\code {--disable-missing}}{23}
-\entry {\code {--disable-native-texlive-build}}{22}
-\entry {\code {--disable-\var {prog}}}{24}
-\entry {\code {--disable-synctex}}{25}
-\entry {\code {--disable-tex}}{24}
-\entry {\code {--disable-web-progs}}{24}
-\entry {\code {--disable-xdvipdfmx}}{25}
-\entry {\code {--enable-*win \r {for Metafont window support}}}{25}
-\entry {\code {--enable-auto-core}}{25}
-\entry {\code {--enable-compiler-warnings=\var {level}}}{23}
-\entry {\code {--enable-cxx-runtime-hack}}{14}
-\entry {\code {--enable-etex}}{24}
-\entry {\code {--enable-libtool-hack}}{25}
-\entry {\code {--enable-maintainer-mode}}{12, 23}
-\entry {\code {--enable-missing \r {to ignore dependencies}}}{6}
-\entry {\code {--enable-mktextfm-default}}{17}
-\entry {\code {--enable-multiplatform}}{23}
-\entry {\code {--enable-\var {prog}}}{24}
-\entry {\code {--enable-shared}}{23}
-\entry {\code {--enable-silent-rules}}{23}
-\entry {\code {--enable-tex-synctex}}{25}
-\entry {\code {--enable-texlive-build}}{22}
-\entry {\code {--enable-xi2-scrolling}}{26}
-\entry {\code {--enable-xindy-docs}}{26}
-\entry {\code {--enable-xindy-rules}}{26}
-\entry {\code {--host=\var {host}}}{7}
-\entry {\code {--libdir configure \r {option}}}{23}
-\entry {\code {--no-clean Build \r {option}}}{4}
-\entry {\code {--prefix configure \r {option}}}{22}
-\entry {\code {--with-banner-add=\var {str}}}{24}
-\entry {\code {--with-clisp-runtime=\var {filename}}}{26}
-\entry {\code {--with-editor=\var {cmd}}}{24}
-\entry {\code {--with-fontconfig-includes=\var {dir}}}{24}
-\entry {\code {--with-fontconfig-libdir=\var {dir}}}{24}
-\entry {\code {--with-gs=\var {filename}}}{26}
-\entry {\code {--with-\var {lib}-includes=\var {dir}\r {,} -libdir}}{26}
-\entry {\code {--with-libgs-includes\r {,} -libdir}}{25}
-\entry {\code {--with-system-kpathsea}}{17}
-\entry {\code {--with-system-\var {lib}}}{21, 26}
-\entry {\code {--with-system-libgs}}{25}
-\entry {\code {--with-system-poppler}}{27}
-\entry {\code {--with-system-xpdf}}{27}
-\entry {\code {--with-xdvi-x-toolkit}}{18}
-\entry {\code {--with-xdvi-x-toolkit=\var {kit}}}{26}
-\entry {\code {--without-libgs}}{25}
-\entry {\code {--without-ln-s}}{23}
-\entry {\code {--without-x}}{24}
-\entry {\code {-C configure \r {option}}}{4}
-\entry {\code {-j make \r {option}}}{4}
-\initial {A}
-\entry {adapting \TL {} for distros}{11}
-\entry {adding a new generic library}{20}
-\entry {adding a new program}{19}
-\entry {adding a new \TeX {}-specific library}{21}
-\entry {adding to \TL {}}{19}
-\entry {\file {am/} top-level directory}{12}
-\entry {ANSI C}{29}
-\entry {\code {ApplicationServices} Mac framework, required by \code {xetex}}{3}
-\entry {\code {asymptote}}{10, 19}
-\entry {Autoconf}{2}
-\entry {autoconf macros}{13}
-\entry {Automake}{2}
-\initial {B}
-\entry {\code {biber}}{10}
-\entry {\code {bibtex-x}}{25}
-\entry {\code {bibtex8}}{25}
-\entry {\code {bibtexu}}{25}
-\entry {BSD distro}{10}
-\entry {build directory, required}{4}
-\entry {build iteration}{4}
-\entry {build on demand}{5}
-\entry {build one engine}{6}
-\entry {build one package}{5}
-\entry {build problems}{4}
-\entry {\code {Build \r {script}}}{4}
-\entry {build system, design of}{2}
-\entry {\file {build-aux/} top-level directory}{13}
-\entry {\code {BUILDCC\r {,} BUILDCFLAGS\r {, \dots {}}}}{7}
-\entry {building}{4}
-\entry {building a distribution}{4}
-\entry {building in parallel}{4}
-\initial {C}
-\entry {C++11, required}{3}
-\entry {C, ANSI, required}{29}
-\entry {C99, avoided}{29}
-\entry {cache file, for \code {configure}}{4}
-\entry {cache for \code {configure}}{4}
-\entry {\code {callexe.c}}{16}
-\entry {\code {CC}}{27}
-\entry {\code {CC=\var {c-compiler}}}{6}
-\entry {\code {CC_BUILD}}{8}
-\entry {\code {chktex}}{29}
-\entry {\code {clisp}}{27}
-\entry {\code {clisp}, required by \code {xindy}}{3}
-\entry {CLISP}{26, 27}
-\entry {\code {Cocoa} Mac framework, required by \code {xetex}}{3}
-\entry {coding conventions}{29}
-\entry {compilers, C and C++11}{3}
-\entry {\code {config.guess\r {,} config.sub, \dots {}}}{13}
-\entry {\code {configure} options}{22}
-\entry {\code {configure} options, for \code {bibtex-x}}{25}
-\entry {\code {configure} options, for \code {dvipdfm-x}}{25}
-\entry {\code {configure} options, for \file {dvisvgm}}{25}
-\entry {\code {configure} options, for \code {kpathsea}}{26}
-\entry {\code {configure} options, for system \code {poppler}}{27}
-\entry {\code {configure} options, for \file {texk/texlive}}{26}
-\entry {\code {configure} options, for \code {web2c}}{24}
-\entry {\code {configure} options, for \file {xdvik}}{26}
-\entry {\code {configure} options, for \file {xindy}}{26}
-\entry {\code {configure} options, global}{22}
-\entry {\code {configure} options, library-specific}{26}
-\entry {\code {configure} options, program-specific}{24}
-\entry {\code {configure} variables}{27}
-\entry {configuring, for cross compilation}{7}
-\entry {\code {const}}{30}
-\entry {continuous integration}{31}
-\entry {conventions, coding}{29}
-\entry {\code {CPPFLAGS}}{27}
-\entry {cross compilation}{6}
-\entry {cross compilation configuring}{7}
-\entry {cross compilation problems}{7}
-\entry {cross compilation, with host binary}{18}
-\entry {\code {ctangle}}{8}
-\entry {\code {CXX}}{27}
-\entry {\code {CXX=\var {c++-compiler}}}{6}
-\initial {D}
-\entry {declarations and definitions, in source code}{29}
-\entry {declarations before statements, avoiding}{29}
-\entry {dependencies, with several output files}{4}
-\entry {\code {DESTDIR}}{22}
-\entry {directories, for installation}{9}
-\entry {directories, top-level}{12}
-\entry {discards qualifiers warning}{30}
-\entry {\code {dist} and \code {distcheck} targets for \code {make}}{4}
-\entry {distribution tarball, making}{4}
-\entry {distro, building for}{10}
-\entry {\code {dvipdfm-x}}{25}
-\entry {\code {dvipdfmx}}{25}
-\entry {\code {dvisvgm}}{25}
-\initial {E}
-\entry {engine, building one}{6}
-\entry {environment variables, for \code {configure}}{22}
-\entry {\code {exec_prefix}}{23}
-\entry {extending \TL {}}{19}
-\entry {\code {extern} functions}{29}
-\initial {F}
-\entry {failure to build}{4}
-\entry {flags, macros for library and header}{15}
-\entry {\code {fontconfig} library, required by \code {xetex}}{3}
-\entry {FreeType}{3}
-\entry {\code {freetype} cross compiling}{8}
-\entry {\code {freetype \r {library}}}{17}
-\entry {\code {freetype-config}}{17, 27}
-\entry {\code {FT2_CONFIG}}{27}
-\initial {G}
-\entry {\code {gcc\r {, default compilers}}}{6}
-\entry {general setup macros}{13}
-\entry {generic library module, adding}{20}
-\entry {Ghostscript location for Xdvik}{26}
-\entry {\code {git-svn}}{31}
-\entry {global \code {configure} options}{22}
-\entry {\code {gmake}, required}{3}
-\entry {GNU \code {make}, required}{3}
-\entry {GNU tools, needed for building}{12}
-\entry {GNU/Linux distro}{10}
-\entry {Gnulib, used for common files}{13}
-\initial {I}
-\entry {\code {icu-config}}{27}
-\entry {ICU cross compiling}{8}
-\entry {ICU libraries}{27}
-\entry {\code {ICU_CONFIG}}{27}
-\entry {infrastructure, tools needed for}{12}
-\entry {\file {inst/} top-level directory}{13}
-\entry {\code {install-tl\r {, \TL {} installer}}}{9}
-\entry {installation directories}{9}
-\entry {installing}{9}
-\entry {interprocess communication}{24}
-\entry {introduction}{1}
-\entry {iteration through sources, by \code {configure} and \code {make}}{4}
-\initial {K}
-\entry {\code {kpathsea \r {library}}}{17}
-\entry {\code {kpathsea.ac}}{17}
-\entry {\code {kpse-libpng-flags.m4}}{17}
-\entry {\code {kpse-pkgs.m4}}{2}
-\entry {\code {kpse-zlib-flags.m4}}{17}
-\entry {\code {kpse_cv_cxx_hack}}{14}
-\entry {\code {kpse_cv_have_win32}}{16}
-\entry {\code {kpse_cv_visibility_c[xx]flags}}{14}
-\entry {\code {kpse_cv_warning_cflags}}{14}
-\entry {\code {kpse_libs_pkgs}}{20}
-\entry {\code {kpse_texk_pkgs}}{19}
-\entry {\code {kpse_texlibs_pkgs}}{21}
-\entry {\code {kpse_utils_pkgs}}{19}
-\entry {\code {KPSE_ADD_FLAGS}}{15}
-\entry {\code {KPSE_ALL_SYSTEM_FLAGS}}{21}
-\entry {\code {KPSE_BASIC}}{13}
-\entry {\code {KPSE_CHECK_LATEX}}{14}
-\entry {\code {KPSE_CHECK_PDFLATEX}}{14}
-\entry {\code {KPSE_CHECK_PERL}}{14}
-\entry {\code {KPSE_CHECK_WIN32}}{16}
-\entry {\code {KPSE_COMMON}}{13}
-\entry {\code {KPSE_COMPILER_VISIBILITY}}{14}
-\entry {\code {KPSE_COMPILER_WARNINGS}}{14}
-\entry {\code {KPSE_COND_MINGW32}}{16}
-\entry {\code {KPSE_COND_WIN32}}{16}
-\entry {\code {KPSE_COND_WIN32_WRAP}}{16}
-\entry {\code {KPSE_CXX_HACK}}{14}
-\entry {\code {KPSE_ENABLE_PROG}}{19}
-\entry {\code {KPSE_LARGEFILE}}{14}
-\entry {\code {KPSE_\var {LIB}_FLAGS}}{15, 20}
-\entry {\code {KPSE_\var {LIB}_SYSTEM_FLAGS}}{21}
-\entry {\code {KPSE_LIBPNG_FLAGS}}{15, 17}
-\entry {\code {KPSE_PROG_LEX}}{14}
-\entry {\code {KPSE_RESTORE_FLAGS}}{15}
-\entry {\code {KPSE_TRY_LIB}}{16, 20}
-\entry {\code {KPSE_TRY_LIBXX}}{17, 20}
-\entry {\code {KPSE_WIN32_CALL}}{16}
-\entry {\code {KPSE_WITH_LIB}}{20}
-\entry {\code {KPSE_WITH_TEXLIB}}{21}
-\entry {\code {kpsewhich}}{27}
-\entry {\code {KPSEWHICH}}{27}
-\initial {L}
-\entry {large file support}{22}
-\entry {\code {LATEX}}{28}
-\entry {layout of sources}{12}
-\entry {LFS (large file support)}{22}
-\entry {\code {libexpat\r {, dependency of \code {libfontconfig}}}}{25}
-\entry {\code {libfontconfig\r {, hack for avoiding linking dependencies}}}{25}
-\entry {\code {libfreetype}}{27}
-\entry {\code {libfreetype}, and \code {const}}{30}
-\entry {\code {libpng \r {library}}}{16}
-\entry {library module, generic, adding}{20}
-\entry {library module, \TeX {}-specific, adding}{21}
-\entry {library modules}{16}
-\entry {library-specific \code {configure} options}{26}
-\entry {\code {libsigsegv}, required by \code {xindy}}{3}
-\entry {\code {libstc++\r {, statically linking}}}{14}
-\entry {Libtool}{2}
-\entry {\code {libtool\r {, hack for avoiding excessive linking}}}{25}
-\entry {\code {libXt}}{24}
-\entry {linked scripts}{9}
-\entry {linking C++ libraries statically}{14}
-\entry {\code {lisp.run\r {,} lisp.exe}}{26}
-\entry {LittleEndian architectures}{24}
-\initial {M}
-\entry {\file {m4/} top-level directory}{12}
-\entry {macros, for compilers}{14}
-\entry {macros, for libraries}{14}
-\entry {macros, for library and header flags}{15}
-\entry {macros, for programs}{14}
-\entry {macros, for Windows}{15}
-\entry {macros, general setup}{13}
-\entry {\code {make -t}}{12}
-\entry {\code {make} rules, verbose vs.\: silent}{23}
-\entry {\code {MAKE}}{28}
-\entry {\code {mf-nowin}}{24}
-\entry {\code {mingw32}}{7}
-\entry {\code {MINGW32\r {, Automake conditional}}}{16}
-\entry {\code {mktex.ac}}{17}
-\entry {\code {mktextfm}}{17}
-\entry {modules, for libraries}{16}
-\entry {modules, for programs}{18}
-\entry {\code {motif}}{26}
-\initial {N}
-\entry {native cross compilation}{6}
-\initial {O}
-\entry {\code {OBJCXX=\var {objc-compiler}}}{6}
-\entry {one engine, building}{6}
-\entry {one package, building}{5}
-\entry {OpenGL, required for Asymptote}{19}
-\entry {operating system distribution, building for}{10}
-\entry {\code {otangle}}{8}
-\entry {overall build process}{4}
-\initial {P}
-\entry {parallel build}{4}
-\entry {paths, for installation}{9}
-\entry {PDF files, size of}{22}
-\entry {\code {PDFLATEX}}{28}
-\entry {\code {perl}, required by \code {web2c}, etc.}{3}
-\entry {\code {PERL}}{28}
-\entry {\code {PKG_CONFIG}}{27}
-\entry {\code {plain.tex\r {, not in source tree}}}{9}
-\entry {\code {png \r {library}}}{16}
-\entry {\code {poppler}}{27}
-\entry {PostScript files, size of}{22}
-\entry {Preining, Norbert}{11}
-\entry {preloaded binaries}{25}
-\entry {prerequisites for building}{3}
-\entry {problems with build}{4}
-\entry {program module, adding}{19}
-\entry {program modules}{18}
-\entry {program-specific \code {configure} options}{24}
-\entry {proxy build system}{17}
-\initial {R}
-\entry {\code {reautoconf}}{12}
-\entry {requirements for building}{3}
-\entry {\code {runscript.exe}}{16}
-\initial {S}
-\entry {scripts, linked and not maintained}{9}
-\entry {\code {scrolling, smooth}}{26}
-\entry {\code {SED}}{28}
-\entry {setup macros, general}{13}
-\entry {shared libraries, using vs.\: avoiding}{10}
-\entry {size of PDF and PS files}{22}
-\entry {size of source tree}{6}
-\entry {source code declarations}{29}
-\entry {source directory building, not supported}{4}
-\entry {source tree}{12}
-\entry {\code {squeeze}}{8}
-\entry {\code {squeeze/configure.ac}}{18}
-\entry {\code {static} functions}{29}
-\entry {static linking for C++}{14}
-\entry {\code {stpcpy}}{29}
-\entry {Subversion repository}{12}
-\entry {support files, separate from build}{9}
-\entry {symlinks, used for scripts}{9}
-\entry {synctex}{25}
-\entry {system distribution, building for}{10}
-\initial {T}
-\entry {\code {t1utils \r {package}}}{18}
-\entry {\code {tangle}}{8}
-\entry {tests, running}{2}
-\entry {\TeX {}-specific library module, adding}{21}
-\entry {\code {texlive.tlpdb\r {, \TL {} database}}}{9}
-\entry {\code {tie}}{8}
-\entry {timestamps, in repository}{12}
-\entry {tools, for building}{12}
-\entry {top-level directories}{12}
-\entry {touching files to avoid rerunning}{12}
-\entry {Travis-CI}{31}
-\entry {\code {travis.yml}}{32}
-\entry {type cast from const, avoiding}{30}
-\initial {U}
-\entry {\code {use-commit-times\r {, Subversion}}}{12}
-\initial {V}
-\entry {variable declarations, in source code}{29}
-\entry {variables for \code {configure}}{27}
-\initial {W}
-\entry {warning, discards qualifiers}{30}
-\entry {\code {WARNING_C[XX]FLAGS}}{14}
-\entry {\code {web2c \r {program}}}{8}
-\entry {\code {web2c.ac}}{24}
-\entry {\code {wget}}{10}
-\entry {\code {WIN32\r {, Automake conditional}}}{16}
-\entry {\code {WIN32_WRAP\r {, Automake conditional}}}{16}
-\entry {Windows, invoking scripts on}{9}
-\entry {Windows, macros for}{15}
-\entry {\code {withenable.ac\r {, for new modules}}}{19}
-\entry {\file {Work/} top-level directory}{13}
-\entry {wrapper binary for scripts on Windows}{9}
-\entry {wrapper build system}{17}
-\initial {X}
-\entry {X toolkit}{24}
-\entry {X11 development, required by X clients}{3}
-\entry {X11 headers, and \code {const}}{30}
-\entry {\code {xasy}}{19}
-\entry {\code {xaw}}{26}
-\entry {\code {xdvik}}{18, 26}
-\entry {\code {xdvipdfmx}}{25}
-\entry {\code {xindy}}{10, 18, 26}
-\entry {\code {xindy} cross compiling impossible}{8}
-\entry {\code {XInput}}{26}
-\entry {\code {Xlib}}{24}
-\entry {\code {xpdf \r {as library}}}{27}
-\entry {\code {xz}}{10}
-\initial {Z}
-\entry {\code {zlib \r {library}}}{17}

Modified: branches/stable/source/src/doc/tlbuild.info
===================================================================
--- branches/stable/source/src/doc/tlbuild.info	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/doc/tlbuild.info	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,9 +1,9 @@
-This is tlbuild.info, produced by makeinfo version 6.7 from
+This is tlbuild.info, produced by makeinfo version 5.1 from
 tlbuild.texi.
 
 This file documents the TeX Live build system and more.
 
-Copyright (C) 2016-2020 Karl Berry.
+Copyright (C) 2016-2021 Karl Berry.
 Copyright (C) 2013-2015 Karl Berry & Peter Breitenlohner.
 
    Permission is granted to make and distribute verbatim copies of this
@@ -33,7 +33,7 @@
 
 File: tlbuild.info,  Node: Top,  Next: Introduction,  Up: (dir)
 
-Building TeX Live (2020)
+Building TeX Live (2021)
 ************************
 
 For an overview of this manual, *note Introduction::.
@@ -59,7 +59,7 @@
 1 Introduction
 **************
 
-This manual (dated November 2020) corresponds to the TeX Live 2020
+This manual (dated February 2021) corresponds to the TeX Live 2021
 release.
 
    This manual is aimed at system installers and programmers, and
@@ -322,8 +322,8 @@
 =====================
 
 To build one package, the basic idea is to use the 'configure' option
-'--disable-all-pkgs' (*note --disable-all-pkgs::).  Then all program and
-library modules are configured but none are made.  However, the
+'--disable-all-pkgs' (*note '--disable-all-pkgs'::).  Then all program
+and library modules are configured but none are made.  However, the
 'Makefile's still contain all build rules and dependencies and can be
 invoked to build an individual program or library, first building any
 required libraries.
@@ -1050,13 +1050,13 @@
 
 * Menu:
 
-* png library::       'libs/libpng'
-* zlib library::      'libs/zlib'
-* freetype library::  'libs/freetype2'
-* kpathsea library::  'texk/kpathsea'
+* 'png' library::       'libs/libpng'
+* 'zlib' library::      'libs/zlib'
+* 'freetype' library::  'libs/freetype2'
+* 'kpathsea' library::  'texk/kpathsea'
 
 
-File: tlbuild.info,  Node: png library,  Next: zlib library,  Up: Library modules
+File: tlbuild.info,  Node: 'png' library,  Next: 'zlib' library,  Up: Library modules
 
 6.4.1 The 'png' library in 'libs/libpng'
 ----------------------------------------
@@ -1112,7 +1112,7 @@
 flags required for the system library.
 
 
-File: tlbuild.info,  Node: zlib library,  Next: freetype library,  Prev: png library,  Up: Library modules
+File: tlbuild.info,  Node: 'zlib' library,  Next: 'freetype' library,  Prev: 'png' library,  Up: Library modules
 
 6.4.2 The 'zlib' library in 'libs/zlib'
 ---------------------------------------
@@ -1124,7 +1124,7 @@
 locations of the 'zlib' headers and/or library.
 
 
-File: tlbuild.info,  Node: freetype library,  Next: kpathsea library,  Prev: zlib library,  Up: Library modules
+File: tlbuild.info,  Node: 'freetype' library,  Next: 'kpathsea' library,  Prev: 'zlib' library,  Up: Library modules
 
 6.4.3 The 'freetype' library in 'libs/freetype2'
 ------------------------------------------------
@@ -1140,7 +1140,7 @@
 'freetype-config'.
 
 
-File: tlbuild.info,  Node: kpathsea library,  Prev: freetype library,  Up: Library modules
+File: tlbuild.info,  Node: 'kpathsea' library,  Prev: 'freetype' library,  Up: Library modules
 
 6.4.4 The 'kpathsea' library in 'texk/kpathsea'
 -----------------------------------------------
@@ -1178,13 +1178,13 @@
 
 * Menu:
 
-* t1utils package:: 'utils/t1utils'
-* xindy package::   'utils/xindy'
-* xdvik package::   'texk/xdvik'
-* asymptote::       'utils/asymptote'
+* 't1utils' package:: 'utils/t1utils'
+* 'xindy' package::   'utils/xindy'
+* 'xdvik' package::   'texk/xdvik'
+* 'asymptote'::       'utils/asymptote'
 
 
-File: tlbuild.info,  Node: t1utils package,  Next: xindy package,  Up: Program modules
+File: tlbuild.info,  Node: 't1utils' package,  Next: 'xindy' package,  Up: Program modules
 
 6.5.1 The 't1utils' package in 'utils/t1utils'
 ----------------------------------------------
@@ -1200,7 +1200,7 @@
 configure option '--disable-t1utils'.
 
 
-File: tlbuild.info,  Node: xindy package,  Next: xdvik package,  Prev: t1utils package,  Up: Program modules
+File: tlbuild.info,  Node: 'xindy' package,  Next: 'xdvik' package,  Prev: 't1utils' package,  Up: Program modules
 
 6.5.2 The 'xindy' package in 'utils/xindy'
 ------------------------------------------
@@ -1226,7 +1226,7 @@
 included by 'configure.ac'.
 
 
-File: tlbuild.info,  Node: xdvik package,  Next: asymptote,  Prev: xindy package,  Up: Program modules
+File: tlbuild.info,  Node: 'xdvik' package,  Next: 'asymptote',  Prev: 'xindy' package,  Up: Program modules
 
 6.5.3 The 'xdvik' package in 'texk/xdvik'
 -----------------------------------------
@@ -1251,7 +1251,7 @@
 also seen at the top level.
 
 
-File: tlbuild.info,  Node: asymptote,  Prev: xdvik package,  Up: Program modules
+File: tlbuild.info,  Node: 'asymptote',  Prev: 'xdvik' package,  Up: Program modules
 
 6.5.4 The subdirectory 'utils/asymptote'
 ----------------------------------------
@@ -1368,6 +1368,11 @@
 'autom4te.cache'.  (This is so people checking out the TL source tree do
 not have to run any autotools, but can simply run 'configure'.)
 
+   To reiterate: do not fail to commit the generated 'configure' and
+other files.  The m4 code in 'kpse-pkgs.m4' uses the existence of
+'configure' to determine whether to descend into (and configure) a given
+subdirectory.
+
    Then, run the TL tool 'reautoconf' in the top-level TL
 'Build/source/' directory, to incorporate the new program into the build
 tree.  It is good to then rebuild the whole tree (e.g., using TL's
@@ -1494,21 +1499,21 @@
 
 * Menu:
 
-* --disable-native-texlive-build::
-* --prefix --bindir ...::
-* --disable-largefile::
-* --disable-missing::
-* --enable-compiler-warnings=LEVEL::
-* --enable-cxx-runtime-hack::
-* --enable-maintainer-mode::
-* --enable-multiplatform::
-* --enable-shared::
-* --enable-silent-rules::
-* --without-ln-s::
-* --without-x::
+* '--disable-native-texlive-build'::
+* '--prefix' '--bindir' ...::
+* '--disable-largefile'::
+* '--disable-missing'::
+* '--enable-compiler-warnings='LEVEL::
+* '--enable-cxx-runtime-hack'::
+* '--enable-maintainer-mode'::
+* '--enable-multiplatform'::
+* '--enable-shared'::
+* '--enable-silent-rules'::
+* '--without-ln-s'::
+* '--without-x'::
 
 
-File: tlbuild.info,  Node: --disable-native-texlive-build,  Next: --prefix --bindir ...,  Up: Global configure options
+File: tlbuild.info,  Node: '--disable-native-texlive-build',  Next: '--prefix' '--bindir' ...,  Up: Global configure options
 
 7.1.1 '--disable-native-texlive-build'
 --------------------------------------
@@ -1529,7 +1534,7 @@
 TL-specific adaptations, such as installation paths.
 
 
-File: tlbuild.info,  Node: --prefix --bindir ...,  Next: --disable-largefile,  Prev: --disable-native-texlive-build,  Up: Global configure options
+File: tlbuild.info,  Node: '--prefix' '--bindir' ...,  Next: '--disable-largefile',  Prev: '--disable-native-texlive-build',  Up: Global configure options
 
 7.1.2 '--prefix', '--bindir', ...
 ---------------------------------
@@ -1542,7 +1547,7 @@
 location: (automake)Staged Installs.).
 
 
-File: tlbuild.info,  Node: --disable-largefile,  Next: --disable-missing,  Prev: --prefix --bindir ...,  Up: Global configure options
+File: tlbuild.info,  Node: '--disable-largefile',  Next: '--disable-missing',  Prev: '--prefix' '--bindir' ...,  Up: Global configure options
 
 7.1.3 '--disable-largefile'
 ---------------------------
@@ -1556,7 +1561,7 @@
 'pdftex' or PostScript files created by 'dvips'.
 
 
-File: tlbuild.info,  Node: --disable-missing,  Next: --enable-compiler-warnings=LEVEL,  Prev: --disable-largefile,  Up: Global configure options
+File: tlbuild.info,  Node: '--disable-missing',  Next: '--enable-compiler-warnings='LEVEL,  Prev: '--disable-largefile',  Up: Global configure options
 
 7.1.4 '--disable-missing'
 -------------------------
@@ -1566,7 +1571,7 @@
 when figuring out a specific (sub)set of modules to enable.
 
 
-File: tlbuild.info,  Node: --enable-compiler-warnings=LEVEL,  Next: --enable-cxx-runtime-hack,  Prev: --disable-missing,  Up: Global configure options
+File: tlbuild.info,  Node: '--enable-compiler-warnings='LEVEL,  Next: '--enable-cxx-runtime-hack',  Prev: '--disable-missing',  Up: Global configure options
 
 7.1.5 '--enable-compiler-warnings='LEVEL
 ----------------------------------------
@@ -1579,7 +1584,7 @@
 At present, these warning flags assume options from the GNU compilers.
 
 
-File: tlbuild.info,  Node: --enable-cxx-runtime-hack,  Next: --enable-maintainer-mode,  Prev: --enable-compiler-warnings=LEVEL,  Up: Global configure options
+File: tlbuild.info,  Node: '--enable-cxx-runtime-hack',  Next: '--enable-maintainer-mode',  Prev: '--enable-compiler-warnings='LEVEL,  Up: Global configure options
 
 7.1.6 '--enable-cxx-runtime-hack'
 ---------------------------------
@@ -1589,7 +1594,7 @@
 resulting binary.  *Note Macros for compilers::.
 
 
-File: tlbuild.info,  Node: --enable-maintainer-mode,  Next: --enable-multiplatform,  Prev: --enable-cxx-runtime-hack,  Up: Global configure options
+File: tlbuild.info,  Node: '--enable-maintainer-mode',  Next: '--enable-multiplatform',  Prev: '--enable-cxx-runtime-hack',  Up: Global configure options
 
 7.1.7 '--enable-maintainer-mode'
 --------------------------------
@@ -1601,7 +1606,7 @@
 'AM_MAINTAINER_MODE': (automake)maintainer-mode.
 
 
-File: tlbuild.info,  Node: --enable-multiplatform,  Next: --enable-shared,  Prev: --enable-maintainer-mode,  Up: Global configure options
+File: tlbuild.info,  Node: '--enable-multiplatform',  Next: '--enable-shared',  Prev: '--enable-maintainer-mode',  Up: Global configure options
 
 7.1.8 '--enable-multiplatform'
 ------------------------------
@@ -1614,7 +1619,7 @@
 subdirectories.
 
 
-File: tlbuild.info,  Node: --enable-shared,  Next: --enable-silent-rules,  Prev: --enable-multiplatform,  Up: Global configure options
+File: tlbuild.info,  Node: '--enable-shared',  Next: '--enable-silent-rules',  Prev: '--enable-multiplatform',  Up: Global configure options
 
 7.1.9 '--enable-shared'
 -----------------------
@@ -1624,7 +1629,7 @@
 '--disable-native-texlive-build' must also be specified).
 
 
-File: tlbuild.info,  Node: --enable-silent-rules,  Next: --without-ln-s,  Prev: --enable-shared,  Up: Global configure options
+File: tlbuild.info,  Node: '--enable-silent-rules',  Next: '--without-ln-s',  Prev: '--enable-shared',  Up: Global configure options
 
 7.1.10 '--enable-silent-rules'
 ------------------------------
@@ -1635,7 +1640,7 @@
 'V=0' to get less, regardless of this option.
 
 
-File: tlbuild.info,  Node: --without-ln-s,  Next: --without-x,  Prev: --enable-silent-rules,  Up: Global configure options
+File: tlbuild.info,  Node: '--without-ln-s',  Next: '--without-x',  Prev: '--enable-silent-rules',  Up: Global configure options
 
 7.1.11 '--without-ln-s'
 -----------------------
@@ -1645,7 +1650,7 @@
 anything useful, and might fail.
 
 
-File: tlbuild.info,  Node: --without-x,  Prev: --without-ln-s,  Up: Global configure options
+File: tlbuild.info,  Node: '--without-x',  Prev: '--without-ln-s',  Up: Global configure options
 
 7.1.12 '--without-x'
 --------------------
@@ -1662,18 +1667,18 @@
 
 * Menu:
 
-* --enable-PROG --disable-PROG::
-* --disable-all-pkgs::
-* Configure options for texk/web2c::
-* Configure options for texk/bibtex-x::
-* Configure options for texk/dvipdfm-x::
-* Configure options for texk/dvisvgm::
-* Configure options for texk/texlive::
-* Configure options for texk/xdvik::
-* Configure options for utils/xindy::
+* '--enable-PROG' '--disable-PROG'::
+* '--disable-all-pkgs'::
+* Configure options for 'texk/web2c'::
+* Configure options for 'texk/bibtex-x'::
+* Configure options for 'texk/dvipdfm-x'::
+* Configure options for 'texk/dvisvgm'::
+* Configure options for 'texk/texlive'::
+* Configure options for 'texk/xdvik'::
+* Configure options for 'utils/xindy'::
 
 
-File: tlbuild.info,  Node: --enable-PROG --disable-PROG,  Next: --disable-all-pkgs,  Up: Program-specific configure options
+File: tlbuild.info,  Node: '--enable-PROG' '--disable-PROG',  Next: '--disable-all-pkgs',  Up: Program-specific configure options
 
 7.2.1 '--enable-PROG', '--disable-PROG'
 ---------------------------------------
@@ -1681,7 +1686,7 @@
 Do or do not build and install the program(s) of module 'PROG'.
 
 
-File: tlbuild.info,  Node: --disable-all-pkgs,  Next: Configure options for texk/web2c,  Prev: --enable-PROG --disable-PROG,  Up: Program-specific configure options
+File: tlbuild.info,  Node: '--disable-all-pkgs',  Next: Configure options for 'texk/web2c',  Prev: '--enable-PROG' '--disable-PROG',  Up: Program-specific configure options
 
 7.2.2 '--disable-all-pkgs'
 --------------------------
@@ -1698,7 +1703,7 @@
 fragment.
 
 
-File: tlbuild.info,  Node: Configure options for texk/web2c,  Next: Configure options for texk/bibtex-x,  Prev: --disable-all-pkgs,  Up: Program-specific configure options
+File: tlbuild.info,  Node: Configure options for 'texk/web2c',  Next: Configure options for 'texk/bibtex-x',  Prev: '--disable-all-pkgs',  Up: Program-specific configure options
 
 7.2.3 Configure options for 'texk/web2c'
 ----------------------------------------
@@ -1765,7 +1770,7 @@
 Do not build the 'SyncTeX' library and tool.
 
 
-File: tlbuild.info,  Node: Configure options for texk/bibtex-x,  Next: Configure options for texk/dvipdfm-x,  Prev: Configure options for texk/web2c,  Up: Program-specific configure options
+File: tlbuild.info,  Node: Configure options for 'texk/bibtex-x',  Next: Configure options for 'texk/dvipdfm-x',  Prev: Configure options for 'texk/web2c',  Up: Program-specific configure options
 
 7.2.4 Configure options for 'texk/bibtex-x'
 -------------------------------------------
@@ -1781,7 +1786,7 @@
 libraries).
 
 
-File: tlbuild.info,  Node: Configure options for texk/dvipdfm-x,  Next: Configure options for texk/dvisvgm,  Prev: Configure options for texk/bibtex-x,  Up: Program-specific configure options
+File: tlbuild.info,  Node: Configure options for 'texk/dvipdfm-x',  Next: Configure options for 'texk/dvisvgm',  Prev: Configure options for 'texk/bibtex-x',  Up: Program-specific configure options
 
 7.2.5 Configure options for 'texk/dvipdfm-x'
 --------------------------------------------
@@ -1799,7 +1804,7 @@
 Do not build the 'xdvipdfmx' program.
 
 
-File: tlbuild.info,  Node: Configure options for texk/dvisvgm,  Next: Configure options for texk/texlive,  Prev: Configure options for texk/dvipdfm-x,  Up: Program-specific configure options
+File: tlbuild.info,  Node: Configure options for 'texk/dvisvgm',  Next: Configure options for 'texk/texlive',  Prev: Configure options for 'texk/dvipdfm-x',  Up: Program-specific configure options
 
 7.2.6 Configure options for 'texk/dvisvgm'
 ------------------------------------------
@@ -1819,7 +1824,7 @@
 Specify non-standard locations of the Ghostscript headers and library.
 
 
-File: tlbuild.info,  Node: Configure options for texk/texlive,  Next: Configure options for texk/xdvik,  Prev: Configure options for texk/dvisvgm,  Up: Program-specific configure options
+File: tlbuild.info,  Node: Configure options for 'texk/texlive',  Next: Configure options for 'texk/xdvik',  Prev: Configure options for 'texk/dvisvgm',  Up: Program-specific configure options
 
 7.2.7 Configure options for 'texk/texlive'
 ------------------------------------------
@@ -1829,7 +1834,7 @@
 the TL scripts required to run 'texlinks'.
 
 
-File: tlbuild.info,  Node: Configure options for texk/xdvik,  Next: Configure options for utils/xindy,  Prev: Configure options for texk/texlive,  Up: Program-specific configure options
+File: tlbuild.info,  Node: Configure options for 'texk/xdvik',  Next: Configure options for 'utils/xindy',  Prev: Configure options for 'texk/texlive',  Up: Program-specific configure options
 
 7.2.8 Configure options for 'texk/xdvik'
 ----------------------------------------
@@ -1846,7 +1851,7 @@
 a native TL build).
 
 
-File: tlbuild.info,  Node: Configure options for utils/xindy,  Prev: Configure options for texk/xdvik,  Up: Program-specific configure options
+File: tlbuild.info,  Node: Configure options for 'utils/xindy',  Prev: Configure options for 'texk/xdvik',  Up: Program-specific configure options
 
 7.2.9 Configure options for 'utils/xindy'
 -----------------------------------------
@@ -1892,10 +1897,10 @@
 
 * Menu:
 
-* Configure options for kpathsea::
+* Configure options for 'kpathsea'::
 
 
-File: tlbuild.info,  Node: Configure options for kpathsea,  Up: Library-specific configure options
+File: tlbuild.info,  Node: Configure options for 'kpathsea',  Up: Library-specific configure options
 
 7.3.1 Configure options for 'kpathsea'
 --------------------------------------
@@ -1919,7 +1924,7 @@
      (TFM file)
 
 to generate the specified type of file dynamically.  The default can be
-overridden by the user in any case (*note kpathsea library::).
+overridden by the user in any case (*note 'kpathsea' library::).
 
 
 File: tlbuild.info,  Node: Variables for configure,  Prev: Library-specific configure options,  Up: Configure options
@@ -5092,11 +5097,11 @@
 
 * Menu:
 
-* tlmgr Machine-readable update and install output::
-* tlmgr Machine-readable option output::
+* tlmgr Machine-readable 'update' and 'install' output::
+* tlmgr Machine-readable 'option' output::
 
 
-File: tlbuild.info,  Node: tlmgr Machine-readable update and install output,  Next: tlmgr Machine-readable option output,  Up: tlmgr MACHINE-READABLE OUTPUT
+File: tlbuild.info,  Node: tlmgr Machine-readable 'update' and 'install' output,  Next: tlmgr Machine-readable 'option' output,  Up: tlmgr MACHINE-READABLE OUTPUT
 
 B.12.1 Machine-readable 'update' and 'install' output
 -----------------------------------------------------
@@ -5214,7 +5219,7 @@
      The estimated total time.
 
 
-File: tlbuild.info,  Node: tlmgr Machine-readable option output,  Prev: tlmgr Machine-readable update and install output,  Up: tlmgr MACHINE-READABLE OUTPUT
+File: tlbuild.info,  Node: tlmgr Machine-readable 'option' output,  Prev: tlmgr Machine-readable 'update' and 'install' output,  Up: tlmgr MACHINE-READABLE OUTPUT
 
 B.12.2 Machine-readable 'option' output
 ---------------------------------------
@@ -5335,570 +5340,597 @@
  [index ]
 * Menu:
 
-* --bindir configure option:             --prefix --bindir ....
-                                                               (line  6)
-* --bindir configure option <1>:         --enable-multiplatform.
-                                                               (line  6)
-* --build=HOST:                          Cross configuring.    (line  6)
-* --disable-all-packages:                Build one package.    (line  6)
-* --disable-all-pkgs:                    --disable-all-pkgs.   (line  6)
-* --disable-bibtex8:                     Configure options for texk/bibtex-x.
-                                                               (line  9)
-* --disable-bibtexu:                     Configure options for texk/bibtex-x.
-                                                               (line 12)
-* --disable-dump-share:                  Configure options for texk/web2c.
-                                                               (line 27)
-* --disable-dvipdfmx:                    Configure options for texk/dvipdfm-x.
-                                                               (line 12)
-* --disable-etex-synctex:                Configure options for texk/web2c.
-                                                               (line 59)
-* --disable-ipc:                         Configure options for texk/web2c.
-                                                               (line 31)
-* --disable-largefile:                   --disable-largefile.  (line  6)
-* --disable-linked-scripts:              Configure options for texk/texlive.
-                                                               (line  6)
-* --disable-mf-nowin:                    Configure options for texk/web2c.
-                                                               (line 34)
-* --disable-missing:                     --disable-missing.    (line  6)
-* --disable-native-texlive-build:        --disable-native-texlive-build.
-                                                               (line  6)
-* --disable-PROG:                        --enable-PROG --disable-PROG.
-                                                               (line  6)
-* --disable-synctex:                     Configure options for texk/web2c.
-                                                               (line 64)
-* --disable-tex:                         Configure options for texk/web2c.
-                                                               (line 37)
-* --disable-web-progs:                   Configure options for texk/web2c.
-                                                               (line 41)
-* --disable-xdvipdfmx:                   Configure options for texk/dvipdfm-x.
-                                                               (line 15)
-* --enable-*win for Metafont window support: Configure options for texk/web2c.
-                                                               (line 55)
-* --enable-auto-core:                    Configure options for texk/web2c.
-                                                               (line 45)
-* --enable-compiler-warnings=LEVEL:      --enable-compiler-warnings=LEVEL.
-                                                               (line  6)
-* --enable-cxx-runtime-hack:             Macros for compilers. (line 29)
-* --enable-etex:                         Configure options for texk/web2c.
-                                                               (line 37)
-* --enable-libtool-hack:                 Configure options for texk/web2c.
-                                                               (line 50)
-* --enable-maintainer-mode:              Build system tools.   (line 28)
-* --enable-maintainer-mode <1>:          --enable-maintainer-mode.
-                                                               (line  6)
-* --enable-missing to ignore dependencies: Build one package.  (line 71)
-* --enable-mktextfm-default:             kpathsea library.     (line 18)
-* --enable-multiplatform:                --enable-multiplatform.
-                                                               (line  6)
-* --enable-PROG:                         --enable-PROG --disable-PROG.
-                                                               (line  6)
-* --enable-shared:                       --enable-shared.      (line  6)
-* --enable-silent-rules:                 --enable-silent-rules.
-                                                               (line  6)
-* --enable-tex-synctex:                  Configure options for texk/web2c.
-                                                               (line 59)
-* --enable-texlive-build:                --disable-native-texlive-build.
-                                                               (line 15)
-* --enable-xi2-scrolling:                Configure options for texk/xdvik.
-                                                               (line 13)
-* --enable-xindy-docs:                   Configure options for utils/xindy.
-                                                               (line 10)
-* --enable-xindy-rules:                  Configure options for utils/xindy.
-                                                               (line  6)
-* --host=HOST:                           Cross configuring.    (line  6)
-* --libdir configure option:             --enable-multiplatform.
-                                                               (line  6)
-* --no-clean Build option:               Build problems.       (line  6)
-* --prefix configure option:             --prefix --bindir ....
-                                                               (line  6)
-* --with-banner-add=STR:                 Configure options for texk/web2c.
-                                                               (line  6)
-* --with-clisp-runtime=FILENAME:         Configure options for utils/xindy.
-                                                               (line 14)
-* --with-editor=CMD:                     Configure options for texk/web2c.
-                                                               (line 11)
-* --with-fontconfig-includes=DIR:        Configure options for texk/web2c.
-                                                               (line 16)
-* --with-fontconfig-libdir=DIR:          Configure options for texk/web2c.
-                                                               (line 16)
-* --with-gs=FILENAME:                    Configure options for texk/xdvik.
-                                                               (line  6)
+* --bindir configure option:             '--prefix' '--bindir' ....
+                                                              (line   6)
+* --bindir configure option <1>:         '--enable-multiplatform'.
+                                                              (line   6)
+* --build=HOST:                          Cross configuring.   (line   6)
+* --disable-all-packages:                Build one package.   (line   6)
+* --disable-all-pkgs:                    '--disable-all-pkgs'.
+                                                              (line   6)
+* --disable-bibtex8:                     Configure options for 'texk/bibtex-x'.
+                                                              (line   9)
+* --disable-bibtexu:                     Configure options for 'texk/bibtex-x'.
+                                                              (line  12)
+* --disable-dump-share:                  Configure options for 'texk/web2c'.
+                                                              (line  27)
+* --disable-dvipdfmx:                    Configure options for 'texk/dvipdfm-x'.
+                                                              (line  12)
+* --disable-etex-synctex:                Configure options for 'texk/web2c'.
+                                                              (line  59)
+* --disable-ipc:                         Configure options for 'texk/web2c'.
+                                                              (line  31)
+* --disable-largefile:                   '--disable-largefile'.
+                                                              (line   6)
+* --disable-linked-scripts:              Configure options for 'texk/texlive'.
+                                                              (line   6)
+* --disable-mf-nowin:                    Configure options for 'texk/web2c'.
+                                                              (line  34)
+* --disable-missing:                     '--disable-missing'. (line   6)
+* --disable-native-texlive-build:        '--disable-native-texlive-build'.
+                                                              (line   6)
+* --disable-PROG:                        '--enable-PROG' '--disable-PROG'.
+                                                              (line   6)
+* --disable-synctex:                     Configure options for 'texk/web2c'.
+                                                              (line  64)
+* --disable-tex:                         Configure options for 'texk/web2c'.
+                                                              (line  37)
+* --disable-web-progs:                   Configure options for 'texk/web2c'.
+                                                              (line  41)
+* --disable-xdvipdfmx:                   Configure options for 'texk/dvipdfm-x'.
+                                                              (line  15)
+* --enable-*win for Metafont window support: Configure options for 'texk/web2c'.
+                                                              (line  55)
+* --enable-auto-core:                    Configure options for 'texk/web2c'.
+                                                              (line  45)
+* --enable-compiler-warnings=LEVEL:      '--enable-compiler-warnings='LEVEL.
+                                                              (line   6)
+* --enable-cxx-runtime-hack:             Macros for compilers.
+                                                              (line  29)
+* --enable-etex:                         Configure options for 'texk/web2c'.
+                                                              (line  37)
+* --enable-libtool-hack:                 Configure options for 'texk/web2c'.
+                                                              (line  50)
+* --enable-maintainer-mode:              Build system tools.  (line  28)
+* --enable-maintainer-mode <1>:          '--enable-maintainer-mode'.
+                                                              (line   6)
+* --enable-missing to ignore dependencies: Build one package. (line  71)
+* --enable-mktextfm-default:             'kpathsea' library.  (line  18)
+* --enable-multiplatform:                '--enable-multiplatform'.
+                                                              (line   6)
+* --enable-PROG:                         '--enable-PROG' '--disable-PROG'.
+                                                              (line   6)
+* --enable-shared:                       '--enable-shared'.   (line   6)
+* --enable-silent-rules:                 '--enable-silent-rules'.
+                                                              (line   6)
+* --enable-tex-synctex:                  Configure options for 'texk/web2c'.
+                                                              (line  59)
+* --enable-texlive-build:                '--disable-native-texlive-build'.
+                                                              (line  15)
+* --enable-xi2-scrolling:                Configure options for 'texk/xdvik'.
+                                                              (line  13)
+* --enable-xindy-docs:                   Configure options for 'utils/xindy'.
+                                                              (line  10)
+* --enable-xindy-rules:                  Configure options for 'utils/xindy'.
+                                                              (line   6)
+* --host=HOST:                           Cross configuring.   (line   6)
+* --libdir configure option:             '--enable-multiplatform'.
+                                                              (line   6)
+* --no-clean Build option:               Build problems.      (line   6)
+* --prefix configure option:             '--prefix' '--bindir' ....
+                                                              (line   6)
+* --with-banner-add=STR:                 Configure options for 'texk/web2c'.
+                                                              (line   6)
+* --with-clisp-runtime=FILENAME:         Configure options for 'utils/xindy'.
+                                                              (line  14)
+* --with-editor=CMD:                     Configure options for 'texk/web2c'.
+                                                              (line  11)
+* --with-fontconfig-includes=DIR:        Configure options for 'texk/web2c'.
+                                                              (line  16)
+* --with-fontconfig-libdir=DIR:          Configure options for 'texk/web2c'.
+                                                              (line  16)
+* --with-gs=FILENAME:                    Configure options for 'texk/xdvik'.
+                                                              (line   6)
 * --with-LIB-includes=DIR, -libdir:      Library-specific configure options.
-                                                               (line 16)
-* --with-libgs-includes, -libdir:        Configure options for texk/dvisvgm.
-                                                               (line 17)
-* --with-system-kpathsea:                kpathsea library.     (line 13)
+                                                              (line  16)
+* --with-libgs-includes, -libdir:        Configure options for 'texk/dvisvgm'.
+                                                              (line  17)
+* --with-system-kpathsea:                'kpathsea' library.  (line  13)
 * --with-system-LIB:                     Adding a new generic library module.
-                                                               (line 34)
+                                                              (line  34)
 * --with-system-LIB <1>:                 Library-specific configure options.
-                                                               (line  9)
-* --with-system-libgs:                   Configure options for texk/dvisvgm.
-                                                               (line  6)
-* --with-xdvi-x-toolkit:                 xdvik package.        (line 21)
-* --with-xdvi-x-toolkit=KIT:             Configure options for texk/xdvik.
-                                                               (line  9)
-* --without-libgs:                       Configure options for texk/dvisvgm.
-                                                               (line 12)
-* --without-ln-s:                        --without-ln-s.       (line  6)
-* --without-x:                           --without-x.          (line  6)
-* -C configure option:                   Build in parallel.    (line 11)
-* -j make option:                        Build in parallel.    (line  6)
+                                                              (line   9)
+* --with-system-libgs:                   Configure options for 'texk/dvisvgm'.
+                                                              (line   6)
+* --with-xdvi-x-toolkit:                 'xdvik' package.     (line  21)
+* --with-xdvi-x-toolkit=KIT:             Configure options for 'texk/xdvik'.
+                                                              (line   9)
+* --without-libgs:                       Configure options for 'texk/dvisvgm'.
+                                                              (line  12)
+* --without-ln-s:                        '--without-ln-s'.    (line   6)
+* --without-x:                           '--without-x'.       (line   6)
+* -C configure option:                   Build in parallel.   (line  11)
+* -j make option:                        Build in parallel.   (line   6)
 * ac/withenable.ac:                      Adding a new program module.
-                                                               (line 42)
-* adapting TeX Live for distros:         Distro builds.        (line 54)
+                                                              (line  42)
+* adapting TeX Live for distros:         Distro builds.       (line  54)
 * adding a new generic library:          Adding a new generic library module.
-                                                               (line  6)
+                                                              (line   6)
 * adding a new program:                  Adding a new program module.
-                                                               (line  6)
+                                                              (line   6)
 * adding a new TeX-specific library:     Adding a new TeX-specific library module.
-                                                               (line  6)
-* adding to TeX Live:                    Extending TeX Live.   (line  6)
-* am/ top-level directory:               Top-level directories.
-                                                               (line 14)
+                                                              (line   6)
+* adding to TeX Live:                    Extending TeX Live.  (line   6)
+* 'am/' top-level directory:             Top-level directories.
+                                                              (line  14)
 * ANSI C:                                Declarations and definitions.
-                                                               (line  6)
-* ApplicationServices Mac framework, required by xetex: Prerequisites.
-                                                               (line 31)
-* asymptote:                             Linked scripts.       (line 23)
-* asymptote <1>:                         asymptote.            (line  6)
+                                                              (line   6)
+* 'ApplicationServices' Mac framework, required by 'xetex': Prerequisites.
+                                                              (line  31)
+* asymptote:                             Linked scripts.      (line  23)
+* asymptote <1>:                         'asymptote'.         (line   6)
 * Autoconf:                              Overview of build system.
-                                                               (line  6)
-* autoconf macros:                       Autoconf macros.      (line  6)
+                                                              (line   6)
+* autoconf macros:                       Autoconf macros.     (line   6)
 * Automake:                              Overview of build system.
-                                                               (line  6)
+                                                              (line   6)
 * autoreconf, for new program:           Adding a new program module.
-                                                               (line 76)
-* biber:                                 Linked scripts.       (line 23)
-* bibtex-x:                              Configure options for texk/bibtex-x.
-                                                               (line  6)
-* bibtex8:                               Configure options for texk/bibtex-x.
-                                                               (line  6)
-* bibtexu:                               Configure options for texk/bibtex-x.
-                                                               (line  6)
-* BSD distro:                            Distro builds.        (line  6)
-* build directory, required:             Building.             (line 17)
-* build iteration:                       Build iteration.      (line  6)
-* build on demand:                       Build one package.    (line  6)
-* build one engine:                      Build one engine.     (line  6)
-* build one package:                     Build one package.    (line  6)
-* build problems:                        Build problems.       (line  6)
-* Build script:                          Building.             (line  6)
+                                                              (line  76)
+* biber:                                 Linked scripts.      (line  23)
+* bibtex-x:                              Configure options for 'texk/bibtex-x'.
+                                                              (line   6)
+* bibtex8:                               Configure options for 'texk/bibtex-x'.
+                                                              (line   6)
+* bibtexu:                               Configure options for 'texk/bibtex-x'.
+                                                              (line   6)
+* BSD distro:                            Distro builds.       (line   6)
+* build directory, required:             Building.            (line  17)
+* build iteration:                       Build iteration.     (line   6)
+* build on demand:                       Build one package.   (line   6)
+* build one engine:                      Build one engine.    (line   6)
+* build one package:                     Build one package.   (line   6)
+* build problems:                        Build problems.      (line   6)
+* Build script:                          Building.            (line   6)
 * build system, design of:               Overview of build system.
-                                                               (line  6)
-* build-aux/ top-level directory:        Top-level directories.
-                                                               (line 30)
-* BUILDCC, BUILDCFLAGS, ...:             Cross configuring.    (line 42)
-* building:                              Building.             (line  6)
-* building a distribution:               Build distribution.   (line  6)
-* building in parallel:                  Build in parallel.    (line  6)
-* C++11, removing dependent sources:     Build one package.    (line 64)
-* C++11, required:                       Prerequisites.        (line 15)
+                                                              (line   6)
+* 'build-aux/' top-level directory:      Top-level directories.
+                                                              (line  30)
+* BUILDCC, BUILDCFLAGS, ...:             Cross configuring.   (line  42)
+* building:                              Building.            (line   6)
+* building a distribution:               Build distribution.  (line   6)
+* building in parallel:                  Build in parallel.   (line   6)
+* C++11, removing dependent sources:     Build one package.   (line  64)
+* C++11, required:                       Prerequisites.       (line  15)
 * C, ANSI, required:                     Declarations and definitions.
-                                                               (line  6)
+                                                              (line   6)
 * C99, avoided:                          Declarations and definitions.
-                                                               (line  6)
-* cache file, for configure:             Build in parallel.    (line 11)
-* cache for configure:                   Build in parallel.    (line  6)
-* callexe.c:                             Macros for Windows.   (line 32)
+                                                              (line   6)
+* cache file, for 'configure':           Build in parallel.   (line  11)
+* cache for 'configure':                 Build in parallel.   (line   6)
+* callexe.c:                             Macros for Windows.  (line  32)
 * CC:                                    Variables for configure.
-                                                               (line 10)
-* CC=C-COMPILER:                         Build one package.    (line 78)
-* CC_BUILD:                              Cross problems.       (line 13)
+                                                              (line  10)
+* CC=C-COMPILER:                         Build one package.   (line  78)
+* CC_BUILD:                              Cross problems.      (line  13)
 * ChangeLog:                             Adding a new program module.
-                                                               (line 73)
+                                                              (line  73)
 * chktex:                                Declarations and definitions.
-                                                               (line 18)
+                                                              (line  18)
 * clisp:                                 Variables for configure.
-                                                               (line 18)
+                                                              (line  18)
 * CLISP:                                 Variables for configure.
-                                                               (line 17)
-* CLISP <1>:                             Configure options for utils/xindy.
-                                                               (line 14)
-* clisp, required by xindy:              Prerequisites.        (line 35)
-* Cocoa Mac framework, required by xetex: Prerequisites.       (line 31)
-* coding conventions:                    Coding conventions.   (line  6)
-* compilers, C and C++11:                Prerequisites.        (line  6)
+                                                              (line  17)
+* CLISP <1>:                             Configure options for 'utils/xindy'.
+                                                              (line  14)
+* 'clisp', required by 'xindy':          Prerequisites.       (line  35)
+* 'Cocoa' Mac framework, required by 'xetex': Prerequisites.  (line  31)
+* coding conventions:                    Coding conventions.  (line   6)
+* compilers, C and C++11:                Prerequisites.       (line   6)
 * config.guess, config.sub, ...:         Top-level directories.
-                                                               (line 30)
-* configure options:                     Configure options.    (line  6)
-* configure options, for bibtex-x:       Configure options for texk/bibtex-x.
-                                                               (line  6)
-* configure options, for dvipdfm-x:      Configure options for texk/dvipdfm-x.
-                                                               (line  6)
-* configure options, for dvisvgm:        Configure options for texk/dvisvgm.
-                                                               (line  6)
-* configure options, for kpathsea:       Configure options for kpathsea.
-                                                               (line  6)
-* configure options, for texk/texlive:   Configure options for texk/texlive.
-                                                               (line  6)
-* configure options, for web2c:          Configure options for texk/web2c.
-                                                               (line  6)
-* configure options, for xdvik:          Configure options for texk/xdvik.
-                                                               (line  6)
-* configure options, for xindy:          Configure options for utils/xindy.
-                                                               (line  6)
-* configure options, global:             Global configure options.
-                                                               (line  6)
-* configure options, library-specific:   Library-specific configure options.
-                                                               (line  6)
-* configure options, program-specific:   Program-specific configure options.
-                                                               (line  6)
-* configure variables:                   Variables for configure.
-                                                               (line  6)
+                                                              (line  30)
+* 'configure' options:                   Configure options.   (line   6)
+* 'configure' options, for 'bibtex-x':   Configure options for 'texk/bibtex-x'.
+                                                              (line   6)
+* 'configure' options, for 'dvipdfm-x':  Configure options for 'texk/dvipdfm-x'.
+                                                              (line   6)
+* 'configure' options, for 'dvisvgm':    Configure options for 'texk/dvisvgm'.
+                                                              (line   6)
+* 'configure' options, for 'kpathsea':   Configure options for 'kpathsea'.
+                                                              (line   6)
+* 'configure' options, for 'texk/texlive': Configure options for 'texk/texlive'.
+                                                              (line   6)
+* 'configure' options, for 'web2c':      Configure options for 'texk/web2c'.
+                                                              (line   6)
+* 'configure' options, for 'xdvik':      Configure options for 'texk/xdvik'.
+                                                              (line   6)
+* 'configure' options, for 'xindy':      Configure options for 'utils/xindy'.
+                                                              (line   6)
+* 'configure' options, global:           Global configure options.
+                                                              (line   6)
+* 'configure' options, library-specific: Library-specific configure options.
+                                                              (line   6)
+* 'configure' options, program-specific: Program-specific configure options.
+                                                              (line   6)
+* 'configure' variables:                 Variables for configure.
+                                                              (line   6)
 * configure.ac:                          Adding a new program module.
-                                                               (line 45)
-* configuring, for cross compilation:    Cross configuring.    (line  6)
-* const:                                 Const.                (line  6)
+                                                              (line  45)
+* configuring, for cross compilation:    Cross configuring.   (line   6)
+* 'const':                               Const.               (line   6)
 * continuous integration:                Continuous integration.
-                                                               (line  6)
-* conventions, coding:                   Coding conventions.   (line  6)
+                                                              (line   6)
+* conventions, coding:                   Coding conventions.  (line   6)
 * CPPFLAGS:                              Variables for configure.
-                                                               (line 12)
-* cross compilation:                     Cross compilation.    (line  6)
-* cross compilation configuring:         Cross configuring.    (line  6)
-* cross compilation problems:            Cross problems.       (line  6)
-* cross compilation, with host binary:   xdvik package.        (line 14)
-* ctangle:                               Cross problems.       (line 26)
+                                                              (line  12)
+* cross compilation:                     Cross compilation.   (line   6)
+* cross compilation configuring:         Cross configuring.   (line   6)
+* cross compilation problems:            Cross problems.      (line   6)
+* cross compilation, with host binary:   'xdvik' package.     (line  14)
+* ctangle:                               Cross problems.      (line  26)
 * CXX:                                   Variables for configure.
-                                                               (line 11)
-* CXX=C++-COMPILER:                      Build one package.    (line 78)
+                                                              (line  11)
+* CXX=C++-COMPILER:                      Build one package.   (line  78)
 * declarations and definitions, in source code: Declarations and definitions.
-                                                               (line  6)
+                                                              (line   6)
 * declarations before statements, avoiding: Declarations and definitions.
-                                                               (line  6)
-* dependencies, with several output files: Build in parallel.  (line  6)
-* DESTDIR:                               --prefix --bindir ....
-                                                               (line  9)
+                                                              (line   6)
+* dependencies, with several output files: Build in parallel. (line   6)
+* DESTDIR:                               '--prefix' '--bindir' ....
+                                                              (line   9)
 * directories, for installation:         Installation directories.
-                                                               (line  6)
+                                                              (line   6)
 * directories, top-level:                Top-level directories.
-                                                               (line  6)
-* discards qualifiers warning:           Const.                (line 30)
-* dist and distcheck targets for make:   Build distribution.   (line  6)
-* distribution tarball, making:          Build distribution.   (line  6)
-* distro, building for:                  Distro builds.        (line  6)
-* dvipdfm-x:                             Configure options for texk/dvipdfm-x.
-                                                               (line  6)
-* dvipdfmx:                              Configure options for texk/dvipdfm-x.
-                                                               (line  6)
-* dvisvgm:                               Configure options for texk/dvisvgm.
-                                                               (line  6)
+                                                              (line   6)
+* discards qualifiers warning:           Const.               (line  30)
+* 'dist' and 'distcheck' targets for 'make': Build distribution.
+                                                              (line   6)
+* distribution tarball, making:          Build distribution.  (line   6)
+* distro, building for:                  Distro builds.       (line   6)
+* dvipdfm-x:                             Configure options for 'texk/dvipdfm-x'.
+                                                              (line   6)
+* dvipdfmx:                              Configure options for 'texk/dvipdfm-x'.
+                                                              (line   6)
+* dvisvgm:                               Configure options for 'texk/dvisvgm'.
+                                                              (line   6)
 * engine, adding new:                    Adding a new program module.
-                                                               (line 99)
-* engine, building one:                  Build one engine.     (line  6)
-* environment variables, for configure:  Configure options.    (line 16)
-* exec_prefix:                           --enable-multiplatform.
-                                                               (line  6)
-* extending TeX Live:                    Extending TeX Live.   (line  6)
-* extern functions:                      Declarations and definitions.
-                                                               (line 41)
-* failure to build:                      Build problems.       (line  6)
+                                                              (line 104)
+* engine, building one:                  Build one engine.    (line   6)
+* environment variables, for 'configure': Configure options.  (line  16)
+* exec_prefix:                           '--enable-multiplatform'.
+                                                              (line   6)
+* extending TeX Live:                    Extending TeX Live.  (line   6)
+* 'extern' functions:                    Declarations and definitions.
+                                                              (line  41)
+* failure to build:                      Build problems.      (line   6)
 * flags, macros for library and header:  Macros for library and header flags.
-                                                               (line  6)
-* fontconfig library, required by xetex: Prerequisites.        (line 31)
-* FreeType:                              Prerequisites.        (line 11)
-* freetype cross compiling:              Cross problems.       (line 13)
-* freetype library:                      freetype library.     (line  6)
-* freetype-config:                       freetype library.     (line 13)
+                                                              (line   6)
+* 'fontconfig' library, required by 'xetex': Prerequisites.   (line  31)
+* FreeType:                              Prerequisites.       (line  11)
+* 'freetype' cross compiling:            Cross problems.      (line  13)
+* freetype library:                      'freetype' library.  (line   6)
+* freetype-config:                       'freetype' library.  (line  13)
 * freetype-config <1>:                   Variables for configure.
-                                                               (line 24)
+                                                              (line  24)
 * FT2_CONFIG:                            Variables for configure.
-                                                               (line 21)
-* gcc, default compilers:                Build one package.    (line 78)
-* general setup macros:                  General setup macros. (line  6)
+                                                              (line  21)
+* gcc, default compilers:                Build one package.   (line  78)
+* general setup macros:                  General setup macros.
+                                                              (line   6)
 * generic library module, adding:        Adding a new generic library module.
-                                                               (line  6)
-* Ghostscript location for Xdvik:        Configure options for texk/xdvik.
-                                                               (line  6)
+                                                              (line   6)
+* Ghostscript location for Xdvik:        Configure options for 'texk/xdvik'.
+                                                              (line   6)
 * git-svn:                               Transfer from Subversion to Github.
-                                                               (line  6)
-* global configure options:              Global configure options.
-                                                               (line  6)
-* gmake, required:                       Prerequisites.        (line 11)
-* GNU make, required:                    Prerequisites.        (line 11)
-* GNU tools, needed for building:        Build system tools.   (line  6)
-* GNU/Linux distro:                      Distro builds.        (line  6)
+                                                              (line   6)
+* global 'configure' options:            Global configure options.
+                                                              (line   6)
+* 'gmake', required:                     Prerequisites.       (line  11)
+* GNU 'make', required:                  Prerequisites.       (line  11)
+* GNU tools, needed for building:        Build system tools.  (line   6)
+* GNU/Linux distro:                      Distro builds.       (line   6)
 * Gnulib, used for common files:         Top-level directories.
-                                                               (line 30)
-* ICU cross compiling:                   Cross problems.       (line 20)
+                                                              (line  30)
+* ICU cross compiling:                   Cross problems.      (line  20)
 * ICU libraries:                         Variables for configure.
-                                                               (line 24)
+                                                              (line  24)
 * icu-config:                            Variables for configure.
-                                                               (line 24)
+                                                              (line  24)
 * ICU_CONFIG:                            Variables for configure.
-                                                               (line 22)
-* infrastructure, tools needed for:      Build system tools.   (line  6)
-* inst/ top-level directory:             Top-level directories.
-                                                               (line 39)
-* install-tl, TeX Live installer:        Installing.           (line  8)
+                                                              (line  22)
+* infrastructure, tools needed for:      Build system tools.  (line   6)
+* 'inst/' top-level directory:           Top-level directories.
+                                                              (line  39)
+* install-tl, TeX Live installer:        Installing.          (line   8)
 * installation directories:              Installation directories.
-                                                               (line  6)
-* installing:                            Installing.           (line  6)
-* interprocess communication:            Configure options for texk/web2c.
-                                                               (line 31)
-* introduction:                          Introduction.         (line  6)
-* iteration through sources, by configure and make: Build iteration.
-                                                               (line  6)
-* kpathsea library:                      kpathsea library.     (line  6)
-* kpathsea.ac:                           kpathsea library.     (line 18)
-* kpse-libpng-flags.m4:                  png library.          (line 46)
+                                                              (line   6)
+* installing:                            Installing.          (line   6)
+* interprocess communication:            Configure options for 'texk/web2c'.
+                                                              (line  31)
+* introduction:                          Introduction.        (line   6)
+* iteration through sources, by 'configure' and 'make': Build iteration.
+                                                              (line   6)
+* kpathsea library:                      'kpathsea' library.  (line   6)
+* kpathsea.ac:                           'kpathsea' library.  (line  18)
+* kpse-libpng-flags.m4:                  'png' library.       (line  46)
 * kpse-pkgs.m4:                          Overview of build system.
-                                                               (line 30)
-* kpse-zlib-flags.m4:                    zlib library.         (line  6)
+                                                              (line  30)
+* kpse-zlib-flags.m4:                    'zlib' library.      (line   6)
 * kpsewhich:                             Variables for configure.
-                                                               (line 30)
+                                                              (line  30)
 * KPSEWHICH:                             Variables for configure.
-                                                               (line 29)
+                                                              (line  29)
 * KPSE_ADD_FLAGS:                        Macros for library and header flags.
-                                                               (line 20)
+                                                              (line  20)
 * KPSE_ALL_SYSTEM_FLAGS:                 Adding a new generic library module.
-                                                               (line 34)
-* KPSE_BASIC:                            General setup macros. (line  8)
-* KPSE_CHECK_LATEX:                      Macros for programs.  (line  8)
-* KPSE_CHECK_PDFLATEX:                   Macros for programs.  (line 15)
-* KPSE_CHECK_PERL:                       Macros for programs.  (line 18)
-* KPSE_CHECK_WIN32:                      Macros for Windows.   (line  9)
-* KPSE_COMMON:                           General setup macros. (line 16)
-* KPSE_COMPILER_VISIBILITY:              Macros for compilers. (line 18)
-* KPSE_COMPILER_WARNINGS:                Macros for compilers. (line  8)
-* KPSE_COND_MINGW32:                     Macros for Windows.   (line 19)
-* KPSE_COND_WIN32:                       Macros for Windows.   (line 15)
-* KPSE_COND_WIN32_WRAP:                  Macros for Windows.   (line 24)
-* kpse_cv_cxx_hack:                      Macros for compilers. (line 33)
-* kpse_cv_have_win32:                    Macros for Windows.   (line 10)
-* kpse_cv_visibility_c[xx]flags:         Macros for compilers. (line 25)
-* kpse_cv_warning_cflags:                Macros for compilers. (line 15)
-* KPSE_CXX_HACK:                         Macros for compilers. (line 28)
+                                                              (line  34)
+* KPSE_BASIC:                            General setup macros.
+                                                              (line   8)
+* KPSE_CHECK_LATEX:                      Macros for programs. (line   8)
+* KPSE_CHECK_PDFLATEX:                   Macros for programs. (line  15)
+* KPSE_CHECK_PERL:                       Macros for programs. (line  18)
+* KPSE_CHECK_WIN32:                      Macros for Windows.  (line   9)
+* KPSE_COMMON:                           General setup macros.
+                                                              (line  16)
+* KPSE_COMPILER_VISIBILITY:              Macros for compilers.
+                                                              (line  18)
+* KPSE_COMPILER_WARNINGS:                Macros for compilers.
+                                                              (line   8)
+* KPSE_COND_MINGW32:                     Macros for Windows.  (line  19)
+* KPSE_COND_WIN32:                       Macros for Windows.  (line  15)
+* KPSE_COND_WIN32_WRAP:                  Macros for Windows.  (line  24)
+* kpse_cv_cxx_hack:                      Macros for compilers.
+                                                              (line  33)
+* kpse_cv_have_win32:                    Macros for Windows.  (line  10)
+* kpse_cv_visibility_c[xx]flags:         Macros for compilers.
+                                                              (line  25)
+* kpse_cv_warning_cflags:                Macros for compilers.
+                                                              (line  15)
+* KPSE_CXX_HACK:                         Macros for compilers.
+                                                              (line  28)
 * KPSE_ENABLE_PROG:                      Adding a new program module.
-                                                               (line 14)
-* KPSE_LARGEFILE:                        Macros for libraries. (line  8)
+                                                              (line  14)
+* KPSE_LARGEFILE:                        Macros for libraries.
+                                                              (line   8)
 * KPSE_LIBPNG_FLAGS:                     Macros for library and header flags.
-                                                               (line 10)
-* KPSE_LIBPNG_FLAGS <1>:                 png library.          (line 46)
+                                                              (line  10)
+* KPSE_LIBPNG_FLAGS <1>:                 'png' library.       (line  46)
 * kpse_libs_pkgs:                        Adding a new generic library module.
-                                                               (line  6)
+                                                              (line   6)
 * KPSE_LIB_FLAGS:                        Macros for library and header flags.
-                                                               (line  6)
+                                                              (line   6)
 * KPSE_LIB_FLAGS <1>:                    Adding a new generic library module.
-                                                               (line 26)
+                                                              (line  26)
 * KPSE_LIB_SYSTEM_FLAGS:                 Adding a new generic library module.
-                                                               (line 34)
-* KPSE_PROG_LEX:                         Macros for programs.  (line 21)
+                                                              (line  34)
+* KPSE_PROG_LEX:                         Macros for programs. (line  21)
 * KPSE_RESTORE_FLAGS:                    Macros for library and header flags.
-                                                               (line 24)
+                                                              (line  24)
 * kpse_texk_pkgs:                        Adding a new program module.
-                                                               (line  6)
+                                                              (line   6)
 * kpse_texlibs_pkgs:                     Adding a new TeX-specific library module.
-                                                               (line 11)
-* KPSE_TRY_LIB:                          png library.          (line 18)
+                                                              (line  11)
+* KPSE_TRY_LIB:                          'png' library.       (line  18)
 * KPSE_TRY_LIB <1>:                      Adding a new generic library module.
-                                                               (line 20)
-* KPSE_TRY_LIBXX:                        png library.          (line 31)
+                                                              (line  20)
+* KPSE_TRY_LIBXX:                        'png' library.       (line  31)
 * KPSE_TRY_LIBXX <1>:                    Adding a new generic library module.
-                                                               (line 20)
+                                                              (line  20)
 * kpse_utils_pkgs:                       Adding a new program module.
-                                                               (line 10)
-* KPSE_WIN32_CALL:                       Macros for Windows.   (line 31)
+                                                              (line  10)
+* KPSE_WIN32_CALL:                       Macros for Windows.  (line  31)
 * KPSE_WITH_LIB:                         Adding a new generic library module.
-                                                               (line 11)
+                                                              (line  11)
 * KPSE_WITH_TEXLIB:                      Adding a new TeX-specific library module.
-                                                               (line 14)
-* large file support:                    --disable-largefile.  (line  6)
+                                                              (line  14)
+* large file support:                    '--disable-largefile'.
+                                                              (line   6)
 * LATEX:                                 Variables for configure.
-                                                               (line 40)
+                                                              (line  40)
 * layout of sources:                     Layout and infrastructure.
-                                                               (line  6)
-* LFS (large file support):              --disable-largefile.  (line  6)
-* libexpat, dependency of libfontconfig: Configure options for texk/web2c.
-                                                               (line 50)
-* libfontconfig, hack for avoiding linking dependencies: Configure options for texk/web2c.
-                                                               (line 50)
+                                                              (line   6)
+* LFS (large file support):              '--disable-largefile'.
+                                                              (line   6)
+* libexpat, dependency of 'libfontconfig': Configure options for 'texk/web2c'.
+                                                              (line  50)
+* libfontconfig, hack for avoiding linking dependencies: Configure options for 'texk/web2c'.
+                                                              (line  50)
 * libfreetype:                           Variables for configure.
-                                                               (line 24)
-* libfreetype, and const:                Const.                (line 21)
-* libpng library:                        png library.          (line  6)
+                                                              (line  24)
+* 'libfreetype', and 'const':            Const.               (line  21)
+* libpng library:                        'png' library.       (line   6)
 * library module, generic, adding:       Adding a new generic library module.
-                                                               (line  6)
+                                                              (line   6)
 * library module, TeX-specific, adding:  Adding a new TeX-specific library module.
-                                                               (line  6)
-* library modules:                       Library modules.      (line  6)
-* library-specific configure options:    Library-specific configure options.
-                                                               (line  6)
-* libsigsegv, required by xindy:         Prerequisites.        (line 35)
-* libstc++, statically linking:          Macros for compilers. (line 29)
+                                                              (line   6)
+* library modules:                       Library modules.     (line   6)
+* library-specific 'configure' options:  Library-specific configure options.
+                                                              (line   6)
+* 'libsigsegv', required by 'xindy':     Prerequisites.       (line  35)
+* libstc++, statically linking:          Macros for compilers.
+                                                              (line  29)
 * Libtool:                               Overview of build system.
-                                                               (line  6)
-* libtool, hack for avoiding excessive linking: Configure options for texk/web2c.
-                                                               (line 50)
-* libXt:                                 Configure options for texk/web2c.
-                                                               (line 22)
-* linked scripts:                        Linked scripts.       (line  6)
-* linking C++ libraries statically:      Macros for compilers. (line 29)
-* lisp.run, lisp.exe:                    Configure options for utils/xindy.
-                                                               (line 14)
-* LittleEndian architectures:            Configure options for texk/web2c.
-                                                               (line 27)
-* m4/ top-level directory:               Top-level directories.
-                                                               (line 14)
-* macros, for compilers:                 Macros for compilers. (line  6)
-* macros, for libraries:                 Macros for libraries. (line  6)
+                                                              (line   6)
+* libtool, hack for avoiding excessive linking: Configure options for 'texk/web2c'.
+                                                              (line  50)
+* libXt:                                 Configure options for 'texk/web2c'.
+                                                              (line  22)
+* linked scripts:                        Linked scripts.      (line   6)
+* linking C++ libraries statically:      Macros for compilers.
+                                                              (line  29)
+* lisp.run, lisp.exe:                    Configure options for 'utils/xindy'.
+                                                              (line  14)
+* LittleEndian architectures:            Configure options for 'texk/web2c'.
+                                                              (line  27)
+* 'm4/' top-level directory:             Top-level directories.
+                                                              (line  14)
+* macros, for compilers:                 Macros for compilers.
+                                                              (line   6)
+* macros, for libraries:                 Macros for libraries.
+                                                              (line   6)
 * macros, for library and header flags:  Macros for library and header flags.
-                                                               (line  6)
-* macros, for programs:                  Macros for programs.  (line  6)
-* macros, for Windows:                   Macros for Windows.   (line  6)
-* macros, general setup:                 General setup macros. (line  6)
+                                                              (line   6)
+* macros, for programs:                  Macros for programs. (line   6)
+* macros, for Windows:                   Macros for Windows.  (line   6)
+* macros, general setup:                 General setup macros.
+                                                              (line   6)
 * MAKE:                                  Variables for configure.
-                                                               (line 33)
-* make -t:                               Build system tools.   (line 43)
-* make rules, verbose vs. silent:        --enable-silent-rules.
-                                                               (line  6)
+                                                              (line  33)
+* make -t:                               Build system tools.  (line  43)
+* 'make' rules, verbose vs. silent:      '--enable-silent-rules'.
+                                                              (line   6)
 * Makefile.am:                           Adding a new program module.
-                                                               (line 46)
-* mf-nowin:                              Configure options for texk/web2c.
-                                                               (line 34)
-* mingw32:                               Cross configuring.    (line 27)
-* MINGW32, Automake conditional:         Macros for Windows.   (line 20)
-* mktex.ac:                              kpathsea library.     (line 18)
-* mktextfm:                              kpathsea library.     (line 18)
-* modules, for libraries:                Library modules.      (line  6)
-* modules, for programs:                 Program modules.      (line  6)
-* motif:                                 Configure options for texk/xdvik.
-                                                               (line  9)
-* native cross compilation:              Cross compilation.    (line 10)
+                                                              (line  46)
+* mf-nowin:                              Configure options for 'texk/web2c'.
+                                                              (line  34)
+* 'mingw32':                             Cross configuring.   (line  27)
+* MINGW32, Automake conditional:         Macros for Windows.  (line  20)
+* mktex.ac:                              'kpathsea' library.  (line  18)
+* mktextfm:                              'kpathsea' library.  (line  18)
+* modules, for libraries:                Library modules.     (line   6)
+* modules, for programs:                 Program modules.     (line   6)
+* motif:                                 Configure options for 'texk/xdvik'.
+                                                              (line   9)
+* native cross compilation:              Cross compilation.   (line  10)
 * NEWPROG-SRC, original source subdirectory: Adding a new program module.
-                                                               (line 33)
-* OBJCXX=OBJC-COMPILER:                  Build one package.    (line 78)
-* one engine, building:                  Build one engine.     (line  6)
-* one package, building:                 Build one package.    (line  6)
-* OpenGL, required for Asymptote:        asymptote.            (line  6)
-* operating system distribution, building for: Distro builds.  (line  6)
-* otangle:                               Cross problems.       (line 26)
-* overall build process:                 Building.             (line  6)
-* parallel build:                        Build in parallel.    (line  6)
+                                                              (line  33)
+* OBJCXX=OBJC-COMPILER:                  Build one package.   (line  78)
+* one engine, building:                  Build one engine.    (line   6)
+* one package, building:                 Build one package.   (line   6)
+* OpenGL, required for Asymptote:        'asymptote'.         (line   6)
+* operating system distribution, building for: Distro builds. (line   6)
+* otangle:                               Cross problems.      (line  26)
+* overall build process:                 Building.            (line   6)
+* parallel build:                        Build in parallel.   (line   6)
 * paths, for installation:               Installation directories.
-                                                               (line  6)
-* PDF files, size of:                    --disable-largefile.  (line 11)
+                                                              (line   6)
+* PDF files, size of:                    '--disable-largefile'.
+                                                              (line  11)
 * PDFLATEX:                              Variables for configure.
-                                                               (line 41)
+                                                              (line  41)
 * PERL:                                  Variables for configure.
-                                                               (line 39)
-* perl, required by web2c, etc.:         Prerequisites.        (line 23)
+                                                              (line  39)
+* 'perl', required by 'web2c', etc.:     Prerequisites.       (line  23)
 * PKG_CONFIG:                            Variables for configure.
-                                                               (line 23)
-* plain.tex, not in source tree:         Installing.           (line  8)
-* png library:                           png library.          (line  6)
-* PostScript files, size of:             --disable-largefile.  (line 11)
-* Preining, Norbert:                     Distro builds.        (line 54)
-* preloaded binaries:                    Configure options for texk/web2c.
-                                                               (line 45)
-* prerequisites for building:            Prerequisites.        (line  6)
-* problems with build:                   Build problems.       (line  6)
+                                                              (line  23)
+* plain.tex, not in source tree:         Installing.          (line   8)
+* png library:                           'png' library.       (line   6)
+* PostScript files, size of:             '--disable-largefile'.
+                                                              (line  11)
+* Preining, Norbert:                     Distro builds.       (line  54)
+* preloaded binaries:                    Configure options for 'texk/web2c'.
+                                                              (line  45)
+* prerequisites for building:            Prerequisites.       (line   6)
+* problems with build:                   Build problems.      (line   6)
 * program module, adding:                Adding a new program module.
-                                                               (line  6)
-* program modules:                       Program modules.      (line  6)
-* program-specific configure options:    Program-specific configure options.
-                                                               (line  6)
-* proxy build system:                    png library.          (line 36)
-* reautoconf:                            Build system tools.   (line 28)
+                                                              (line   6)
+* program modules:                       Program modules.     (line   6)
+* program-specific 'configure' options:  Program-specific configure options.
+                                                              (line   6)
+* proxy build system:                    'png' library.       (line  36)
+* reautoconf:                            Build system tools.  (line  28)
 * reautoconf, for new program:           Adding a new program module.
-                                                               (line 84)
-* requirements for building:             Prerequisites.        (line  6)
-* runscript.exe:                         Macros for Windows.   (line 25)
-* scripts, linked and not maintained:    Linked scripts.       (line  6)
-* scrolling, smooth:                     Configure options for texk/xdvik.
-                                                               (line 13)
+                                                              (line  89)
+* requirements for building:             Prerequisites.       (line   6)
+* runscript.exe:                         Macros for Windows.  (line  25)
+* scripts, linked and not maintained:    Linked scripts.      (line   6)
+* scrolling, smooth:                     Configure options for 'texk/xdvik'.
+                                                              (line  13)
 * SED:                                   Variables for configure.
-                                                               (line 34)
-* setup macros, general:                 General setup macros. (line  6)
-* shared libraries, using vs. avoiding:  Distro builds.        (line 11)
-* size of PDF and PS files:              --disable-largefile.  (line 11)
-* size of source tree:                   Build one package.    (line 53)
+                                                              (line  34)
+* setup macros, general:                 General setup macros.
+                                                              (line   6)
+* shared libraries, using vs. avoiding:  Distro builds.       (line  11)
+* size of PDF and PS files:              '--disable-largefile'.
+                                                              (line  11)
+* size of source tree:                   Build one package.   (line  53)
 * source code declarations:              Declarations and definitions.
-                                                               (line  6)
-* source directory building, not supported: Building.          (line 17)
+                                                              (line   6)
+* source directory building, not supported: Building.         (line  17)
 * source tree:                           Layout and infrastructure.
-                                                               (line  6)
-* squeeze:                               Cross problems.       (line 13)
-* squeeze/configure.ac:                  xdvik package.        (line 14)
-* static functions:                      Declarations and definitions.
-                                                               (line 35)
-* static linking for C++:                Macros for compilers. (line 29)
+                                                              (line   6)
+* squeeze:                               Cross problems.      (line  13)
+* squeeze/configure.ac:                  'xdvik' package.     (line  14)
+* 'static' functions:                    Declarations and definitions.
+                                                              (line  35)
+* static linking for C++:                Macros for compilers.
+                                                              (line  29)
 * stpcpy:                                Declarations and definitions.
-                                                               (line 18)
-* Subversion repository:                 Build system tools.   (line 38)
-* support files, separate from build:    Installing.           (line  8)
-* symlinks, used for scripts:            Linked scripts.       (line  6)
-* synctex:                               Configure options for texk/web2c.
-                                                               (line 59)
-* synctex <1>:                           Configure options for texk/web2c.
-                                                               (line 64)
-* system distribution, building for:     Distro builds.        (line  6)
-* t1utils package:                       t1utils package.      (line  6)
-* tangle:                                Cross problems.       (line 26)
+                                                              (line  18)
+* Subversion repository:                 Build system tools.  (line  38)
+* support files, separate from build:    Installing.          (line   8)
+* symlinks, used for scripts:            Linked scripts.      (line   6)
+* synctex:                               Configure options for 'texk/web2c'.
+                                                              (line  59)
+* synctex <1>:                           Configure options for 'texk/web2c'.
+                                                              (line  64)
+* system distribution, building for:     Distro builds.       (line   6)
+* t1utils package:                       't1utils' package.   (line   6)
+* tangle:                                Cross problems.      (line  26)
 * tests, running:                        Overview of build system.
-                                                               (line  6)
+                                                              (line   6)
 * TeX-specific library module, adding:   Adding a new TeX-specific library module.
-                                                               (line  6)
-* texlive.tlpdb, TeX Live database:      Installing.           (line  8)
-* tie:                                   Cross problems.       (line 26)
-* timestamps, in repository:             Build system tools.   (line 38)
+                                                              (line   6)
+* texlive.tlpdb, TeX Live database:      Installing.          (line   8)
+* tie:                                   Cross problems.      (line  26)
+* timestamps, in repository:             Build system tools.  (line  38)
 * TLpatches/patch-...:                   Adding a new program module.
-                                                               (line 68)
+                                                              (line  68)
 * TLpatches/TL-Changes:                  Adding a new program module.
-                                                               (line 64)
-* tools, for building:                   Build system tools.   (line  6)
+                                                              (line  64)
+* tools, for building:                   Build system tools.  (line   6)
 * top-level directories:                 Top-level directories.
-                                                               (line  6)
-* touching files to avoid rerunning:     Build system tools.   (line 43)
+                                                              (line   6)
+* touching files to avoid rerunning:     Build system tools.  (line  43)
 * Travis-CI:                             Continuous integration.
-                                                               (line  6)
+                                                              (line   6)
 * travis.yml:                            CI testing on Travis-CI.
-                                                               (line  6)
-* type cast from const, avoiding:        Const.                (line 38)
-* use-commit-times, Subversion:          Build system tools.   (line 38)
+                                                              (line   6)
+* type cast from const, avoiding:        Const.               (line  38)
+* use-commit-times, Subversion:          Build system tools.  (line  38)
 * variable declarations, in source code: Declarations and definitions.
-                                                               (line 52)
-* variables for configure:               Variables for configure.
-                                                               (line  6)
-* warning, discards qualifiers:          Const.                (line 30)
-* WARNING_C[XX]FLAGS:                    Macros for compilers. (line  9)
-* web2c program:                         Cross problems.       (line 13)
-* web2c.ac:                              Configure options for texk/web2c.
-                                                               (line 37)
-* wget:                                  Linked scripts.       (line 23)
-* WIN32, Automake conditional:           Macros for Windows.   (line 16)
-* WIN32_WRAP, Automake conditional:      Macros for Windows.   (line 25)
-* Windows, invoking scripts on:          Linked scripts.       (line  6)
-* Windows, macros for:                   Macros for Windows.   (line  6)
+                                                              (line  52)
+* variables for 'configure':             Variables for configure.
+                                                              (line   6)
+* warning, discards qualifiers:          Const.               (line  30)
+* WARNING_C[XX]FLAGS:                    Macros for compilers.
+                                                              (line   9)
+* web2c program:                         Cross problems.      (line  13)
+* web2c.ac:                              Configure options for 'texk/web2c'.
+                                                              (line  37)
+* wget:                                  Linked scripts.      (line  23)
+* WIN32, Automake conditional:           Macros for Windows.  (line  16)
+* WIN32_WRAP, Automake conditional:      Macros for Windows.  (line  25)
+* Windows, invoking scripts on:          Linked scripts.      (line   6)
+* Windows, macros for:                   Macros for Windows.  (line   6)
 * withenable.ac, for new modules:        Adding a new program module.
-                                                               (line 14)
-* Work/ top-level directory:             Top-level directories.
-                                                               (line 39)
-* wrapper binary for scripts on Windows: Linked scripts.       (line  6)
-* wrapper build system:                  freetype library.     (line  6)
-* X toolkit:                             Configure options for texk/web2c.
-                                                               (line 22)
-* X11 development, required by X clients: Prerequisites.       (line 27)
-* X11 headers, and const:                Const.                (line 21)
-* xasy:                                  asymptote.            (line  6)
-* xaw:                                   Configure options for texk/xdvik.
-                                                               (line  9)
-* xdvik:                                 xdvik package.        (line  6)
-* xdvik <1>:                             Configure options for texk/xdvik.
-                                                               (line  6)
-* xdvipdfmx:                             Configure options for texk/dvipdfm-x.
-                                                               (line  6)
-* xindy:                                 Linked scripts.       (line 23)
-* xindy <1>:                             xindy package.        (line  6)
-* xindy <2>:                             Configure options for utils/xindy.
-                                                               (line  6)
-* xindy cross compiling requires clisp:  Cross problems.       (line 33)
-* XInput:                                Configure options for texk/xdvik.
-                                                               (line 13)
-* Xlib:                                  Configure options for texk/web2c.
-                                                               (line 22)
-* xz:                                    Linked scripts.       (line 23)
-* zlib library:                          zlib library.         (line  6)
+                                                              (line  14)
+* 'Work/' top-level directory:           Top-level directories.
+                                                              (line  39)
+* wrapper binary for scripts on Windows: Linked scripts.      (line   6)
+* wrapper build system:                  'freetype' library.  (line   6)
+* X toolkit:                             Configure options for 'texk/web2c'.
+                                                              (line  22)
+* X11 development, required by X clients: Prerequisites.      (line  27)
+* X11 headers, and 'const':              Const.               (line  21)
+* xasy:                                  'asymptote'.         (line   6)
+* xaw:                                   Configure options for 'texk/xdvik'.
+                                                              (line   9)
+* xdvik:                                 'xdvik' package.     (line   6)
+* xdvik <1>:                             Configure options for 'texk/xdvik'.
+                                                              (line   6)
+* xdvipdfmx:                             Configure options for 'texk/dvipdfm-x'.
+                                                              (line   6)
+* xindy:                                 Linked scripts.      (line  23)
+* xindy <1>:                             'xindy' package.     (line   6)
+* xindy <2>:                             Configure options for 'utils/xindy'.
+                                                              (line   6)
+* 'xindy' cross compiling requires 'clisp': Cross problems.   (line  33)
+* XInput:                                Configure options for 'texk/xdvik'.
+                                                              (line  13)
+* Xlib:                                  Configure options for 'texk/web2c'.
+                                                              (line  22)
+* xz:                                    Linked scripts.      (line  23)
+* zlib library:                          'zlib' library.      (line   6)
 
 
 
@@ -5913,396 +5945,391 @@
 Node: Build in parallel11474
 Node: Build distribution12078
 Node: Build one package12726
-Node: Build one engine16371
-Node: Cross compilation17885
-Node: Cross configuring19165
-Node: Cross problems20842
-Node: Installing22504
-Node: Installation directories23524
-Node: Linked scripts25342
-Node: Distro builds26833
-Node: Layout and infrastructure29209
-Node: Build system tools30040
-Node: Top-level directories32257
-Node: Autoconf macros34493
-Node: General setup macros35255
-Node: Macros for programs36130
-Node: Macros for compilers36931
-Node: Macros for libraries38339
-Node: Macros for library and header flags38765
-Node: Macros for Windows40676
-Node: Library modules42263
-Node: png library42752
-Node: zlib library45100
-Node: freetype library45615
-Node: kpathsea library46311
-Node: Program modules47690
-Node: t1utils package48118
-Node: xindy package48663
-Node: xdvik package49777
-Node: asymptote50836
-Node: Extending TeX Live51332
-Node: Adding a new program module52115
-Node: Adding a new generic library module57025
-Node: Adding a new TeX-specific library module59254
-Node: Configure options59952
-Node: Global configure options61333
-Node: --disable-native-texlive-build61875
-Node: --prefix --bindir ...62837
-Node: --disable-largefile63377
-Node: --disable-missing63919
-Node: --enable-compiler-warnings=LEVEL64320
-Node: --enable-cxx-runtime-hack64976
-Node: --enable-maintainer-mode65396
-Node: --enable-multiplatform65925
-Node: --enable-shared66498
-Node: --enable-silent-rules66869
-Node: --without-ln-s67321
-Node: --without-x67668
-Node: Program-specific configure options67856
-Node: --enable-PROG --disable-PROG68499
-Node: --disable-all-pkgs68772
-Node: Configure options for texk/web2c69555
-Node: Configure options for texk/bibtex-x72093
-Node: Configure options for texk/dvipdfm-x72636
-Node: Configure options for texk/dvisvgm73412
-Node: Configure options for texk/texlive74293
-Node: Configure options for texk/xdvik74714
-Node: Configure options for utils/xindy75335
-Node: Library-specific configure options76225
-Node: Configure options for kpathsea77186
-Node: Variables for configure77890
-Node: Coding conventions79316
-Node: Declarations and definitions80031
-Node: Const82205
-Node: Continuous integration84069
-Node: Transfer from Subversion to Github84733
-Node: Automatic update of the Git mirror86895
-Node: CI testing on Travis-CI87477
-Node: Releases on Github88186
-Node: install-tl88626
-Node: install-tl NAME88995
-Node: install-tl SYNOPSIS89153
-Node: install-tl DESCRIPTION89411
-Node: install-tl REFERENCES90471
-Node: install-tl OPTIONS90995
-Ref: install-tl *-gui* [[=]_module_]91336
-Ref: install-tl text91544
-Ref: install-tl tcl91664
-Ref: install-tl wizard92006
-Ref: install-tl expert92139
-Ref: install-tl perltk92261
-Ref: install-tl *-no-gui*92807
-Ref: install-tl *-lang* _llcode_92897
-Ref: install-tl *-repository* _url|path_93653
-Ref: install-tl *-select-repository*94541
-Ref: install-tl *-all-options*94977
-Ref: install-tl *-custom-bin* _path_95232
-Ref: install-tl *-debug-translation*96066
-Ref: install-tl *-force-platform* _platform_96285
-Ref: install-tl *-help*, *--help*, *-?*96529
-Ref: install-tl *-in-place*96942
-Ref: install-tl *-init-from-profile* _profile_file_97487
-Ref: install-tl *-logfile* _file_97756
-Ref: install-tl *-no-cls*98107
-Ref: install-tl *-no-persistent-downloads*98255
-Ref: install-tl *-persistent-downloads*98280
-Ref: install-tl *-no-verify-downloads*98898
-Ref: install-tl *-non-admin*99261
-Ref: install-tl *-portable*99354
-Ref: install-tl *-print-platform*99493
-Ref: install-tl *-profile* _profile_file_99691
-Ref: install-tl *-q*99912
-Ref: install-tl *-scheme* _scheme_99974
-Ref: install-tl *-v*100448
-Ref: install-tl *-version*, *--version*100603
-Node: install-tl PROFILES100737
-Ref: install-tl instopt_adjustpath (default 0 on Unix, 1 on Windows)103603
-Ref: install-tl instopt_adjustrepo (default 1)103679
-Ref: install-tl instopt_letter (default 0)103816
-Ref: install-tl instopt_portable (default 0)103907
-Ref: install-tl instopt_write18_restricted (default 1)104003
-Node: install-tl ENVIRONMENT VARIABLES105342
-Ref: install-tl TEXLIVE_DOWNLOADER105720
-Ref: install-tl TL_DOWNLOAD_PROGRAM105743
-Ref: install-tl TL_DOWNLOAD_ARGS105763
-Ref: install-tl TEXLIVE_INSTALL_ENV_NOCHECK105967
-Ref: install-tl TEXLIVE_INSTALL_NO_CONTEXT_CACHE106169
-Ref: install-tl TEXLIVE_INSTALL_NO_IMPORT106278
-Ref: install-tl TEXLIVE_INSTALL_NO_WELCOME106430
-Ref: install-tl TEXLIVE_INSTALL_PREFIX106552
-Ref: install-tl TEXLIVE_INSTALL_TEXDIR106578
-Ref: install-tl TEXLIVE_INSTALL_TEXMFCONFIG106609
-Ref: install-tl TEXLIVE_INSTALL_TEXMFVAR106637
-Ref: install-tl TEXLIVE_INSTALL_TEXMFHOME106666
-Ref: install-tl TEXLIVE_INSTALL_TEXMFLOCAL106696
-Ref: install-tl TEXLIVE_INSTALL_TEXMFSYSCONFIG106730
-Ref: install-tl TEXLIVE_INSTALL_TEXMFSYSVAR106761
-Ref: install-tl NOPERLDOC107132
-Node: install-tl AUTHORS AND COPYRIGHT107196
-Node: tlmgr107609
-Node: tlmgr NAME108094
-Node: tlmgr SYNOPSIS108226
-Node: tlmgr DESCRIPTION108416
-Node: tlmgr EXAMPLES109515
-Ref: tlmgr tlmgr option repository ctan109766
-Ref: tlmgr tlmgr option repository http://mirror.ctan.org/systems/texlive/tlnet109838
-Ref: tlmgr tlmgr update --list110443
-Ref: tlmgr tlmgr update --all110536
-Ref: tlmgr tlmgr info _what_110693
-Node: tlmgr OPTIONS110955
-Ref: tlmgr *--repository* _url|path_111475
-Ref: tlmgr /some/local/dir112661
-Ref: tlmgr file:/some/local/dir112690
-Ref: tlmgr ctan112763
-Ref: tlmgr http://mirror.ctan.org/systems/texlive/tlnet112816
-Ref: tlmgr http://server/path/to/tlnet113157
-Ref: tlmgr https://server/path/to/tlnet113538
-Ref: tlmgr ftp://server/path/to/tlnet114006
-Ref: tlmgr user at machine:/path/to/tlnet114138
-Ref: tlmgr scp://user@machine/path/to/tlnet114179
-Ref: tlmgr ssh://user@machine/path/to/tlnet114220
-Ref: tlmgr *--gui* [_action_]114613
-Ref: tlmgr *--gui-lang* _llcode_115426
-Ref: tlmgr *--debug-translation*116162
-Ref: tlmgr *--machine-readable*116365
-Ref: tlmgr *--no-execute-actions*116633
-Ref: tlmgr *--package-logfile* _file_116826
-Ref: tlmgr *--pause*117080
-Ref: tlmgr *--persistent-downloads*117235
-Ref: tlmgr *--no-persistent-downloads*117263
-Ref: tlmgr *--pin-file*117757
-Ref: tlmgr *--usermode*117975
-Ref: tlmgr *--usertree* _dir_118095
-Ref: tlmgr *--verify-repo=[none|main|all]*118221
-Node: tlmgr ACTIONS119120
-Node: tlmgr help119981
-Node: tlmgr version120458
-Node: tlmgr backup120721
-Ref: tlmgr *backup [_option_...] --all*120892
-Ref: tlmgr *backup [_option_...] _pkg_...*120925
-Ref: tlmgr *--backupdir* _directory_121991
-Ref: tlmgr *--all*122208
-Ref: tlmgr *--clean*[=_N_]122460
-Ref: tlmgr *--dry-run*122787
-Node: tlmgr candidates _pkg_122917
-Node: tlmgr check [_option_...] [depends|executes|files|runfiles|texmfdbs|all]123272
-Ref: tlmgr *depends*123786
-Ref: tlmgr *executes*124128
-Ref: tlmgr *files*124243
-Ref: tlmgr *runfiles*124379
-Ref: tlmgr *texmfdbs*124516
-Ref: tlmgr - all items in TEXMFDBS have the !! prefix.124746
-Ref: tlmgr - all items in TEXMFBDS have an ls-R file (if they exist at all).124822
-Ref: tlmgr - all items in TEXMF with !! are listed in TEXMFDBS.124887
-Ref: tlmgr - all items in TEXMF with an ls-R file are listed in TEXMFDBS.124962
-Ref: tlmgr *--use-svn*124987
-Node: tlmgr conf125128
-Ref: tlmgr *conf [texmf|tlmgr|updmap [--conffile _file_] [--delete] [_key_ [_value_]]]*125416
-Ref: tlmgr *conf auxtrees [--conffile _file_] [show|add|remove] [_value_]*125480
-Node: tlmgr dump-tlpdb [_option_...] [--json]127895
-Ref: tlmgr *--local*128328
-Ref: tlmgr *--remote*128367
-Ref: tlmgr *--json*128405
-Node: tlmgr generate128976
-Ref: tlmgr *generate [_option_...] language*129172
-Ref: tlmgr *generate [_option_...] language.dat*129211
-Ref: tlmgr *generate [_option_...] language.def*129250
-Ref: tlmgr *generate [_option_...] language.dat.lua*129293
-Ref: tlmgr *--dest* _output_file_131620
-Ref: tlmgr *--localcfg* _local_conf_file_132196
-Ref: tlmgr *--rebuild-sys*132319
-Node: tlmgr gui133134
-Node: tlmgr info133312
-Ref: tlmgr *info [_option_...] _pkg_...*133474
-Ref: tlmgr *info [_option_...] collections*133508
-Ref: tlmgr *info [_option_...] schemes*133538
-Ref: tlmgr *--list*135068
-Ref: tlmgr *--only-installed*135382
-Ref: tlmgr *--only-remote*135570
-Ref: tlmgr *--data item1,item2,...*135874
-Ref: tlmgr *--json* 1136455
-Node: tlmgr init-usertree136838
-Node: tlmgr install [_option_...] _pkg_...137219
-Ref: tlmgr *--dry-run* 1137727
-Ref: tlmgr *--file*137844
-Ref: tlmgr *--force*138066
-Ref: tlmgr *--no-depends*138286
-Ref: tlmgr *--no-depends-at-all*138445
-Ref: tlmgr *--reinstall*138845
-Ref: tlmgr *--with-doc*139223
-Ref: tlmgr *--with-src*139236
-Node: tlmgr key139964
-Ref: tlmgr *key list*140122
-Ref: tlmgr *key add _file_*140140
-Ref: tlmgr *key remove _keyid_*140162
-Node: tlmgr list140756
-Node: tlmgr option140918
-Ref: tlmgr *option [--json] [show]*141073
-Ref: tlmgr *option [--json] showall|help*141104
-Ref: tlmgr *option _key_ [_value_]*141130
-Node: tlmgr paper145708
-Ref: tlmgr *paper [a4|letter]*145857
-Ref: tlmgr *<[xdvi|pdftex|dvips|dvipdfmx|context|psutils] paper [_papersize_|--list]*>145933
-Ref: tlmgr *paper --json*145948
-Node: tlmgr path147163
-Ref: tlmgr *path [--w32mode=user|admin] add*147324
-Ref: tlmgr *path [--w32mode=user|admin] remove*147361
-Node: tlmgr pinning148846
-Ref: tlmgr pinning show149087
-Ref: tlmgr pinning add _repo_ _pkgglob_...149160
-Ref: tlmgr pinning remove _repo_ _pkgglob_...149279
-Ref: tlmgr pinning remove _repo_ --all149432
-Node: tlmgr platform149486
-Ref: tlmgr *platform list|add|remove _platform_...*149672
-Ref: tlmgr *platform set _platform_*149699
-Ref: tlmgr *platform set auto*149720
-Ref: tlmgr *--dry-run* 2150597
-Node: tlmgr postaction150716
-Ref: tlmgr *postaction [_option_...] install [shortcut|fileassoc|script] [_pkg_...]*150946
-Ref: tlmgr *postaction [_option_...] remove [shortcut|fileassoc|script] [_pkg_...]*151020
-Ref: tlmgr *--w32mode=[user|admin]*151335
-Ref: tlmgr *--fileassocmode=[1|2]*151751
-Ref: tlmgr *--all* 1152036
-Node: tlmgr print-platform152091
-Node: tlmgr print-platform-info152422
-Node: tlmgr remove [_option_...] _pkg_...152722
-Ref: tlmgr *--all* 2153206
-Ref: tlmgr *--backup*153316
-Ref: tlmgr *--backupdir* _directory_ 1153342
-Ref: tlmgr *--no-depends* 1153747
-Ref: tlmgr *--no-depends-at-all* 1153809
-Ref: tlmgr *--force* 1153912
-Ref: tlmgr *--dry-run* 3154385
-Node: tlmgr repository154721
-Ref: tlmgr *repository list*154909
-Ref: tlmgr *repository list _path|url|tag_*154943
-Ref: tlmgr *repository add _path_ [_tag_]*154976
-Ref: tlmgr *repository remove _path|tag_*155008
-Ref: tlmgr *repository set _path_[#_tag_] [_path_[#_tag_] ...]*155062
-Ref: tlmgr *repository status*155083
-Ref: tlmgr The tag (which can be the same as the url);156310
-Node: tlmgr restore156788
-Ref: tlmgr *restore [_option_...] _pkg_ [_rev_]*156967
-Ref: tlmgr *restore [_option_...] --all*156997
-Ref: tlmgr *--all* 3157697
-Ref: tlmgr *--backupdir* _directory_ 2157911
-Ref: tlmgr *--dry-run* 4158092
-Ref: tlmgr *--force* 2158224
-Ref: tlmgr *--json* 2158270
-Node: tlmgr search158597
-Ref: tlmgr *search [_option_...] _what_*158761
-Ref: tlmgr *search [_option_...] --file _what_*158798
-Ref: tlmgr *search [_option_...] --all _what_*158834
-Ref: tlmgr *--file* 1159054
-Ref: tlmgr *--all* 4159116
-Ref: tlmgr *--global*159205
-Ref: tlmgr *--word*159332
-Node: tlmgr shell159647
-Ref: tlmgr protocol160382
-Ref: tlmgr help 1160446
-Ref: tlmgr version 1160499
-Ref: tlmgr quit, end, bye, byebye, EOF160567
-Ref: tlmgr restart160588
-Ref: tlmgr load [local|remote]160711
-Ref: tlmgr save160781
-Ref: tlmgr get [_var_] =item set [_var_ [_val_]]160904
-Node: tlmgr show161505
-Node: tlmgr uninstall161672
-Node: tlmgr update [_option_...] [_pkg_...]161902
-Ref: tlmgr *--all* 5162273
-Ref: tlmgr *--self*164452
-Ref: tlmgr *--dry-run* 5165216
-Ref: tlmgr *--list* [_pkg_]165393
-Ref: tlmgr *--exclude* _pkg_166082
-Ref: tlmgr *--no-auto-remove* [_pkg_...]166882
-Ref: tlmgr *--no-auto-install* [_pkg_...]167366
-Ref: tlmgr *--reinstall-forcibly-removed*168128
-Ref: tlmgr *--backup* 1168663
-Ref: tlmgr *--backupdir* _directory_ 3168689
-Ref: tlmgr *--no-depends* 2169855
-Ref: tlmgr *--no-depends-at-all* 2170058
-Ref: tlmgr *--force* 3170161
-Node: tlmgr CONFIGURATION FILE FOR TLMGR171181
-Ref: tlmgr auto-remove, value 0 or 1 (default 1), same as command-line option.172188
-Ref: tlmgr gui-expertmode, value 0 or 1 (default 1). This switches between the full GUI and a simplified GUI with only the most common settings.172325
-Ref: tlmgr gui-lang _llcode_, with a language code value as with the command-line option.172407
-Ref: tlmgr no-checksums, value 0 or 1 (default 0, see below).172461
-Ref: tlmgr persistent-downloads, value 0 or 1 (default 1), same as command-line option.172541
-Ref: tlmgr require-verification, value 0 or 1 (default 0), same as command-line option.172621
-Ref: tlmgr update-exclude, value: comma-separated list of packages (no space allowed). Same as the command line option --exclude for the action update.172769
-Ref: tlmgr verify-downloads, value 0 or 1 (default 1), same as command-line option.172845
-Ref: tlmgr allowed-actions _action1_ [,_action_,...] The value is a comma-separated list of tlmgr actions which are allowed to be executed when tlmgr is invoked in system mode (that is, without --usermode).173114
-Node: tlmgr CRYPTOGRAPHIC VERIFICATION174202
-Node: tlmgr Configuration of GnuPG invocation176375
-Node: tlmgr USER MODE177013
-Node: tlmgr User mode install179859
-Node: tlmgr User mode backup, restore, remove, update181003
-Node: tlmgr User mode generate, option, paper181445
-Node: tlmgr MULTIPLE REPOSITORIES181821
-Node: tlmgr Pinning183550
-Node: tlmgr GUI FOR TLMGR185473
-Node: tlmgr Main display187122
-Node: tlmgr Display configuration area187374
-Ref: tlmgr Status187735
-Ref: tlmgr Category187899
-Ref: tlmgr Match188085
-Ref: tlmgr Selection188266
-Ref: tlmgr Display configuration buttons188470
-Node: tlmgr Package list area188653
-Ref: tlmgr a checkbox189237
-Ref: tlmgr package name189373
-Ref: tlmgr local revision (and version)189472
-Ref: tlmgr remote revision (and version)189847
-Ref: tlmgr short description190144
-Node: tlmgr Main display action buttons190189
-Ref: tlmgr Update all installed190455
-Ref: tlmgr Update190827
-Ref: tlmgr Install190877
-Ref: tlmgr Remove191063
-Ref: tlmgr Backup191241
-Node: tlmgr Menu bar191398
-Ref: tlmgr tlmgr menu191621
-Ref: tlmgr Options menu191929
-Ref: tlmgr Actions menu193012
-Ref: tlmgr Help menu193440
-Node: tlmgr GUI options193574
-Ref: tlmgr -background _color_193820
-Ref: tlmgr -font " _fontname_ _fontsize_ "193885
-Ref: tlmgr -foreground _color_194043
-Ref: tlmgr -geometry _geomspec_194095
-Ref: tlmgr -xrm _xresource_194287
-Node: tlmgr MACHINE-READABLE OUTPUT194556
-Node: tlmgr Machine-readable update and install output195366
-Ref: tlmgr location-url _location_196642
-Ref: tlmgr total-bytes _count_196858
-Ref: tlmgr _pkgname_197268
-Ref: tlmgr _status_197478
-Ref: tlmgr d197556
-Ref: tlmgr f197616
-Ref: tlmgr u197795
-Ref: tlmgr r197841
-Ref: tlmgr a197964
-Ref: tlmgr i198142
-Ref: tlmgr I198261
-Ref: tlmgr _localrev_198363
-Ref: tlmgr _serverrev_198470
-Ref: tlmgr _size_198582
-Ref: tlmgr _runtime_198751
-Ref: tlmgr _esttot_198821
-Node: tlmgr Machine-readable option output198854
-Node: tlmgr ENVIRONMENT VARIABLES199366
-Ref: tlmgr TEXLIVE_COMPRESSOR199877
-Ref: tlmgr TEXLIVE_DOWNLOADER200725
-Ref: tlmgr TL_DOWNLOAD_PROGRAM200748
-Ref: tlmgr TL_DOWNLOAD_ARGS200768
-Ref: tlmgr TEXLIVE_PREFER_OWN201794
-Node: tlmgr AUTHORS AND COPYRIGHT202618
-Node: Index203016
+Node: Build one engine16373
+Node: Cross compilation17887
+Node: Cross configuring19167
+Node: Cross problems20844
+Node: Installing22506
+Node: Installation directories23526
+Node: Linked scripts25344
+Node: Distro builds26835
+Node: Layout and infrastructure29211
+Node: Build system tools30042
+Node: Top-level directories32259
+Node: Autoconf macros34495
+Node: General setup macros35257
+Node: Macros for programs36132
+Node: Macros for compilers36933
+Node: Macros for libraries38341
+Node: Macros for library and header flags38767
+Node: Macros for Windows40678
+Node: Library modules42265
+Node: 'png' library42762
+Node: 'zlib' library45114
+Node: 'freetype' library45635
+Node: 'kpathsea' library46337
+Node: Program modules47720
+Node: 't1utils' package48156
+Node: 'xindy' package48705
+Node: 'xdvik' package49825
+Node: 'asymptote'50890
+Node: Extending TeX Live51390
+Node: Adding a new program module52173
+Node: Adding a new generic library module57306
+Node: Adding a new TeX-specific library module59535
+Node: Configure options60233
+Node: Global configure options61614
+Node: '--disable-native-texlive-build'62182
+Node: '--prefix' '--bindir' ...63150
+Node: '--disable-largefile'63698
+Node: '--disable-missing'64248
+Node: '--enable-compiler-warnings='LEVEL64655
+Node: '--enable-cxx-runtime-hack'65317
+Node: '--enable-maintainer-mode'65743
+Node: '--enable-multiplatform'66278
+Node: '--enable-shared'66857
+Node: '--enable-silent-rules'67234
+Node: '--without-ln-s'67692
+Node: '--without-x'68045
+Node: Program-specific configure options68237
+Node: '--enable-PROG' '--disable-PROG'68900
+Node: '--disable-all-pkgs'69179
+Node: Configure options for 'texk/web2c'69970
+Node: Configure options for 'texk/bibtex-x'72514
+Node: Configure options for 'texk/dvipdfm-x'73063
+Node: Configure options for 'texk/dvisvgm'73845
+Node: Configure options for 'texk/texlive'74732
+Node: Configure options for 'texk/xdvik'75159
+Node: Configure options for 'utils/xindy'75786
+Node: Library-specific configure options76680
+Node: Configure options for 'kpathsea'77643
+Node: Variables for configure78351
+Node: Coding conventions79777
+Node: Declarations and definitions80492
+Node: Const82666
+Node: Continuous integration84530
+Node: Transfer from Subversion to Github85194
+Node: Automatic update of the Git mirror87356
+Node: CI testing on Travis-CI87938
+Node: Releases on Github88647
+Node: install-tl89087
+Node: install-tl NAME89456
+Node: install-tl SYNOPSIS89614
+Node: install-tl DESCRIPTION89872
+Node: install-tl REFERENCES90932
+Node: install-tl OPTIONS91456
+Ref: install-tl *-gui* [[=]_module_]91797
+Ref: install-tl 'text'92005
+Ref: install-tl 'tcl'92125
+Ref: install-tl 'wizard'92467
+Ref: install-tl 'expert'92600
+Ref: install-tl 'perltk'92722
+Ref: install-tl *-no-gui*93268
+Ref: install-tl *-lang* _llcode_93358
+Ref: install-tl *-repository* _url|path_94114
+Ref: install-tl *-select-repository*95002
+Ref: install-tl *-all-options*95438
+Ref: install-tl *-custom-bin* _path_95693
+Ref: install-tl *-debug-translation*96527
+Ref: install-tl *-force-platform* _platform_96746
+Ref: install-tl *-help*, *--help*, *-?*96990
+Ref: install-tl *-in-place*97403
+Ref: install-tl *-init-from-profile* _profile_file_97948
+Ref: install-tl *-logfile* _file_98217
+Ref: install-tl *-no-cls*98568
+Ref: install-tl *-no-persistent-downloads*98716
+Ref: install-tl *-persistent-downloads*98741
+Ref: install-tl *-no-verify-downloads*99359
+Ref: install-tl *-non-admin*99722
+Ref: install-tl *-portable*99815
+Ref: install-tl *-print-platform*99954
+Ref: install-tl *-profile* _profile_file_100152
+Ref: install-tl *-q*100373
+Ref: install-tl *-scheme* _scheme_100435
+Ref: install-tl *-v*100909
+Ref: install-tl *-version*, *--version*101064
+Node: install-tl PROFILES101198
+Ref: install-tl 'instopt_adjustpath' (default 0 on Unix, 1 on Windows)104064
+Ref: install-tl 'instopt_adjustrepo' (default 1)104140
+Ref: install-tl 'instopt_letter' (default 0)104277
+Ref: install-tl 'instopt_portable' (default 0)104368
+Ref: install-tl 'instopt_write18_restricted' (default 1)104464
+Node: install-tl ENVIRONMENT VARIABLES105803
+Ref: install-tl 'TEXLIVE_DOWNLOADER'106181
+Ref: install-tl 'TL_DOWNLOAD_PROGRAM'106204
+Ref: install-tl 'TL_DOWNLOAD_ARGS'106224
+Ref: install-tl 'TEXLIVE_INSTALL_ENV_NOCHECK'106428
+Ref: install-tl 'TEXLIVE_INSTALL_NO_CONTEXT_CACHE'106630
+Ref: install-tl 'TEXLIVE_INSTALL_NO_IMPORT'106739
+Ref: install-tl 'TEXLIVE_INSTALL_NO_WELCOME'106891
+Ref: install-tl 'TEXLIVE_INSTALL_PREFIX'107013
+Ref: install-tl 'TEXLIVE_INSTALL_TEXDIR'107039
+Ref: install-tl 'TEXLIVE_INSTALL_TEXMFCONFIG'107070
+Ref: install-tl 'TEXLIVE_INSTALL_TEXMFVAR'107098
+Ref: install-tl 'TEXLIVE_INSTALL_TEXMFHOME'107127
+Ref: install-tl 'TEXLIVE_INSTALL_TEXMFLOCAL'107157
+Ref: install-tl 'TEXLIVE_INSTALL_TEXMFSYSCONFIG'107191
+Ref: install-tl 'TEXLIVE_INSTALL_TEXMFSYSVAR'107222
+Ref: install-tl 'NOPERLDOC'107593
+Node: install-tl AUTHORS AND COPYRIGHT107657
+Node: tlmgr108070
+Node: tlmgr NAME108555
+Node: tlmgr SYNOPSIS108687
+Node: tlmgr DESCRIPTION108877
+Node: tlmgr EXAMPLES109976
+Ref: tlmgr 'tlmgr option repository ctan'110227
+Ref: tlmgr 'tlmgr option repository http://mirror.ctan.org/systems/texlive/tlnet'110299
+Ref: tlmgr 'tlmgr update --list'110904
+Ref: tlmgr 'tlmgr update --all'110997
+Ref: tlmgr 'tlmgr info' _what_111154
+Node: tlmgr OPTIONS111416
+Ref: tlmgr *--repository* _url|path_111936
+Ref: tlmgr '/some/local/dir'113122
+Ref: tlmgr 'file:/some/local/dir'113151
+Ref: tlmgr 'ctan'113224
+Ref: tlmgr 'http://mirror.ctan.org/systems/texlive/tlnet'113277
+Ref: tlmgr 'http://server/path/to/tlnet'113618
+Ref: tlmgr 'https://server/path/to/tlnet'113999
+Ref: tlmgr 'ftp://server/path/to/tlnet'114467
+Ref: tlmgr 'user at machine:/path/to/tlnet'114599
+Ref: tlmgr 'scp://user@machine/path/to/tlnet'114640
+Ref: tlmgr 'ssh://user@machine/path/to/tlnet'114681
+Ref: tlmgr *--gui* [_action_]115074
+Ref: tlmgr *--gui-lang* _llcode_115887
+Ref: tlmgr *--debug-translation*116623
+Ref: tlmgr *--machine-readable*116826
+Ref: tlmgr *--no-execute-actions*117094
+Ref: tlmgr *--package-logfile* _file_117287
+Ref: tlmgr *--pause*117541
+Ref: tlmgr *--persistent-downloads*117696
+Ref: tlmgr *--no-persistent-downloads*117724
+Ref: tlmgr *--pin-file*118218
+Ref: tlmgr *--usermode*118436
+Ref: tlmgr *--usertree* _dir_118556
+Ref: tlmgr *--verify-repo=[none|main|all]*118682
+Node: tlmgr ACTIONS119581
+Node: tlmgr help120442
+Node: tlmgr version120919
+Node: tlmgr backup121182
+Ref: tlmgr *backup [_option_...] --all*121353
+Ref: tlmgr *backup [_option_...] _pkg_...*121386
+Ref: tlmgr *--backupdir* _directory_122452
+Ref: tlmgr *--all*122669
+Ref: tlmgr *--clean*[=_N_]122921
+Ref: tlmgr *--dry-run*123248
+Node: tlmgr candidates _pkg_123378
+Node: tlmgr check [_option_...] [depends|executes|files|runfiles|texmfdbs|all]123733
+Ref: tlmgr *depends*124247
+Ref: tlmgr *executes*124589
+Ref: tlmgr *files*124704
+Ref: tlmgr *runfiles*124840
+Ref: tlmgr *texmfdbs*124977
+Ref: tlmgr - all items in 'TEXMFDBS' have the '!!' prefix.125207
+Ref: tlmgr - all items in 'TEXMFBDS' have an 'ls-R' file (if they exist at all).125283
+Ref: tlmgr - all items in 'TEXMF' with '!!' are listed in 'TEXMFDBS'.125348
+Ref: tlmgr - all items in 'TEXMF' with an 'ls-R' file are listed in 'TEXMFDBS'.125423
+Ref: tlmgr *--use-svn*125448
+Node: tlmgr conf125589
+Ref: tlmgr *conf [texmf|tlmgr|updmap [--conffile _file_] [--delete] [_key_ [_value_]]]*125877
+Ref: tlmgr *conf auxtrees [--conffile _file_] [show|add|remove] [_value_]*125941
+Node: tlmgr dump-tlpdb [_option_...] [--json]128356
+Ref: tlmgr *--local*128789
+Ref: tlmgr *--remote*128828
+Ref: tlmgr *--json*128866
+Node: tlmgr generate129437
+Ref: tlmgr *generate [_option_...] language*129633
+Ref: tlmgr *generate [_option_...] language.dat*129672
+Ref: tlmgr *generate [_option_...] language.def*129711
+Ref: tlmgr *generate [_option_...] language.dat.lua*129754
+Ref: tlmgr *--dest* _output_file_132081
+Ref: tlmgr *--localcfg* _local_conf_file_132657
+Ref: tlmgr *--rebuild-sys*132780
+Node: tlmgr gui133595
+Node: tlmgr info133773
+Ref: tlmgr *info [_option_...] _pkg_...*133935
+Ref: tlmgr *info [_option_...] collections*133969
+Ref: tlmgr *info [_option_...] schemes*133999
+Ref: tlmgr *--list*135529
+Ref: tlmgr *--only-installed*135843
+Ref: tlmgr *--only-remote*136031
+Ref: tlmgr *--data 'item1,item2,...'*136335
+Ref: tlmgr *--json* 1136916
+Node: tlmgr init-usertree137299
+Node: tlmgr install [_option_...] _pkg_...137680
+Ref: tlmgr *--dry-run* 1138188
+Ref: tlmgr *--file*138305
+Ref: tlmgr *--force*138527
+Ref: tlmgr *--no-depends*138747
+Ref: tlmgr *--no-depends-at-all*138906
+Ref: tlmgr *--reinstall*139306
+Ref: tlmgr *--with-doc*139684
+Ref: tlmgr *--with-src*139697
+Node: tlmgr key140425
+Ref: tlmgr *key list*140583
+Ref: tlmgr *key add _file_*140601
+Ref: tlmgr *key remove _keyid_*140623
+Node: tlmgr list141217
+Node: tlmgr option141379
+Ref: tlmgr *option [--json] [show]*141534
+Ref: tlmgr *option [--json] showall|help*141565
+Ref: tlmgr *option _key_ [_value_]*141591
+Node: tlmgr paper146169
+Ref: tlmgr *paper [a4|letter]*146318
+Ref: tlmgr *<[xdvi|pdftex|dvips|dvipdfmx|context|psutils] paper [_papersize_|--list]*>146394
+Ref: tlmgr *paper --json*146409
+Node: tlmgr path147624
+Ref: tlmgr *path [--w32mode=user|admin] add*147785
+Ref: tlmgr *path [--w32mode=user|admin] remove*147822
+Node: tlmgr pinning149307
+Ref: tlmgr 'pinning show'149548
+Ref: tlmgr 'pinning add' _repo_ _pkgglob_...149621
+Ref: tlmgr 'pinning remove' _repo_ _pkgglob_...149740
+Ref: tlmgr 'pinning remove _repo_ --all'149893
+Node: tlmgr platform149947
+Ref: tlmgr *platform list|add|remove _platform_...*150133
+Ref: tlmgr *platform set _platform_*150160
+Ref: tlmgr *platform set auto*150181
+Ref: tlmgr *--dry-run* 2151058
+Node: tlmgr postaction151177
+Ref: tlmgr *postaction [_option_...] install [shortcut|fileassoc|script] [_pkg_...]*151407
+Ref: tlmgr *postaction [_option_...] remove [shortcut|fileassoc|script] [_pkg_...]*151481
+Ref: tlmgr *--w32mode=[user|admin]*151796
+Ref: tlmgr *--fileassocmode=[1|2]*152212
+Ref: tlmgr *--all* 1152497
+Node: tlmgr print-platform152552
+Node: tlmgr print-platform-info152883
+Node: tlmgr remove [_option_...] _pkg_...153183
+Ref: tlmgr *--all* 2153667
+Ref: tlmgr *--backup*153777
+Ref: tlmgr *--backupdir* _directory_ 1153803
+Ref: tlmgr *--no-depends* 1154208
+Ref: tlmgr *--no-depends-at-all* 1154270
+Ref: tlmgr *--force* 1154373
+Ref: tlmgr *--dry-run* 3154846
+Node: tlmgr repository155182
+Ref: tlmgr *repository list*155370
+Ref: tlmgr *repository list _path|url|tag_*155404
+Ref: tlmgr *repository add _path_ [_tag_]*155437
+Ref: tlmgr *repository remove _path|tag_*155469
+Ref: tlmgr *repository set _path_[#_tag_] [_path_[#_tag_] ...]*155523
+Ref: tlmgr *repository status*155544
+Ref: tlmgr The tag (which can be the same as the url);156771
+Node: tlmgr restore157249
+Ref: tlmgr *restore [_option_...] _pkg_ [_rev_]*157428
+Ref: tlmgr *restore [_option_...] --all*157458
+Ref: tlmgr *--all* 3158158
+Ref: tlmgr *--backupdir* _directory_ 2158372
+Ref: tlmgr *--dry-run* 4158553
+Ref: tlmgr *--force* 2158685
+Ref: tlmgr *--json* 2158731
+Node: tlmgr search159058
+Ref: tlmgr *search [_option_...] _what_*159222
+Ref: tlmgr *search [_option_...] --file _what_*159259
+Ref: tlmgr *search [_option_...] --all _what_*159295
+Ref: tlmgr *--file* 1159515
+Ref: tlmgr *--all* 4159577
+Ref: tlmgr *--global*159666
+Ref: tlmgr *--word*159793
+Node: tlmgr shell160108
+Ref: tlmgr protocol160843
+Ref: tlmgr help 1160907
+Ref: tlmgr version 1160960
+Ref: tlmgr quit, end, bye, byebye, EOF161028
+Ref: tlmgr restart161049
+Ref: tlmgr load [local|remote]161172
+Ref: tlmgr save161242
+Ref: tlmgr get [_var_] =item set [_var_ [_val_]]161365
+Node: tlmgr show161966
+Node: tlmgr uninstall162133
+Node: tlmgr update [_option_...] [_pkg_...]162363
+Ref: tlmgr *--all* 5162734
+Ref: tlmgr *--self*164913
+Ref: tlmgr *--dry-run* 5165677
+Ref: tlmgr *--list* [_pkg_]165854
+Ref: tlmgr *--exclude* _pkg_166543
+Ref: tlmgr *--no-auto-remove* [_pkg_...]167343
+Ref: tlmgr *--no-auto-install* [_pkg_...]167827
+Ref: tlmgr *--reinstall-forcibly-removed*168589
+Ref: tlmgr *--backup* 1169124
+Ref: tlmgr *--backupdir* _directory_ 3169150
+Ref: tlmgr *--no-depends* 2170316
+Ref: tlmgr *--no-depends-at-all* 2170519
+Ref: tlmgr *--force* 3170622
+Node: tlmgr CONFIGURATION FILE FOR TLMGR171642
+Ref: tlmgr 'auto-remove', value 0 or 1 (default 1), same as command-line option.172649
+Ref: tlmgr 'gui-expertmode', value 0 or 1 (default 1). This switches between the full GUI and a simplified GUI with only the most common settings.172786
+Ref: tlmgr 'gui-lang' _llcode_, with a language code value as with the command-line option.172868
+Ref: tlmgr 'no-checksums', value 0 or 1 (default 0, see below).172922
+Ref: tlmgr 'persistent-downloads', value 0 or 1 (default 1), same as command-line option.173002
+Ref: tlmgr 'require-verification', value 0 or 1 (default 0), same as command-line option.173082
+Ref: tlmgr 'update-exclude', value: comma-separated list of packages (no space allowed). Same as the command line option '--exclude' for the action 'update'.173230
+Ref: tlmgr 'verify-downloads', value 0 or 1 (default 1), same as command-line option.173306
+Ref: tlmgr 'allowed-actions' _action1_ [,_action_,...] The value is a comma-separated list of 'tlmgr' actions which are allowed to be executed when 'tlmgr' is invoked in system mode (that is, without '--usermode').173575
+Node: tlmgr CRYPTOGRAPHIC VERIFICATION174663
+Node: tlmgr Configuration of GnuPG invocation176836
+Node: tlmgr USER MODE177474
+Node: tlmgr User mode install180320
+Node: tlmgr User mode backup, restore, remove, update181464
+Node: tlmgr User mode generate, option, paper181906
+Node: tlmgr MULTIPLE REPOSITORIES182282
+Node: tlmgr Pinning184011
+Node: tlmgr GUI FOR TLMGR185934
+Node: tlmgr Main display187583
+Node: tlmgr Display configuration area187835
+Ref: tlmgr Status188196
+Ref: tlmgr Category188360
+Ref: tlmgr Match188546
+Ref: tlmgr Selection188727
+Ref: tlmgr Display configuration buttons188931
+Node: tlmgr Package list area189114
+Ref: tlmgr a checkbox189698
+Ref: tlmgr package name189834
+Ref: tlmgr local revision (and version)189933
+Ref: tlmgr remote revision (and version)190308
+Ref: tlmgr short description190605
+Node: tlmgr Main display action buttons190650
+Ref: tlmgr Update all installed190916
+Ref: tlmgr Update191288
+Ref: tlmgr Install191338
+Ref: tlmgr Remove191524
+Ref: tlmgr Backup191702
+Node: tlmgr Menu bar191859
+Ref: tlmgr 'tlmgr' menu192082
+Ref: tlmgr 'Options menu'192390
+Ref: tlmgr 'Actions menu'193473
+Ref: tlmgr 'Help menu'193901
+Node: tlmgr GUI options194035
+Ref: tlmgr '-background' _color_194281
+Ref: tlmgr '-font "' _fontname_ _fontsize_ '"'194346
+Ref: tlmgr '-foreground' _color_194504
+Ref: tlmgr '-geometry' _geomspec_194556
+Ref: tlmgr '-xrm' _xresource_194748
+Node: tlmgr MACHINE-READABLE OUTPUT195017
+Node: tlmgr Machine-readable 'update' and 'install' output195833
+Ref: tlmgr 'location-url' _location_197115
+Ref: tlmgr 'total-bytes' _count_197331
+Ref: tlmgr _pkgname_197741
+Ref: tlmgr _status_197951
+Ref: tlmgr 'd'198029
+Ref: tlmgr 'f'198089
+Ref: tlmgr 'u'198268
+Ref: tlmgr 'r'198314
+Ref: tlmgr 'a'198437
+Ref: tlmgr 'i'198615
+Ref: tlmgr 'I'198734
+Ref: tlmgr _localrev_198836
+Ref: tlmgr _serverrev_198943
+Ref: tlmgr _size_199055
+Ref: tlmgr _runtime_199224
+Ref: tlmgr _esttot_199294
+Node: tlmgr Machine-readable 'option' output199327
+Node: tlmgr ENVIRONMENT VARIABLES199845
+Ref: tlmgr 'TEXLIVE_COMPRESSOR'200356
+Ref: tlmgr 'TEXLIVE_DOWNLOADER'201204
+Ref: tlmgr 'TL_DOWNLOAD_PROGRAM'201227
+Ref: tlmgr 'TL_DOWNLOAD_ARGS'201247
+Ref: tlmgr 'TEXLIVE_PREFER_OWN'202273
+Node: tlmgr AUTHORS AND COPYRIGHT203097
+Node: Index203495
 
 End Tag Table
-
-
-Local Variables:
-coding: utf-8
-End:

Deleted: branches/stable/source/src/doc/tlbuild.pdf
===================================================================
(Binary files differ)

Modified: branches/stable/source/src/doc/tlbuild.texi
===================================================================
--- branches/stable/source/src/doc/tlbuild.texi	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/doc/tlbuild.texi	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,8 +1,8 @@
 \input texinfo
 @setfilename tlbuild.info
 
- at set version 2020
- at set month-year November 2020
+ at set version 2021
+ at set month-year February 2021
 
 @set mytitle Building @TeX{} Live (@value{version})
 @settitle @value{mytitle}
@@ -15,7 +15,7 @@
 This file documents the @TL{} build system and more.
 
 @noindent
-Copyright @copyright{} 2016--2020 Karl Berry.@*
+Copyright @copyright{} 2016--2021 Karl Berry.@*
 Copyright @copyright{} 2013--2015 Karl Berry & Peter Breitenlohner.
 
 Permission is granted to make and distribute verbatim copies of this
@@ -1721,6 +1721,11 @@
 so people checking out the TL source tree do not have to run any
 autotools, but can simply run @code{configure}.)
 
+To reiterate: do not fail to commit the generated @file{configure} and
+other files. The m4 code in @file{kpse-pkgs.m4} uses the existence of
+ at file{configure} to determine whether to descend into (and configure)
+a given subdirectory.
+
 @pindex reautoconf at r{, for new program}
 Then, run the TL tool @code{reautoconf} in the top-level TL
 @code{Build/source/} directory, to incorporate the new program into

Modified: branches/stable/source/src/libs/Makefile.in
===================================================================
--- branches/stable/source/src/libs/Makefile.in	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/Makefile.in	2021-02-15 19:17:20 UTC (rev 845)
@@ -131,6 +131,7 @@
 	$(top_srcdir)/../utils/xindy/ac/withenable.ac \
 	$(top_srcdir)/../utils/xindy/ac/xindy.ac \
 	$(top_srcdir)/../utils/xindy/ac/clisp.ac \
+	$(top_srcdir)/../utils/xml2pmx/ac/withenable.ac \
 	$(top_srcdir)/../utils/xpdfopen/ac/withenable.ac \
 	$(top_srcdir)/../texk/web2c/ac/withenable.ac \
 	$(top_srcdir)/../texk/web2c/ac/web2c.ac \

Modified: branches/stable/source/src/libs/README
===================================================================
--- branches/stable/source/src/libs/README	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/README	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,4 +1,4 @@
-$Id: README 57237 2020-12-27 02:02:34Z kakuto $
+$Id: README 57727 2021-02-13 17:46:14Z karl $
 Public domain.  Originally created by Karl Berry, 2005.
 
 Libraries we compile for TeX Live.
@@ -15,7 +15,7 @@
 freetype2 2.10.4 - checked 21oct20
   http://savannah.nongnu.org/download/freetype/
 
-gd 2.3.0 - checked 10apr20
+gd 2.3.1 - checked 03feb21
   https://github.com/libgd/libgd/releases
 
 gmp 6.2.1 - checked 15nov20
@@ -28,7 +28,7 @@
 harfbuzz 2.7.4 - checked 27dec20
   https://github.com/harfbuzz/harfbuzz/releases/download/2.7.4/
 
-icu 63.1 - checked 8jan19
+icu 68.2 - checked 13feb21
   http://download.icu-project.org/files/icu4c/
 
 libpaper 1.1.24+nmu2 - checked 24oct13
@@ -58,7 +58,7 @@
 teckit 2.5.10 - checked 06may20
   https://github.com/silnrsi/teckit/archive/2.5.10.tar.gz
 
-xpdf 4.02 - checked 29sep19
+xpdf 4.03 - checked 01feb21
   http://www.xpdfreader.com/download.html
   with modifications for pdftex
 

Modified: branches/stable/source/src/libs/configure
===================================================================
--- branches/stable/source/src/libs/configure	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/configure	2021-02-15 19:17:20 UTC (rev 845)
@@ -709,6 +709,7 @@
 enable_xindy_rules
 enable_xindy_docs
 with_clisp_runtime
+enable_xml2pmx
 enable_xpdfopen
 enable_web2c
 with_banner_add
@@ -1494,6 +1495,7 @@
   --enable-xindy          build the xindy package
   --enable-xindy-rules      build and install make-rules package
   --enable-xindy-docs       build and install documentation
+  --disable-xml2pmx       do not build the xml2pmx package
   --disable-xpdfopen      do not build the xpdfopen package
   --disable-web2c         do not build the web2c (TeX & Co.) package
   --enable-auto-core        cause TeX&MF to dump core, given a certain
@@ -3635,6 +3637,24 @@
 fi ;;
 esac
 
+## utils/xml2pmx/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory utils/xml2pmx/
+## configure options and TL libraries required for xml2pmx
+# Check whether --enable-xml2pmx was given.
+if test "${enable_xml2pmx+set}" = set; then :
+  enableval=$enable_xml2pmx;
+fi
+case $enable_xml2pmx in #(
+  yes|no) :
+     ;; #(
+  *) :
+
+   enable_xml2pmx=$enable_all_pkgs
+     { $as_echo "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-xml2pmx=$enable_xml2pmx'" >&5
+$as_echo "$as_me: Assuming \`--enable-xml2pmx=$enable_xml2pmx'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-xml2pmx=$enable_xml2pmx'"
+    ;;
+esac
+
 ## utils/xpdfopen/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory utils/xpdfopen/
 ## configure options and TL libraries required for xpdfopen
 # Check whether --enable-xpdfopen was given.
@@ -6425,74 +6445,110 @@
 if test -x $srcdir/pplib/configure; then
   test "x$with_system_pplib" != xyes && test "x$need_pplib" = xyes && MAKE_SUBDIRS="pplib $MAKE_SUBDIRS"
   CONF_SUBDIRS="pplib $CONF_SUBDIRS"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/pplib/configure' >&5
 fi
 if test -x $srcdir/harfbuzz/configure; then
   test "x$with_system_harfbuzz" != xyes && test "x$need_harfbuzz" = xyes && MAKE_SUBDIRS="harfbuzz $MAKE_SUBDIRS"
   CONF_SUBDIRS="harfbuzz $CONF_SUBDIRS"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/harfbuzz/configure' >&5
 fi
 if test -x $srcdir/icu/configure; then
   test "x$with_system_icu" != xyes && test "x$need_icu" = xyes && MAKE_SUBDIRS="icu $MAKE_SUBDIRS"
   CONF_SUBDIRS="icu $CONF_SUBDIRS"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/icu/configure' >&5
 fi
 if test -x $srcdir/teckit/configure; then
   test "x$with_system_teckit" != xyes && test "x$need_teckit" = xyes && MAKE_SUBDIRS="teckit $MAKE_SUBDIRS"
   CONF_SUBDIRS="teckit $CONF_SUBDIRS"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/teckit/configure' >&5
 fi
 if test -x $srcdir/graphite2/configure; then
   test "x$with_system_graphite2" != xyes && test "x$need_graphite2" = xyes && MAKE_SUBDIRS="graphite2 $MAKE_SUBDIRS"
   CONF_SUBDIRS="graphite2 $CONF_SUBDIRS"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/graphite2/configure' >&5
 fi
 if test -x $srcdir/zziplib/configure; then
   test "x$with_system_zziplib" != xyes && test "x$need_zziplib" = xyes && MAKE_SUBDIRS="zziplib $MAKE_SUBDIRS"
   CONF_SUBDIRS="zziplib $CONF_SUBDIRS"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/zziplib/configure' >&5
 fi
 if test -x $srcdir/xpdf/configure; then
   test "x$with_system_xpdf" != xyes && test "x$need_xpdf" = xyes && MAKE_SUBDIRS="xpdf $MAKE_SUBDIRS"
   CONF_SUBDIRS="xpdf $CONF_SUBDIRS"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/xpdf/configure' >&5
 fi
 if test -x $srcdir/mpfr/configure; then
   test "x$with_system_mpfr" != xyes && test "x$need_mpfr" = xyes && MAKE_SUBDIRS="mpfr $MAKE_SUBDIRS"
   CONF_SUBDIRS="mpfr $CONF_SUBDIRS"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/mpfr/configure' >&5
 fi
 if test -x $srcdir/gmp/configure; then
   test "x$with_system_gmp" != xyes && test "x$need_gmp" = xyes && MAKE_SUBDIRS="gmp $MAKE_SUBDIRS"
   CONF_SUBDIRS="gmp $CONF_SUBDIRS"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/gmp/configure' >&5
 fi
 if test -x $srcdir/cairo/configure; then
   test "x$with_system_cairo" != xyes && test "x$need_cairo" = xyes && MAKE_SUBDIRS="cairo $MAKE_SUBDIRS"
   CONF_SUBDIRS="cairo $CONF_SUBDIRS"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/cairo/configure' >&5
 fi
 if test -x $srcdir/pixman/configure; then
   test "x$with_system_pixman" != xyes && test "x$need_pixman" = xyes && MAKE_SUBDIRS="pixman $MAKE_SUBDIRS"
   CONF_SUBDIRS="pixman $CONF_SUBDIRS"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/pixman/configure' >&5
 fi
 if test -x $srcdir/gd/configure; then
   test "x$with_system_gd" != xyes && test "x$need_gd" = xyes && MAKE_SUBDIRS="gd $MAKE_SUBDIRS"
   CONF_SUBDIRS="gd $CONF_SUBDIRS"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/gd/configure' >&5
 fi
 if test -x $srcdir/freetype2/configure; then
   test "x$with_system_freetype2" != xyes && test "x$need_freetype2" = xyes && MAKE_SUBDIRS="freetype2 $MAKE_SUBDIRS"
   CONF_SUBDIRS="freetype2 $CONF_SUBDIRS"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/freetype2/configure' >&5
 fi
 if test -x $srcdir/libpng/configure; then
   test "x$with_system_libpng" != xyes && test "x$need_libpng" = xyes && MAKE_SUBDIRS="libpng $MAKE_SUBDIRS"
   CONF_SUBDIRS="libpng $CONF_SUBDIRS"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/libpng/configure' >&5
 fi
 if test -x $srcdir/libpaper/configure; then
   test "x$with_system_libpaper" != xyes && test "x$need_libpaper" = xyes && MAKE_SUBDIRS="libpaper $MAKE_SUBDIRS"
   CONF_SUBDIRS="libpaper $CONF_SUBDIRS"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/libpaper/configure' >&5
 fi
 if test -x $srcdir/luajit/configure; then
   test "x$with_system_luajit" != xyes && test "x$need_luajit" = xyes && MAKE_SUBDIRS="luajit $MAKE_SUBDIRS"
   CONF_SUBDIRS="luajit $CONF_SUBDIRS"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/luajit/configure' >&5
 fi
 if test -x $srcdir/lua53/configure; then
   test "x$with_system_lua53" != xyes && test "x$need_lua53" = xyes && MAKE_SUBDIRS="lua53 $MAKE_SUBDIRS"
   CONF_SUBDIRS="lua53 $CONF_SUBDIRS"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/lua53/configure' >&5
 fi
 if test -x $srcdir/zlib/configure; then
   test "x$with_system_zlib" != xyes && test "x$need_zlib" = xyes && MAKE_SUBDIRS="zlib $MAKE_SUBDIRS"
   CONF_SUBDIRS="zlib $CONF_SUBDIRS"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/zlib/configure' >&5
 fi
 
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAKE_SUBDIRS" >&5

Modified: branches/stable/source/src/libs/xpdf/ChangeLog
===================================================================
--- branches/stable/source/src/libs/xpdf/ChangeLog	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/ChangeLog	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,3 +1,8 @@
+2021-02-01  Akira Kakuto  <kakuto at w32tex.org>
+
+	* Import xpdf-4.03.
+	* version.ac, Makefile.am: Adjust.
+
 2020-05-14  Karl Berry  <karl at freefriends.org>
 
 	* ac/xpdf.ac: doc change for poppler no longer supported in TL.

Modified: branches/stable/source/src/libs/xpdf/Makefile.am
===================================================================
--- branches/stable/source/src/libs/xpdf/Makefile.am	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/Makefile.am	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,4 +1,4 @@
-## $Id: Makefile.am 50122 2019-02-25 03:01:12Z kakuto $
+## $Id: Makefile.am 57588 2021-02-01 06:11:18Z kakuto $
 ## Proxy Makefile.am to build xpdf for TeX Live.
 ##
 ##   Copyright 2016-2017 Karl Berry <tex-live at tug.org>
@@ -62,6 +62,7 @@
 	@XPDF_TREE@/goo/GHash.cc \
 	@XPDF_TREE@/goo/GList.cc \
 	@XPDF_TREE@/goo/GString.cc \
+	@XPDF_TREE@/goo/Trace.cc \
 	@XPDF_TREE@/goo/gfile.cc \
 	@XPDF_TREE@/goo/gmem.cc \
 	@XPDF_TREE@/goo/gmempp.cc
@@ -87,7 +88,6 @@
 	@XPDF_TREE@/xpdf/Dict.cc \
 	@XPDF_TREE@/xpdf/Error.cc \
 	@XPDF_TREE@/xpdf/FontEncodingTables.cc \
-	@XPDF_TREE@/xpdf/Form.cc \
 	@XPDF_TREE@/xpdf/Function.cc \
 	@XPDF_TREE@/xpdf/Gfx.cc \
 	@XPDF_TREE@/xpdf/GfxFont.cc \
@@ -115,7 +115,7 @@
 	@XPDF_TREE@/xpdf/UnicodeMap.cc \
 	@XPDF_TREE@/xpdf/UnicodeRemapping.cc \
 	@XPDF_TREE@/xpdf/UTF8.cc \
-	@XPDF_TREE@/xpdf/XFAForm.cc \
+	@XPDF_TREE@/xpdf/XFAScanner.cc \
 	@XPDF_TREE@/xpdf/XRef.cc \
 	@XPDF_TREE@/xpdf/Zoox.cc
 

Modified: branches/stable/source/src/libs/xpdf/Makefile.in
===================================================================
--- branches/stable/source/src/libs/xpdf/Makefile.in	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/Makefile.in	2021-02-15 19:17:20 UTC (rev 845)
@@ -115,6 +115,7 @@
 	@XPDF_TREE@/goo/GHash.$(OBJEXT) \
 	@XPDF_TREE@/goo/GList.$(OBJEXT) \
 	@XPDF_TREE@/goo/GString.$(OBJEXT) \
+	@XPDF_TREE@/goo/Trace.$(OBJEXT) \
 	@XPDF_TREE@/goo/gfile.$(OBJEXT) @XPDF_TREE@/goo/gmem.$(OBJEXT) \
 	@XPDF_TREE@/goo/gmempp.$(OBJEXT)
 am__objects_2 = @XPDF_TREE@/fofi/FoFiBase.$(OBJEXT) \
@@ -135,7 +136,6 @@
 	@XPDF_TREE@/xpdf/Dict.$(OBJEXT) \
 	@XPDF_TREE@/xpdf/Error.$(OBJEXT) \
 	@XPDF_TREE@/xpdf/FontEncodingTables.$(OBJEXT) \
-	@XPDF_TREE@/xpdf/Form.$(OBJEXT) \
 	@XPDF_TREE@/xpdf/Function.$(OBJEXT) \
 	@XPDF_TREE@/xpdf/Gfx.$(OBJEXT) \
 	@XPDF_TREE@/xpdf/GfxFont.$(OBJEXT) \
@@ -163,7 +163,7 @@
 	@XPDF_TREE@/xpdf/UnicodeMap.$(OBJEXT) \
 	@XPDF_TREE@/xpdf/UnicodeRemapping.$(OBJEXT) \
 	@XPDF_TREE@/xpdf/UTF8.$(OBJEXT) \
-	@XPDF_TREE@/xpdf/XFAForm.$(OBJEXT) \
+	@XPDF_TREE@/xpdf/XFAScanner.$(OBJEXT) \
 	@XPDF_TREE@/xpdf/XRef.$(OBJEXT) \
 	@XPDF_TREE@/xpdf/Zoox.$(OBJEXT)
 nodist_libxpdf_a_OBJECTS = $(am__objects_1) $(am__objects_2) \
@@ -194,6 +194,7 @@
 	@XPDF_TREE@/goo/$(DEPDIR)/GHash.Po \
 	@XPDF_TREE@/goo/$(DEPDIR)/GList.Po \
 	@XPDF_TREE@/goo/$(DEPDIR)/GString.Po \
+	@XPDF_TREE@/goo/$(DEPDIR)/Trace.Po \
 	@XPDF_TREE@/goo/$(DEPDIR)/gfile.Po \
 	@XPDF_TREE@/goo/$(DEPDIR)/gmem.Po \
 	@XPDF_TREE@/goo/$(DEPDIR)/gmempp.Po \
@@ -209,7 +210,6 @@
 	@XPDF_TREE@/xpdf/$(DEPDIR)/Dict.Po \
 	@XPDF_TREE@/xpdf/$(DEPDIR)/Error.Po \
 	@XPDF_TREE@/xpdf/$(DEPDIR)/FontEncodingTables.Po \
-	@XPDF_TREE@/xpdf/$(DEPDIR)/Form.Po \
 	@XPDF_TREE@/xpdf/$(DEPDIR)/Function.Po \
 	@XPDF_TREE@/xpdf/$(DEPDIR)/Gfx.Po \
 	@XPDF_TREE@/xpdf/$(DEPDIR)/GfxFont.Po \
@@ -237,7 +237,7 @@
 	@XPDF_TREE@/xpdf/$(DEPDIR)/UTF8.Po \
 	@XPDF_TREE@/xpdf/$(DEPDIR)/UnicodeMap.Po \
 	@XPDF_TREE@/xpdf/$(DEPDIR)/UnicodeRemapping.Po \
-	@XPDF_TREE@/xpdf/$(DEPDIR)/XFAForm.Po \
+	@XPDF_TREE@/xpdf/$(DEPDIR)/XFAScanner.Po \
 	@XPDF_TREE@/xpdf/$(DEPDIR)/XRef.Po \
 	@XPDF_TREE@/xpdf/$(DEPDIR)/Zoox.Po
 am__mv = mv -f
@@ -483,6 +483,7 @@
 	@XPDF_TREE@/goo/GHash.cc \
 	@XPDF_TREE@/goo/GList.cc \
 	@XPDF_TREE@/goo/GString.cc \
+	@XPDF_TREE@/goo/Trace.cc \
 	@XPDF_TREE@/goo/gfile.cc \
 	@XPDF_TREE@/goo/gmem.cc \
 	@XPDF_TREE@/goo/gmempp.cc
@@ -508,7 +509,6 @@
 	@XPDF_TREE@/xpdf/Dict.cc \
 	@XPDF_TREE@/xpdf/Error.cc \
 	@XPDF_TREE@/xpdf/FontEncodingTables.cc \
-	@XPDF_TREE@/xpdf/Form.cc \
 	@XPDF_TREE@/xpdf/Function.cc \
 	@XPDF_TREE@/xpdf/Gfx.cc \
 	@XPDF_TREE@/xpdf/GfxFont.cc \
@@ -536,7 +536,7 @@
 	@XPDF_TREE@/xpdf/UnicodeMap.cc \
 	@XPDF_TREE@/xpdf/UnicodeRemapping.cc \
 	@XPDF_TREE@/xpdf/UTF8.cc \
-	@XPDF_TREE@/xpdf/XFAForm.cc \
+	@XPDF_TREE@/xpdf/XFAScanner.cc \
 	@XPDF_TREE@/xpdf/XRef.cc \
 	@XPDF_TREE@/xpdf/Zoox.cc
 
@@ -616,6 +616,8 @@
 	@XPDF_TREE@/goo/$(DEPDIR)/$(am__dirstamp)
 @XPDF_TREE@/goo/GString.$(OBJEXT): @XPDF_TREE@/goo/$(am__dirstamp) \
 	@XPDF_TREE@/goo/$(DEPDIR)/$(am__dirstamp)
+ at XPDF_TREE@/goo/Trace.$(OBJEXT): @XPDF_TREE@/goo/$(am__dirstamp) \
+	@XPDF_TREE@/goo/$(DEPDIR)/$(am__dirstamp)
 @XPDF_TREE@/goo/gfile.$(OBJEXT): @XPDF_TREE@/goo/$(am__dirstamp) \
 	@XPDF_TREE@/goo/$(DEPDIR)/$(am__dirstamp)
 @XPDF_TREE@/goo/gmem.$(OBJEXT): @XPDF_TREE@/goo/$(am__dirstamp) \
@@ -679,8 +681,6 @@
 @XPDF_TREE@/xpdf/FontEncodingTables.$(OBJEXT):  \
 	@XPDF_TREE@/xpdf/$(am__dirstamp) \
 	@XPDF_TREE@/xpdf/$(DEPDIR)/$(am__dirstamp)
- at XPDF_TREE@/xpdf/Form.$(OBJEXT): @XPDF_TREE@/xpdf/$(am__dirstamp) \
-	@XPDF_TREE@/xpdf/$(DEPDIR)/$(am__dirstamp)
 @XPDF_TREE@/xpdf/Function.$(OBJEXT): @XPDF_TREE@/xpdf/$(am__dirstamp) \
 	@XPDF_TREE@/xpdf/$(DEPDIR)/$(am__dirstamp)
 @XPDF_TREE@/xpdf/Gfx.$(OBJEXT): @XPDF_TREE@/xpdf/$(am__dirstamp) \
@@ -749,7 +749,8 @@
 	@XPDF_TREE@/xpdf/$(DEPDIR)/$(am__dirstamp)
 @XPDF_TREE@/xpdf/UTF8.$(OBJEXT): @XPDF_TREE@/xpdf/$(am__dirstamp) \
 	@XPDF_TREE@/xpdf/$(DEPDIR)/$(am__dirstamp)
- at XPDF_TREE@/xpdf/XFAForm.$(OBJEXT): @XPDF_TREE@/xpdf/$(am__dirstamp) \
+ at XPDF_TREE@/xpdf/XFAScanner.$(OBJEXT):  \
+	@XPDF_TREE@/xpdf/$(am__dirstamp) \
 	@XPDF_TREE@/xpdf/$(DEPDIR)/$(am__dirstamp)
 @XPDF_TREE@/xpdf/XRef.$(OBJEXT): @XPDF_TREE@/xpdf/$(am__dirstamp) \
 	@XPDF_TREE@/xpdf/$(DEPDIR)/$(am__dirstamp)
@@ -780,6 +781,7 @@
 @AMDEP_TRUE@@am__include@ @am__quote@@XPDF_TREE@/goo/$(DEPDIR)/GHash.Po at am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@@XPDF_TREE@/goo/$(DEPDIR)/GList.Po at am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@@XPDF_TREE@/goo/$(DEPDIR)/GString.Po at am__quote@ # am--include-marker
+ at AMDEP_TRUE@@am__include@ @am__quote@@XPDF_TREE@/goo/$(DEPDIR)/Trace.Po at am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@@XPDF_TREE@/goo/$(DEPDIR)/gfile.Po at am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@@XPDF_TREE@/goo/$(DEPDIR)/gmem.Po at am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@@XPDF_TREE@/goo/$(DEPDIR)/gmempp.Po at am__quote@ # am--include-marker
@@ -795,7 +797,6 @@
 @AMDEP_TRUE@@am__include@ @am__quote@@XPDF_TREE@/xpdf/$(DEPDIR)/Dict.Po at am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@@XPDF_TREE@/xpdf/$(DEPDIR)/Error.Po at am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@@XPDF_TREE@/xpdf/$(DEPDIR)/FontEncodingTables.Po at am__quote@ # am--include-marker
- at AMDEP_TRUE@@am__include@ @am__quote@@XPDF_TREE@/xpdf/$(DEPDIR)/Form.Po at am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@@XPDF_TREE@/xpdf/$(DEPDIR)/Function.Po at am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@@XPDF_TREE@/xpdf/$(DEPDIR)/Gfx.Po at am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@@XPDF_TREE@/xpdf/$(DEPDIR)/GfxFont.Po at am__quote@ # am--include-marker
@@ -823,7 +824,7 @@
 @AMDEP_TRUE@@am__include@ @am__quote@@XPDF_TREE@/xpdf/$(DEPDIR)/UTF8.Po at am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@@XPDF_TREE@/xpdf/$(DEPDIR)/UnicodeMap.Po at am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@@XPDF_TREE@/xpdf/$(DEPDIR)/UnicodeRemapping.Po at am__quote@ # am--include-marker
- at AMDEP_TRUE@@am__include@ @am__quote@@XPDF_TREE@/xpdf/$(DEPDIR)/XFAForm.Po at am__quote@ # am--include-marker
+ at AMDEP_TRUE@@am__include@ @am__quote@@XPDF_TREE@/xpdf/$(DEPDIR)/XFAScanner.Po at am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@@XPDF_TREE@/xpdf/$(DEPDIR)/XRef.Po at am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote@@XPDF_TREE@/xpdf/$(DEPDIR)/Zoox.Po at am__quote@ # am--include-marker
 
@@ -1213,6 +1214,7 @@
 	-rm -f @XPDF_TREE@/goo/$(DEPDIR)/GHash.Po
 	-rm -f @XPDF_TREE@/goo/$(DEPDIR)/GList.Po
 	-rm -f @XPDF_TREE@/goo/$(DEPDIR)/GString.Po
+	-rm -f @XPDF_TREE@/goo/$(DEPDIR)/Trace.Po
 	-rm -f @XPDF_TREE@/goo/$(DEPDIR)/gfile.Po
 	-rm -f @XPDF_TREE@/goo/$(DEPDIR)/gmem.Po
 	-rm -f @XPDF_TREE@/goo/$(DEPDIR)/gmempp.Po
@@ -1228,7 +1230,6 @@
 	-rm -f @XPDF_TREE@/xpdf/$(DEPDIR)/Dict.Po
 	-rm -f @XPDF_TREE@/xpdf/$(DEPDIR)/Error.Po
 	-rm -f @XPDF_TREE@/xpdf/$(DEPDIR)/FontEncodingTables.Po
-	-rm -f @XPDF_TREE@/xpdf/$(DEPDIR)/Form.Po
 	-rm -f @XPDF_TREE@/xpdf/$(DEPDIR)/Function.Po
 	-rm -f @XPDF_TREE@/xpdf/$(DEPDIR)/Gfx.Po
 	-rm -f @XPDF_TREE@/xpdf/$(DEPDIR)/GfxFont.Po
@@ -1256,7 +1257,7 @@
 	-rm -f @XPDF_TREE@/xpdf/$(DEPDIR)/UTF8.Po
 	-rm -f @XPDF_TREE@/xpdf/$(DEPDIR)/UnicodeMap.Po
 	-rm -f @XPDF_TREE@/xpdf/$(DEPDIR)/UnicodeRemapping.Po
-	-rm -f @XPDF_TREE@/xpdf/$(DEPDIR)/XFAForm.Po
+	-rm -f @XPDF_TREE@/xpdf/$(DEPDIR)/XFAScanner.Po
 	-rm -f @XPDF_TREE@/xpdf/$(DEPDIR)/XRef.Po
 	-rm -f @XPDF_TREE@/xpdf/$(DEPDIR)/Zoox.Po
 	-rm -f Makefile
@@ -1316,6 +1317,7 @@
 	-rm -f @XPDF_TREE@/goo/$(DEPDIR)/GHash.Po
 	-rm -f @XPDF_TREE@/goo/$(DEPDIR)/GList.Po
 	-rm -f @XPDF_TREE@/goo/$(DEPDIR)/GString.Po
+	-rm -f @XPDF_TREE@/goo/$(DEPDIR)/Trace.Po
 	-rm -f @XPDF_TREE@/goo/$(DEPDIR)/gfile.Po
 	-rm -f @XPDF_TREE@/goo/$(DEPDIR)/gmem.Po
 	-rm -f @XPDF_TREE@/goo/$(DEPDIR)/gmempp.Po
@@ -1331,7 +1333,6 @@
 	-rm -f @XPDF_TREE@/xpdf/$(DEPDIR)/Dict.Po
 	-rm -f @XPDF_TREE@/xpdf/$(DEPDIR)/Error.Po
 	-rm -f @XPDF_TREE@/xpdf/$(DEPDIR)/FontEncodingTables.Po
-	-rm -f @XPDF_TREE@/xpdf/$(DEPDIR)/Form.Po
 	-rm -f @XPDF_TREE@/xpdf/$(DEPDIR)/Function.Po
 	-rm -f @XPDF_TREE@/xpdf/$(DEPDIR)/Gfx.Po
 	-rm -f @XPDF_TREE@/xpdf/$(DEPDIR)/GfxFont.Po
@@ -1359,7 +1360,7 @@
 	-rm -f @XPDF_TREE@/xpdf/$(DEPDIR)/UTF8.Po
 	-rm -f @XPDF_TREE@/xpdf/$(DEPDIR)/UnicodeMap.Po
 	-rm -f @XPDF_TREE@/xpdf/$(DEPDIR)/UnicodeRemapping.Po
-	-rm -f @XPDF_TREE@/xpdf/$(DEPDIR)/XFAForm.Po
+	-rm -f @XPDF_TREE@/xpdf/$(DEPDIR)/XFAScanner.Po
 	-rm -f @XPDF_TREE@/xpdf/$(DEPDIR)/XRef.Po
 	-rm -f @XPDF_TREE@/xpdf/$(DEPDIR)/Zoox.Po
 	-rm -f Makefile

Modified: branches/stable/source/src/libs/xpdf/TLpatches/ChangeLog
===================================================================
--- branches/stable/source/src/libs/xpdf/TLpatches/ChangeLog	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/TLpatches/ChangeLog	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,3 +1,7 @@
+2021-02-01  Akira Kakuto  <kakuto at w32tex.org>
+
+	* patch-bunched: Adjust.
+
 2019-09-29  Akira Kakuto  <kakuto at w32tex.org>
 
 	* patch-bunched: Adjust.

Modified: branches/stable/source/src/libs/xpdf/TLpatches/TL-Changes
===================================================================
--- branches/stable/source/src/libs/xpdf/TLpatches/TL-Changes	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/TLpatches/TL-Changes	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,4 +1,4 @@
-Changes applied to the xpdf-4.02/ tree as obtained from:
+Changes applied to the xpdf-4.03/ tree as obtained from:
 	http://www.xpdfreader.com/download.html
 
 Removed:

Modified: branches/stable/source/src/libs/xpdf/TLpatches/patch-bunched
===================================================================
--- branches/stable/source/src/libs/xpdf/TLpatches/patch-bunched	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/TLpatches/patch-bunched	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,6 +1,6 @@
-diff -ur xpdf-4.02/goo/gfile.cc xpdf-src/goo/gfile.cc
---- xpdf-4.02/goo/gfile.cc	Thu Sep 26 04:54:33 2019
-+++ xpdf-src/goo/gfile.cc	Sun Sep 29 11:23:53 2019
+diff -ur xpdf-4.03/goo/gfile.cc xpdf-src/goo/gfile.cc
+--- xpdf-4.03/goo/gfile.cc	Thu Jan 28 07:23:51 2021
++++ xpdf-src/goo/gfile.cc	Mon Feb 01 13:13:50 2021
 @@ -7,6 +7,9 @@
  // Copyright 1996-2003 Glyph & Cog, LLC
  //
@@ -11,7 +11,7 @@
  
  #include <aconf.h>
  
-@@ -54,7 +57,11 @@
+@@ -56,7 +59,11 @@
    char *s;
    GString *ret;
  
@@ -23,7 +23,7 @@
      ret = new GString(s);
    else
      ret = new GString(".");
-@@ -403,6 +410,7 @@
+@@ -405,6 +412,7 @@
  #endif
  }
  
@@ -31,7 +31,7 @@
  GBool openTempFile(GString **name, FILE **f,
  		   const char *mode, const char *ext) {
  #if defined(_WIN32)
-@@ -517,10 +525,11 @@
+@@ -519,10 +527,11 @@
    return gTrue;
  #endif
  }
@@ -44,41 +44,76 @@
  #else
    return !mkdir(path, mode);
  #endif
-@@ -574,6 +583,8 @@
+@@ -602,6 +611,8 @@
  
  FILE *openFile(const char *path, const char *mode) {
  #if defined(_WIN32)
 +  return fopen(path, mode);
 +#if 0
-   OSVERSIONINFO version;
    wchar_t wPath[_MAX_PATH + 1];
-   char nPath[_MAX_PATH + 1];
-@@ -630,6 +641,7 @@
-     nPath[i] = '\0';
-     return fopen(nPath, mode);
-   }
+   wchar_t wMode[8];
+   int i;
+@@ -613,6 +624,7 @@
+   wMode[i] = (wchar_t)0;
+   readWindowsShortcut(wPath, _MAX_PATH + 1);
+   return _wfopen(wPath, wMode);
 +#endif /* 0 */
  #elif defined(VMS)
    return fopen(path, mode, "ctx=stm");
  #else
-@@ -690,6 +702,7 @@
+@@ -620,6 +632,7 @@
  #endif
  }
  
++#if 0
+ #ifdef _WIN32
+ void readWindowsShortcut(wchar_t *wPath, size_t wPathSize) {
+   size_t n = wcslen(wPath);
+@@ -665,11 +678,11 @@
+   wcscpy(wPath, target);
+ }
+ #endif
++#endif /* 0 */
+ 
+ int makeDir(const char *path, int mode) {
+ #ifdef _WIN32
+-  wchar_t wPath[_MAX_PATH + 1];
+-  return _wmkdir(fileNameToUCS2(path, wPath, sizeof(wPath) / sizeof(wchar_t)));
++  return _mkdir(path);
+ #else
+   return mkdir(path, (mode_t)mode);
+ #endif
+@@ -728,6 +741,7 @@
+ #endif
+ }
+ 
 +#ifndef PDF_PARSER_ONLY
  void fixCommandLine(int *argc, char **argv[]) {
  #ifdef _WIN32
    int argcw;
-@@ -715,3 +728,4 @@
+@@ -753,3 +767,4 @@
    LocalFree(argvw);
  #endif
  }
 +#endif /* !PDF_PARSER_ONLY */
-diff -ur xpdf-4.02/goo/gfile.h xpdf-src/goo/gfile.h
---- xpdf-4.02/goo/gfile.h	Thu Sep 26 04:54:33 2019
-+++ xpdf-src/goo/gfile.h	Sun Sep 29 11:25:19 2019
-@@ -115,6 +115,8 @@
+diff -ur xpdf-4.03/goo/gfile.h xpdf-src/goo/gfile.h
+--- xpdf-4.03/goo/gfile.h	Thu Jan 28 07:23:51 2021
++++ xpdf-src/goo/gfile.h	Mon Feb 01 13:14:50 2021
+@@ -91,12 +91,6 @@
+ // UCS-2 and calls _wfopen().  On other OSes, this simply calls fopen().
+ extern FILE *openFile(const char *path, const char *mode);
  
+-#ifdef _WIN32
+-// If [wPath] is a Windows shortcut (.lnk file), read the target path
+-// and store it back into [wPath].
+-extern void readWindowsShortcut(wchar_t *wPath, size_t wPathSize);
+-#endif
+-
+ // Create a directory.  On Windows, this converts the path from UTF-8
+ // to UCS-2 and calls _wmkdir(), ignoring the mode argument.  On other
+ // OSes, this simply calls mkdir().
+@@ -130,6 +124,8 @@
+ 
  // On Windows, this gets the Unicode command line and converts it to
  // UTF-8.  On other systems, this is a nop.
 +#ifndef PDF_PARSER_ONLY
@@ -86,9 +121,9 @@
 +#endif /* !PDF_PARSER_ONLY */
  
  #endif
-diff -ur xpdf-4.02/xpdf/GlobalParams.cc xpdf-src/xpdf/GlobalParams.cc
---- xpdf-4.02/xpdf/GlobalParams.cc	Thu Sep 26 04:54:33 2019
-+++ xpdf-src/xpdf/GlobalParams.cc	Sun Sep 29 11:32:58 2019
+diff -ur xpdf-4.03/xpdf/GlobalParams.cc xpdf-src/xpdf/GlobalParams.cc
+--- xpdf-4.03/xpdf/GlobalParams.cc	Thu Jan 28 07:23:51 2021
++++ xpdf-src/xpdf/GlobalParams.cc	Mon Feb 01 12:20:24 2021
 @@ -5,6 +5,9 @@
  // Copyright 2001-2003 Glyph & Cog, LLC
  //
@@ -114,7 +149,7 @@
  #endif
  
  #if MULTITHREADED
-@@ -803,6 +810,7 @@
+@@ -787,6 +794,7 @@
    f = NULL;
    fileName = NULL;
    if (cfgFileName && cfgFileName[0]) {
@@ -122,7 +157,7 @@
      fileName = new GString(cfgFileName);
      if (!(f = fopen(fileName->getCString(), "r"))) {
        delete fileName;
-@@ -835,6 +843,7 @@
+@@ -819,6 +827,7 @@
      parseFile(fileName, f);
      delete fileName;
      fclose(f);
@@ -130,7 +165,7 @@
    }
  }
  
-@@ -2265,8 +2274,11 @@
+@@ -2358,8 +2367,11 @@
  				   base14->fontNum,
  				   displayFontTab[i].obliqueFactor));
        } else {
@@ -142,9 +177,9 @@
        }
      }
    }
-diff -ur xpdf-4.02/xpdf/GlobalParams.h xpdf-src/xpdf/GlobalParams.h
---- xpdf-4.02/xpdf/GlobalParams.h	Thu Sep 26 04:54:33 2019
-+++ xpdf-src/xpdf/GlobalParams.h	Sun Sep 29 11:34:12 2019
+diff -ur xpdf-4.03/xpdf/GlobalParams.h xpdf-src/xpdf/GlobalParams.h
+--- xpdf-4.03/xpdf/GlobalParams.h	Thu Jan 28 07:23:51 2021
++++ xpdf-src/xpdf/GlobalParams.h	Mon Feb 01 12:23:07 2021
 @@ -5,6 +5,9 @@
  // Copyright 2001-2003 Glyph & Cog, LLC
  //
@@ -155,7 +190,7 @@
  
  #ifndef GLOBALPARAMS_H
  #define GLOBALPARAMS_H
-@@ -219,7 +222,7 @@
+@@ -237,7 +240,7 @@
  
    // Initialize the global parameters by attempting to read a config
    // file.
@@ -164,11 +199,23 @@
  
    ~GlobalParams();
  
-diff -ur xpdf-4.02/xpdf/PDFDoc.cc xpdf-src/xpdf/PDFDoc.cc
---- xpdf-4.02/xpdf/PDFDoc.cc	Thu Sep 26 04:54:33 2019
-+++ xpdf-src/xpdf/PDFDoc.cc	Sun Sep 29 11:41:09 2019
-@@ -156,20 +156,25 @@
+diff -ur xpdf-4.03/xpdf/PDFDoc.cc xpdf-src/xpdf/PDFDoc.cc
+--- xpdf-4.03/xpdf/PDFDoc.cc	Thu Jan 28 07:23:51 2021
++++ xpdf-src/xpdf/PDFDoc.cc	Mon Feb 01 13:01:20 2021
+@@ -114,6 +114,7 @@
+   ok = setup(ownerPassword, userPassword);
+ }
  
++#if 0
+ #ifdef _WIN32
+ PDFDoc::PDFDoc(wchar_t *fileNameA, int fileNameLen, GString *ownerPassword,
+ 	       GString *userPassword, PDFCore *coreA) {
+@@ -161,23 +162,29 @@
+   ok = setup(ownerPassword, userPassword);
+ }
+ #endif
++#endif /* 0 */
+ 
  PDFDoc::PDFDoc(char *fileNameA, GString *ownerPassword,
  	       GString *userPassword, PDFCore *coreA) {
 +/*
@@ -180,7 +227,7 @@
 +/*
  #ifdef _WIN32
    Unicode u;
-   int n, i, j;
+   int i, j;
  #endif
 +*/
  
@@ -190,10 +237,10 @@
  
  #if defined(_WIN32)
 +#if 0
-   n = 0;
+   wchar_t wPath[MAX_PATH + 1];
    i = 0;
-   while (getUTF8(fileName, &i, &u)) {
-@@ -187,8 +192,11 @@
+   j = 0;
+@@ -197,8 +204,11 @@
    if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) {
      file = _wfopen(fileNameU, wfopenReadMode);
    } else {
@@ -205,7 +252,7 @@
  #elif defined(VMS)
    file = fopen(fileName->getCString(), fopenReadMode, "ctx=stm");
  #else
-@@ -581,6 +589,7 @@
+@@ -603,6 +613,7 @@
    GBool ret;
  
    // NB: _wfopen is only available in NT
@@ -213,7 +260,7 @@
    version.dwOSVersionInfoSize = sizeof(version);
    GetVersionEx(&version);
    if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) {
-@@ -590,12 +599,15 @@
+@@ -612,12 +623,15 @@
      path2w[i] = 0;
      f = _wfopen(path2w, L"wb");
    } else {
@@ -229,10 +276,10 @@
    if (!f) {
      return gFalse;
    }
-diff -ur xpdf-4.02/xpdf/Page.cc xpdf-src/xpdf/Page.cc
---- xpdf-4.02/xpdf/Page.cc	Thu Sep 26 04:54:33 2019
-+++ xpdf-src/xpdf/Page.cc	Sun Sep 29 11:43:12 2019
-@@ -480,9 +480,9 @@
+diff -ur xpdf-4.03/xpdf/Page.cc xpdf-src/xpdf/Page.cc
+--- xpdf-4.03/xpdf/Page.cc	Thu Jan 28 07:23:51 2021
++++ xpdf-src/xpdf/Page.cc	Mon Feb 01 12:31:27 2021
+@@ -485,9 +485,9 @@
    delete links;
  }
  
@@ -243,7 +290,7 @@
    GfxState *state;
    int i;
  
-@@ -499,5 +499,5 @@
+@@ -504,5 +504,5 @@
      ctm[i] = state->getCTM()[i];
    }
    delete state;
@@ -250,26 +297,10 @@
 -}
  #endif
 +}
-diff -ur xpdf-4.02/xpdf/XFAForm.cc xpdf-src/xpdf/XFAForm.cc
---- xpdf-4.02/xpdf/XFAForm.cc	Thu Sep 26 04:54:33 2019
-+++ xpdf-src/xpdf/XFAForm.cc	Sun Sep 29 11:44:10 2019
-@@ -29,8 +29,10 @@
- #include "XFAForm.h"
- 
- #ifdef _WIN32
--#  define strcasecmp stricmp
--#  define strncasecmp strnicmp
-+#  undef strcasecmp
-+#  undef strncasecmp
-+#  define strcasecmp _stricmp
-+#  define strncasecmp _strnicmp
- #endif
- 
- //------------------------------------------------------------------------
-diff -ur xpdf-4.02/xpdf/config.h xpdf-src/xpdf/config.h
---- xpdf-4.02/xpdf/config.h	Thu Sep 26 04:54:33 2019
-+++ xpdf-src/xpdf/config.h	Sun Sep 29 11:45:39 2019
-@@ -78,11 +78,6 @@
+diff -ur xpdf-4.03/xpdf/config.h xpdf-src/xpdf/config.h
+--- xpdf-4.03/xpdf/config.h	Thu Jan 28 07:23:52 2021
++++ xpdf-src/xpdf/config.h	Mon Feb 01 12:34:28 2021
+@@ -80,11 +80,6 @@
  // popen
  //------------------------------------------------------------------------
  

Modified: branches/stable/source/src/libs/xpdf/configure
===================================================================
--- branches/stable/source/src/libs/xpdf/configure	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/configure	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for xpdf (TeX Live) 4.02.
+# Generated by GNU Autoconf 2.69 for xpdf (TeX Live) 4.03.
 #
 # Report bugs to <tex-k at tug.org>.
 #
@@ -580,8 +580,8 @@
 # Identity of this package.
 PACKAGE_NAME='xpdf (TeX Live)'
 PACKAGE_TARNAME='xpdf--tex-live-'
-PACKAGE_VERSION='4.02'
-PACKAGE_STRING='xpdf (TeX Live) 4.02'
+PACKAGE_VERSION='4.03'
+PACKAGE_STRING='xpdf (TeX Live) 4.03'
 PACKAGE_BUGREPORT='tex-k at tug.org'
 PACKAGE_URL=''
 
@@ -1290,7 +1290,7 @@
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures xpdf (TeX Live) 4.02 to adapt to many kinds of systems.
+\`configure' configures xpdf (TeX Live) 4.03 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1356,7 +1356,7 @@
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of xpdf (TeX Live) 4.02:";;
+     short | recursive ) echo "Configuration of xpdf (TeX Live) 4.03:";;
    esac
   cat <<\_ACEOF
 
@@ -1460,7 +1460,7 @@
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-xpdf (TeX Live) configure 4.02
+xpdf (TeX Live) configure 4.03
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1867,7 +1867,7 @@
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by xpdf (TeX Live) $as_me 4.02, which was
+It was created by xpdf (TeX Live) $as_me 4.03, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -3786,7 +3786,7 @@
 
 # Define the identity of the package.
  PACKAGE='xpdf--tex-live-'
- VERSION='4.02'
+ VERSION='4.03'
 
 
 # Some tools Automake needs.
@@ -6699,7 +6699,7 @@
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by xpdf (TeX Live) $as_me 4.02, which was
+This file was extended by xpdf (TeX Live) $as_me 4.03, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -6769,7 +6769,7 @@
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-xpdf (TeX Live) config.status 4.02
+xpdf (TeX Live) config.status 4.03
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 

Modified: branches/stable/source/src/libs/xpdf/version.ac
===================================================================
--- branches/stable/source/src/libs/xpdf/version.ac	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/version.ac	2021-02-15 19:17:20 UTC (rev 845)
@@ -8,4 +8,4 @@
 dnl --------------------------------------------------------
 dnl
 dnl  m4-include this file to define the current xpdf version
-m4_define([xpdf_version], [4.02])
+m4_define([xpdf_version], [4.03])

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/ANNOUNCE
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/ANNOUNCE	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/ANNOUNCE	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,4 +1,4 @@
-Subject: ANNOUNCE: Xpdf 4.02 - a PDF viewer and related tools
+Subject: ANNOUNCE: Xpdf 4.03 - a PDF viewer and related tools
 
 Glyph & Cog, LLC is pleased to announce a new version of Xpdf, the
 open source Portable Document Format (PDF) viewer.  The Xpdf project
@@ -10,19 +10,17 @@
 Unix, Windows, MacOSX, and pretty much any other system with a decent
 C++ compiler.
 
-4.02 is primarily a bug fix release.  There are some new features:
+4.03 is primarily a bug fix release.  There are some new features:
 
-* Pdftohtml now extracts embedded fonts.
+* XpdfReader improvements:
+  - Implemented selection extension via shift-click, and word/line
+    selection via double/triple click.
+  - Added default bindings for ctrl-mousewheel-up/down to zoom in/out.
+  - Added a help menu item that shows all of the key bindings.
 
-* Various user interface tweaks in XpdfReader: added a button to
-  toggle sidebar visibilty, added menu items to toggle the sidebar and
-  toolbar, added the 'initialDisplayMode', 'initialToolbarState', and
-  'initialSelectMode' xpdfrc settings.
+* Various new command line options for pdftotext, pdftohtml, pdftoppm,
+  pdftopng, and xpdf.
 
-* If XpdfReader is already running, double-clicking on a PDF file (or
-  dragging-and-dropping it on the XpdfReader icon) opens the file in a
-  new tab (via the new '-open' command line switch).
-
 See the `CHANGES' file for a complete list of changes.
 
 Source (C++ and C) is available, and it should be fairly easy to

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/CHANGES
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/CHANGES	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/CHANGES	2021-02-15 19:17:20 UTC (rev 845)
@@ -2645,4 +2645,98 @@
 Function objects weren't checking their input/output counts properly.
   [Thanks to Pangu Lab for the bug report.]
 TextPage::findGaps() wasn't checking the x/y min/max values for int
-  overflow.  [Thanks to Taolaw for the bugf report.]
+  overflow.  [Thanks to Taolaw for the bug report.]
+
+4.03 (2021-jan-28)
+------------------
+Implemented selection extension via shift-click, and word/line
+  selection via double/triple click.
+Added default bindings for ctrl-mousewheel-up/down to zoom in/out.
+Added the "-nofonts" option to pdftohtml.
+Added the "simple2" mode to pdftotext.
+Added the "-rot" flag to xpdf, pdftoppm, and pdftopng.
+Added the "-listencodings" flag to pdftotext.
+Added the 'copyLinkTarget' command.
+Added the 'selectionColor' xpdfrc setting.
+Added the 'initialSidebarWidth' xpdfrc setting.
+Added support for @"..." strings in xpdfrc files.  This includes using
+  '%' as an escape character, and also the '${DATADIR}' variable.
+Added a help menu item that shows all of the key bindings.
+Reorganized the gradient shading rasterization code to avoid
+  transparency artifacts between triangles/patches.
+Use interpolation rather than subdivision to rasterize Gouraud
+  triangle shadings.
+Allow escaping (via the \x01 character) in command args, so that "xpdf
+  -open foo(123).pdf" works correctly.
+Extended the damaged file repair code to handle PDF files that use
+  xref streams and object streams.
+Modified pdfinfo to print the encryption algorithm used (if any).
+Handle Windows shortcut (.lnk) files in Xpdf and in the command line
+  tools.
+Display an error dialog when trying to copy text from a protected
+  file.
+Updated all four of the CJK language support packages with the latest
+  Adobe data.
+Modified pdftohtml to draw 'invisible' text over non-horizontal words.
+Catalog.pageLabels wasn't being properly initialized to NULL.  [Thanks
+  to Dhiraj for the bug report.]
+Added a sanity check for JBIG2 symbol width.  [Reported by Marc
+  Schoenefeld.]
+Fixed a bug in the fontconfig calls that was causing Xpdf to crash.
+The Type 3 font cache code wasn't correctly handling the case where a
+  Type 3 char refers to another char in the same T3 font.  [Thanks to
+  Pangu Lab for the bug report.]
+Xpdf was crashing if 'view page labels' was enabled without any
+  document open.  [Thanks to TeamSeri0us for the bug report.]
+The Type 1C-to-Type 1 font converter wasn't checking for
+  divide-by-zero with rational numbers.  [Thanks to TeamSeri0us for
+  the bug report.]
+Fixed a bug in the TrueType font parser - zero-length loca tables
+  weren't handled correctly.  [Thanks to TeamSeri0us for the bug
+  report.]
+Fixed an integer overflow bug in the transparency group setup code.
+  [Thanks to TeamSeri0us for the bug report.]
+Pdfinfo with the "-box" option was crashing on zero-page PDF files.
+  [Thanks to TeamSeri0us for the bug report.]
+The code that caches scaled images wasn't checking the rendering
+  intent.  [Thanks to Martin Muskens at Ergosoft for the bug report.]
+The JBIG2 decoder now checks for gibberish values in various segment
+  headers, but keeps any data decoded prior to that.
+Fixed two bugs in the FoFi code that handles CFF fonts.  [Thanks to
+  dsmic for the bug report.]
+Redesigned the image scaling code, for performance.
+Cleaned up the code that sanity-checks font sizes to avoid trying to
+  allocate too much memory for the font cache.
+Implemented precincts in the JPEG 2000 decoder.
+The page-up/down snapping code was calling TileMap::getPageTopY() with
+  invalid page numbers.  [Thanks to dfandrich for the bug report.]
+Added missing error-checking when parsing an annotation appearance
+  stream's bbox.
+Handled UTF-16 sequences in ToUnicode maps.
+Rewrote the code that draws static XFA forms: combined it with the
+  AcroForm code, to match Adobe's behavior.  Removed the enableXFA
+  xpdfrc setting.
+Check for indirect references in content streams and report an error.
+Doing overprint preview in tiling patterns requires tracking the
+  overprint mask at each pixel.
+Check for "decompression bombs" in Flate and LZW streams.
+The nextPageNoScroll and prevPageNoScroll commands weren't working
+  correctly in continuous mode.
+Disable stroke adjustment when drawing Type 3 characters.
+The "xpdf -open" flag now constructs an absolute path, so it's not
+  dependent on the current directory when xpdf was started.
+Check for infinite loops in Type 1C charstring subroutines.  [Thanks
+  to blbi for the bug report.]
+Fixed an incomplete test for headless CFF files.  [Thanks to Chengbin
+  for the bug report.]
+Tweaked the code that computes segment slope in SplashXPath.cc to
+  avoid problems with extremely small coordinate values.  [Thanks to
+  Chengbin for the bug report.]
+Check for an invalid segment length in PSOutputDev's PFB parse.
+  [Thanks to Chengbin for the bug report.]
+Check for JPEG 2000 segments that are only allowed in the first
+  tile-part of a tile.  [Thanks to Chengbin for the bug report.]
+Check for invalid AcroForm ListBox field top index.  [Thanks to
+  Chengbin for the bug report.]
+Check for invalid mesh shading parameters.  [Thanks to Chengbin for
+  the bug report.]

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/INSTALL
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/INSTALL	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/INSTALL	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,11 +1,11 @@
 Xpdf
 ====
 
-version 4.02
-2019-sep-25
+version 4.03
+2021-jan-28
 
 The Xpdf software and documentation are
-copyright 1996-2019 Glyph & Cog, LLC.
+copyright 1996-2021 Glyph & Cog, LLC.
 
 Email: xpdf at xpdfreader.com
 WWW: http://www.xpdfreader.com/
@@ -115,25 +115,29 @@
     -DSYSTEM_XPDFRC="/etc/xpdfrc"
         Look for a system-wide xpdfrc config file in this directory.
 
-     -DCMAKE_DISABLE_FIND_PACKAGE_Qt4=1
-     -DCMAKE_DISABLE_FIND_PACKAGE_Qt5Widgets=1
+    -DXPDFRC_DATADIR="/usr/share/xpdf"
+        The ${DATADIR} variable in xpdfrc config files will expand to
+        this string.
+
+    -DCMAKE_DISABLE_FIND_PACKAGE_Qt4=1
+    -DCMAKE_DISABLE_FIND_PACKAGE_Qt5Widgets=1
         Do not search for the Qt4/Qt5 libraries.  This will disable
         building the GUI viewer (xpdf).  Cmake will look for a "qmake"
         binary -- make sure the first qmake binary on your executable
         search path matches the desired version of Qt.
 
-     -DCMAKE_C_FLAGS="..."
-     -DCMAKE_CXX_FLAGS="..."
+    -DCMAKE_C_FLAGS="..."
+    -DCMAKE_CXX_FLAGS="..."
         Set additional options to pass to the C and/or C++ compilers.
 
-     -DCMAKE_EXE_LINKER_FLAGS="..."
+    -DCMAKE_EXE_LINKER_FLAGS="..."
         Set additional options to pass to the linker.
 
-     -DCMAKE_INSTALL_BINDIR
+    -DCMAKE_INSTALL_BINDIR
         Set the bin directory, relative to CMAKE_INSTALL_PREFIX
         (typically "bin").
 
-     -DCMAKE_INSTALL_MANDIR
+    -DCMAKE_INSTALL_MANDIR
         Set the man directory, relative to CMAKE_INSTALL_PREFIX
         (typically "man" or "share/man").
 

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/README
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/README	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/README	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,17 +1,17 @@
 Xpdf
 ====
 
-version 4.02
-2019-sep-25
+version 4.03
+2021-jan-28
 
 The Xpdf software and documentation are
-copyright 1996-2019 Glyph & Cog, LLC.
+copyright 1996-2021 Glyph & Cog, LLC.
 
 Email: xpdf at xpdfreader.com
 WWW: http://www.xpdfreader.com/
 
 The PDF data structures, operators, and specification are
-documented in ISO 32000-2:2017.
+documented in ISO 32000-2:2020.
 
 
 What is Xpdf?
@@ -326,8 +326,8 @@
 published spec.]
 
 ISO, International Standard -- Document Management - Portable document
-format - Part 2: PDF 2.0.  ISO 32000-2:2017.
-[The manual for PDF version 2.0.]
+format - Part 2: PDF 2.0.  ISO 32000-2:2020.
+[The specification for PDF version 2.0.]
 
 ITU, "Standardization of Group 3 facsimile terminals for document
 transmission", ITU-T Recommendation T.4, 1999.

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/cmake-config.txt
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/cmake-config.txt	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/cmake-config.txt	2021-02-15 19:17:20 UTC (rev 845)
@@ -8,6 +8,17 @@
 #
 #========================================================================
 
+if (POLICY CMP0074)
+  cmake_policy(SET CMP0074 NEW)
+endif ()
+
+if (APPLE)
+  if (POLICY CMP0042)
+    cmake_policy(SET CMP0042 NEW)
+  endif ()
+  set(CMAKE_MACOSX_RPATH 1)
+endif ()
+
 include(CheckFunctionExists)
 include(CheckCXXSourceCompiles)
 include(GNUInstallDirs)
@@ -41,12 +52,12 @@
     CMAKE_CXX_FLAGS_PROFILING
     CMAKE_EXE_LINKER_FLAGS_PROFILING)
   set(CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}" CACHE STRING
-      "Choose build mode - options are: None Debug Release RelWithDebInfo MinSiz
-eRel Profiling")
+      "Choose build mode - options are: None Debug Release RelWithDebInfo MinSizeRel Profiling")
 endif ()
 
 #--- set default C/C++ compiler flags for Windows
 if (WIN32)
+  option(USE_MT_IN_DEBUG "use /MT instead of /MTd in debug builds" OFF)
   foreach (var CMAKE_C_FLAGS_DEBUG CMAKE_CXX_FLAGS_DEBUG
                CMAKE_C_FLAGS_RELEASE CMAKE_CXX_FLAGS_RELEASE
                CMAKE_C_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_MINSIZEREL
@@ -54,8 +65,13 @@
     # note: this converts /MD to /MT and /MDd to /MTd
     string(REGEX REPLACE "/MD" "/MT" ${var} "${${var}}")
   endforeach ()
-  set(CMAKE_EXE_LINKER_FLAGS_DEBUG "/NODEFAULTLIB:libcmt ${CMAKE_EXE_LINKER_FLAGS_DEBUG}")
-  set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "/NODEFAULTLIB:libcmt ${CMAKE_SHARED_LINKER_FLAGS_DEBUG}")
+  if (USE_MT_IN_DEBUG)
+    string(REPLACE "/MTd" "/MT" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
+    string(REPLACE "/MTd" "/MT" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
+  else ()
+    set(CMAKE_EXE_LINKER_FLAGS_DEBUG "/NODEFAULTLIB:libcmt ${CMAKE_EXE_LINKER_FLAGS_DEBUG}")
+    set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "/NODEFAULTLIB:libcmt ${CMAKE_SHARED_LINKER_FLAGS_DEBUG}")
+  endif ()
   foreach (var CMAKE_C_FLAGS_DEBUG
                CMAKE_C_FLAGS_RELEASE
                CMAKE_C_FLAGS_MINSIZEREL
@@ -88,6 +104,12 @@
 else ()
   set(SYSTEM_XPDFRC_DEFINE "/* #undef SYSTEM_XPDFRC */")
 endif ()
+option(XPDFRC_DATADIR "directory to use for the DATADIR xpdfrc variable" "")
+if (XPDFRC_DATADIR)
+  set(XPDFRC_DATADIR_DEFINE "#define XPDFRC_DATADIR \"${XPDFRC_DATADIR}\"")
+else ()
+  set(XPDFRC_DATADIR_DEFINE "/* #undef SYSTEM_XPDFRC */")
+endif ()
 if (WIN32)
   option(XPDFWIDGET_PRINTING "include printing support in XpdfWidget" OFF)
 else ()
@@ -194,7 +216,7 @@
   find_package(Qt5Network)
   find_package(Qt5PrintSupport)
 else ()
-  find_package(Qt4 COMPONENTS QtCore QtGui QtNetwork REQUIRED)
+  find_package(Qt4 COMPONENTS QtCore QtGui QtNetwork)
 endif ()
 if(Qt5Widgets_FOUND)
   message(STATUS "Qt5 found")

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdfdetach.1
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdfdetach.1	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdfdetach.1	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,8 +1,8 @@
-.\" Copyright 2013-2019 Glyph & Cog, LLC
-.TH pdfdetach 1 "25 Sep 2019"
+.\" Copyright 2013-2021 Glyph & Cog, LLC
+.TH pdfdetach 1 "28 Jan 2021"
 .SH NAME
 pdfdetach \- Portable Document Format (PDF) document embedded file
-extractor (version 4.02)
+extractor (version 4.03)
 .SH SYNOPSIS
 .B pdfdetach
 [options]
@@ -90,7 +90,7 @@
 99
 Other error.
 .SH AUTHOR
-The pdfinfo software and documentation are copyright 1996-2019 Glyph &
+The pdfinfo software and documentation are copyright 1996-2021 Glyph &
 Cog, LLC.
 .SH "SEE ALSO"
 .BR xpdf (1),

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdfdetach.cat
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdfdetach.cat	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdfdetach.cat	2021-02-15 19:17:20 UTC (rev 845)
@@ -4,7 +4,7 @@
 
 NAME
        pdfdetach  -  Portable  Document  Format  (PDF)  document embedded file
-       extractor (version 4.02)
+       extractor (version 4.03)
 
 SYNOPSIS
        pdfdetach [options] [PDF-file]
@@ -79,7 +79,7 @@
        99     Other error.
 
 AUTHOR
-       The pdfinfo software and documentation are copyright 1996-2019 Glyph  &
+       The pdfinfo software and documentation are copyright 1996-2021 Glyph  &
        Cog, LLC.
 
 SEE ALSO
@@ -89,4 +89,4 @@
 
 
 
-                                  25 Sep 2019                     pdfdetach(1)
+                                  28 Jan 2021                     pdfdetach(1)

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdffonts.1
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdffonts.1	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdffonts.1	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,8 +1,8 @@
-.\" Copyright 1999-2019 Glyph & Cog, LLC
-.TH pdffonts 1 "25 Sep 2019"
+.\" Copyright 1999-2021 Glyph & Cog, LLC
+.TH pdffonts 1 "28 Jan 2021"
 .SH NAME
 pdffonts \- Portable Document Format (PDF) font analyzer (version
-4.02)
+4.03)
 .SH SYNOPSIS
 .B pdffonts
 [options]
@@ -147,7 +147,7 @@
 99
 Other error.
 .SH AUTHOR
-The pdffonts software and documentation are copyright 1996-2019 Glyph
+The pdffonts software and documentation are copyright 1996-2021 Glyph
 & Cog, LLC.
 .SH "SEE ALSO"
 .BR xpdf (1),

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdffonts.cat
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdffonts.cat	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdffonts.cat	2021-02-15 19:17:20 UTC (rev 845)
@@ -3,7 +3,7 @@
 
 
 NAME
-       pdffonts - Portable Document Format (PDF) font analyzer (version 4.02)
+       pdffonts - Portable Document Format (PDF) font analyzer (version 4.03)
 
 SYNOPSIS
        pdffonts [options] [PDF-file]
@@ -105,7 +105,7 @@
        99     Other error.
 
 AUTHOR
-       The pdffonts software and documentation are copyright 1996-2019 Glyph &
+       The pdffonts software and documentation are copyright 1996-2021 Glyph &
        Cog, LLC.
 
 SEE ALSO
@@ -115,4 +115,4 @@
 
 
 
-                                  25 Sep 2019                      pdffonts(1)
+                                  28 Jan 2021                      pdffonts(1)

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdfimages.1
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdfimages.1	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdfimages.1	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,8 +1,8 @@
-.\" Copyright 1998-2019 Glyph & Cog, LLC
-.TH pdfimages 1 "25 Sep 2019"
+.\" Copyright 1998-2021 Glyph & Cog, LLC
+.TH pdfimages 1 "28 Jan 2021"
 .SH NAME
 pdfimages \- Portable Document Format (PDF) image extractor
-(version 4.02)
+(version 4.03)
 .SH SYNOPSIS
 .B pdfimages
 [options]
@@ -102,7 +102,7 @@
 99
 Other error.
 .SH AUTHOR
-The pdfimages software and documentation are copyright 1998-2019 Glyph
+The pdfimages software and documentation are copyright 1998-2021 Glyph
 & Cog, LLC.
 .SH "SEE ALSO"
 .BR xpdf (1),

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdfimages.cat
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdfimages.cat	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdfimages.cat	2021-02-15 19:17:20 UTC (rev 845)
@@ -4,7 +4,7 @@
 
 NAME
        pdfimages  -  Portable  Document  Format (PDF) image extractor (version
-       4.02)
+       4.03)
 
 SYNOPSIS
        pdfimages [options] PDF-file image-root
@@ -85,7 +85,7 @@
        99     Other error.
 
 AUTHOR
-       The  pdfimages software and documentation are copyright 1998-2019 Glyph
+       The  pdfimages software and documentation are copyright 1998-2021 Glyph
        & Cog, LLC.
 
 SEE ALSO
@@ -95,4 +95,4 @@
 
 
 
-                                  25 Sep 2019                     pdfimages(1)
+                                  28 Jan 2021                     pdfimages(1)

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdfinfo.1
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdfinfo.1	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdfinfo.1	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,8 +1,8 @@
-.\" Copyright 1999-2019 Glyph & Cog, LLC
-.TH pdfinfo 1 "25 Sep 2019"
+.\" Copyright 1999-2021 Glyph & Cog, LLC
+.TH pdfinfo 1 "28 Jan 2021"
 .SH NAME
 pdfinfo \- Portable Document Format (PDF) document information
-extractor (version 4.02)
+extractor (version 4.03)
 .SH SYNOPSIS
 .B pdfinfo
 [options]
@@ -150,7 +150,7 @@
 99
 Other error.
 .SH AUTHOR
-The pdfinfo software and documentation are copyright 1996-2019 Glyph &
+The pdfinfo software and documentation are copyright 1996-2021 Glyph &
 Cog, LLC.
 .SH "SEE ALSO"
 .BR xpdf (1),

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdfinfo.cat
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdfinfo.cat	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdfinfo.cat	2021-02-15 19:17:20 UTC (rev 845)
@@ -4,7 +4,7 @@
 
 NAME
        pdfinfo - Portable Document Format (PDF) document information extractor
-       (version 4.02)
+       (version 4.03)
 
 SYNOPSIS
        pdfinfo [options] [PDF-file]
@@ -104,7 +104,7 @@
        99     Other error.
 
 AUTHOR
-       The  pdfinfo software and documentation are copyright 1996-2019 Glyph &
+       The  pdfinfo software and documentation are copyright 1996-2021 Glyph &
        Cog, LLC.
 
 SEE ALSO
@@ -114,4 +114,4 @@
 
 
 
-                                  25 Sep 2019                       pdfinfo(1)
+                                  28 Jan 2021                       pdfinfo(1)

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftohtml.1
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftohtml.1	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftohtml.1	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,8 +1,8 @@
-.\" Copyright 1997-2019 Glyph & Cog, LLC
-.TH pdftohtml 1 "25 Sep 2019"
+.\" Copyright 1997-2021 Glyph & Cog, LLC
+.TH pdftohtml 1 "28 Jan 2021"
 .SH NAME
 pdftohtml \- Portable Document Format (PDF) to HTML converter
-(version 4.02)
+(version 4.03)
 .SH SYNOPSIS
 .B pdftohtml
 [options]
@@ -50,6 +50,11 @@
 \'-r' value will allow the viewer to zoom in farther without upscaling
 artifacts in the background.
 .TP
+.B \-nofonts
+Disable extraction of embedded fonts.  By default, pdftohtml extracts
+TrueType and OpenType fonts.  Disabling extraction can work around
+problems with buggy fonts.
+.TP
 .B \-skipinvisible
 Don't draw invisible text.  By default, invisible text (commonly used
 in OCR'ed PDF files) is drawn as transparent (alpha=0) HTML text.
@@ -109,7 +114,7 @@
 99
 Other error.
 .SH AUTHOR
-The pdftohtml software and documentation are copyright 1996-2019 Glyph
+The pdftohtml software and documentation are copyright 1996-2021 Glyph
 & Cog, LLC.
 .SH "SEE ALSO"
 .BR xpdf (1),

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftohtml.cat
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftohtml.cat	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftohtml.cat	2021-02-15 19:17:20 UTC (rev 845)
@@ -4,7 +4,7 @@
 
 NAME
        pdftohtml  -  Portable Document Format (PDF) to HTML converter (version
-       4.02)
+       4.03)
 
 SYNOPSIS
        pdftohtml [options] PDF-file HTML-dir
@@ -48,6 +48,11 @@
               larger '-r' value will allow the viewer to zoom in farther with-
               out upscaling artifacts in the background.
 
+       -nofonts
+              Disable extraction of embedded  fonts.   By  default,  pdftohtml
+              extracts  TrueType and OpenType fonts.  Disabling extraction can
+              work around problems with buggy fonts.
+
        -skipinvisible
               Don't draw invisible text.  By default, invisible text (commonly
               used in OCR'ed PDF files) is drawn as transparent (alpha=0) HTML
@@ -97,7 +102,7 @@
        99     Other error.
 
 AUTHOR
-       The  pdftohtml software and documentation are copyright 1996-2019 Glyph
+       The  pdftohtml software and documentation are copyright 1996-2021 Glyph
        & Cog, LLC.
 
 SEE ALSO
@@ -107,4 +112,4 @@
 
 
 
-                                  25 Sep 2019                     pdftohtml(1)
+                                  28 Jan 2021                     pdftohtml(1)

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftopng.1
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftopng.1	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftopng.1	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,8 +1,8 @@
-.\" Copyright 2017-2019 Glyph & Cog, LLC
-.TH pdftopng 1 "25 Sep 2019"
+.\" Copyright 2017-2021 Glyph & Cog, LLC
+.TH pdftopng 1 "28 Jan 2021"
 .SH NAME
 pdftopng \- Portable Document Format (PDF) to Portable Network Graphics
-(PNG) converter (version 4.02)
+(PNG) converter (version 4.03)
 .SH SYNOPSIS
 .B pdftopng
 [options]
@@ -56,6 +56,9 @@
 PDF files that have been constructed with a transparent background.
 The \-alpha flag cannot be used with \-mono.
 .TP
+.BI \-rot " angle"
+Rotate pages by 0 (the default), 90, 180, or 270 degrees.
+.TP
 .BI \-freetype " yes | no"
 Enable or disable FreeType (a TrueType / Type 1 font rasterizer).
 This defaults to "yes".
@@ -107,7 +110,7 @@
 99
 Other error.
 .SH AUTHOR
-The pdftopng software and documentation are copyright 1996-2019 Glyph
+The pdftopng software and documentation are copyright 1996-2021 Glyph
 & Cog, LLC.
 .SH "SEE ALSO"
 .BR xpdf (1),

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftopng.cat
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftopng.cat	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftopng.cat	2021-02-15 19:17:20 UTC (rev 845)
@@ -4,7 +4,7 @@
 
 NAME
        pdftopng  - Portable Document Format (PDF) to Portable Network Graphics
-       (PNG) converter (version 4.02)
+       (PNG) converter (version 4.03)
 
 SYNOPSIS
        pdftopng [options] PDF-file PNG-root
@@ -48,6 +48,9 @@
               with PDF files that have been  constructed  with  a  transparent
               background.  The -alpha flag cannot be used with -mono.
 
+       -rot angle
+              Rotate pages by 0 (the default), 90, 180, or 270 degrees.
+
        -freetype yes | no
               Enable  or  disable  FreeType  (a TrueType / Type 1 font raster-
               izer).  This defaults to "yes".  [config file: enableFreeType]
@@ -87,7 +90,7 @@
        99     Other error.
 
 AUTHOR
-       The pdftopng software and documentation are copyright 1996-2019 Glyph &
+       The pdftopng software and documentation are copyright 1996-2021 Glyph &
        Cog, LLC.
 
 SEE ALSO
@@ -97,4 +100,4 @@
 
 
 
-                                  25 Sep 2019                      pdftopng(1)
+                                  28 Jan 2021                      pdftopng(1)

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftoppm.1
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftoppm.1	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftoppm.1	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,8 +1,8 @@
-.\" Copyright 2005-2019 Glyph & Cog, LLC
-.TH pdftoppm 1 "25 Sep 2019"
+.\" Copyright 2005-2021 Glyph & Cog, LLC
+.TH pdftoppm 1 "28 Jan 2021"
 .SH NAME
 pdftoppm \- Portable Document Format (PDF) to Portable Pixmap (PPM)
-converter (version 4.02)
+converter (version 4.03)
 .SH SYNOPSIS
 .B pdftoppm
 [options]
@@ -56,6 +56,9 @@
 .B \-cmyk
 Generate a CMYK PAM file (instead of an RGB PPM file).
 .TP
+.BI \-rot " angle"
+Rotate pages by 0 (the default), 90, 180, or 270 degrees.
+.TP
 .BI \-freetype " yes | no"
 Enable or disable FreeType (a TrueType / Type 1 font rasterizer).
 This defaults to "yes".
@@ -107,7 +110,7 @@
 99
 Other error.
 .SH AUTHOR
-The pdftoppm software and documentation are copyright 1996-2019 Glyph
+The pdftoppm software and documentation are copyright 1996-2021 Glyph
 & Cog, LLC.
 .SH "SEE ALSO"
 .BR xpdf (1),

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftoppm.cat
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftoppm.cat	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftoppm.cat	2021-02-15 19:17:20 UTC (rev 845)
@@ -4,7 +4,7 @@
 
 NAME
        pdftoppm - Portable Document Format (PDF) to Portable Pixmap (PPM) con-
-       verter (version 4.02)
+       verter (version 4.03)
 
 SYNOPSIS
        pdftoppm [options] PDF-file PPM-root
@@ -47,6 +47,9 @@
 
        -cmyk  Generate a CMYK PAM file (instead of an RGB PPM file).
 
+       -rot angle
+              Rotate pages by 0 (the default), 90, 180, or 270 degrees.
+
        -freetype yes | no
               Enable or disable FreeType (a TrueType /  Type  1  font  raster-
               izer).  This defaults to "yes".  [config file: enableFreeType]
@@ -86,7 +89,7 @@
        99     Other error.
 
 AUTHOR
-       The pdftoppm software and documentation are copyright 1996-2019 Glyph &
+       The pdftoppm software and documentation are copyright 1996-2021 Glyph &
        Cog, LLC.
 
 SEE ALSO
@@ -96,4 +99,4 @@
 
 
 
-                                  25 Sep 2019                      pdftoppm(1)
+                                  28 Jan 2021                      pdftoppm(1)

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftops.1
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftops.1	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftops.1	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,8 +1,8 @@
-.\" Copyright 1996-2019 Glyph & Cog, LLC
-.TH pdftops 1 "25 Sep 2019"
+.\" Copyright 1996-2021 Glyph & Cog, LLC
+.TH pdftops 1 "28 Jan 2021"
 .SH NAME
 pdftops \- Portable Document Format (PDF) to PostScript converter
-(version 4.02)
+(version 4.03)
 .SH SYNOPSIS
 .B pdftops
 [options]
@@ -51,7 +51,7 @@
 significantly larger (if they contain images), but will print on Level
 1 printers.  This also converts all images to black and white.  No
 more than one of the PostScript level options (\-level1, \-level1sep,
-\-level2, \-level2sep, \-level3, \-level3Sep) may be given.
+\-level2, \-level2sep, \-level3, \-level3sep) may be given.
 .RB "[config file: " psLevel ]
 .TP
 .B \-level1sep
@@ -86,9 +86,9 @@
 are converted to grayscale.
 .RB "[config file: " psLevel ]
 .TP
-.B \-level3Sep
+.B \-level3sep
 Generate Level 3 separable PostScript.  The separation handling is the
-same as for \-level2Sep.
+same as for \-level2sep.
 .RB "[config file: " psLevel ]
 .TP
 .B \-eps
@@ -236,7 +236,7 @@
 99
 Other error.
 .SH AUTHOR
-The pdftops software and documentation are copyright 1996-2019 Glyph &
+The pdftops software and documentation are copyright 1996-2021 Glyph &
 Cog, LLC.
 .SH "SEE ALSO"
 .BR xpdf (1),

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftops.cat
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftops.cat	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftops.cat	2021-02-15 19:17:20 UTC (rev 845)
@@ -4,7 +4,7 @@
 
 NAME
        pdftops  - Portable Document Format (PDF) to PostScript converter (ver-
-       sion 4.02)
+       sion 4.03)
 
 SYNOPSIS
        pdftops [options] [PDF-file [PS-file]]
@@ -42,7 +42,7 @@
               print on Level 1 printers.  This also  converts  all  images  to
               black  and  white.   No  more  than  one of the PostScript level
               options  (-level1,  -level1sep,  -level2,  -level2sep,  -level3,
-              -level3Sep) may be given.  [config file: psLevel]
+              -level3sep) may be given.  [config file: psLevel]
 
        -level1sep
               Generate Level 1 separable PostScript.  All colors are converted
@@ -72,9 +72,9 @@
               Generate grayscale Level 3 PostScript.   All  colors,  including
               images, are converted to grayscale.  [config file: psLevel]
 
-       -level3Sep
+       -level3sep
               Generate  Level 3 separable PostScript.  The separation handling
-              is the same as for -level2Sep.  [config file: psLevel]
+              is the same as for -level2sep.  [config file: psLevel]
 
        -eps   Generate an Encapsulated PostScript (EPS)  file.   An  EPS  file
               contains a single image, so if you use this option with a multi-
@@ -201,7 +201,7 @@
        99     Other error.
 
 AUTHOR
-       The  pdftops software and documentation are copyright 1996-2019 Glyph &
+       The  pdftops software and documentation are copyright 1996-2021 Glyph &
        Cog, LLC.
 
 SEE ALSO
@@ -211,4 +211,4 @@
 
 
 
-                                  25 Sep 2019                       pdftops(1)
+                                  28 Jan 2021                       pdftops(1)

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftotext.1
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftotext.1	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftotext.1	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,8 +1,8 @@
-.\" Copyright 1997-2019 Glyph & Cog, LLC
-.TH pdftotext 1 "25 Sep 2019"
+.\" Copyright 1997-2021 Glyph & Cog, LLC
+.TH pdftotext 1 "28 Jan 2021"
 .SH NAME
 pdftotext \- Portable Document Format (PDF) to text converter
-(version 4.02)
+(version 4.03)
 .SH SYNOPSIS
 .B pdftotext
 [options]
@@ -59,6 +59,12 @@
 job of maintaining horizontal spacing, but it will only work properly
 with a single column of text.
 .TP
+.B \-simple2
+Similar to
+.BR \-simple ,
+but handles slightly rotated text (e.g., OCR output) better.  Only works
+for pages with a single column of text.
+.TP
 .B \-table
 Table mode is similar to physical layout mode, but optimized for
 tabular data, with the goal of keeping rows and columns aligned (at
@@ -161,11 +167,14 @@
 .I config-file
 in place of ~/.xpdfrc or the system-wide config file.
 .TP
+.B \-listencodings
+List all available text output encodings, then exit.
+.TP
 .B \-v
-Print copyright and version information.
+Print copyright and version information, then exit.
 .TP
 .B \-h
-Print usage information.
+Print usage information, then exit.
 .RB ( \-help
 and
 .B \-\-help
@@ -192,7 +201,7 @@
 99
 Other error.
 .SH AUTHOR
-The pdftotext software and documentation are copyright 1996-2019 Glyph
+The pdftotext software and documentation are copyright 1996-2021 Glyph
 & Cog, LLC.
 .SH "SEE ALSO"
 .BR xpdf (1),

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftotext.cat
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftotext.cat	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/doc/pdftotext.cat	2021-02-15 19:17:20 UTC (rev 845)
@@ -4,7 +4,7 @@
 
 NAME
        pdftotext  -  Portable Document Format (PDF) to text converter (version
-       4.02)
+       4.03)
 
 SYNOPSIS
        pdftotext [options] [PDF-file [text-file]]
@@ -47,6 +47,11 @@
               ing, but it will only work properly  with  a  single  column  of
               text.
 
+       -simple2
+              Similar to -simple, but handles slightly rotated text (e.g., OCR
+              output) better.  Only works for pages with a  single  column  of
+              text.
+
        -table Table mode is similar to physical layout mode, but optimized for
               tabular data, with the goal of keeping rows and columns  aligned
               (at  the  expense of inserting extra whitespace).  If the -fixed
@@ -135,12 +140,16 @@
               Read config-file in place of ~/.xpdfrc or the system-wide config
               file.
 
-       -v     Print copyright and version information.
+       -listencodings
+              List all available text output encodings, then exit.
 
-       -h     Print usage information.  (-help and --help are equivalent.)
+       -v     Print copyright and version information, then exit.
 
+       -h     Print  usage  information,  then  exit.   (-help  and --help are
+              equivalent.)
+
 BUGS
-       Some  PDF  files contain fonts whose encodings have been mangled beyond
+       Some PDF files contain fonts whose encodings have been  mangled  beyond
        recognition.  There is no way (short of OCR) to extract text from these
        files.
 
@@ -158,7 +167,7 @@
        99     Other error.
 
 AUTHOR
-       The  pdftotext software and documentation are copyright 1996-2019 Glyph
+       The pdftotext software and documentation are copyright 1996-2021  Glyph
        & Cog, LLC.
 
 SEE ALSO
@@ -168,4 +177,4 @@
 
 
 
-                                  25 Sep 2019                     pdftotext(1)
+                                  28 Jan 2021                     pdftotext(1)

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/doc/xpdf.1
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/doc/xpdf.1	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/doc/xpdf.1	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,7 +1,7 @@
-.\" Copyright 1996-2019 Glyph & Cog, LLC
-.TH xpdf 1 "25 Sep 2019"
+.\" Copyright 1996-2021 Glyph & Cog, LLC
+.TH xpdf 1 "28 Jan 2021"
 .SH NAME
-xpdf \- Portable Document Format (PDF) file viewer (version 4.02)
+xpdf \- Portable Document Format (PDF) file viewer (version 4.03)
 .SH SYNOPSIS
 .B xpdf
 [options]
@@ -118,6 +118,9 @@
 width.
 .RB "[config file: " initialZoom ]
 .TP
+.BI \-rot " angle"
+Rotate pages by 0 (the default), 90, 180, or 270 degrees.
+.TP
 .BI \-aa " yes | no"
 Enable or disable font anti-aliasing.  This defaults to "yes".
 .RB "[config file: " antialias ]
@@ -152,6 +155,10 @@
 Print commands as they're executed (useful for debugging).
 .RB "[config file: " printCommands ]
 .TP
+.BI \-tabstate " tabstate-file"
+Sets the file used by the loadTabState and saveTabState commands.
+.RB "[config file: " tabStateFile ]
+.TP
 .BI \-cfg " config-file"
 Read
 .I config-file
@@ -240,11 +247,19 @@
 attachments.
 .PP
 .SS Text selection
-Dragging the mouse with the left button held down will highlight an
-arbitrary rectangle.  Selected text can be copied to the clipboard
-(with the edit/copy menu item).  On X11, selected text will be
-available in the X selection buffer.
+In block selection mode, dragging the mouse with the left button held
+down will highlight an arbitrary rectangle.  Shift-clicking will
+extend the selection.
 .PP
+In linear selection mode, dragging with the left button will highlight
+text in reading order.  Double-clicking or triple-clicking will select
+a word or a line, respectively.  Shift-clicking will extend the
+selection.
+.PP
+Selected text can be copied to the clipboard (with the edit/copy menu
+item).  On X11, selected text will be available in the X selection
+buffer.
+.PP
 .SS Links
 When the mouse is over a hyperlink, the link target will be shown in a
 popup near the bottom of the window.
@@ -400,6 +415,12 @@
 The bind command allows you to bind a key or mouse button to a
 sequence of one or more commands.
 .PP
+In commands that take arguments (inside parentheses), special
+characters (namely '(', ')', ',', and '\\x01') can be escaped by
+preceding them with a '\\x01' character.  This is mostly useful in
+things like scripts that need to be able to open arbitrary PDF files,
+using the \'openFile' command.
+.PP
 The following commands are supported:
 .TP
 .B about
@@ -452,6 +473,9 @@
 .B copy
 Copy selected text to the clipboard.
 .TP
+.B copyLinkTarget
+Copy the target of the link under the mouse cursor to the clipboard.
+.TP
 .B endPan
 End a pan operation.
 .TP
@@ -626,6 +650,9 @@
 .B quit
 Quit from xpdf.
 .TP
+.B raise
+Bring the xpdf window to the front.
+.TP
 .B reload
 Reload the current PDF file.
 .TP
@@ -751,9 +778,18 @@
 .I n
 pixels, moving to the previous page if appropriate.
 .TP
+.B selectLine
+Set the selection to the line at the current mouse position.
+.TP
+.B selectWord
+Set the selection to the word at the current mouse position.
+.TP
 .BI setSelection( pg , ulx , uly , lrx , lry )
 Set the selection to the specified coordinates on the specified page.
 .TP
+.B showKeyBindings
+Open the key bindings dialog.
+.TP
 .B showToolbar
 Show the toolbar.
 .TP
@@ -772,6 +808,10 @@
 .B singlePageMode
 Switch to single-page view mode.
 .TP
+.B startExtendedSelection
+Extend the selection to the current mouse position, and continue
+extending as the mouse moves.
+.TP
 .B startPan
 Start a pan operation at the current mouse position, which will scroll
 the document as the mouse moves.
@@ -868,7 +908,7 @@
 99
 Other error.
 .SH AUTHOR
-The xpdf software and documentation are copyright 1996-2019 Glyph &
+The xpdf software and documentation are copyright 1996-2021 Glyph &
 Cog, LLC.
 .SH "SEE ALSO"
 .BR pdftops (1),

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/doc/xpdf.cat
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/doc/xpdf.cat	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/doc/xpdf.cat	2021-02-15 19:17:20 UTC (rev 845)
@@ -3,7 +3,7 @@
 
 
 NAME
-       xpdf - Portable Document Format (PDF) file viewer (version 4.02)
+       xpdf - Portable Document Format (PDF) file viewer (version 4.03)
 
 SYNOPSIS
        xpdf [options] [PDF-file [:page | +dest]] ...
@@ -98,6 +98,9 @@
               fit the page to the window size, or 'width',  to  fit  the  page
               width to the window width.  [config file: initialZoom]
 
+       -rot angle
+              Rotate pages by 0 (the default), 90, 180, or 270 degrees.
+
        -aa yes | no
               Enable  or  disable font anti-aliasing.  This defaults to "yes".
               [config file: antialias]
@@ -130,6 +133,10 @@
        -cmd   Print  commands  as  they're  executed  (useful  for debugging).
               [config file: printCommands]
 
+       -tabstate tabstate-file
+              Sets the file used by the  loadTabState  and  saveTabState  com-
+              mands.  [config file: tabStateFile]
+
        -cfg config-file
               Read config-file in place of ~/.xpdfrc or the system-wide config
               file.
@@ -144,18 +151,18 @@
               Toggles (i.e., shows or hides) the sidebar.
 
        status indicator
-              This  icon is animated while Xpdf is rendering a page.  It turns
-              red when an error or warning has been issued.   Clicking  on  it
+              This icon is animated while Xpdf is rendering a page.  It  turns
+              red  when  an  error or warning has been issued.  Clicking on it
               opens the error dialog.
 
        selection mode
-              This  icon is an "I-beam" in linear selection mode, and an arrow
+              This icon is an "I-beam" in linear selection mode, and an  arrow
               in block selection mode.  Clicking on it toggles between the two
               selection modes.
 
        page number entry box
-              Move  to  a  specific page number.  Click in the box to activate
-              it, type the page number, then hit return.   This  will  instead
+              Move to a specific page number.  Click in the  box  to  activate
+              it,  type  the  page number, then hit return.  This will instead
               display and accept page labels, if the "view - page labels" menu
               item is checked.
 
@@ -166,11 +173,11 @@
               Zoom out or in (i.e., change magnification) incrementally.
 
        zoom popup menu
-              Change the zoom factor (see the description  of  the  -z  option
+              Change  the  zoom  factor  (see the description of the -z option
               above).
 
        fit width button
-              Change  the  zoom  factor  to  fit  the page width to the window
+              Change the zoom factor to fit  the  page  width  to  the  window
               width.
 
        fit page button
@@ -177,7 +184,7 @@
               Change the zoom factor to fit the page to the window size.
 
        find entry box
-              Find a text string.  Click in the box to  activate  it,  type  a
+              Find  a  text  string.   Click in the box to activate it, type a
               search string, then hit return.
 
        find next button
@@ -191,7 +198,7 @@
               whole words (on/off).
 
    Menu bar
-       The menu bar is above the toolbar.  The  menu  items  should  be  self-
+       The  menu  bar  is  above  the toolbar.  The menu items should be self-
        explanatory.
 
    Tab list
@@ -199,33 +206,41 @@
        tabs.
 
    Outline/layers/attachments pane
-       This pane is on the left, below the tab list.  The popup allows you  to
+       This  pane is on the left, below the tab list.  The popup allows you to
        select from outline, layers, or attachments.
 
-       The  outline  is  a tree-like structure of bookmarks that allows moving
+       The outline is a tree-like structure of bookmarks  that  allows  moving
        within the PDF file.  Not all PDF files have outlines.
 
-       Layers (a.k.a. optional content) allow parts of the PDF content  to  be
+       Layers  (a.k.a.  optional content) allow parts of the PDF content to be
        shown or hidden.  Not all PDF files have layers.
 
-       Attachments  are  other files embedded within the PDF file.  There is a
-       'save' button for each attached file.  Not all PDF files  have  attach-
+       Attachments are other files embedded within the PDF file.  There  is  a
+       'save'  button  for each attached file.  Not all PDF files have attach-
        ments.
 
    Text selection
-       Dragging  the  mouse  with  the left button held down will highlight an
-       arbitrary rectangle.  Selected text can  be  copied  to  the  clipboard
-       (with  the  edit/copy menu item).  On X11, selected text will be avail-
-       able in the X selection buffer.
+       In block selection mode, dragging the mouse with the left  button  held
+       down will highlight an arbitrary rectangle.  Shift-clicking will extend
+       the selection.
 
+       In linear selection mode, dragging with the left button will  highlight
+       text  in reading order.  Double-clicking or triple-clicking will select
+       a word or a line, respectively.  Shift-clicking will extend the  selec-
+       tion.
+
+       Selected  text  can be copied to the clipboard (with the edit/copy menu
+       item).  On X11, selected text will be available in the X selection buf-
+       fer.
+
    Links
-       When the mouse is over a hyperlink, the link target will be shown in  a
+       When  the mouse is over a hyperlink, the link target will be shown in a
        popup near the bottom of the window.
 
        Clicking on a hyperlink will jump to the link's destination.  A link to
-       another PDF document will make xpdf load  that  document.   A  'launch'
-       link  to  an executable program will display a dialog, and if you click
-       'ok', execute the program.  URL links are opened in a  system-dependent
+       another  PDF  document  will  make xpdf load that document.  A 'launch'
+       link to an executable program will display a dialog, and if  you  click
+       'ok',  execute the program.  URL links are opened in a system-dependent
        way.  (On UNIX, Qt uses the $BROWSER environment variable.)
 
    Mouse bindings
@@ -235,11 +250,11 @@
 
        Dragging the mouse with the middle button held down pans the window.
 
-       The  right  mouse  button  opens  a  popup  menu  (see  popupMenuCmd in
+       The right  mouse  button  opens  a  popup  menu  (see  popupMenuCmd  in
        xpdfrc(5)).
 
    Key bindings
-       This section lists the default key bindings.  Bindings can  be  changed
+       This  section  lists the default key bindings.  Bindings can be changed
        using the config file (see xpdfrc(5)).
 
        control-o
@@ -246,8 +261,8 @@
               Open a new PDF file via a file requester.
 
        control-r
-              Reload  the  current  PDF  file.  Note that Xpdf will reload the
-              file automatically (on a  page  change  or  redraw)  if  it  has
+              Reload the current PDF file.  Note that  Xpdf  will  reload  the
+              file  automatically  (on  a  page  change  or  redraw) if it has
               changed since it was last loaded.
 
        control-f
@@ -281,8 +296,8 @@
               Open a new window.
 
        control-w
-              Close  the  current tab.  Closes the window if this was the last
-              open tab.  Quits the application if this was the last open  win-
+              Close the current tab.  Closes the window if this was  the  last
+              open  tab.  Quits the application if this was the last open win-
               dow.
 
        control-l
@@ -317,11 +332,11 @@
               Go to the last page.
 
        <space> or <PageDown>
-              Scroll  down  on the current page; if already at bottom, move to
+              Scroll down on the current page; if already at bottom,  move  to
               next page.
 
        control-<PageDown> or control-<down-arrow>
-              Go to the next page.  If <ScrollLock> is active, this  maintains
+              Go  to the next page.  If <ScrollLock> is active, this maintains
               the relative position on the page.
 
        <PageUp>
@@ -329,7 +344,7 @@
               ous page.
 
        control-<PageUp> or control-<up-arrow>
-              Go to the previous page.  If <ScrollLock> is active, this  main-
+              Go  to the previous page.  If <ScrollLock> is active, this main-
               tains the relative position on the page.
 
        <esc>  Exit full-screen mode.
@@ -343,22 +358,28 @@
        w      Set the zoom factor to 'width' (fit page width to window).
 
 Full-screen mode
-       Xpdf  can  be  placed into full-screen mode via the -fullscreen command
-       line option,  the  'full  screen'  menu  item,  or  a  binding  to  the
+       Xpdf can be placed into full-screen mode via  the  -fullscreen  command
+       line  option,  the  'full  screen'  menu  item,  or  a  binding  to the
        fullScreenMode or toggleFullScreenMode command.
 
-       Entering  full-screen  mode  automatically switches to single-page view
+       Entering full-screen mode automatically switches  to  single-page  view
        mode and to the fit-page zoom factor.
 
-       Full-screen mode can be exited via the default <esc>  key  binding,  or
+       Full-screen  mode  can  be exited via the default <esc> key binding, or
        via a binding to the windowMode or toggleFullScreenModecommand.
 
 COMMANDS
        Xpdf's key and mouse bindings are user-configurable, using the bind and
-       unbind commands in the config file (see xpdfrc(5)).  The  bind  command
-       allows  you  to bind a key or mouse button to a sequence of one or more
+       unbind  commands  in the config file (see xpdfrc(5)).  The bind command
+       allows you to bind a key or mouse button to a sequence of one  or  more
        commands.
 
+       In  commands  that take arguments (inside parentheses), special charac-
+       ters (namely '(', ')', ',', and '\x01') can  be  escaped  by  preceding
+       them  with  a  '\x01'  character.  This is mostly useful in things like
+       scripts that need to be able to open arbitrary  PDF  files,  using  the
+       'openFile' command.
+
        The following commands are supported:
 
        about  Open the 'about' dialog.
@@ -372,11 +393,11 @@
               Check that file is open in the current tab, and open it if not.
 
        checkOpenFileAtDest(file,dest)
-              Check that file is open in the current tab, and open it if  not.
+              Check  that file is open in the current tab, and open it if not.
               In either case go to the specified named destination.
 
        checkOpenFileAtPage(file,page)
-              Check  that file is open in the current tab, and open it if not.
+              Check that file is open in the current tab, and open it if  not.
               In either case go to the specified page.
 
        closeSidebar
@@ -403,6 +424,10 @@
 
        copy   Copy selected text to the clipboard.
 
+       copyLinkTarget
+              Copy  the target of the link under the mouse cursor to the clip-
+              board.
+
        endPan End a pan operation.
 
        endSelection
@@ -571,6 +596,8 @@
 
        quit   Quit from xpdf.
 
+       raise  Bring the xpdf window to the front.
+
        reload Reload the current PDF file.
 
        rotateCCW
@@ -674,10 +701,19 @@
               Scroll up by n pixels, moving to the previous page if  appropri-
               ate.
 
+       selectLine
+              Set the selection to the line at the current mouse position.
+
+       selectWord
+              Set the selection to the word at the current mouse position.
+
        setSelection(pg,ulx,uly,lrx,lry)
               Set  the selection to the specified coordinates on the specified
               page.
 
+       showKeyBindings
+              Open the key bindings dialog.
+
        showToolbar
               Show the toolbar.
 
@@ -694,12 +730,16 @@
        singlePageMode
               Switch to single-page view mode.
 
+       startExtendedSelection
+              Extend the selection to the current mouse position, and continue
+              extending as the mouse moves.
+
        startPan
-              Start  a pan operation at the current mouse position, which will
+              Start a pan operation at the current mouse position, which  will
               scroll the document as the mouse moves.
 
        startSelection
-              Start a selection at the current mouse position, which  will  be
+              Start  a  selection at the current mouse position, which will be
               extended as the mouse moves.
 
        toggleContinuousMode
@@ -715,12 +755,12 @@
               Toggle the sidebar between open and closed.
 
        toggleSidebarMoveResizeWin
-              Toggle  the sidebar between open and closed, resizing the window
-              so that the document size doesn't change, and moving the  window
+              Toggle the sidebar between open and closed, resizing the  window
+              so  that the document size doesn't change, and moving the window
               so that the document stays in the same place on the screen.
 
        toggleSidebarResizeWin
-              Toggle  the sidebar between open and closed, resizing the window
+              Toggle the sidebar between open and closed, resizing the  window
               so that the document size doesn't change.
 
        toggleToolbar
@@ -727,7 +767,7 @@
               Toggle the toolbar between shown and hidden.
 
        viewPageLabels
-              Show page labels (if the PDF file has them),  rather  than  page
+              Show  page  labels  (if the PDF file has them), rather than page
               numbers.
 
        viewPageNumbers
@@ -754,19 +794,19 @@
               Zoom to the current selection.
 
 REMOTE SERVER MODE
-       Starting  xpdf  with  the  "-remote"  switch puts it into remote server
-       mode.  All remaining command line options are commands  (see  the  COM-
+       Starting xpdf with the "-remote" switch  puts  it  into  remote  server
+       mode.   All  remaining  command line options are commands (see the COM-
        MANDS section).  Subsequent invocations of "xpdf -remote" with the same
-       remote server name will send commands to the  already-running  instance
-       of  xpdf.  The "checkOpenFile" commands are useful here for things like
+       remote  server  name will send commands to the already-running instance
+       of xpdf.  The "checkOpenFile" commands are useful here for things  like
        changing pages.  For example:
 
                   # Start up xpdf, and open something.pdf.
                   xpdf -remote foo 'openFile(something.pdf)'
 
-                  # Switch to page 7 in the  already-open  something.pdf.   If
+                  #  Switch  to  page 7 in the already-open something.pdf.  If
               the user
-                  #  has closed xpdf in the meantime, this will restart it and
+                  # has closed xpdf in the meantime, this will restart it  and
               reopen
                   # the file.
                   xpdf -remote foo 'checkOpenFileAtPage(something.pdf, 7)'
@@ -785,7 +825,7 @@
        99     Other error.
 
 AUTHOR
-       The xpdf software and documentation are  copyright  1996-2019  Glyph  &
+       The  xpdf  software  and  documentation are copyright 1996-2021 Glyph &
        Cog, LLC.
 
 SEE ALSO
@@ -795,4 +835,4 @@
 
 
 
-                                  25 Sep 2019                          xpdf(1)
+                                  28 Jan 2021                          xpdf(1)

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/doc/xpdfrc.5
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/doc/xpdfrc.5	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/doc/xpdfrc.5	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,7 +1,7 @@
-.\" Copyright 2002-2019 Glyph & Cog, LLC
-.TH xpdfrc 5 "25 Sep 2019"
+.\" Copyright 2002-2021 Glyph & Cog, LLC
+.TH xpdfrc 5 "28 Jan 2021"
 .SH NAME
-xpdfrc \- configuration file for Xpdf tools (version 4.02)
+xpdfrc \- configuration file for Xpdf tools (version 4.03)
 .SH DESCRIPTION
 All of the Xpdf tools read a single configuration file.  If you have a
 .I .xpdfrc
@@ -17,9 +17,26 @@
 per line.  Blank lines and lines starting with a \'#' (comments) are
 ignored.
 .PP
-Arguments may be quoted, using "double-quote" characters, e.g., for
-file names that contain spaces.
+Arguments can be single-quoted or double-quoted, e.g., for file names
+that contain spaces ("aaa bbb", 'aaa bbb').  This quoting does not
+provide any escaping, so there's no way to include a double quote in a
+double-quoted argument or a single quote in a single-quoted argument.
 .PP
+
+Arguments can also be at-quoted: @"aaa bbb".  At-quoted strings allow
+use of the DATADIR variable, which is set to the 'data' subdirectory
+in the xpdf install directory.  The percent sign (%) is an escape
+character: a percent sign followed by any other character is replaced
+with that character.
+.PP
+.RS
+.nf
+@"abc %"def%" ghi" --> abc "def" ghi    
+@"${DATADIR}/foo"  --> ...install-dir.../data/foo
+@"%${DATADIR}/foo" --> ${DATADIR}/foo
+.fi
+.RE
+.PP
 The following sections list all of the configuration options, sorted
 into functional groups.  There is an examples section at the end.
 .SH INCLUDE FILES
@@ -549,6 +566,11 @@
 visible.  If set to "no", xpdf opens with the sidebar collapsed.  The
 default is "yes".
 .TP
+.BI initialSidebarWidth " width"
+Sets the initial sidebar width, in pixels.  This is only relevant if
+initialSidebarState is "yes".  The default value is zero, which tells
+xpdf to use an internal default size.
+.TP
 .BR initialSelectMode " block | linear"
 Sets the initial selection mode.  The default setting is "linear".
 .TP
@@ -567,6 +589,10 @@
 Set the matte color for full-screen mode.  The color can be #RRGGBB
 (hexadecimal) or a named color.
 .TP
+.BI selectionColor " color"
+Set the selection color.  The color can be #RRGGBB (hexadecimal) or a
+named color.
+.TP
 .BI reverseVideoInvertImages " yes | no"
 If set to "no", xpdf's reverse-video mode inverts text and vector
 graphic content, but not images.  If set to "yes", xpdf inverts images
@@ -641,11 +667,13 @@
     end
     pgup
     pgdn
-    left / right / up / down        (arrow keys)
-    f1 .. f35                       (function keys)
-    mousePress1 .. mousePress7      (mouse buttons)
-    mouseRelease1 .. mouseRelease7  (mouse buttons)
-    mouseClick1 .. mouseClick7      (mouse buttons)
+    left / right / up / down                (arrow keys)
+    f1 .. f35                               (function keys)
+    mousePress1 .. mousePress7              (mouse buttons)
+    mouseRelease1 .. mouseRelease7          (mouse buttons)
+    mouseClick1 .. mouseClick7              (mouse buttons)
+    mouseDoubleClick1 .. mouseDoubleClick7  (mouse buttons)
+    mouseTripleClick1 .. mouseTripleClick7  (mouse buttons)
 
 .fi
 .I Context
@@ -708,11 +736,6 @@
 If set to "no", form fields will not be drawn or printed.  The default
 value is "yes".
 .TP
-.BI enableXFA " yes | no"
-If set to "yes", an XFA form (if present) will be rendered in place of
-an AcroForm.  If "no", an XFA form will never be rendered.  This
-defaults to "yes".
-.TP
 .BI printCommands " yes | no"
 If set to "yes", drawing commands are printed as they're executed
 (useful for debugging).  This defaults to "no".
@@ -783,7 +806,7 @@
 This is the user's configuration file.  If it exists, it will be read
 in place of the system-wide file.
 .SH AUTHOR
-The Xpdf software and documentation are copyright 1996-2019 Glyph &
+The Xpdf software and documentation are copyright 1996-2021 Glyph &
 Cog, LLC.
 .SH "SEE ALSO"
 .BR xpdf (1),

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/doc/xpdfrc.cat
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/doc/xpdfrc.cat	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/doc/xpdfrc.cat	2021-02-15 19:17:20 UTC (rev 845)
@@ -3,7 +3,7 @@
 
 
 NAME
-       xpdfrc - configuration file for Xpdf tools (version 4.02)
+       xpdfrc - configuration file for Xpdf tools (version 4.03)
 
 DESCRIPTION
        All  of the Xpdf tools read a single configuration file.  If you have a
@@ -17,9 +17,21 @@
        line.   Blank  lines  and  lines  starting  with  a  '#' (comments) are
        ignored.
 
-       Arguments may be quoted, using  "double-quote"  characters,  e.g.,  for
-       file names that contain spaces.
+       Arguments can be single-quoted or double-quoted, e.g., for  file  names
+       that contain spaces ("aaa bbb", 'aaa bbb').  This quoting does not pro-
+       vide any escaping, so there's no way to include a  double  quote  in  a
+       double-quoted argument or a single quote in a single-quoted argument.
 
+       Arguments  can  also be at-quoted: @"aaa bbb".  At-quoted strings allow
+       use of the DATADIR variable, which is set to the 'data' subdirectory in
+       the  xpdf install directory.  The percent sign (%) is an escape charac-
+       ter: a percent sign followed by any other character  is  replaced  with
+       that character.
+
+              @"abc %"def%" ghi" --> abc "def" ghi
+              @"${DATADIR}/foo"  --> ...install-dir.../data/foo
+              @"%${DATADIR}/foo" --> ${DATADIR}/foo
+
        The  following  sections  list all of the configuration options, sorted
        into functional groups.  There is an examples section at the end.
 
@@ -507,6 +519,11 @@
               etc.)  visible.  If set to "no", xpdf  opens  with  the  sidebar
               collapsed.  The default is "yes".
 
+       initialSidebarWidth width
+              Sets  the  initial sidebar width, in pixels.  This is only rele-
+              vant if initialSidebarState is  "yes".   The  default  value  is
+              zero, which tells xpdf to use an internal default size.
+
        initialSelectMode block | linear
               Sets  the  initial selection mode.  The default setting is "lin-
               ear".
@@ -526,15 +543,19 @@
               Set  the  matte  color  for  full-screen mode.  The color can be
               #RRGGBB (hexadecimal) or a named color.
 
+       selectionColor color
+              Set the selection color.  The color can be #RRGGBB (hexadecimal)
+              or a named color.
+
        reverseVideoInvertImages yes | no
-              If set to "no", xpdf's reverse-video mode inverts text and  vec-
-              tor  graphic  content,  but  not  images.  If set to "yes", xpdf
+              If  set to "no", xpdf's reverse-video mode inverts text and vec-
+              tor graphic content, but not images.   If  set  to  "yes",  xpdf
               inverts images as well.  The default is "no".
 
        popupMenuCmd title command ...
-              Add a command to the popup menu.  Title is the text to  be  dis-
-              played  in  the  menu.  Command is an Xpdf command (see the COM-
-              MANDS section of the xpdf(1) man page  for  details).   Multiple
+              Add  a  command to the popup menu.  Title is the text to be dis-
+              played in the menu.  Command is an Xpdf command  (see  the  COM-
+              MANDS  section  of  the xpdf(1) man page for details).  Multiple
               commands are separated by whitespace.
 
        maxTileWidth pixels
@@ -542,11 +563,11 @@
               ing pages.  This defaults to 1500.
 
        maxTileHeight pixels
-              Set the maximum height of tiles to be used by xpdf when  raster-
+              Set  the maximum height of tiles to be used by xpdf when raster-
               izing pages.  This defaults to 1500.
 
        tileCacheSize tiles
-              Set  the  maximum number of tiles to be cached by xpdf when ras-
+              Set the maximum number of tiles to be cached by xpdf  when  ras-
               terizing pages.  This defaults to 10.
 
        workerThreads numThreads
@@ -554,16 +575,16 @@
               izing pages.  This defaults to 1.
 
        launchCommand command
-              Sets  the  command  executed  when  you click on a "launch"-type
-              link.  The intent is for the  command  to  be  a  program/script
-              which  determines the file type and runs the appropriate viewer.
-              The command line will consist of the file to be  launched,  fol-
-              lowed  by  any  parameters  specified with the link.  Do not use
-              "%s" in "command".  By default, this is  unset,  and  Xpdf  will
+              Sets the command executed when  you  click  on  a  "launch"-type
+              link.   The  intent  is  for  the command to be a program/script
+              which determines the file type and runs the appropriate  viewer.
+              The  command  line will consist of the file to be launched, fol-
+              lowed by any parameters specified with the  link.   Do  not  use
+              "%s"  in  "command".   By  default, this is unset, and Xpdf will
               simply try to execute the file (after prompting the user).
 
        movieCommand command
-              Sets  the command executed when you click on a movie annotation.
+              Sets the command executed when you click on a movie  annotation.
               The string "%s" will be replaced with the movie file name.  This
               has no default value.
 
@@ -571,7 +592,7 @@
               Sets the default printer used in the viewer's print dialog.
 
        bind modifiers-key context command ...
-              Add  a  key  or  mouse button binding.  Modifiers can be zero or
+              Add a key or mouse button binding.  Modifiers  can  be  zero  or
               more of:
 
                   shift-
@@ -592,11 +613,13 @@
                   end
                   pgup
                   pgdn
-                  left / right / up / down        (arrow keys)
-                  f1 .. f35                       (function keys)
-                  mousePress1 .. mousePress7      (mouse buttons)
-                  mouseRelease1 .. mouseRelease7  (mouse buttons)
-                  mouseClick1 .. mouseClick7      (mouse buttons)
+                  left / right / up / down                (arrow keys)
+                  f1 .. f35                               (function keys)
+                  mousePress1 .. mousePress7              (mouse buttons)
+                  mouseRelease1 .. mouseRelease7          (mouse buttons)
+                  mouseClick1 .. mouseClick7              (mouse buttons)
+                  mouseDoubleClick1 .. mouseDoubleClick7  (mouse buttons)
+                  mouseTripleClick1 .. mouseTripleClick7  (mouse buttons)
 
               Context is either "any" or a comma-separated combination of:
 
@@ -605,14 +628,14 @@
                   overLink / offLink        (mouse over link or not)
                   scrLockOn / scrLockOff    (scroll lock on/off)
 
-              The context string can include only one  of  each  pair  in  the
+              The  context  string  can  include  only one of each pair in the
               above list.
 
-              Command  is  an  Xpdf  command  (see the COMMANDS section of the
-              xpdf(1) man page for details).  Multiple commands are  separated
+              Command is an Xpdf command (see  the  COMMANDS  section  of  the
+              xpdf(1)  man page for details).  Multiple commands are separated
               by whitespace.
 
-              The  bind  command replaces any existing binding, but only if it
+              The bind command replaces any existing binding, but only  if  it
               was defined for the exact same modifiers, key, and context.  All
               tokens (modifiers, key, context, commands) are case-sensitive.
 
@@ -630,10 +653,10 @@
               See the xpdf(1) man page for more examples.
 
        unbind modifiers-key context
-              Removes  a  key binding established with the bind command.  This
-              is most useful to remove default key bindings before  establish-
-              ing  new  ones  (e.g.,  if  the default key binding is given for
-              "any" context, and you want to create new key bindings for  mul-
+              Removes a key binding established with the bind  command.   This
+              is  most useful to remove default key bindings before establish-
+              ing new ones (e.g., if the default  key  binding  is  given  for
+              "any"  context, and you want to create new key bindings for mul-
               tiple contexts).
 
        tabStateFile path
@@ -642,24 +665,19 @@
 
 MISCELLANEOUS SETTINGS
        drawAnnotations yes | no
-              If set to "no", annotations will not be drawn or  printed.   The
+              If  set  to "no", annotations will not be drawn or printed.  The
               default value is "yes".
 
        drawFormFields yes | no
-              If  set  to "no", form fields will not be drawn or printed.  The
+              If set to "no", form fields will not be drawn or  printed.   The
               default value is "yes".
 
-       enableXFA yes | no
-              If set to "yes", an XFA form (if present) will  be  rendered  in
-              place  of  an AcroForm.  If "no", an XFA form will never be ren-
-              dered.  This defaults to "yes".
-
        printCommands yes | no
-              If set to "yes", drawing commands are printed  as  they're  exe-
+              If  set  to  "yes", drawing commands are printed as they're exe-
               cuted (useful for debugging).  This defaults to "no".
 
        errQuiet yes | no
-              If  set to "yes", this suppresses all error and warning messages
+              If set to "yes", this suppresses all error and warning  messages
               from all of the Xpdf tools.  This defaults to "no".
 
 EXAMPLES
@@ -716,7 +734,7 @@
 
 FILES
        /usr/local/etc/xpdfrc
-              This is the default location for the  system-wide  configuration
+              This  is  the default location for the system-wide configuration
               file.  Depending on build options, it may be placed elsewhere.
 
        $HOME/.xpdfrc
@@ -724,14 +742,14 @@
               read in place of the system-wide file.
 
 AUTHOR
-       The Xpdf software and documentation are  copyright  1996-2019  Glyph  &
+       The  Xpdf  software  and  documentation are copyright 1996-2021 Glyph &
        Cog, LLC.
 
 SEE ALSO
-       xpdf(1),   pdftops(1),  pdftotext(1),  pdftohtml(1),  pdfinfo(1),  pdf-
+       xpdf(1),  pdftops(1),  pdftotext(1),  pdftohtml(1),  pdfinfo(1),   pdf-
        fonts(1), pdfdetach(1), pdftoppm(1), pdftopng(1), pdfimages(1)
        http://www.xpdfreader.com/
 
 
 
-                                  25 Sep 2019                        xpdfrc(5)
+                                  28 Jan 2021                        xpdfrc(5)

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/fofi/FoFiIdentifier.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/fofi/FoFiIdentifier.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/fofi/FoFiIdentifier.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -561,7 +561,7 @@
 
 static FoFiIdentifierType identifyCFF(Reader *reader, int start) {
   Guint offset0, offset1;
-  int hdrSize, offSize0, offSize1, pos, endPos, b0, n, i;
+  int hdrSize, offSize0, offSize1, pos, endPos, b0, n;
 
   //----- read the header
   if (reader->getByte(start) != 0x01 ||
@@ -622,20 +622,19 @@
   //----- parse the top dict, look for ROS as first entry
   // for a CID font, the top dict starts with:
   //     <int> <int> <int> ROS
-  for (i = 0; i < 3; ++i) {
-    b0 = reader->getByte(pos++);
+  while (pos >= 0 && pos < endPos) {
+    b0 = reader->getByte(pos);
     if (b0 == 0x1c) {
-      pos += 2;
+      pos += 3;
     } else if (b0 == 0x1d) {
-      pos += 4;
+      pos += 5;
     } else if (b0 >= 0xf7 && b0 <= 0xfe) {
+      pos += 2;
+    } else if (b0 >= 0x20 && b0 <= 0xf6) {
       pos += 1;
-    } else if (b0 < 0x20 || b0 > 0xf6) {
-      return fofiIdCFF8Bit;
+    } else {
+      break;
     }
-    if (pos >= endPos || pos < 0) {
-      return fofiIdCFF8Bit;
-    }
   }
   if (pos + 1 < endPos &&
       reader->getByte(pos) == 12 &&

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/fofi/FoFiTrueType.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/fofi/FoFiTrueType.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/fofi/FoFiTrueType.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -1730,7 +1730,7 @@
     if (encoding) {
       name = encoding[i];
     } else {
-      sprintf(buf2, "c%02x", i);
+      snprintf(buf2, sizeof(buf2), "c%02x", i);
       name = buf2;
     }
     if (name && strcmp(name, ".notdef")) {
@@ -2143,7 +2143,7 @@
 
 void FoFiTrueType::parse(int fontNum, GBool allowHeadlessCFF) {
   Guint topTag;
-  int offset, pos, ver, i, j;
+  int offset, pos, ver, i, j, k;
 
   parsedOk = gTrue;
 
@@ -2206,7 +2206,7 @@
   // check for the head table; allow for a head-less OpenType CFF font
   headlessCFF = gFalse;
   if (seekTable("head") < 0) {
-    if (openTypeCFF && allowHeadlessCFF) {
+    if (openTypeCFF && allowHeadlessCFF && seekTable("CFF ") >= 0) {
       headlessCFF = gTrue;
       nGlyphs = 0;
       bbox[0] = bbox[1] = bbox[2] = bbox[3] = 0;
@@ -2238,14 +2238,22 @@
       return;
     }
     cmaps = (TrueTypeCmap *)gmallocn(nCmaps, sizeof(TrueTypeCmap));
+    k = 0;
     for (j = 0; j < nCmaps; ++j) {
-      cmaps[j].platform = getU16BE(pos, &parsedOk);
-      cmaps[j].encoding = getU16BE(pos + 2, &parsedOk);
-      cmaps[j].offset = tables[i].offset + getU32BE(pos + 4, &parsedOk);
+      cmaps[k].platform = getU16BE(pos, &parsedOk);
+      cmaps[k].encoding = getU16BE(pos + 2, &parsedOk);
+      cmaps[k].offset = getU32BE(pos + 4, &parsedOk);
       pos += 8;
-      cmaps[j].fmt = getU16BE(cmaps[j].offset, &parsedOk);
-      cmaps[j].len = getU16BE(cmaps[j].offset + 2, &parsedOk);
+      if (cmaps[k].offset >= tables[i].len) {
+	// skip any invalid subtables
+	continue;
+      }
+      cmaps[k].offset += tables[i].offset;
+      cmaps[k].fmt = getU16BE(cmaps[k].offset, &parsedOk);
+      cmaps[k].len = getU16BE(cmaps[k].offset + 2, &parsedOk);
+      ++k;
     }
+    nCmaps = k;
     if (!parsedOk) {
       return;
     }
@@ -2273,7 +2281,7 @@
   // NB: out-of-bounds entries are handled in writeTTF()
   if (!openTypeCFF) {
     i = seekTable("loca");
-    if (tables[i].len < 0) {
+    if (tables[i].len < (locaFmt ? 4 : 2)) {
       parsedOk = gFalse;
       return;
     }

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/fofi/FoFiType1.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/fofi/FoFiType1.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/fofi/FoFiType1.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -114,7 +114,7 @@
 		"0 1 255 {1 index exch /.notdef put} for\n", 40);
   for (i = 0; i < 256; ++i) {
     if (newEncoding[i]) {
-      sprintf(buf, "dup %d /%s put\n", i, newEncoding[i]);
+      snprintf(buf, sizeof(buf), "dup %d /%s put\n", i, newEncoding[i]);
       (*outputFunc)(outputStream, buf, (int)strlen(buf));
     }
   }

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/fofi/FoFiType1C.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/fofi/FoFiType1C.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/fofi/FoFiType1C.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -26,6 +26,8 @@
 
 static char hexChars[17] = "0123456789ABCDEF";
 
+#define type1cSubrRecursionLimit 20
+
 //------------------------------------------------------------------------
 
 GBool Type1COp::isZero() {
@@ -39,28 +41,52 @@
 
 GBool Type1COp::isNegative() {
   switch (kind) {
-  case type1COpInteger:  return intgr < 0;
-  case type1COpFloat:    return flt < 0;
-  case type1COpRational: return (rat.num < 0) != (rat.den < 0);
-  default:               return gFalse;   // shouldn't happen
+  case type1COpInteger:
+    return intgr < 0;
+  case type1COpFloat:
+    return flt < 0;
+  case type1COpRational:
+    return (rat.num < 0) != (rat.den < 0);
+  default:
+    // shouldn't happen
+    return gFalse;
   }
 }
 
 int Type1COp::toInt() {
   switch (kind) {
-  case type1COpInteger:  return intgr;
-  case type1COpFloat:    return (int)flt;
-  case type1COpRational: return rat.num / rat.den;
-  default:               return 0;   // shouldn't happen
+  case type1COpInteger:
+    return intgr;
+  case type1COpFloat:
+    if (flt < -2e9 || flt > 2e9) {
+      return 0;
+    }
+    return (int)flt;
+  case type1COpRational:
+    if (rat.den == 0) {
+      return 0;
+    }
+    return rat.num / rat.den;
+  default:
+    // shouldn't happen
+    return 0;
   }
 }
 
 double Type1COp::toFloat() {
   switch (kind) {
-  case type1COpInteger:  return (double)intgr;
-  case type1COpFloat:    return flt;
-  case type1COpRational: return (double)rat.num / (double)rat.den;
-  default:               return 0.0;   // shouldn't happen
+  case type1COpInteger:
+    return (double)intgr;
+  case type1COpFloat:
+    return flt;
+  case type1COpRational:
+    if (rat.den == 0) {
+      return 0;
+    }
+    return (double)rat.num / (double)rat.den;
+  default:
+    // shouldn't happen
+    return 0.0;
   }
 }
 
@@ -607,7 +633,8 @@
 	  subrIdx.pos = -1;
 	}
 	cvtGlyph(val.pos, val.len, charStrings,
-		 &subrIdx, &privateDicts[fdSelect ? fdSelect[gid] : 0], gTrue);
+		 &subrIdx, &privateDicts[fdSelect ? fdSelect[gid] : 0],
+		 gTrue, 0);
       }
     }
   }
@@ -969,6 +996,10 @@
 	}
       }
     }
+    if (fd < 0 || fd >= nFDs) {
+      // this will only happen in a broken/damaged font
+      fd = 0;
+    }
 
     // font dictionary (unencrypted section)
     (*outputFunc)(outputStream, "16 dict begin\n", 14);
@@ -1269,7 +1300,7 @@
 
   // generate the charstring
   charBuf = new GString();
-  cvtGlyph(offset, nBytes, charBuf, subrIdx, pDict, gTrue);
+  cvtGlyph(offset, nBytes, charBuf, subrIdx, pDict, gTrue, 0);
 
   buf = GString::format("/{0:s} {1:d} RD ", glyphName, charBuf->getLength());
   eexecWrite(eb, buf->getCString());
@@ -1283,7 +1314,7 @@
 
 void FoFiType1C::cvtGlyph(int offset, int nBytes, GString *charBuf,
 			  Type1CIndex *subrIdx, Type1CPrivateDict *pDict,
-			  GBool top) {
+			  GBool top, int recursion) {
   Type1CIndexVal val;
   Type1COp zero, tmp;
   GBool ok, dInt;
@@ -1292,6 +1323,11 @@
   Guchar byte;
   int pos, subrBias, start, num, den, i, k;
 
+  if (recursion > type1cSubrRecursionLimit) {
+    //~ error(-1, "Recursive loop in Type1C glyph");
+    return;
+  }
+
   start = charBuf->getLength();
   if (top) {
     charBuf->append((char)73);
@@ -1504,7 +1540,8 @@
 	  ok = gTrue;
 	  getIndexVal(subrIdx, k, &val, &ok);
 	  if (ok) {
-	    cvtGlyph(val.pos, val.len, charBuf, subrIdx, pDict, gFalse);
+	    cvtGlyph(val.pos, val.len, charBuf, subrIdx, pDict, gFalse,
+		     recursion + 1);
 	  }
 	} else {
 	  //~ error(-1, "Too few args to Type 2 callsubr");
@@ -1739,7 +1776,8 @@
 	  ok = gTrue;
 	  getIndexVal(&gsubrIdx, k, &val, &ok);
 	  if (ok) {
-	    cvtGlyph(val.pos, val.len, charBuf, subrIdx, pDict, gFalse);
+	    cvtGlyph(val.pos, val.len, charBuf, subrIdx, pDict, gFalse,
+		     recursion + 1);
 	  }
 	} else {
 	  //~ error(-1, "Too few args to Type 2 callgsubr");
@@ -2945,11 +2983,10 @@
   int fdSelectFmt, pos, nRanges, gid0, gid1, fd, i, j;
 
   fdSelect = (Guchar *)gmalloc(nGlyphs);
-  if (topDict.fdSelectOffset == 0) {
-    for (i = 0; i < nGlyphs; ++i) {
-      fdSelect[i] = 0;
-    }
-  } else {
+  for (i = 0; i < nGlyphs; ++i) {
+    fdSelect[i] = 0;
+  }
+  if (topDict.fdSelectOffset != 0) {
     pos = topDict.fdSelectOffset;
     fdSelectFmt = getU8(pos++, &parsedOk);
     if (!parsedOk) {
@@ -2992,9 +3029,6 @@
       }
     } else {
       //~ error(-1, "Unknown FDSelect table format in CID font");
-      for (i = 0; i < nGlyphs; ++i) {
-	fdSelect[i] = 0;
-      }
     }
   }
 }

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/fofi/FoFiType1C.h
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/fofi/FoFiType1C.h	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/fofi/FoFiType1C.h	2021-02-15 19:17:20 UTC (rev 845)
@@ -229,7 +229,7 @@
 		     Type1CPrivateDict *pDict);
   void cvtGlyph(int offset, int nBytes, GString *charBuf,
 		Type1CIndex *subrIdx, Type1CPrivateDict *pDict,
-		GBool top);
+		GBool top, int recursion);
   void cvtGlyphWidth(GBool useOp, GString *charBuf,
 		     Type1CPrivateDict *pDict);
   void cvtNum(Type1COp op, GString *charBuf);

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/goo/CMakeLists.txt
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/goo/CMakeLists.txt	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/goo/CMakeLists.txt	2021-02-15 19:17:20 UTC (rev 845)
@@ -20,6 +20,7 @@
   gmem.cc
   gmempp.cc
   parseargs.c
+  Trace.cc
 )
 
 add_library(goo

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/goo/FixedPoint.h
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/goo/FixedPoint.h	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/goo/FixedPoint.h	2021-02-15 19:17:20 UTC (rev 845)
@@ -36,6 +36,7 @@
   FixedPoint(const FixedPoint &x) { val = x.val; }
   FixedPoint(double x) { val = (int)(x * (1 << fixptShift) + 0.5); }
   FixedPoint(int x) { val = x << fixptShift; }
+  FixedPoint(Guint x) { val = x << fixptShift; }
   FixedPoint(long x) { val = (int)x << fixptShift; }
 
   operator float()
@@ -52,31 +53,37 @@
   bool operator ==(FixedPoint x) const { return val == x.val; }
   bool operator ==(double x) const { return *this == (FixedPoint)x; }
   bool operator ==(int x) const { return *this == (FixedPoint)x; }
+  bool operator ==(Guint x) const { return *this == (FixedPoint)x; }
   bool operator ==(long x) const { return *this == (FixedPoint)x; }
 
   bool operator !=(FixedPoint x) const { return val != x.val; }
   bool operator !=(double x) const { return *this != (FixedPoint)x; }
   bool operator !=(int x) const { return *this != (FixedPoint)x; }
+  bool operator !=(Guint x) const { return *this != (FixedPoint)x; }
   bool operator !=(long x) const { return *this != (FixedPoint)x; }
 
   bool operator <(FixedPoint x) const { return val < x.val; }
   bool operator <(double x) const { return *this < (FixedPoint)x; }
   bool operator <(int x) const { return *this < (FixedPoint)x; }
+  bool operator <(Guint x) const { return *this < (FixedPoint)x; }
   bool operator <(long x) const { return *this < (FixedPoint)x; }
 
   bool operator <=(FixedPoint x) const { return val <= x.val; }
   bool operator <=(double x) const { return *this <= (FixedPoint)x; }
   bool operator <=(int x) const { return *this <= (FixedPoint)x; }
+  bool operator <=(Guint x) const { return *this <= (FixedPoint)x; }
   bool operator <=(long x) const { return *this <= (FixedPoint)x; }
 
   bool operator >(FixedPoint x) const { return val > x.val; }
   bool operator >(double x) const { return *this > (FixedPoint)x; }
   bool operator >(int x) const { return *this > (FixedPoint)x; }
+  bool operator >(Guint x) const { return *this > (FixedPoint)x; }
   bool operator >(long x) const { return *this > (FixedPoint)x; }
 
   bool operator >=(FixedPoint x) const { return val >= x.val; }
   bool operator >=(double x) const { return *this >= (FixedPoint)x; }
   bool operator >=(int x) const { return *this >= (FixedPoint)x; }
+  bool operator >=(Guint x) const { return *this >= (FixedPoint)x; }
   bool operator >=(long x) const { return *this >= (FixedPoint)x; }
 
   FixedPoint operator -() { return make(-val); }
@@ -84,41 +91,49 @@
   FixedPoint operator +(FixedPoint x) { return make(val + x.val); }
   FixedPoint operator +(double x) { return *this + (FixedPoint)x; }
   FixedPoint operator +(int x) { return *this + (FixedPoint)x; }
+  FixedPoint operator +(Guint x) { return *this + (FixedPoint)x; }
   FixedPoint operator +(long x) { return *this + (FixedPoint)x; }
 
   FixedPoint operator +=(FixedPoint x) { val = val + x.val; return *this; }
   FixedPoint operator +=(double x) { return *this += (FixedPoint)x; }
   FixedPoint operator +=(int x) { return *this += (FixedPoint)x; }
+  FixedPoint operator +=(Guint x) { return *this += (FixedPoint)x; }
   FixedPoint operator +=(long x) { return *this += (FixedPoint)x; }
 
   FixedPoint operator -(FixedPoint x) { return make(val - x.val); }
   FixedPoint operator -(double x) { return *this - (FixedPoint)x; }
   FixedPoint operator -(int x) { return *this - (FixedPoint)x; }
+  FixedPoint operator -(Guint x) { return *this - (FixedPoint)x; }
   FixedPoint operator -(long x) { return *this - (FixedPoint)x; }
 
   FixedPoint operator -=(FixedPoint x) { val = val - x.val; return *this; }
   FixedPoint operator -=(double x) { return *this -= (FixedPoint)x; }
   FixedPoint operator -=(int x) { return *this -= (FixedPoint)x; }
+  FixedPoint operator -=(Guint x) { return *this -= (FixedPoint)x; }
   FixedPoint operator -=(long x) { return *this -= (FixedPoint)x; }
 
   FixedPoint operator *(FixedPoint x) { return make(mul(val, x.val)); }
   FixedPoint operator *(double x) { return *this * (FixedPoint)x; }
   FixedPoint operator *(int x) { return *this * (FixedPoint)x; }
+  FixedPoint operator *(Guint x) { return *this * (FixedPoint)x; }
   FixedPoint operator *(long x) { return *this * (FixedPoint)x; }
 
   FixedPoint operator *=(FixedPoint x) { val = mul(val, x.val); return *this; }
   FixedPoint operator *=(double x) { return *this *= (FixedPoint)x; }
   FixedPoint operator *=(int x) { return *this *= (FixedPoint)x; }
+  FixedPoint operator *=(Guint x) { return *this *= (FixedPoint)x; }
   FixedPoint operator *=(long x) { return *this *= (FixedPoint)x; }
 
   FixedPoint operator /(FixedPoint x) { return make(div(val, x.val)); }
   FixedPoint operator /(double x) { return *this / (FixedPoint)x; }
   FixedPoint operator /(int x) { return *this / (FixedPoint)x; }
+  FixedPoint operator /(Guint x) { return *this / (FixedPoint)x; }
   FixedPoint operator /(long x) { return *this / (FixedPoint)x; }
 
   FixedPoint operator /=(FixedPoint x) { val = div(val, x.val); return *this; }
   FixedPoint operator /=(double x) { return *this /= (FixedPoint)x; }
   FixedPoint operator /=(int x) { return *this /= (FixedPoint)x; }
+  FixedPoint operator /=(Guint x) { return *this /= (FixedPoint)x; }
   FixedPoint operator /=(long x) { return *this /= (FixedPoint)x; }
 
   static FixedPoint abs(FixedPoint x) { return make(::abs(x.val)); }

Added: branches/stable/source/src/libs/xpdf/xpdf-src/goo/Trace.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/goo/Trace.cc	                        (rev 0)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/goo/Trace.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -0,0 +1,114 @@
+//========================================================================
+//
+// Trace.cc
+//
+// Nested tracing.
+//
+// Copyright 2020 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#if ENABLE_TRACING
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include "GString.h"
+#include "Trace.h"
+
+// NB: This module is NOT thread-safe.
+
+static bool traceInitialized = false;
+static FILE *traceOut = NULL;
+
+static void traceInit() {
+  if (traceInitialized) {
+    return;
+  }
+  //~ this could read an env var to set up an output file
+  GString *fileName = GString::format("/tmp/trace.{0:d}", (int)getpid());
+  traceOut = fopen(fileName->getCString(), "w");
+  delete fileName;
+  traceInitialized = true;
+}
+
+static void traceHeader(char flag, void *handle) {
+  timeval tv;
+  gettimeofday(&tv, NULL);
+  if (handle) {
+    fprintf(traceOut, "%c %ld %06ld %p ", flag, tv.tv_sec, tv.tv_usec, handle);
+  } else {
+    fprintf(traceOut, "%c %ld %06ld 0x0 ", flag, tv.tv_sec, tv.tv_usec);
+  }
+}
+
+void traceBegin(void *nestHandle, const char *fmt, ...) {
+  traceInit();
+  if (!traceOut) {
+    return;
+  }
+  traceHeader('B', nestHandle);
+  va_list args;
+  va_start(args, fmt);
+  vfprintf(traceOut, fmt, args);
+  va_end(args);
+  fprintf(traceOut, "\n");
+}
+
+void traceEnd(void *nestHandle, const char *fmt, ...) {
+  traceInit();
+  if (!traceOut) {
+    return;
+  }
+  traceHeader('E', nestHandle);
+  va_list args;
+  va_start(args, fmt);
+  vfprintf(traceOut, fmt, args);
+  va_end(args);
+  fprintf(traceOut, "\n");
+}
+
+void traceAlloc(void *resourceHandle, const char *fmt, ...) {
+  traceInit();
+  if (!traceOut) {
+    return;
+  }
+  traceHeader('A', resourceHandle);
+  va_list args;
+  va_start(args, fmt);
+  vfprintf(traceOut, fmt, args);
+  va_end(args);
+  fprintf(traceOut, "\n");
+}
+
+void traceFree(void *resourceHandle, const char *fmt, ...) {
+  traceInit();
+  if (!traceOut) {
+    return;
+  }
+  traceHeader('F', resourceHandle);
+  va_list args;
+  va_start(args, fmt);
+  vfprintf(traceOut, fmt, args);
+  va_end(args);
+  fprintf(traceOut, "\n");
+}
+
+void traceMessage(const char *fmt, ...) {
+  traceInit();
+  if (!traceOut) {
+    return;
+  }
+  traceHeader('M', NULL);
+  va_list args;
+  va_start(args, fmt);
+  vfprintf(traceOut, fmt, args);
+  va_end(args);
+  fprintf(traceOut, "\n");
+}
+
+#endif // ENABLE_TRACING


Property changes on: branches/stable/source/src/libs/xpdf/xpdf-src/goo/Trace.cc
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: branches/stable/source/src/libs/xpdf/xpdf-src/goo/Trace.h
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/goo/Trace.h	                        (rev 0)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/goo/Trace.h	2021-02-15 19:17:20 UTC (rev 845)
@@ -0,0 +1,43 @@
+//========================================================================
+//
+// Trace.h
+//
+// Nested tracing.
+//
+// Copyright 2020 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef TRACING_H
+#define TRACING_H
+
+#include <aconf.h>
+
+#if ENABLE_TRACING
+
+// Enter a nesting level.
+extern void traceBegin(void *nestHandle, const char *fmt, ...);
+
+// Exit a nesting level.
+extern void traceEnd(void *nestHandle, const char *fmt, ...);
+
+// Mark a resource as allocated.
+extern void traceAlloc(void *resourceHandle, const char *fmt, ...);
+
+// Mark a resource as freed.
+extern void traceFree(void *resourceHandle, const char *fmt, ...);
+
+// Misc message.
+extern void traceMessage(const char *fmt, ...);
+
+#else // ENABLE_TRACING
+
+static inline void traceBegin(void *nestHandle, const char *fmt, ...) {}
+static inline void traceEnd(void *nestHandle, const char *fmt, ...) {}
+static inline void traceAlloc(void *resourceHandle, const char *fmt, ...) {}
+static inline void traceFree(void *nestHandle, const char *fmt, ...) {}
+static inline void traceMessage(const char *fmt, ...) {}
+
+#endif // ENABLE_TRACING
+
+#endif // TRACING_H


Property changes on: branches/stable/source/src/libs/xpdf/xpdf-src/goo/Trace.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Modified: branches/stable/source/src/libs/xpdf/xpdf-src/goo/gfile.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/goo/gfile.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/goo/gfile.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -18,6 +18,8 @@
 #  include <windows.h>
 #  include <time.h>
 #  include <direct.h>
+#  include <shobjidl.h>
+#  include <shlguid.h>
 #else
 #  if !defined(ACORN)
 #    include <sys/types.h>
@@ -579,6 +581,32 @@
   }
   return s;
 }
+
+wchar_t *fileNameToUCS2(const char *path, wchar_t *out, size_t outSize) {
+  const char *p;
+  size_t i;
+
+  for (p = path, i = 0; *p && i < outSize - 1; ++i) {
+    if ((p[0] & 0xe0) == 0xc0 &&
+	p[1] && (p[1] & 0xc0) == 0x80) {
+      out[i] = (wchar_t)(((p[0] & 0x1f) << 6) |
+			  (p[1] & 0x3f));
+      p += 2;
+    } else if ((p[0] & 0xf0) == 0xe0 &&
+	       (p[1] & 0xc0) == 0x80 &&
+	       (p[2] & 0xc0) == 0x80) {
+      out[i] = (wchar_t)(((p[0] & 0x0f) << 12) |
+			 ((p[1] & 0x3f) << 6) |
+			  (p[2] & 0x3f));
+      p += 3;
+    } else {
+      out[i] = (wchar_t)(p[0] & 0xff);
+      p += 1;
+    }
+  }
+  out[i] = (wchar_t)0;
+  return out;
+}
 #endif
 
 FILE *openFile(const char *path, const char *mode) {
@@ -585,62 +613,17 @@
 #if defined(_WIN32)
   return fopen(path, mode);
 #if 0
-  OSVERSIONINFO version;
   wchar_t wPath[_MAX_PATH + 1];
-  char nPath[_MAX_PATH + 1];
   wchar_t wMode[8];
-  const char *p;
   int i;
 
-  // NB: _wfopen is only available in NT
-  version.dwOSVersionInfoSize = sizeof(version);
-  GetVersionEx(&version);
-  if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) {
-    for (p = path, i = 0; *p && i < _MAX_PATH; ++i) {
-      if ((p[0] & 0xe0) == 0xc0 &&
-	  p[1] && (p[1] & 0xc0) == 0x80) {
-	wPath[i] = (wchar_t)(((p[0] & 0x1f) << 6) |
-			     (p[1] & 0x3f));
-	p += 2;
-      } else if ((p[0] & 0xf0) == 0xe0 &&
-		 p[1] && (p[1] & 0xc0) == 0x80 &&
-		 p[2] && (p[2] & 0xc0) == 0x80) {
-	wPath[i] = (wchar_t)(((p[0] & 0x0f) << 12) |
-			     ((p[1] & 0x3f) << 6) |
-			     (p[2] & 0x3f));
-	p += 3;
-      } else {
-	wPath[i] = (wchar_t)(p[0] & 0xff);
-	p += 1;
-      }
-    }
-    wPath[i] = (wchar_t)0;
-    for (i = 0; mode[i] && i < sizeof(wMode)/sizeof(wchar_t) - 1; ++i) {
-      wMode[i] = (wchar_t)(mode[i] & 0xff);
-    }
-    wMode[i] = (wchar_t)0;
-    return _wfopen(wPath, wMode);
-  } else {
-    for (p = path, i = 0; *p && i < _MAX_PATH; ++i) {
-      if ((p[0] & 0xe0) == 0xc0 &&
-	  p[1] && (p[1] & 0xc0) == 0x80) {
-	nPath[i] = (char)(((p[0] & 0x1f) << 6) |
-			  (p[1] & 0x3f));
-	p += 2;
-      } else if ((p[0] & 0xf0) == 0xe0 &&
-		 p[1] && (p[1] & 0xc0) == 0x80 &&
-		 p[2] && (p[2] & 0xc0) == 0x80) {
-	nPath[i] = (char)(((p[1] & 0x3f) << 6) |
-			  (p[2] & 0x3f));
-	p += 3;
-      } else {
-	nPath[i] = p[0];
-	p += 1;
-      }
-    }
-    nPath[i] = '\0';
-    return fopen(nPath, mode);
+  fileNameToUCS2(path, wPath, sizeof(wPath) / sizeof(wchar_t));
+  for (i = 0; mode[i] && i < sizeof(wMode)/sizeof(wchar_t) - 1; ++i) {
+    wMode[i] = (wchar_t)(mode[i] & 0xff);
   }
+  wMode[i] = (wchar_t)0;
+  readWindowsShortcut(wPath, _MAX_PATH + 1);
+  return _wfopen(wPath, wMode);
 #endif /* 0 */
 #elif defined(VMS)
   return fopen(path, mode, "ctx=stm");
@@ -649,6 +632,62 @@
 #endif
 }
 
+#if 0
+#ifdef _WIN32
+void readWindowsShortcut(wchar_t *wPath, size_t wPathSize) {
+  size_t n = wcslen(wPath);
+  if (n < 4 || wcscmp(wPath + n - 4, L".lnk")) {
+    return;
+  }
+  IShellLinkW *shellLink;
+  HRESULT hres;
+  hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
+			  IID_IShellLinkW, (LPVOID *)&shellLink);
+  bool needCoUninit = false;
+  if (hres == CO_E_NOTINITIALIZED) {
+    CoInitialize(NULL);
+    needCoUninit = true;
+    hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
+			    IID_IShellLinkW, (LPVOID *)&shellLink);
+  }
+  if (FAILED(hres)) {
+    return;
+  }
+  IPersistFile *persistFile;
+  hres = shellLink->QueryInterface(IID_IPersistFile, (LPVOID *)&persistFile);
+  if (FAILED(hres)) {
+    return;
+  }
+  hres = persistFile->Load(wPath, STGM_READ);
+  if (FAILED(hres)) {
+    fprintf(stderr, "IPersistFile.Load failed: 0x%08x\n", hres);
+    exit(1);
+  }
+  wchar_t target[_MAX_PATH + 1];
+  hres = shellLink->GetPath(target, _MAX_PATH + 1, NULL, 0);
+  if (FAILED(hres)) {
+    return;
+  }
+  shellLink->Release();
+  if (needCoUninit) {
+    CoUninitialize();
+  }
+  if (wcslen(target) > wPathSize - 1) {
+    return;
+  }
+  wcscpy(wPath, target);
+}
+#endif
+#endif /* 0 */
+
+int makeDir(const char *path, int mode) {
+#ifdef _WIN32
+  return _mkdir(path);
+#else
+  return mkdir(path, (mode_t)mode);
+#endif
+}
+
 char *getLine(char *buf, int size, FILE *f) {
   int c, i;
 

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/goo/gfile.h
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/goo/gfile.h	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/goo/gfile.h	2021-02-15 19:17:20 UTC (rev 845)
@@ -80,13 +80,22 @@
 
 // Convert a file name from UCS-2 to UTF-8.
 extern GString *fileNameToUTF8(wchar_t *path);
+
+// Convert a file name from UTF-8 to UCS-2.  [out] has space for
+// [outSize] wchar_t elements (including the trailing zero).  Returns
+// [out].
+extern wchar_t *fileNameToUCS2(const char *path, wchar_t *out, size_t outSize);
 #endif
 
 // Open a file.  On Windows, this converts the path from UTF-8 to
-// UCS-2 and calls _wfopen (if available).  On other OSes, this simply
-// calls fopen.
+// UCS-2 and calls _wfopen().  On other OSes, this simply calls fopen().
 extern FILE *openFile(const char *path, const char *mode);
 
+// Create a directory.  On Windows, this converts the path from UTF-8
+// to UCS-2 and calls _wmkdir(), ignoring the mode argument.  On other
+// OSes, this simply calls mkdir().
+extern int makeDir(const char *path, int mode);
+
 // Just like fgets, but handles Unix, Mac, and/or DOS end-of-line
 // conventions.
 extern char *getLine(char *buf, int size, FILE *f);

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/goo/gmem.h
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/goo/gmem.h	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/goo/gmem.h	2021-02-15 19:17:20 UTC (rev 845)
@@ -32,10 +32,6 @@
 
 #endif // USE_EXCEPTIONS
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /*
  * Same as malloc, but prints error message and exits if malloc()
  * returns NULL.
@@ -96,8 +92,4 @@
  */
 extern char *copyString(const char *s);
 
-#ifdef __cplusplus
-}
 #endif
-
-#endif

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/splash/Splash.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/splash/Splash.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/splash/Splash.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -2,7 +2,7 @@
 //
 // Splash.cc
 //
-// Copyright 2003-2013 Glyph & Cog, LLC
+// Copyright 2003-2020 Glyph & Cog, LLC
 //
 //========================================================================
 
@@ -80,6 +80,12 @@
   Guchar aInput;
   SplashColor cSrcVal;
 
+  // source overprint mask
+  //~ this is a kludge - this pointer should be passed as an arg to the
+  //~   pipeRun function, but that would require passing in a lot of
+  //~   null pointers, since it's rarely used
+  Guint *srcOverprintMaskPtr;
+
   // special cases and result color
   GBool noTransparency;
   GBool shapeOnly;
@@ -163,7 +169,7 @@
 
 inline void Splash::pipeInit(SplashPipe *pipe, SplashPattern *pattern,
 			     Guchar aInput, GBool usesShape,
-			     GBool nonIsolatedGroup) {
+			     GBool nonIsolatedGroup, GBool usesSrcOverprint) {
   SplashColorMode mode;
 
   mode = bitmap->mode;
@@ -181,6 +187,9 @@
   // source alpha
   pipe->aInput = aInput;
 
+  // source overprint mask
+  pipe->srcOverprintMaskPtr = NULL;
+
   // special cases
   pipe->noTransparency = aInput == 255 &&
                          !state->softMask &&
@@ -212,7 +221,9 @@
 
   // select the 'run' function
   pipe->run = &Splash::pipeRun;
-  if (!pipe->pattern && pipe->noTransparency && !state->blendFunc) {
+  if (overprintMaskBitmap || usesSrcOverprint) {
+    // use Splash::pipeRun
+  } else if (!pipe->pattern && pipe->noTransparency && !state->blendFunc) {
     if (mode == splashModeMono1 && !bitmap->alpha) {
       pipe->run = &Splash::pipeRunSimpleMono1;
     } else if (mode == splashModeMono8 && bitmap->alpha) {
@@ -239,6 +250,9 @@
     } else if (mode == splashModeCMYK8 && bitmap->alpha) {
       pipe->run = &Splash::pipeRunShapeCMYK8;
 #endif
+    } else if (mode == splashModeMono8 && !bitmap->alpha) {
+      // this is used when drawing soft-masked images
+      pipe->run = &Splash::pipeRunShapeNoAlphaMono8;
     }
   } else if (!pipe->pattern && !pipe->noTransparency && !state->softMask &&
 	     usesShape &&
@@ -258,6 +272,26 @@
       pipe->run = &Splash::pipeRunAACMYK8;
 #endif
     }
+  } else if (!pipe->pattern &&
+             aInput == 255 &&
+             state->softMask &&
+             usesShape &&
+             !state->inNonIsolatedGroup &&
+             !state->inKnockoutGroup &&
+             !nonIsolatedGroup &&
+             state->overprintMask == 0xffffffff &&
+             !state->blendFunc) {
+    if (mode == splashModeMono8 && bitmap->alpha) {
+      pipe->run = &Splash::pipeRunSoftMaskMono8;
+    } else if (mode == splashModeRGB8 && bitmap->alpha) {
+      pipe->run = &Splash::pipeRunSoftMaskRGB8;
+    } else if (mode == splashModeBGR8 && bitmap->alpha) {
+      pipe->run = &Splash::pipeRunSoftMaskBGR8;
+#if SPLASH_CMYK
+    } else if (mode == splashModeCMYK8 && bitmap->alpha) {
+      pipe->run = &Splash::pipeRunSoftMaskCMYK8;
+#endif
+    }
   } else if (!pipe->pattern && !pipe->noTransparency && !state->softMask &&
 	     usesShape &&
 	     state->inNonIsolatedGroup && groupBackBitmap->alpha &&
@@ -292,6 +326,8 @@
   Guchar color0Mask;
   Guchar *alpha0Ptr;
   SplashColorPtr softMaskPtr;
+  Guint overprintMask;
+  Guint *overprintMaskPtr;
 #if SPLASH_CMYK
   Guchar aPrev;
   SplashColor cSrc2, cDest2;
@@ -313,6 +349,9 @@
       }
       cSrcPtr += cSrcStride;
       ++shapePtr2;
+      if (pipe->srcOverprintMaskPtr) {
+	++pipe->srcOverprintMaskPtr;
+      }
     }
   } else {
     shapeVal = 0xff;
@@ -326,6 +365,8 @@
   updateModY(y);
   lastX = x0;
 
+  useDestRow(y);
+
   if (bitmap->mode == splashModeMono1) {
     destColorPtr = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)];
     destColorMask = (Guchar)(0x80 >> (x0 & 7));
@@ -367,6 +408,11 @@
   } else {
     alpha0Ptr = NULL;
   }
+  if (overprintMaskBitmap) {
+    overprintMaskPtr = overprintMaskBitmap + y * bitmap->width + x0;
+  } else {
+    overprintMaskPtr = NULL;
+  }
 
   for (x = x0; x <= x1; ++x) {
 
@@ -399,6 +445,12 @@
       }
       cSrcPtr += cSrcStride;
       shapePtr2 += shapeStride;
+      if (pipe->srcOverprintMaskPtr) {
+	++pipe->srcOverprintMaskPtr;
+      }
+      if (overprintMaskPtr) {
+	++overprintMaskPtr;
+      }
       continue;
     }
     lastX = x;
@@ -519,6 +571,15 @@
 
       //----- read source color; handle overprint
 
+      if (pipe->srcOverprintMaskPtr) {
+	overprintMask = *pipe->srcOverprintMaskPtr++;
+      } else {
+	overprintMask = state->overprintMask;
+      }
+      if (overprintMaskPtr) {
+	*overprintMaskPtr++ |= overprintMask;
+      }
+
       switch (bitmap->mode) {
       case splashModeMono1:
       case splashModeMono8:
@@ -545,22 +606,22 @@
 	    aPrev = aDest;
 	  }
 	}
-	if (state->overprintMask & 0x01) {
+	if (overprintMask & 0x01) {
 	  cSrc[0] = state->cmykTransferC[cSrcPtr[0]];
 	} else {
 	  cSrc[0] = div255(aPrev * cDest[0]);
 	}
-	if (state->overprintMask & 0x02) {
+	if (overprintMask & 0x02) {
 	  cSrc[1] = state->cmykTransferM[cSrcPtr[1]];
 	} else {
 	  cSrc[1] = div255(aPrev * cDest[1]);
 	}
-	if (state->overprintMask & 0x04) {
+	if (overprintMask & 0x04) {
 	  cSrc[2] = state->cmykTransferY[cSrcPtr[2]];
 	} else {
 	  cSrc[2] = div255(aPrev * cDest[2]);
 	}
-	if (state->overprintMask & 0x08) {
+	if (overprintMask & 0x08) {
 	  cSrc[3] = state->cmykTransferK[cSrcPtr[3]];
 	} else {
 	  cSrc[3] = div255(aPrev * cDest[3]);
@@ -862,6 +923,8 @@
   updateModX(x1);
   updateModY(y);
 
+  useDestRow(y);
+
   destColorPtr = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)];
   destColorMask = (Guchar)(0x80 >> (x0 & 7));
 
@@ -905,6 +968,8 @@
   updateModX(x1);
   updateModY(y);
 
+  useDestRow(y);
+
   destColorPtr = &bitmap->data[y * bitmap->rowSize + x0];
   destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
 
@@ -940,6 +1005,8 @@
   updateModX(x1);
   updateModY(y);
 
+  useDestRow(y);
+
   destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0];
   destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
 
@@ -978,6 +1045,8 @@
   updateModX(x1);
   updateModY(y);
 
+  useDestRow(y);
+
   destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0];
   destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
 
@@ -1017,6 +1086,8 @@
   updateModX(x1);
   updateModY(y);
 
+  useDestRow(y);
+
   destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x0];
   destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
 
@@ -1067,6 +1138,8 @@
   updateModY(y);
   lastX = x0;
 
+  useDestRow(y);
+
   destColorPtr = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)];
   destColorMask = (Guchar)(0x80 >> (x0 & 7));
 
@@ -1150,6 +1223,8 @@
   updateModY(y);
   lastX = x0;
 
+  useDestRow(y);
+
   destColorPtr = &bitmap->data[y * bitmap->rowSize + x0];
   destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
 
@@ -1243,6 +1318,8 @@
   updateModY(y);
   lastX = x0;
 
+  useDestRow(y);
+
   destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0];
   destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
 
@@ -1349,6 +1426,8 @@
   updateModY(y);
   lastX = x0;
 
+  useDestRow(y);
+
   destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0];
   destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
 
@@ -1456,6 +1535,8 @@
   updateModY(y);
   lastX = x0;
 
+  useDestRow(y);
+
   destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x0];
   destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
 
@@ -1480,26 +1561,10 @@
     aDest = *destAlphaPtr;
 
     //----- overprint
-    if (state->overprintMask & 1) {
-      cSrc0 = state->cmykTransferC[cSrcPtr[0]];
-    } else {
-      cSrc0 = div255(aDest * cDest0);
-    }
-    if (state->overprintMask & 2) {
-      cSrc1 = state->cmykTransferM[cSrcPtr[1]];
-    } else {
-      cSrc1 = div255(aDest * cDest1);
-    }
-    if (state->overprintMask & 4) {
-      cSrc2 = state->cmykTransferY[cSrcPtr[2]];
-    } else {
-      cSrc2 = div255(aDest * cDest2);
-    }
-    if (state->overprintMask & 8) {
-      cSrc3 = state->cmykTransferK[cSrcPtr[3]];
-    } else {
-      cSrc3 = div255(aDest * cDest3);
-    }
+    cSrc0 = state->cmykTransferC[cSrcPtr[0]];
+    cSrc1 = state->cmykTransferM[cSrcPtr[1]];
+    cSrc2 = state->cmykTransferY[cSrcPtr[2]];
+    cSrc3 = state->cmykTransferK[cSrcPtr[3]];
 
     //----- source alpha
     aSrc = shape;
@@ -1552,6 +1617,80 @@
 
 
 // special case:
+// !pipe->pattern && pipe->shapeOnly && !state->blendFunc &&
+// bitmap->mode == splashModeMono8 && !bitmap->alpha
+void Splash::pipeRunShapeNoAlphaMono8(SplashPipe *pipe, int x0, int x1, int y,
+                                      Guchar *shapePtr,
+                                      SplashColorPtr cSrcPtr) {
+  Guchar shape, aSrc, cSrc0, cDest0, cResult0;
+  SplashColorPtr destColorPtr;
+  int cSrcStride, x, lastX;
+
+  if (cSrcPtr) {
+    cSrcStride = 1;
+  } else {
+    cSrcPtr = pipe->cSrcVal;
+    cSrcStride = 0;
+  }
+  for (; x0 <= x1; ++x0) {
+    if (*shapePtr) {
+      break;
+    }
+    cSrcPtr += cSrcStride;
+    ++shapePtr;
+  }
+  if (x0 > x1) {
+    return;
+  }
+  updateModX(x0);
+  updateModY(y);
+  lastX = x0;
+
+  useDestRow(y);
+
+  destColorPtr = &bitmap->data[y * bitmap->rowSize + x0];
+
+  for (x = x0; x <= x1; ++x) {
+
+    //----- shape
+    shape = *shapePtr;
+    if (!shape) {
+      ++destColorPtr;
+      cSrcPtr += cSrcStride;
+      ++shapePtr;
+      continue;
+    }
+    lastX = x;
+
+    //----- source color
+    cSrc0 = state->grayTransfer[cSrcPtr[0]];
+
+    //----- source alpha
+    aSrc = shape;
+
+    //----- special case for aSrc = 255
+    if (aSrc == 255) {
+      cResult0 = cSrc0;
+    } else {
+
+      //----- read destination pixel
+      cDest0 = *destColorPtr;
+
+      //----- result color
+      cResult0 = div255((255 - aSrc) * cDest0 + aSrc * cSrc0);
+    }
+
+    //----- write destination pixel
+    *destColorPtr++ = cResult0;
+
+    cSrcPtr += cSrcStride;
+    ++shapePtr;
+  }
+
+  updateModX(lastX);
+}
+
+// special case:
 // !pipe->pattern && !pipe->noTransparency && !state->softMask &&
 // pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
 // !pipe->nonIsolatedGroup &&
@@ -1584,6 +1723,8 @@
   updateModY(y);
   lastX = x0;
 
+  useDestRow(y);
+
   destColorPtr = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)];
   destColorMask = (Guchar)(0x80 >> (x0 & 7));
 
@@ -1663,6 +1804,8 @@
   updateModY(y);
   lastX = x0;
 
+  useDestRow(y);
+
   destColorPtr = &bitmap->data[y * bitmap->rowSize + x0];
   destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
 
@@ -1746,6 +1889,8 @@
   updateModY(y);
   lastX = x0;
 
+  useDestRow(y);
+
   destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0];
   destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
 
@@ -1840,6 +1985,8 @@
   updateModY(y);
   lastX = x0;
 
+  useDestRow(y);
+
   destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0];
   destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
 
@@ -1935,6 +2082,8 @@
   updateModY(y);
   lastX = x0;
 
+  useDestRow(y);
+
   destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x0];
   destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
 
@@ -2017,6 +2166,457 @@
 #endif
 
 
+// special case:
+// !pipe->pattern && aInput == 255 && state->softMask && usesShape &&
+// !state->inNonIsolatedGroup && !state->inKnockoutGroup &&
+// !nonIsolatedGroup && state->overprintMask == 0xffffffff &&
+// !state->blendFunc &&
+// bitmap->mode == splashModeMono8 && bitmap->alpha
+void Splash::pipeRunSoftMaskMono8(SplashPipe *pipe, int x0, int x1, int y,
+				  Guchar *shapePtr, SplashColorPtr cSrcPtr) {
+  Guchar shape, aSrc, aDest, alphaI, aResult;
+  Guchar cSrc0, cDest0, cResult0;
+  SplashColorPtr destColorPtr;
+  Guchar *destAlphaPtr;
+  SplashColorPtr softMaskPtr;
+  int cSrcStride, x, lastX;
+
+  if (cSrcPtr) {
+    cSrcStride = 1;
+  } else {
+    cSrcPtr = pipe->cSrcVal;
+    cSrcStride = 0;
+  }
+  for (; x0 <= x1; ++x0) {
+    if (*shapePtr) {
+      break;
+    }
+    cSrcPtr += cSrcStride;
+    ++shapePtr;
+  }
+  if (x0 > x1) {
+    return;
+  }
+  updateModX(x0);
+  updateModY(y);
+  lastX = x0;
+
+  useDestRow(y);
+
+  destColorPtr = &bitmap->data[y * bitmap->rowSize + x0];
+  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
+  softMaskPtr = &state->softMask->data[y * state->softMask->rowSize + x0];
+
+  for (x = x0; x <= x1; ++x) {
+
+    //----- shape
+    shape = *shapePtr;
+    if (!shape) {
+      ++destColorPtr;
+      ++destAlphaPtr;
+      ++softMaskPtr;
+      cSrcPtr += cSrcStride;
+      ++shapePtr;
+      continue;
+    }
+    lastX = x;
+
+    //----- read source color
+    cSrc0 = state->grayTransfer[cSrcPtr[0]];
+
+    //----- source alpha
+    aSrc = div255(*softMaskPtr++ * shape);
+
+    //----- special case for aSrc = 255
+    if (aSrc == 255) {
+      aResult = 255;
+      cResult0 = cSrc0;
+    } else {
+
+      //----- read destination alpha
+      aDest = *destAlphaPtr;
+
+      //----- special case for aDest = 0
+      if (aDest == 0) {
+        aResult = aSrc;
+        cResult0 = cSrc0;
+      } else {
+
+        //----- read destination pixel
+        cDest0 = destColorPtr[0];
+
+        //----- result alpha and non-isolated group element correction
+        aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
+        alphaI = aResult;
+
+        //----- result color
+        cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
+      }
+    }
+
+    //----- write destination pixel
+    destColorPtr[0] = cResult0;
+    ++destColorPtr;
+    *destAlphaPtr++ = aResult;
+
+    cSrcPtr += cSrcStride;
+    ++shapePtr;
+  }
+
+  updateModX(lastX);
+}
+
+// special case:
+// !pipe->pattern && aInput == 255 && state->softMask && usesShape &&
+// !state->inNonIsolatedGroup && !state->inKnockoutGroup &&
+// !nonIsolatedGroup && state->overprintMask == 0xffffffff &&
+// !state->blendFunc &&
+// bitmap->mode == splashModeRGB8 && bitmap->alpha
+void Splash::pipeRunSoftMaskRGB8(SplashPipe *pipe, int x0, int x1, int y,
+                                 Guchar *shapePtr, SplashColorPtr cSrcPtr) {
+  Guchar shape, aSrc, aDest, alphaI, aResult;
+  Guchar cSrc0, cSrc1, cSrc2;
+  Guchar cDest0, cDest1, cDest2;
+  Guchar cResult0, cResult1, cResult2;
+  SplashColorPtr destColorPtr;
+  Guchar *destAlphaPtr;
+  SplashColorPtr softMaskPtr;
+  int cSrcStride, x, lastX;
+
+  if (cSrcPtr) {
+    cSrcStride = 3;
+  } else {
+    cSrcPtr = pipe->cSrcVal;
+    cSrcStride = 0;
+  }
+  for (; x0 <= x1; ++x0) {
+    if (*shapePtr) {
+      break;
+    }
+    cSrcPtr += cSrcStride;
+    ++shapePtr;
+  }
+  if (x0 > x1) {
+    return;
+  }
+  updateModX(x0);
+  updateModY(y);
+  lastX = x0;
+
+  useDestRow(y);
+
+  destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * 3];
+  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
+  softMaskPtr = &state->softMask->data[y * state->softMask->rowSize + x0];
+
+  for (x = x0; x <= x1; ++x) {
+
+    //----- shape
+    shape = *shapePtr;
+    if (!shape) {
+      destColorPtr += 3;
+      ++destAlphaPtr;
+      ++softMaskPtr;
+      cSrcPtr += cSrcStride;
+      ++shapePtr;
+      continue;
+    }
+    lastX = x;
+
+    //----- read source color
+    cSrc0 = state->rgbTransferR[cSrcPtr[0]];
+    cSrc1 = state->rgbTransferG[cSrcPtr[1]];
+    cSrc2 = state->rgbTransferB[cSrcPtr[2]];
+
+    //----- source alpha
+    aSrc = div255(*softMaskPtr++ * shape);
+
+    //----- special case for aSrc = 255
+    if (aSrc == 255) {
+      aResult = 255;
+      cResult0 = cSrc0;
+      cResult1 = cSrc1;
+      cResult2 = cSrc2;
+    } else {
+
+      //----- read destination alpha
+      aDest = *destAlphaPtr;
+
+      //----- special case for aDest = 0
+      if (aDest == 0) {
+        aResult = aSrc;
+        cResult0 = cSrc0;
+        cResult1 = cSrc1;
+        cResult2 = cSrc2;
+      } else {
+
+        //----- read destination pixel
+        cDest0 = destColorPtr[0];
+        cDest1 = destColorPtr[1];
+        cDest2 = destColorPtr[2];
+
+        //----- result alpha and non-isolated group element correction
+        aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
+        alphaI = aResult;
+
+        //----- result color
+        cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
+        cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI);
+        cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI);
+      }
+    }
+
+    //----- write destination pixel
+    destColorPtr[0] = cResult0;
+    destColorPtr[1] = cResult1;
+    destColorPtr[2] = cResult2;
+    destColorPtr += 3;
+    *destAlphaPtr++ = aResult;
+
+    cSrcPtr += cSrcStride;
+    ++shapePtr;
+  }
+
+  updateModX(lastX);
+}
+
+// special case:
+// !pipe->pattern && aInput == 255 && state->softMask && usesShape &&
+// !state->inNonIsolatedGroup && !state->inKnockoutGroup &&
+// !nonIsolatedGroup && state->overprintMask == 0xffffffff &&
+// !state->blendFunc &&
+// bitmap->mode == splashModeBGR8 && bitmap->alpha
+void Splash::pipeRunSoftMaskBGR8(SplashPipe *pipe, int x0, int x1, int y,
+                                 Guchar *shapePtr, SplashColorPtr cSrcPtr) {
+  Guchar shape, aSrc, aDest, alphaI, aResult;
+  Guchar cSrc0, cSrc1, cSrc2;
+  Guchar cDest0, cDest1, cDest2;
+  Guchar cResult0, cResult1, cResult2;
+  SplashColorPtr destColorPtr;
+  Guchar *destAlphaPtr;
+  SplashColorPtr softMaskPtr;
+  int cSrcStride, x, lastX;
+
+  if (cSrcPtr) {
+    cSrcStride = 3;
+  } else {
+    cSrcPtr = pipe->cSrcVal;
+    cSrcStride = 0;
+  }
+  for (; x0 <= x1; ++x0) {
+    if (*shapePtr) {
+      break;
+    }
+    cSrcPtr += cSrcStride;
+    ++shapePtr;
+  }
+  if (x0 > x1) {
+    return;
+  }
+  updateModX(x0);
+  updateModY(y);
+  lastX = x0;
+
+  useDestRow(y);
+
+  destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * 3];
+  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
+  softMaskPtr = &state->softMask->data[y * state->softMask->rowSize + x0];
+
+  for (x = x0; x <= x1; ++x) {
+
+    //----- shape
+    shape = *shapePtr;
+    if (!shape) {
+      destColorPtr += 3;
+      ++destAlphaPtr;
+      ++softMaskPtr;
+      cSrcPtr += cSrcStride;
+      ++shapePtr;
+      continue;
+    }
+    lastX = x;
+
+    //----- read source color
+    cSrc0 = state->rgbTransferR[cSrcPtr[0]];
+    cSrc1 = state->rgbTransferG[cSrcPtr[1]];
+    cSrc2 = state->rgbTransferB[cSrcPtr[2]];
+
+    //----- source alpha
+    aSrc = div255(*softMaskPtr++ * shape);
+
+    //----- special case for aSrc = 255
+    if (aSrc == 255) {
+      aResult = 255;
+      cResult0 = cSrc0;
+      cResult1 = cSrc1;
+      cResult2 = cSrc2;
+    } else {
+
+      //----- read destination alpha
+      aDest = *destAlphaPtr;
+
+      //----- special case for aDest = 0
+      if (aDest == 0) {
+        aResult = aSrc;
+        cResult0 = cSrc0;
+        cResult1 = cSrc1;
+        cResult2 = cSrc2;
+      } else {
+
+        //----- read destination pixel
+        cDest0 = destColorPtr[2];
+        cDest1 = destColorPtr[1];
+        cDest2 = destColorPtr[0];
+
+        //----- result alpha and non-isolated group element correction
+        aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
+        alphaI = aResult;
+
+        //----- result color
+        cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
+        cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI);
+        cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI);
+      }
+    }
+
+    //----- write destination pixel
+    destColorPtr[2] = cResult0;
+    destColorPtr[1] = cResult1;
+    destColorPtr[0] = cResult2;
+    destColorPtr += 3;
+    *destAlphaPtr++ = aResult;
+
+    cSrcPtr += cSrcStride;
+    ++shapePtr;
+  }
+
+  updateModX(lastX);
+}
+
+#if SPLASH_CMYK
+// special case:
+// !pipe->pattern && aInput == 255 && state->softMask && usesShape &&
+// !state->inNonIsolatedGroup && !state->inKnockoutGroup &&
+// !nonIsolatedGroup && state->overprintMask == 0xffffffff &&
+// !state->blendFunc &&
+// bitmap->mode == splashModeCMYK8 && bitmap->alpha
+void Splash::pipeRunSoftMaskCMYK8(SplashPipe *pipe, int x0, int x1, int y,
+				  Guchar *shapePtr, SplashColorPtr cSrcPtr) {
+  Guchar shape, aSrc, aDest, alphaI, aResult;
+  Guchar cSrc0, cSrc1, cSrc2, cSrc3;
+  Guchar cDest0, cDest1, cDest2, cDest3;
+  Guchar cResult0, cResult1, cResult2, cResult3;
+  SplashColorPtr destColorPtr;
+  Guchar *destAlphaPtr;
+  SplashColorPtr softMaskPtr;
+  int cSrcStride, x, lastX;
+
+  if (cSrcPtr) {
+    cSrcStride = 4;
+  } else {
+    cSrcPtr = pipe->cSrcVal;
+    cSrcStride = 0;
+  }
+  for (; x0 <= x1; ++x0) {
+    if (*shapePtr) {
+      break;
+    }
+    cSrcPtr += cSrcStride;
+    ++shapePtr;
+  }
+  if (x0 > x1) {
+    return;
+  }
+  updateModX(x0);
+  updateModY(y);
+  lastX = x0;
+
+  useDestRow(y);
+
+  destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * 4];
+  destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
+  softMaskPtr = &state->softMask->data[y * state->softMask->rowSize + x0];
+
+  for (x = x0; x <= x1; ++x) {
+
+    //----- shape
+    shape = *shapePtr;
+    if (!shape) {
+      destColorPtr += 4;
+      ++destAlphaPtr;
+      ++softMaskPtr;
+      cSrcPtr += cSrcStride;
+      ++shapePtr;
+      continue;
+    }
+    lastX = x;
+
+    //----- read destination pixel
+    cDest0 = destColorPtr[0];
+    cDest1 = destColorPtr[1];
+    cDest2 = destColorPtr[2];
+    cDest3 = destColorPtr[3];
+
+    //----- read destination alpha
+    aDest = *destAlphaPtr;
+
+    //----- overprint
+    cSrc0 = state->cmykTransferC[cSrcPtr[0]];
+    cSrc1 = state->cmykTransferM[cSrcPtr[1]];
+    cSrc2 = state->cmykTransferY[cSrcPtr[2]];
+    cSrc3 = state->cmykTransferK[cSrcPtr[3]];
+
+    //----- source alpha
+    aSrc = div255(*softMaskPtr++ * shape);
+
+    //----- special case for aSrc = 255
+    if (aSrc == 255) {
+      aResult = 255;
+      cResult0 = cSrc0;
+      cResult1 = cSrc1;
+      cResult2 = cSrc2;
+      cResult3 = cSrc3;
+    } else {
+
+      //----- special case for aDest = 0
+      if (aDest == 0) {
+        aResult = aSrc;
+        cResult0 = cSrc0;
+        cResult1 = cSrc1;
+        cResult2 = cSrc2;
+        cResult3 = cSrc3;
+      } else {
+
+        //----- result alpha and non-isolated group element correction
+        aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest));
+        alphaI = aResult;
+
+        //----- result color
+        cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI);
+        cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI);
+        cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI);
+        cResult3 = (Guchar)(((alphaI - aSrc) * cDest3 + aSrc * cSrc3) / alphaI);
+      }
+    }
+
+    //----- write destination pixel
+    destColorPtr[0] = cResult0;
+    destColorPtr[1] = cResult1;
+    destColorPtr[2] = cResult2;
+    destColorPtr[3] = cResult3;
+    destColorPtr += 4;
+    *destAlphaPtr++ = aResult;
+
+    cSrcPtr += cSrcStride;
+    ++shapePtr;
+  }
+
+  updateModX(lastX);
+}
+#endif
+
+
 void Splash::pipeRunNonIsoMono8(SplashPipe *pipe, int x0, int x1, int y,
 				Guchar *shapePtr, SplashColorPtr cSrcPtr) {
   Guchar shape, aSrc, aDest, alphaI, alpha0, aResult;
@@ -2046,6 +2646,8 @@
   updateModY(y);
   lastX = x0;
 
+  useDestRow(y);
+
   destColorPtr = &bitmap->data[y * bitmap->rowSize + x0];
   destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
   alpha0Ptr = &groupBackBitmap->alpha[(groupBackY + y)
@@ -2130,6 +2732,8 @@
   updateModY(y);
   lastX = x0;
 
+  useDestRow(y);
+
   destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * 3];
   destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
   alpha0Ptr = &groupBackBitmap->alpha[(groupBackY + y)
@@ -2225,6 +2829,8 @@
   updateModY(y);
   lastX = x0;
 
+  useDestRow(y);
+
   destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * 3];
   destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
   alpha0Ptr = &groupBackBitmap->alpha[(groupBackY + y)
@@ -2321,6 +2927,8 @@
   updateModY(y);
   lastX = x0;
 
+  useDestRow(y);
+
   destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * 4];
   destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0];
   alpha0Ptr = &groupBackBitmap->alpha[(groupBackY + y)
@@ -2409,6 +3017,84 @@
 #endif
 
 
+void Splash::useDestRow(int y) {
+  int y0, y1, yy;
+
+  if (groupDestInitMode == splashGroupDestPreInit) {
+    return;
+  }
+  if (groupDestInitYMin > groupDestInitYMax) {
+    y0 = y1 = y;
+    groupDestInitYMin = groupDestInitYMax = y;
+  } else if (y < groupDestInitYMin) {
+    y0 = y;
+    y1 = groupDestInitYMin - 1;
+    groupDestInitYMin = y;
+  } else if (y > groupDestInitYMax) {
+    y0 = groupDestInitYMax + 1;
+    y1 = y;
+    groupDestInitYMax = y;
+  } else {
+    return;
+  }
+  for (yy = y0; yy <= y1; ++yy) {
+    if (groupDestInitMode == splashGroupDestInitZero) {
+      // same as clear(color=0, alpha=0)
+      memset(bitmap->data + bitmap->rowSize * yy, 0,
+	     bitmap->rowSize < 0 ? -bitmap->rowSize : bitmap->rowSize);
+      if (bitmap->alpha) {
+	memset(bitmap->alpha + bitmap->alphaRowSize * yy, 0,
+	       bitmap->alphaRowSize);
+      }
+    } else { // (groupDestInitMode == splashGroupDestInitCopy)
+      // same as blitTransparent
+      copyGroupBackdropRow(yy);
+    }
+  }
+}
+
+void Splash::copyGroupBackdropRow(int y) {
+  SplashColorPtr p, q;
+  Guchar mask, srcMask;
+  int x;
+
+  if (groupBackBitmap->mode != bitmap->mode) {
+    return;
+  }
+
+  if (bitmap->mode == splashModeMono1) {
+    p = &bitmap->data[y * bitmap->rowSize];
+    mask = (Guchar)0x80;
+    q = &groupBackBitmap->data[(groupBackY + y) * groupBackBitmap->rowSize
+			       + (groupBackX >> 3)];
+    srcMask = (Guchar)(0x80 >> (groupBackX & 7));
+    for (x = 0; x < bitmap->width; ++x) {
+      if (*q & srcMask) {
+	*p |= mask;
+      } else {
+	*p &= (Guchar)~mask;
+      }
+      if (!(mask = (Guchar)(mask >> 1))) {
+	mask = 0x80;
+	++p;
+      }
+      if (!(srcMask = (Guchar)(srcMask >> 1))) {
+	srcMask = 0x80;
+	++q;
+      }
+    }
+  } else {
+    p = &bitmap->data[y * bitmap->rowSize];
+    q = &groupBackBitmap->data[(groupBackY + y) * groupBackBitmap->rowSize
+			       + bitmapComps * groupBackX];
+    memcpy(p, q, bitmapComps * bitmap->width);
+  }
+
+  if (bitmap->alpha) {
+    memset(&bitmap->alpha[y * bitmap->alphaRowSize], 0, bitmap->width);
+  }
+}
+
 //------------------------------------------------------------------------
 
 // Transform a point from user space to device space.
@@ -2428,7 +3114,13 @@
 
 SplashImageCache::SplashImageCache() {
   tag = NULL;
-  image = NULL;
+  width = 0;
+  height = 0;
+  mode = splashModeRGB8;
+  alpha = gFalse;
+  interpolate = gFalse;
+  colorData = NULL;
+  alphaData = NULL;
   refCount = 1;
 }
 
@@ -2436,9 +3128,39 @@
   if (tag) {
     delete tag;
   }
-  if (image) {
-    delete image;
+  gfree(colorData);
+  gfree(alphaData);
+}
+
+GBool SplashImageCache::match(GString *aTag, int aWidth, int aHeight,
+			      SplashColorMode aMode, GBool aAlpha,
+			      GBool aInterpolate) {
+  return aTag && tag && !aTag->cmp(tag) &&
+	 aWidth == width && aHeight == height &&
+	 aMode == mode && aAlpha == alpha &&
+	 aInterpolate == interpolate;
+}
+
+void SplashImageCache::reset(GString *aTag, int aWidth, int aHeight,
+			     SplashColorMode aMode, GBool aAlpha,
+			     GBool aInterpolate) {
+  if (tag) {
+    delete tag;
   }
+  if (aTag) {
+    tag = aTag->copy();
+  } else {
+    tag = NULL;
+  }
+  width = aWidth;
+  height = aHeight;
+  mode = aMode;
+  alpha = aAlpha;
+  interpolate = aInterpolate; 
+  gfree(colorData);
+  colorData = NULL;
+  gfree(alphaData);
+  alphaData = NULL;
 }
 
 void SplashImageCache::incRefCount() {
@@ -2453,6 +3175,1172 @@
 }
 
 //------------------------------------------------------------------------
+// ImageScaler
+//------------------------------------------------------------------------
+
+// Abstract base class.
+class ImageScaler {
+public:
+
+  ImageScaler() {}
+  virtual ~ImageScaler() {}
+
+  // Compute the next line of the scaled image.  This can be called up
+  // to [scaledHeight] times.
+  virtual void nextLine() = 0;
+
+  // Retrieve the color and alpha data generated by the most recent
+  // call to nextLine().
+  virtual Guchar *colorData() = 0;
+  virtual Guchar *alphaData() = 0;
+};
+
+//------------------------------------------------------------------------
+// BasicImageScaler
+//------------------------------------------------------------------------
+
+// The actual image scaler.
+class BasicImageScaler: public ImageScaler {
+public:
+
+  BasicImageScaler(SplashImageSource aSrc, void *aSrcData,
+		   int aSrcWidth, int aSrcHeight, int aNComps, GBool aHasAlpha,
+		   int aScaledWidth, int aScaledHeight, GBool aInterpolate);
+  virtual ~BasicImageScaler();
+  virtual void nextLine();
+  virtual Guchar *colorData() { return colorLine; }
+  virtual Guchar *alphaData() { return alphaLine; }
+
+protected:
+
+  void vertDownscaleHorizDownscale();
+  void vertDownscaleHorizUpscaleNoInterp();
+  void vertDownscaleHorizUpscaleInterp();
+  void vertUpscaleHorizDownscaleNoInterp();
+  void vertUpscaleHorizDownscaleInterp();
+  void vertUpscaleHorizUpscaleNoInterp();
+  void vertUpscaleHorizUpscaleInterp();
+
+  // source image data function
+  SplashImageSource src;
+  void *srcData;
+
+  // source image size
+  int srcWidth;
+  int srcHeight;
+
+  // scaled image size
+  int scaledWidth;
+  int scaledHeight;
+
+  // number of color and alpha components
+  int nComps;
+  GBool hasAlpha;
+
+  // params/state for vertical scaling
+  int yp, yq;
+  int yt, yn;
+  int ySrcCur, yScaledCur;
+  SplashCoord yInvScale;
+
+  // params for horizontal scaling
+  int xp, xq;
+  SplashCoord xInvScale;
+
+  // scaling function
+  void (BasicImageScaler::*scalingFunc)();
+
+  // temporary buffers for vertical scaling
+  Guchar *colorTmpBuf0;
+  Guchar *colorTmpBuf1;
+  Guchar *colorTmpBuf2;
+  Guchar *alphaTmpBuf0;
+  Guchar *alphaTmpBuf1;
+  Guchar *alphaTmpBuf2;
+  Guint *colorAccBuf;
+  Guint *alphaAccBuf;
+
+  // output of horizontal scaling
+  Guchar *colorLine;
+  Guchar *alphaLine;
+};
+
+BasicImageScaler::BasicImageScaler(SplashImageSource aSrc, void *aSrcData,
+				   int aSrcWidth, int aSrcHeight,
+				   int aNComps, GBool aHasAlpha,
+				   int aScaledWidth, int aScaledHeight,
+				   GBool aInterpolate) {
+  colorTmpBuf0 = NULL;
+  colorTmpBuf1 = NULL;
+  colorTmpBuf2 = NULL;
+  alphaTmpBuf0 = NULL;
+  alphaTmpBuf1 = NULL;
+  alphaTmpBuf2 = NULL;
+  colorAccBuf = NULL;
+  alphaAccBuf = NULL;
+  colorLine = NULL;
+  alphaLine = NULL;
+
+  src = aSrc;
+  srcData = aSrcData;
+  srcWidth = aSrcWidth;
+  srcHeight = aSrcHeight;
+  scaledWidth = aScaledWidth;
+  scaledHeight = aScaledHeight;
+  nComps = aNComps;
+  hasAlpha = aHasAlpha;
+
+  // select scaling function; allocate buffers
+  if (scaledHeight <= srcHeight) {
+    // vertical downscaling
+    yp = srcHeight / scaledHeight;
+    yq = srcHeight % scaledHeight;
+    yt = 0;
+    colorTmpBuf0 = (Guchar *)gmallocn(srcWidth, nComps);
+    colorAccBuf = (Guint *)gmallocn(srcWidth, nComps * (int)sizeof(Guint));
+    if (hasAlpha) {
+      alphaTmpBuf0 = (Guchar *)gmalloc(srcWidth);
+      alphaAccBuf = (Guint *)gmallocn(srcWidth, sizeof(Guint));
+    }
+    if (scaledWidth <= srcWidth) {
+      scalingFunc = &BasicImageScaler::vertDownscaleHorizDownscale;
+    } else {
+      if (aInterpolate) {
+	scalingFunc = &BasicImageScaler::vertDownscaleHorizUpscaleInterp;
+      } else {
+	scalingFunc = &BasicImageScaler::vertDownscaleHorizUpscaleNoInterp;
+      }
+    }
+  } else {
+    // vertical upscaling
+    yp = scaledHeight / srcHeight;
+    yq = scaledHeight % srcHeight;
+    yt = 0;
+    yn = 0;
+    if (aInterpolate) {
+      yInvScale = (SplashCoord)srcHeight / (SplashCoord)scaledHeight;
+      colorTmpBuf0 = (Guchar *)gmallocn(srcWidth, nComps);
+      colorTmpBuf1 = (Guchar *)gmallocn(srcWidth, nComps);
+      if (hasAlpha) {
+	alphaTmpBuf0 = (Guchar *)gmalloc(srcWidth);
+	alphaTmpBuf1 = (Guchar *)gmalloc(srcWidth);
+      }
+      ySrcCur = 0;
+      yScaledCur = 0;
+      if (scaledWidth <= srcWidth) {
+	scalingFunc = &BasicImageScaler::vertUpscaleHorizDownscaleInterp;
+      } else {
+	colorTmpBuf2 = (Guchar *)gmallocn(srcWidth, nComps);
+	if (hasAlpha) {
+	  alphaTmpBuf2 = (Guchar *)gmalloc(srcWidth);
+	}
+	scalingFunc = &BasicImageScaler::vertUpscaleHorizUpscaleInterp;
+      }
+    } else {
+      colorTmpBuf0 = (Guchar *)gmallocn(srcWidth, nComps);
+      if (hasAlpha) {
+	alphaTmpBuf0 = (Guchar *)gmalloc(srcWidth);
+      }
+      if (scaledWidth <= srcWidth) {
+	scalingFunc = &BasicImageScaler::vertUpscaleHorizDownscaleNoInterp;
+      } else {
+	scalingFunc = &BasicImageScaler::vertUpscaleHorizUpscaleNoInterp;
+      }
+    }
+  }
+  if (scaledWidth <= srcWidth) {
+    xp = srcWidth / scaledWidth;
+    xq = srcWidth % scaledWidth;
+  } else {
+    xp = scaledWidth / srcWidth;
+    xq = scaledWidth % srcWidth;
+    if (aInterpolate) {
+      xInvScale = (SplashCoord)srcWidth / (SplashCoord)scaledWidth;
+    }
+  }
+  colorLine = (Guchar *)gmallocn(scaledWidth, nComps);
+  if (hasAlpha) {
+    alphaLine = (Guchar *)gmalloc(scaledWidth);
+  }
+}
+
+BasicImageScaler::~BasicImageScaler() {
+  gfree(colorTmpBuf0);
+  gfree(colorTmpBuf1);
+  gfree(colorTmpBuf2);
+  gfree(alphaTmpBuf0);
+  gfree(alphaTmpBuf1);
+  gfree(alphaTmpBuf2);
+  gfree(colorAccBuf);
+  gfree(alphaAccBuf);
+  gfree(colorLine);
+  gfree(alphaLine);
+}
+
+void BasicImageScaler::nextLine() {
+  (this->*scalingFunc)();
+}
+
+void BasicImageScaler::vertDownscaleHorizDownscale() {
+  //--- vert downscale
+  int yStep = yp;
+  yt += yq;
+  if (yt >= scaledHeight) {
+    yt -= scaledHeight;
+    ++yStep;
+  }
+  memset(colorAccBuf, 0, (srcWidth * nComps) * sizeof(Guint));
+  if (hasAlpha) {
+    memset(alphaAccBuf, 0, srcWidth * sizeof(Guint));
+  }
+  int nRowComps = srcWidth * nComps;
+  for (int i = 0; i < yStep; ++i) {
+    (*src)(srcData, colorTmpBuf0, alphaTmpBuf0);
+    for (int j = 0; j < nRowComps; ++j) {
+      colorAccBuf[j] += colorTmpBuf0[j];
+    }
+    if (hasAlpha) {
+      for (int j = 0; j < srcWidth; ++j) {
+	alphaAccBuf[j] += alphaTmpBuf0[j];
+      }
+    }
+  }
+
+  //--- horiz downscale
+  int colorAcc[splashMaxColorComps];
+  int xt = 0;
+  int unscaledColorIdx = 0;
+  int unscaledAlphaIdx = 0;
+  int scaledColorIdx = 0;
+
+  for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
+    int xStep = xp;
+    xt += xq;
+    if (xt >= scaledWidth) {
+      xt -= scaledWidth;
+      ++xStep;
+    }
+
+    for (int j = 0; j < nComps; ++j) {
+      colorAcc[j] = 0;
+    }
+    for (int i = 0; i < xStep; ++i) {
+      for (int j = 0; j < nComps; ++j) {
+	colorAcc[j] += colorAccBuf[unscaledColorIdx + j];
+      }
+      unscaledColorIdx += nComps;
+    }
+    int nPixels = yStep * xStep;
+    for (int j = 0; j < nComps; ++j) {
+      colorLine[scaledColorIdx + j] = (Guchar)(colorAcc[j] / nPixels);
+    }
+    scaledColorIdx += nComps;
+
+    if (hasAlpha) {
+      int alphaAcc = 0;
+      for (int i = 0; i < xStep; ++i) {
+	alphaAcc += alphaAccBuf[unscaledAlphaIdx];
+	++unscaledAlphaIdx;
+      }
+      alphaLine[scaledIdx] = (Guchar)(alphaAcc / nPixels);
+    }
+  }
+}
+
+void BasicImageScaler::vertDownscaleHorizUpscaleNoInterp() {
+  //--- vert downscale
+  int yStep = yp;
+  yt += yq;
+  if (yt >= scaledHeight) {
+    yt -= scaledHeight;
+    ++yStep;
+  }
+  memset(colorAccBuf, 0, (srcWidth * nComps) * sizeof(Guint));
+  if (hasAlpha) {
+    memset(alphaAccBuf, 0, srcWidth * sizeof(Guint));
+  }
+  int nRowComps = srcWidth * nComps;
+  for (int i = 0; i < yStep; ++i) {
+    (*src)(srcData, colorTmpBuf0, alphaTmpBuf0);
+    for (int j = 0; j < nRowComps; ++j) {
+      colorAccBuf[j] += colorTmpBuf0[j];
+    }
+    if (hasAlpha) {
+      for (int j = 0; j < srcWidth; ++j) {
+	alphaAccBuf[j] += alphaTmpBuf0[j];
+      }
+    }
+  }
+
+  //--- horiz upscale
+  Guchar colorBuf[splashMaxColorComps];
+  int xt = 0;
+  int scaledColorIdx = 0;
+  int srcColorIdx = 0;
+  int scaledAlphaIdx = 0;
+  for (int srcIdx = 0; srcIdx < srcWidth; ++srcIdx) {
+    int xStep = xp;
+    xt += xq;
+    if (xt >= srcWidth) {
+      xt -= srcWidth;
+      ++xStep;
+    }
+    for (int j = 0; j < nComps; ++j) {
+      colorBuf[j] = (Guchar)(colorAccBuf[srcColorIdx + j] / yStep);
+    }
+    srcColorIdx += nComps;
+    for (int i = 0; i < xStep; ++i) {
+      for (int j = 0; j < nComps; ++j) {
+	colorLine[scaledColorIdx + j] = colorBuf[j];
+      }
+      scaledColorIdx += nComps;
+    }
+    if (hasAlpha) {
+      Guchar alphaBuf = (Guchar)(alphaAccBuf[srcIdx] / yStep);
+      for (int i = 0; i < xStep; ++i) {
+	alphaLine[scaledAlphaIdx] = alphaBuf;
+	++scaledAlphaIdx;
+      }
+    }
+  }
+}
+
+void BasicImageScaler::vertDownscaleHorizUpscaleInterp() {
+  //--- vert downscale
+  int yStep = yp;
+  yt += yq;
+  if (yt >= scaledHeight) {
+    yt -= scaledHeight;
+    ++yStep;
+  }
+  memset(colorAccBuf, 0, (srcWidth * nComps) * sizeof(Guint));
+  if (hasAlpha) {
+    memset(alphaAccBuf, 0, srcWidth * sizeof(Guint));
+  }
+  int nRowComps = srcWidth * nComps;
+  for (int i = 0; i < yStep; ++i) {
+    (*src)(srcData, colorTmpBuf0, alphaTmpBuf0);
+    for (int j = 0; j < nRowComps; ++j) {
+      colorAccBuf[j] += colorTmpBuf0[j];
+    }
+    if (hasAlpha) {
+      for (int j = 0; j < srcWidth; ++j) {
+	alphaAccBuf[j] += alphaTmpBuf0[j];
+      }
+    }
+  }
+  for (int j = 0; j < srcWidth * nComps; ++j) {
+    colorAccBuf[j] /= yStep;
+  }
+  if (hasAlpha) {
+    for (int j = 0; j < srcWidth; ++j) {
+      alphaAccBuf[j] /= yStep;
+    }
+  }
+
+  //--- horiz upscale
+  int scaledColorIdx = 0;
+  for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
+    SplashCoord xs = ((SplashCoord)scaledIdx + 0.5) * xInvScale;
+    int x0 = splashFloor(xs - 0.5);
+    int x1 = x0 + 1;
+    SplashCoord s0 = (SplashCoord)x1 + 0.5 - xs;
+    SplashCoord s1 = (SplashCoord)1 - s0;
+    if (x0 < 0) {
+      x0 = 0;
+    }
+    if (x1 >= srcWidth) {
+      x1 = srcWidth - 1;
+    }
+    for (int j = 0; j < nComps; ++j) {
+      colorLine[scaledColorIdx + j] =
+	  (Guchar)(int)(s0 * colorAccBuf[x0 * nComps + j] +
+			s1 * colorAccBuf[x1 * nComps + j]);
+    }
+    scaledColorIdx += nComps;
+    if (hasAlpha) {
+      alphaLine[scaledIdx] = (Guchar)(int)(s0 * alphaAccBuf[x0] +
+					   s1 * alphaAccBuf[x1]);
+    }
+  }
+}
+
+void BasicImageScaler::vertUpscaleHorizDownscaleNoInterp() {
+  //--- vert upscale
+  if (yn == 0) {
+    yn = yp;
+    yt += yq;
+    if (yt >= srcHeight) {
+      yt -= srcHeight;
+      ++yn;
+    }
+    (*src)(srcData, colorTmpBuf0, alphaTmpBuf0);
+  }
+  --yn;
+
+  //--- horiz downscale
+  int colorAcc[splashMaxColorComps];
+  int xt = 0;
+  int unscaledColorIdx = 0;
+  int unscaledAlphaIdx = 0;
+  int scaledColorIdx = 0;
+  for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
+    int xStep = xp;
+    xt += xq;
+    if (xt >= scaledWidth) {
+      xt -= scaledWidth;
+      ++xStep;
+    }
+
+    for (int j = 0; j < nComps; ++j) {
+      colorAcc[j] = 0;
+    }
+    for (int i = 0; i < xStep; ++i) {
+      for (int j = 0; j < nComps; ++j) {
+	colorAcc[j] += colorTmpBuf0[unscaledColorIdx + j];
+      }
+      unscaledColorIdx += nComps;
+    }
+    for (int j = 0; j < nComps; ++j) {
+      colorLine[scaledColorIdx + j] = (Guchar)(colorAcc[j] / xStep);
+    }
+    scaledColorIdx += nComps;
+
+    if (hasAlpha) {
+      int alphaAcc = 0;
+      for (int i = 0; i < xStep; ++i) {
+	alphaAcc += alphaTmpBuf0[unscaledAlphaIdx];
+	++unscaledAlphaIdx;
+      }
+      alphaLine[scaledIdx] = (Guchar)(alphaAcc / xStep);
+    }
+  }
+}
+
+void BasicImageScaler::vertUpscaleHorizDownscaleInterp() {
+  //--- vert upscale
+  if (ySrcCur == 0) {
+    (*src)(srcData, colorTmpBuf0, alphaTmpBuf0);
+    (*src)(srcData, colorTmpBuf1, alphaTmpBuf1);
+    ySrcCur = 1;
+  }
+  SplashCoord ys = ((SplashCoord)yScaledCur + 0.5) * yInvScale;
+  int y0 = splashFloor(ys - 0.5);
+  int y1 = y0 + 1;
+  SplashCoord vs0 = (SplashCoord)y1 + 0.5 - ys;
+  SplashCoord vs1 = (SplashCoord)1 - vs0;
+  if (y1 > ySrcCur && ySrcCur < srcHeight - 1) {
+    Guchar *t = colorTmpBuf0;
+    colorTmpBuf0 = colorTmpBuf1;
+    colorTmpBuf1 = t;
+    if (hasAlpha) {
+      t = alphaTmpBuf0;
+      alphaTmpBuf0 = alphaTmpBuf1;
+      alphaTmpBuf1 = t;
+    }
+    (*src)(srcData, colorTmpBuf1, alphaTmpBuf1);
+    ++ySrcCur;
+  }
+  Guchar *color0 = colorTmpBuf0;
+  Guchar *color1 = colorTmpBuf1;
+  Guchar *alpha0 = alphaTmpBuf0;
+  Guchar *alpha1 = alphaTmpBuf1;
+  if (y0 < 0) {
+    y0 = 0;
+    color1 = color0;
+    alpha1 = alpha0;
+  }
+  if (y1 >= srcHeight) {
+    y1 = srcHeight - 1;
+    color0 = color1;
+    alpha0 = alpha1;
+  }
+  ++yScaledCur;
+
+  //--- horiz downscale
+  int colorAcc[splashMaxColorComps];
+  int xt = 0;
+  int unscaledColorIdx = 0;
+  int unscaledAlphaIdx = 0;
+  int scaledColorIdx = 0;
+  for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
+    int xStep = xp;
+    xt += xq;
+    if (xt >= scaledWidth) {
+      xt -= scaledWidth;
+      ++xStep;
+    }
+
+    for (int j = 0; j < nComps; ++j) {
+      colorAcc[j] = 0;
+    }
+    for (int i = 0; i < xStep; ++i) {
+      for (int j = 0; j < nComps; ++j) {
+	colorAcc[j] += (int)(vs0 * (int)color0[unscaledColorIdx + j] +
+			     vs1 * (int)color1[unscaledColorIdx + j]);
+      }
+      unscaledColorIdx += nComps;
+    }
+    for (int j = 0; j < nComps; ++j) {
+      colorLine[scaledColorIdx + j] = (Guchar)(colorAcc[j] / xStep);
+    }
+    scaledColorIdx += nComps;
+
+    if (hasAlpha) {
+      int alphaAcc = 0;
+      for (int i = 0; i < xStep; ++i) {
+	alphaAcc += (int)(vs0 * (int)alpha0[unscaledAlphaIdx] +
+			  vs1 * (int)alpha1[unscaledAlphaIdx]);
+	++unscaledAlphaIdx;
+      }
+      alphaLine[scaledIdx] = (Guchar)(alphaAcc / xStep);
+    }
+  }
+}
+
+void BasicImageScaler::vertUpscaleHorizUpscaleNoInterp() {
+  //--- vert upscale
+  if (yn == 0) {
+    yn = yp;
+    yt += yq;
+    if (yt >= srcHeight) {
+      yt -= srcHeight;
+      ++yn;
+    }
+    (*src)(srcData, colorTmpBuf0, alphaTmpBuf0);
+  }
+  --yn;
+
+  //--- horiz upscale
+  int xt = 0;
+  int scaledColorIdx = 0;
+  int srcColorIdx = 0;
+  int scaledAlphaIdx = 0;
+  for (int srcIdx = 0; srcIdx < srcWidth; ++srcIdx) {
+    int xStep = xp;
+    xt += xq;
+    if (xt >= srcWidth) {
+      xt -= srcWidth;
+      ++xStep;
+    }
+    for (int i = 0; i < xStep; ++i) {
+      for (int j = 0; j < nComps; ++j) {
+	colorLine[scaledColorIdx + j] = colorTmpBuf0[srcColorIdx + j];
+      }
+      scaledColorIdx += nComps;
+    }
+    srcColorIdx += nComps;
+    if (hasAlpha) {
+      Guchar alphaBuf = alphaTmpBuf0[srcIdx];
+      for (int i = 0; i < xStep; ++i) {
+	alphaLine[scaledAlphaIdx] = alphaBuf;
+	++scaledAlphaIdx;
+      }
+    }
+  }
+}
+
+void BasicImageScaler::vertUpscaleHorizUpscaleInterp() {
+  //--- vert upscale
+  if (ySrcCur == 0) {
+    (*src)(srcData, colorTmpBuf0, alphaTmpBuf0);
+    (*src)(srcData, colorTmpBuf1, alphaTmpBuf1);
+    ySrcCur = 1;
+  }
+  SplashCoord ys = ((SplashCoord)yScaledCur + 0.5) * yInvScale;
+  int y0 = splashFloor(ys - 0.5);
+  int y1 = y0 + 1;
+  SplashCoord vs0 = (SplashCoord)y1 + 0.5 - ys;
+  SplashCoord vs1 = (SplashCoord)1 - vs0;
+  if (y1 > ySrcCur && ySrcCur < srcHeight - 1) {
+    Guchar *t = colorTmpBuf0;
+    colorTmpBuf0 = colorTmpBuf1;
+    colorTmpBuf1 = t;
+    if (hasAlpha) {
+      t = alphaTmpBuf0;
+      alphaTmpBuf0 = alphaTmpBuf1;
+      alphaTmpBuf1 = t;
+    }
+    (*src)(srcData, colorTmpBuf1, alphaTmpBuf1);
+    ++ySrcCur;
+  }
+  Guchar *color0 = colorTmpBuf0;
+  Guchar *color1 = colorTmpBuf1;
+  Guchar *alpha0 = alphaTmpBuf0;
+  Guchar *alpha1 = alphaTmpBuf1;
+  if (y0 < 0) {
+    y0 = 0;
+    color1 = color0;
+    alpha1 = alpha0;
+  }
+  if (y1 >= srcHeight) {
+    y1 = srcHeight - 1;
+    color0 = color1;
+    alpha0 = alpha1;
+  }
+  ++yScaledCur;
+  for (int srcIdx = 0; srcIdx < srcWidth * nComps; ++srcIdx) {
+    colorTmpBuf2[srcIdx] = (Guchar)(int)(vs0 * (int)color0[srcIdx] +
+					 vs1 * (int)color1[srcIdx]);
+  }
+  if (hasAlpha) {
+    for (int srcIdx = 0; srcIdx < srcWidth; ++srcIdx) {
+      alphaTmpBuf2[srcIdx] = (Guchar)(int)(vs0 * (int)alpha0[srcIdx] +
+					   vs1 * (int)alpha1[srcIdx]);
+    }
+  }
+
+  //--- horiz upscale
+  int scaledColorIdx = 0;
+  for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
+    SplashCoord xs = ((SplashCoord)scaledIdx + 0.5) * xInvScale;
+    int x0 = splashFloor(xs - 0.5);
+    int x1 = x0 + 1;
+    SplashCoord hs0 = (SplashCoord)x1 + 0.5 - xs;
+    SplashCoord hs1 = (SplashCoord)1 - hs0;
+    if (x0 < 0) {
+      x0 = 0;
+    }
+    if (x1 >= srcWidth) {
+      x1 = srcWidth - 1;
+    }
+    for (int j = 0; j < nComps; ++j) {
+      colorLine[scaledColorIdx + j] =
+	  (Guchar)(int)(hs0 * (int)colorTmpBuf2[x0 * nComps + j] +
+			hs1 * (int)colorTmpBuf2[x1 * nComps + j]);
+    }
+    scaledColorIdx += nComps;
+    if (hasAlpha) {
+      alphaLine[scaledIdx] = (Guchar)(int)(hs0 * (int)alphaTmpBuf2[x0] +
+					   hs1 * (int)alphaTmpBuf2[x1]);
+    }
+  }
+}
+
+//------------------------------------------------------------------------
+// SavingImageScaler
+//------------------------------------------------------------------------
+
+// Wrapper around BasicImageScaler that saves the scaled image for use
+// by ReplayImageScaler.
+class SavingImageScaler: public BasicImageScaler {
+public:
+
+  SavingImageScaler(SplashImageSource aSrc, void *aSrcData,
+		    int aSrcWidth, int aSrcHeight, int aNComps, GBool aHasAlpha,
+		    int aScaledWidth, int aScaledHeight, GBool aInterpolate,
+		    Guchar *aColorCache, Guchar *aAlphaCache);
+  virtual void nextLine();
+
+private:
+
+  Guchar *colorPtr;
+  Guchar *alphaPtr;
+};
+
+SavingImageScaler::SavingImageScaler(SplashImageSource aSrc, void *aSrcData,
+				     int aSrcWidth, int aSrcHeight,
+				     int aNComps, GBool aHasAlpha,
+				     int aScaledWidth, int aScaledHeight,
+				     GBool aInterpolate,
+				     Guchar *aColorCache, Guchar *aAlphaCache):
+  BasicImageScaler(aSrc, aSrcData, aSrcWidth, aSrcHeight, aNComps, aHasAlpha,
+		   aScaledWidth, aScaledHeight, aInterpolate)
+{
+  colorPtr = aColorCache;
+  alphaPtr = aAlphaCache;
+}
+
+void SavingImageScaler::nextLine() {
+  BasicImageScaler::nextLine();
+  memcpy(colorPtr, colorData(), scaledWidth * nComps);
+  colorPtr += scaledWidth * nComps;
+  if (hasAlpha) {
+    memcpy(alphaPtr, alphaData(), scaledWidth);
+    alphaPtr += scaledWidth;
+  }
+}
+
+//------------------------------------------------------------------------
+// ReplayImageScaler
+//------------------------------------------------------------------------
+
+// "Replay" a scaled image saved by SavingImageScaler.
+class ReplayImageScaler: public ImageScaler {
+public:
+
+  ReplayImageScaler(int aNComps, GBool aHasAlpha,
+		    int aScaledWidth,
+		    Guchar *aColorCache, Guchar *aAlphaCache);
+  virtual void nextLine();
+  virtual Guchar *colorData() { return colorLine; }
+  virtual Guchar *alphaData() { return alphaLine; }
+
+private:
+
+  int nComps;
+  GBool hasAlpha;
+  int scaledWidth;
+  Guchar *colorPtr;
+  Guchar *alphaPtr;
+  Guchar *colorLine;
+  Guchar *alphaLine;
+};
+
+ReplayImageScaler::ReplayImageScaler(int aNComps, GBool aHasAlpha,
+				     int aScaledWidth,
+				     Guchar *aColorCache, Guchar *aAlphaCache) {
+  nComps = aNComps;
+  hasAlpha = aHasAlpha;
+  scaledWidth = aScaledWidth;
+  colorPtr = aColorCache;
+  alphaPtr = aAlphaCache;
+  colorLine = NULL;
+  alphaLine = NULL;
+}
+
+void ReplayImageScaler::nextLine() {
+  colorLine = colorPtr;
+  alphaLine = alphaPtr;
+  colorPtr += scaledWidth * nComps;
+  if (hasAlpha) {
+    alphaPtr += scaledWidth;
+  }
+}
+
+//------------------------------------------------------------------------
+// ImageMaskScaler
+//------------------------------------------------------------------------
+
+class ImageMaskScaler {
+public:
+
+  // Set up a MaskScaler to scale from [srcWidth]x[srcHeight] to
+  // [scaledWidth]x[scaledHeight].
+  ImageMaskScaler(SplashImageMaskSource aSrc, void *aSrcData,
+		  int aSrcWidth, int aSrcHeight,
+		  int aScaledWidth, int aScaledHeight, GBool aInterpolate);
+
+  ~ImageMaskScaler();
+
+  // Compute the next line of the scaled image mask.  This can be
+  // called up to [scaledHeight] times.
+  void nextLine();
+
+  // Retrieve the data generated by the most recent call to
+  // nextLine().
+  Guchar *data() { return line; }
+
+private:
+
+  void vertDownscaleHorizDownscale();
+  void vertDownscaleHorizUpscaleNoInterp();
+  void vertDownscaleHorizUpscaleInterp();
+  void vertUpscaleHorizDownscaleNoInterp();
+  void vertUpscaleHorizDownscaleInterp();
+  void vertUpscaleHorizUpscaleNoInterp();
+  void vertUpscaleHorizUpscaleInterp();
+
+  // source image data function
+  SplashImageMaskSource src;
+  void *srcData;
+
+  // source image size
+  int srcWidth;
+  int srcHeight;
+
+  // scaled image size
+  int scaledWidth;
+  int scaledHeight;
+
+  // params/state for vertical scaling
+  int yp, yq;
+  int yt, yn;
+  int ySrcCur, yScaledCur;
+  SplashCoord yInvScale;
+
+  // params for horizontal scaling
+  int xp, xq;
+  SplashCoord xInvScale;
+
+  // vertical and horizontal scaling functions
+  void (ImageMaskScaler::*scalingFunc)();
+
+  // temporary buffers for vertical scaling
+  Guchar *tmpBuf0;
+  Guchar *tmpBuf1;
+  Guchar *tmpBuf2;
+  Guint *accBuf;
+
+  // output of horizontal scaling
+  Guchar *line;
+};
+
+ImageMaskScaler::ImageMaskScaler(SplashImageMaskSource aSrc, void *aSrcData,
+				 int aSrcWidth, int aSrcHeight,
+				 int aScaledWidth, int aScaledHeight,
+				 GBool aInterpolate) {
+  tmpBuf0 = NULL;
+  tmpBuf1 = NULL;
+  tmpBuf2 = NULL;
+  accBuf = NULL;
+  line = NULL;
+
+  src = aSrc;
+  srcData = aSrcData;
+  srcWidth = aSrcWidth;
+  srcHeight = aSrcHeight;
+  scaledWidth = aScaledWidth;
+  scaledHeight = aScaledHeight;
+
+  // select scaling function; allocate buffers
+  if (scaledHeight <= srcHeight) {
+    // vertical downscaling
+    yp = srcHeight / scaledHeight;
+    yq = srcHeight % scaledHeight;
+    yt = 0;
+    tmpBuf0 = (Guchar *)gmalloc(srcWidth);
+    accBuf = (Guint *)gmallocn(srcWidth, sizeof(Guint));
+    if (scaledWidth <= srcWidth) {
+      scalingFunc = &ImageMaskScaler::vertDownscaleHorizDownscale;
+    } else {
+      if (aInterpolate) {
+	scalingFunc = &ImageMaskScaler::vertDownscaleHorizUpscaleInterp;
+      } else {
+	scalingFunc = &ImageMaskScaler::vertDownscaleHorizUpscaleNoInterp;
+      }
+    }
+  } else {
+    // vertical upscaling
+    yp = scaledHeight / srcHeight;
+    yq = scaledHeight % srcHeight;
+    yt = 0;
+    yn = 0;
+    if (aInterpolate) {
+      yInvScale = (SplashCoord)srcHeight / (SplashCoord)scaledHeight;
+      tmpBuf0 = (Guchar *)gmalloc(srcWidth);
+      tmpBuf1 = (Guchar *)gmalloc(srcWidth);
+      ySrcCur = 0;
+      yScaledCur = 0;
+      if (scaledWidth <= srcWidth) {
+	scalingFunc = &ImageMaskScaler::vertUpscaleHorizDownscaleInterp;
+      } else {
+	tmpBuf2 = (Guchar *)gmalloc(srcWidth);
+	scalingFunc = &ImageMaskScaler::vertUpscaleHorizUpscaleInterp;
+      }
+    } else {
+      tmpBuf0 = (Guchar *)gmalloc(srcWidth);
+      if (scaledWidth <= srcWidth) {
+	scalingFunc = &ImageMaskScaler::vertUpscaleHorizDownscaleNoInterp;
+      } else {
+	scalingFunc = &ImageMaskScaler::vertUpscaleHorizUpscaleNoInterp;
+      }
+    }
+  }
+  if (scaledWidth <= srcWidth) {
+    xp = srcWidth / scaledWidth;
+    xq = srcWidth % scaledWidth;
+  } else {
+    xp = scaledWidth / srcWidth;
+    xq = scaledWidth % srcWidth;
+    if (aInterpolate) {
+      xInvScale = (SplashCoord)srcWidth / (SplashCoord)scaledWidth;
+    }
+  }
+  line = (Guchar *)gmalloc(scaledWidth);
+}
+
+ImageMaskScaler::~ImageMaskScaler() {
+  gfree(tmpBuf0);
+  gfree(tmpBuf1);
+  gfree(tmpBuf2);
+  gfree(accBuf);
+  gfree(line);
+}
+
+void ImageMaskScaler::nextLine() {
+  (this->*scalingFunc)();
+}
+
+void ImageMaskScaler::vertDownscaleHorizDownscale() {
+  //--- vert downscale
+  int yStep = yp;
+  yt += yq;
+  if (yt >= scaledHeight) {
+    yt -= scaledHeight;
+    ++yStep;
+  }
+  memset(accBuf, 0, srcWidth * sizeof(Guint));
+  for (int i = 0; i < yStep; ++i) {
+    (*src)(srcData, tmpBuf0);
+    for (int j = 0; j < srcWidth; ++j) {
+      accBuf[j] += tmpBuf0[j];
+    }
+  }
+
+  //--- horiz downscale
+  int acc;
+  int xt = 0;
+  int unscaledIdx = 0;
+  for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
+    int xStep = xp;
+    xt += xq;
+    if (xt >= scaledWidth) {
+      xt -= scaledWidth;
+      ++xStep;
+    }
+
+    acc = 0;
+    for (int i = 0; i < xStep; ++i) {
+      acc += accBuf[unscaledIdx];
+      ++unscaledIdx;
+    }
+    line[scaledIdx] = (Guchar)((255 * acc) / (xStep * yStep));
+  }
+}
+
+void ImageMaskScaler::vertDownscaleHorizUpscaleNoInterp() {
+  //--- vert downscale
+  int yStep = yp;
+  yt += yq;
+  if (yt >= scaledHeight) {
+    yt -= scaledHeight;
+    ++yStep;
+  }
+  memset(accBuf, 0, srcWidth * sizeof(Guint));
+  for (int i = 0; i < yStep; ++i) {
+    (*src)(srcData, tmpBuf0);
+    for (int j = 0; j < srcWidth; ++j) {
+      accBuf[j] += tmpBuf0[j];
+    }
+  }
+
+  //--- horiz upscale
+  int xt = 0;
+  int scaledIdx = 0;
+  for (int srcIdx = 0; srcIdx < srcWidth; ++srcIdx) {
+    int xStep = xp;
+    xt += xq;
+    if (xt >= srcWidth) {
+      xt -= srcWidth;
+      ++xStep;
+    }
+    Guchar buf = (Guchar)((255 * accBuf[srcIdx]) / yStep);
+    for (int i = 0; i < xStep; ++i) {
+      line[scaledIdx] = buf;
+      ++scaledIdx;
+    }
+  }
+}
+
+void ImageMaskScaler::vertDownscaleHorizUpscaleInterp() {
+  //--- vert downscale
+  int yStep = yp;
+  yt += yq;
+  if (yt >= scaledHeight) {
+    yt -= scaledHeight;
+    ++yStep;
+  }
+  memset(accBuf, 0, srcWidth * sizeof(Guint));
+  for (int i = 0; i < yStep; ++i) {
+    (*src)(srcData, tmpBuf0);
+    for (int j = 0; j < srcWidth; ++j) {
+      accBuf[j] += tmpBuf0[j];
+    }
+  }
+  for (int j = 0; j < srcWidth; ++j) {
+    accBuf[j] = (255 * accBuf[j]) / yStep;
+  }
+
+  //--- horiz upscale
+  for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
+    SplashCoord xs = ((SplashCoord)scaledIdx + 0.5) * xInvScale;
+    int x0 = splashFloor(xs - 0.5);
+    int x1 = x0 + 1;
+    SplashCoord s0 = (SplashCoord)x1 + 0.5 - xs;
+    SplashCoord s1 = (SplashCoord)1 - s0;
+    if (x0 < 0) {
+      x0 = 0;
+    }
+    if (x1 >= srcWidth) {
+      x1 = srcWidth - 1;
+    }
+    line[scaledIdx] = (Guchar)(int)(s0 * accBuf[x0] + s1 * accBuf[x1]);
+  }
+}
+
+void ImageMaskScaler::vertUpscaleHorizDownscaleNoInterp() {
+  //--- vert upscale
+  if (yn == 0) {
+    yn = yp;
+    yt += yq;
+    if (yt >= srcHeight) {
+      yt -= srcHeight;
+      ++yn;
+    }
+    (*src)(srcData, tmpBuf0);
+  }
+  --yn;
+
+  //--- horiz downscale
+  int acc;
+  int xt = 0;
+  int unscaledIdx = 0;
+  for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
+    int xStep = xp;
+    xt += xq;
+    if (xt >= scaledWidth) {
+      xt -= scaledWidth;
+      ++xStep;
+    }
+
+    acc = 0;
+    for (int i = 0; i < xStep; ++i) {
+      acc += tmpBuf0[unscaledIdx];
+      ++unscaledIdx;
+    }
+    line[scaledIdx] = (Guchar)((255 * acc) / xStep);
+  }
+}
+
+void ImageMaskScaler::vertUpscaleHorizDownscaleInterp() {
+  //--- vert upscale
+  if (ySrcCur == 0) {
+    (*src)(srcData, tmpBuf0);
+    (*src)(srcData, tmpBuf1);
+    ySrcCur = 1;
+  }
+  SplashCoord ys = ((SplashCoord)yScaledCur + 0.5) * yInvScale;
+  int y0 = splashFloor(ys - 0.5);
+  int y1 = y0 + 1;
+  SplashCoord vs0 = (SplashCoord)y1 + 0.5 - ys;
+  SplashCoord vs1 = (SplashCoord)1 - vs0;
+  if (y1 > ySrcCur && ySrcCur < srcHeight - 1) {
+    Guchar *t = tmpBuf0;
+    tmpBuf0 = tmpBuf1;
+    tmpBuf1 = t;
+    (*src)(srcData, tmpBuf1);
+    ++ySrcCur;
+  }
+  Guchar *mask0 = tmpBuf0;
+  Guchar *mask1 = tmpBuf1;
+  if (y0 < 0) {
+    y0 = 0;
+    mask1 = mask0;
+  }
+  if (y1 >= srcHeight) {
+    y1 = srcHeight - 1;
+    mask0 = mask1;
+  }
+  ++yScaledCur;
+
+  //--- horiz downscale
+  int acc;
+  int xt = 0;
+  int unscaledIdx = 0;
+  for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
+    int xStep = xp;
+    xt += xq;
+    if (xt >= scaledWidth) {
+      xt -= scaledWidth;
+      ++xStep;
+    }
+
+    acc = 0;
+    for (int i = 0; i < xStep; ++i) {
+      acc += (int)(vs0 * (int)mask0[unscaledIdx] +
+		   vs1 * (int)mask1[unscaledIdx]);
+      ++unscaledIdx;
+    }
+    line[scaledIdx] = (Guchar)((255 * acc) / xStep);
+  }
+}
+
+void ImageMaskScaler::vertUpscaleHorizUpscaleNoInterp() {
+  //--- vert upscale
+  if (yn == 0) {
+    yn = yp;
+    yt += yq;
+    if (yt >= srcHeight) {
+      yt -= srcHeight;
+      ++yn;
+    }
+    (*src)(srcData, tmpBuf0);
+  }
+  --yn;
+
+  //--- horiz upscale
+  int xt = 0;
+  int scaledIdx = 0;
+  for (int srcIdx = 0; srcIdx < srcWidth; ++srcIdx) {
+    int xStep = xp;
+    xt += xq;
+    if (xt >= srcWidth) {
+      xt -= srcWidth;
+      ++xStep;
+    }
+    Guchar buf = (Guchar)(255 * tmpBuf0[srcIdx]);
+    for (int i = 0; i < xStep; ++i) {
+      line[scaledIdx] = buf;
+      ++scaledIdx;
+    }
+  }
+}
+
+void ImageMaskScaler::vertUpscaleHorizUpscaleInterp() {
+  //--- vert upscale
+  if (ySrcCur == 0) {
+    (*src)(srcData, tmpBuf0);
+    (*src)(srcData, tmpBuf1);
+    ySrcCur = 1;
+  }
+  SplashCoord ys = ((SplashCoord)yScaledCur + 0.5) * yInvScale;
+  int y0 = splashFloor(ys - 0.5);
+  int y1 = y0 + 1;
+  SplashCoord vs0 = (SplashCoord)255 * ((SplashCoord)y1 + 0.5 - ys);
+  SplashCoord vs1 = (SplashCoord)255 - vs0;
+  if (y1 > ySrcCur && ySrcCur < srcHeight - 1) {
+    Guchar *t = tmpBuf0;
+    tmpBuf0 = tmpBuf1;
+    tmpBuf1 = t;
+    (*src)(srcData, tmpBuf1);
+    ++ySrcCur;
+  }
+  Guchar *mask0 = tmpBuf0;
+  Guchar *mask1 = tmpBuf1;
+  if (y0 < 0) {
+    y0 = 0;
+    mask1 = mask0;
+  }
+  if (y1 >= srcHeight) {
+    y1 = srcHeight - 1;
+    mask0 = mask1;
+  }
+  ++yScaledCur;
+  for (int srcIdx = 0; srcIdx < srcWidth; ++srcIdx) {
+    tmpBuf2[srcIdx] = (Guchar)(int)(vs0 * (int)mask0[srcIdx] +
+				    vs1 * (int)mask1[srcIdx]);
+  }
+
+  //--- horiz upscale
+  for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) {
+    SplashCoord xs = ((SplashCoord)scaledIdx + 0.5) * xInvScale;
+    int x0 = splashFloor(xs - 0.5);
+    int x1 = x0 + 1;
+    SplashCoord hs0 = (SplashCoord)x1 + 0.5 - xs;
+    SplashCoord hs1 = (SplashCoord)1 - hs0;
+    if (x0 < 0) {
+      x0 = 0;
+    }
+    if (x1 >= srcWidth) {
+      x1 = srcWidth - 1;
+    }
+    line[scaledIdx] = (Guchar)(int)(hs0 * (int)tmpBuf2[x0] +
+				    hs1 * (int)tmpBuf2[x1]);
+  }
+}
+
+//------------------------------------------------------------------------
 // Splash
 //------------------------------------------------------------------------
 
@@ -2472,6 +4360,8 @@
     scanBuf2 = NULL;
   }
   groupBackBitmap = NULL;
+  groupDestInitMode = splashGroupDestPreInit;
+  overprintMaskBitmap = NULL;
   minLineWidth = 0;
   clearModRegion();
   debugMode = gFalse;
@@ -2499,6 +4389,8 @@
     scanBuf2 = NULL;
   }
   groupBackBitmap = NULL;
+  groupDestInitMode = splashGroupDestPreInit;
+  overprintMaskBitmap = NULL;
   minLineWidth = 0;
   clearModRegion();
   debugMode = gFalse;
@@ -2699,14 +4591,23 @@
 
 void Splash::setInTransparencyGroup(SplashBitmap *groupBackBitmapA,
 				    int groupBackXA, int groupBackYA,
+				    SplashGroupDestInitMode groupDestInitModeA,
 				    GBool nonIsolated, GBool knockout) {
   groupBackBitmap = groupBackBitmapA;
   groupBackX = groupBackXA;
   groupBackY = groupBackYA;
+  groupDestInitMode = groupDestInitModeA;
+  groupDestInitYMin = 1;
+  groupDestInitYMax = 0;
   state->inNonIsolatedGroup = nonIsolated;
   state->inKnockoutGroup = knockout;
 }
 
+void Splash::forceDeferredInit(int y, int h) {
+  useDestRow(y);
+  useDestRow(y + h - 1);
+}
+
 void Splash::setTransfer(Guchar *red, Guchar *green, Guchar *blue,
 			 Guchar *gray) {
   state->setTransfer(red, green, blue, gray);
@@ -3839,6 +5740,10 @@
   }
 }
 
+struct SplashDrawImageMaskRowData {
+  SplashPipe pipe;
+};
+
 // The glyphMode flag is not currently used, but may be useful if the
 // stroke adjustment behavior is changed.
 SplashError Splash::fillImageMask(GString *imageTag,
@@ -3845,12 +5750,6 @@
 				  SplashImageMaskSource src, void *srcData,
 				  int w, int h, SplashCoord *mat,
 				  GBool glyphMode, GBool interpolate) {
-  SplashBitmap *scaledMask;
-  SplashClipResult clipRes;
-  GBool minorAxisZero;
-  SplashCoord wSize, hSize, t0, t1;
-  int x0, y0, x1, y1, scaledWidth, scaledHeight;
-
   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],
@@ -3857,1113 +5756,468 @@
 	   (double)mat[3], (double)mat[4], (double)mat[5]);
   }
 
-  // check for singular matrix
+  //--- check for singular matrix
   if (!splashCheckDet(mat[0], mat[1], mat[2], mat[3], 0.000001)) {
     return splashErrSingularMatrix;
   }
 
-  minorAxisZero = splashAbs(mat[1]) <= 0.0001 && splashAbs(mat[2]) <= 0.0001;
-
-  // rough estimate of size of scaled mask
-  t0 = splashAbs(mat[0]);
-  t1 = splashAbs(mat[1]);
-  wSize = t0 > t1 ? t0 : t1;
-  t0 = splashAbs(mat[2]);
-  t1 = splashAbs(mat[3]);
-  hSize = t0 > t1 ? t0 : t1;
-
-  // stream-mode upscaling -- this is slower, so we only use it if the
-  // upscaled mask is large (in which case clipping should remove many
-  // pixels)
-#if USE_FIXEDPOINT
-  if ((wSize > 2 * w && hSize > 2 * h && (int)wSize > 1000000 / (int)hSize) ||
-      (wSize >     w && hSize >     h && (int)wSize > 10000000 / (int)hSize) ||
-      ((wSize > w || hSize > h) && (int)wSize > 25000000 / (int)hSize)) {
-#else
-  if ((wSize > 2 * w && hSize > 2 * h && wSize * hSize > 1000000) ||
-      (wSize >     w && hSize >     h && wSize * hSize > 10000000) ||
-      ((wSize > w || hSize > h) && wSize * hSize > 25000000)) {
-    upscaleMask(src, srcData, w, h, mat, glyphMode, interpolate);
-#endif
-
-  // scaling only
-  } else if (mat[0] > 0 && minorAxisZero && mat[3] > 0) {
-    getImageBounds(mat[4], mat[0] + mat[4], &x0, &x1);
-    getImageBounds(mat[5], mat[3] + mat[5], &y0, &y1);
-    clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1,
-				    state->strokeAdjust);
-    opClipRes = clipRes;
-    if (clipRes != splashClipAllOutside) {
-      scaledWidth = x1 - x0;
-      scaledHeight = y1 - y0;
-      scaledMask = scaleMask(imageTag, src, srcData, w, h,
-			     scaledWidth, scaledHeight, interpolate);
-      if (imageCache->vertFlip) {
-	vertFlipImage(scaledMask, scaledWidth, scaledHeight, 1);
-	imageCache->vertFlip = gFalse;
+  //--- compute image bbox, check clipping
+  GBool flipsOnly = splashAbs(mat[1]) <= 0.0001 && splashAbs(mat[2]) <= 0.0001;
+  GBool horizFlip = gFalse;
+  GBool vertFlip = gFalse;
+  int xMin, yMin, xMax, yMax;
+  if (flipsOnly) {
+    horizFlip = mat[0] < 0;
+    vertFlip = mat[3] < 0;
+    if (vertFlip) {
+      if (horizFlip) {    // bottom-up, mirrored
+	getImageBounds(mat[0] + mat[4], mat[4], &xMin, &xMax);
+	getImageBounds(mat[3] + mat[5], mat[5], &yMin, &yMax);
+      } else {            // bottom-up
+	getImageBounds(mat[4], mat[0] + mat[4], &xMin, &xMax);
+	getImageBounds(mat[3] + mat[5], mat[5], &yMin, &yMax);
       }
-      if (imageCache->horizFlip) {
-	horizFlipImage(scaledMask, scaledWidth, scaledHeight, 1);
-	imageCache->horizFlip = gFalse;
+    } else {
+      if (horizFlip) {    // top-down, mirrored
+	getImageBounds(mat[0] + mat[4], mat[4], &xMin, &xMax);
+	getImageBounds(mat[5], mat[3] + mat[5], &yMin, &yMax);
+      } else {            // top-down
+	getImageBounds(mat[4], mat[0] + mat[4], &xMin, &xMax);
+	getImageBounds(mat[5], mat[3] + mat[5], &yMin, &yMax);
       }
-      blitMask(scaledMask, x0, y0, clipRes);
     }
-    
-  // scaling plus vertical flip
-  } else if (mat[0] > 0 && minorAxisZero && mat[3] < 0) {
-    getImageBounds(mat[4], mat[0] + mat[4], &x0, &x1);
-    getImageBounds(mat[3] + mat[5], mat[5], &y0, &y1);
-    clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1,
-				    state->strokeAdjust);
-    opClipRes = clipRes;
-    if (clipRes != splashClipAllOutside) {
-      scaledWidth = x1 - x0;
-      scaledHeight = y1 - y0;
-      scaledMask = scaleMask(imageTag, src, srcData, w, h,
-			     scaledWidth, scaledHeight, interpolate);
-      if (!imageCache->vertFlip) {
-	vertFlipImage(scaledMask, scaledWidth, scaledHeight, 1);
-	imageCache->vertFlip = gTrue;
-      }
-      if (imageCache->horizFlip) {
-	horizFlipImage(scaledMask, scaledWidth, scaledHeight, 1);
-	imageCache->horizFlip = gFalse;
-      }
-      blitMask(scaledMask, x0, y0, clipRes);
+  } else {
+    int xx = splashRound(mat[4]);		// (0,0)
+    int yy = splashRound(mat[5]);
+    xMin = xMax = xx;
+    yMin = yMax = yy;
+    xx = splashRound(mat[0] + mat[4]);		// (1,0)
+    yy = splashRound(mat[1] + mat[5]);
+    if (xx < xMin) {
+      xMin = xx;
+    } else if (xx > xMax) {
+      xMax = xx;
     }
-
-  // scaling plus horizontal flip
-  } else if (mat[0] < 0 && minorAxisZero && mat[3] > 0) {
-    getImageBounds(mat[0] + mat[4], mat[4], &x0, &x1);
-    getImageBounds(mat[5], mat[3] + mat[5], &y0, &y1);
-    clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1,
-				    state->strokeAdjust);
-    opClipRes = clipRes;
-    if (clipRes != splashClipAllOutside) {
-      scaledWidth = x1 - x0;
-      scaledHeight = y1 - y0;
-      scaledMask = scaleMask(imageTag, src, srcData, w, h,
-			     scaledWidth, scaledHeight, interpolate);
-      if (imageCache->vertFlip) {
-	vertFlipImage(scaledMask, scaledWidth, scaledHeight, 1);
-	imageCache->vertFlip = gFalse;
-      }
-      if (!imageCache->horizFlip) {
-	horizFlipImage(scaledMask, scaledWidth, scaledHeight, 1);
-	imageCache->horizFlip = gTrue;
-      }
-      blitMask(scaledMask, x0, y0, clipRes);
+    if (yy < yMin) {
+      yMin = yy;
+    } else if (yy > yMax) {
+      yMax = yy;
     }
-
-  // scaling plus horizontal and vertical flips
-  } else if (mat[0] < 0 && minorAxisZero && mat[3] < 0) {
-    getImageBounds(mat[0] + mat[4], mat[4], &x0, &x1);
-    getImageBounds(mat[3] + mat[5], mat[5], &y0, &y1);
-    clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1,
-				    state->strokeAdjust);
-    opClipRes = clipRes;
-    if (clipRes != splashClipAllOutside) {
-      scaledWidth = x1 - x0;
-      scaledHeight = y1 - y0;
-      scaledMask = scaleMask(imageTag, src, srcData, w, h,
-			     scaledWidth, scaledHeight, interpolate);
-      if (!imageCache->vertFlip) {
-	vertFlipImage(scaledMask, scaledWidth, scaledHeight, 1);
-	imageCache->vertFlip = gTrue;
-      }
-      if (!imageCache->horizFlip) {
-	horizFlipImage(scaledMask, scaledWidth, scaledHeight, 1);
-	imageCache->horizFlip = gTrue;
-      }
-      blitMask(scaledMask, x0, y0, clipRes);
+    xx = splashRound(mat[2] + mat[4]);		// (0,1)
+    yy = splashRound(mat[3] + mat[5]);
+    if (xx < xMin) {
+      xMin = xx;
+    } else if (xx > xMax) {
+      xMax = xx;
     }
-
-  // all other cases
-  } else {
-    arbitraryTransformMask(imageTag, src, srcData, w, h,
-			   mat, glyphMode, interpolate);
-  }
-
-  return splashOk;
-}
-
-// The glyphMode flag is not currently used, but may be useful if the
-// stroke adjustment behavior is changed.
-void Splash::upscaleMask(SplashImageMaskSource src, void *srcData,
-			 int srcWidth, int srcHeight,
-			 SplashCoord *mat, GBool glyphMode,
-			 GBool interpolate) {
-  SplashClipResult clipRes;
-  SplashPipe pipe;
-  Guchar *unscaledImage, *p;
-  SplashCoord xMin, yMin, xMax, yMax, t;
-  SplashCoord mi0, mi1, mi2, mi3, mi4, mi5, det;
-  SplashCoord ix, iy, sx, sy, pix0, pix1;
-  int xMinI, yMinI, xMaxI, yMaxI, x, y, x0, y0, x1, y1, tt;
-
-  // compute the bbox of the target quadrilateral
-  xMin = xMax = mat[4];
-  t = mat[2] + mat[4];
-  if (t < xMin) {
-    xMin = t;
-  } else if (t > xMax) {
-    xMax = t;
-  }
-  t = mat[0] + mat[2] + mat[4];
-  if (t < xMin) {
-    xMin = t;
-  } else if (t > xMax) {
-    xMax = t;
-  }
-  t = mat[0] + mat[4];
-  if (t < xMin) {
-    xMin = t;
-  } else if (t > xMax) {
-    xMax = t;
-  }
-  getImageBounds(xMin, xMax, &xMinI, &xMaxI);
-  yMin = yMax = mat[5];
-  t = mat[3] + mat[5];
-  if (t < yMin) {
-    yMin = t;
-  } else if (t > yMax) {
-    yMax = t;
-  }
-  t = mat[1] + mat[3] + mat[5];
-  if (t < yMin) {
-    yMin = t;
-  } else if (t > yMax) {
-    yMax = t;
-  }
-  t = mat[1] + mat[5];
-  if (t < yMin) {
-    yMin = t;
-  } else if (t > yMax) {
-    yMax = t;
-  }
-  getImageBounds(yMin, yMax, &yMinI, &yMaxI);
-
-  // clipping
-  clipRes = state->clip->testRect(xMinI, yMinI, xMaxI - 1, yMaxI - 1,
-				  state->strokeAdjust);
-  opClipRes = clipRes;
-  if (clipRes == splashClipAllOutside) {
-    return;
-  }
-  if (clipRes != splashClipAllInside) {
-    if ((tt = state->clip->getXMinI(state->strokeAdjust)) > xMinI) {
-      xMinI = tt;
+    if (yy < yMin) {
+      yMin = yy;
+    } else if (yy > yMax) {
+      yMax = yy;
     }
-    if ((tt = state->clip->getXMaxI(state->strokeAdjust) + 1) < xMaxI) {
-      xMaxI = tt;
+    xx = splashRound(mat[0] + mat[2] + mat[4]);	// (1,1)
+    yy = splashRound(mat[1] + mat[3] + mat[5]);
+    if (xx < xMin) {
+      xMin = xx;
+    } else if (xx > xMax) {
+      xMax = xx;
     }
-    if ((tt = state->clip->getYMinI(state->strokeAdjust)) > yMinI) {
-      yMinI = tt;
+    if (yy < yMin) {
+      yMin = yy;
+    } else if (yy > yMax) {
+      yMax = yy;
     }
-    if ((tt = state->clip->getYMaxI(state->strokeAdjust) + 1) < yMaxI) {
-      yMaxI = tt;
+    if (xMax <= xMin) {
+      xMax = xMin + 1;
     }
+    if (yMax <= yMin) {
+      yMax = yMin + 1;
+    }
   }
+  SplashClipResult clipRes =
+      state->clip->testRect(xMin, yMin, xMax - 1, yMax - 1,
+			    state->strokeAdjust);
+  // If the scaled mask is much wider and/or taller than the clip
+  // region, we use the "arbitrary" scaling path, to avoid a
+  // potentially very slow loop in the flips-only path (which scans
+  // the full width and height of the scaled mask, regardless of the
+  // clip region).
+  int clipW = state->clip->getXMaxI(state->strokeAdjust)
+	      - state->clip->getXMinI(state->strokeAdjust);
+  int clipH = state->clip->getYMaxI(state->strokeAdjust)
+	      - state->clip->getYMinI(state->strokeAdjust);
+  GBool veryLarge = ((xMax - xMin) / 8 > clipW && xMax - xMin > 1000) ||
+                    ((yMax - yMin) / 8 > clipH && yMax - yMin > 1000);
 
-  // invert the matrix
-  det = mat[0] * mat[3] - mat[1] * mat[2];
-  if (splashAbs(det) < 1e-6) {
-    // this should be caught by the singular matrix check in fillImageMask
-    return;
-  }
-  det = (SplashCoord)1 / det;
-  mi0 = det * mat[3] * srcWidth;
-  mi1 = -det * mat[1] * srcHeight;
-  mi2 = -det * mat[2] * srcWidth;
-  mi3 = det * mat[0] * srcHeight;
-  mi4 = det * (mat[2] * mat[5] - mat[3] * mat[4]) * srcWidth;
-  mi5 = -det * (mat[0] * mat[5] - mat[1] * mat[4]) * srcHeight;
+  //--- set up the SplashDrawImageMaskRowData object and the pipes
+  SplashDrawImageMaskRowData dd;
+  pipeInit(&dd.pipe, state->fillPattern,
+	   (Guchar)splashRound(state->fillAlpha * 255),
+	   gTrue, gFalse);
 
-  // grab the image
-  unscaledImage = (Guchar *)gmallocn(srcWidth, srcHeight);
-  for (y = 0, p = unscaledImage; y < srcHeight; ++y, p += srcWidth) {
-    (*src)(srcData, p);
-    for (x = 0; x < srcWidth; ++x) {
-      p[x] = (Guchar)(p[x] * 255);
+  //--- choose the drawRow function
+  SplashDrawImageMaskRowFunc drawRowFunc;
+  if (clipRes == splashClipAllInside) {
+    drawRowFunc = &Splash::drawImageMaskRowNoClip;
+  } else {
+    if (vectorAntialias) {
+      drawRowFunc = &Splash::drawImageMaskRowClipAA;
+    } else {
+      drawRowFunc = &Splash::drawImageMaskRowClipNoAA;
     }
   }
 
-  // draw it
-  pipeInit(&pipe, state->fillPattern,
-	   (Guchar)splashRound(state->fillAlpha * 255),
-	   gTrue, gFalse);
-  for (y = yMinI; y < yMaxI; ++y) {
-    for (x = xMinI; x < xMaxI; ++x) {
-      ix = ((SplashCoord)x + 0.5) * mi0 + ((SplashCoord)y + 0.5) * mi2 + mi4;
-      iy = ((SplashCoord)x + 0.5) * mi1 + ((SplashCoord)y + 0.5) * mi3 + mi5;
-      if (interpolate) {
-	if (ix >= 0 && ix < srcWidth && iy >= 0 && iy < srcHeight) {
-	  x0 = splashFloor(ix - 0.5);
-	  x1 = x0 + 1;
-	  sx = (ix - 0.5) - x0;
-	  y0 = splashFloor(iy - 0.5);
-	  y1 = y0 + 1;
-	  sy = (iy - 0.5) - y0;
-	  if (x0 < 0) {
-	    x0 = 0;
+  //--- horizontal/vertical flips only
+  if (flipsOnly && !veryLarge) {
+    if (clipRes != splashClipAllOutside) {
+      int scaledWidth = xMax - xMin;
+      int scaledHeight = yMax - yMin;
+      ImageMaskScaler scaler(src, srcData, w, h,
+			     scaledWidth, scaledHeight, interpolate);
+      Guchar *tmpLine = NULL;
+      if (horizFlip) {
+	tmpLine = (Guchar *)gmalloc(scaledWidth);
+      }
+      if (vertFlip) {
+	if (horizFlip) {    // bottom-up, mirrored
+	  for (int y = 0; y < scaledHeight; ++y) {
+	    scaler.nextLine();
+	    mirrorImageMaskRow(scaler.data(), tmpLine, scaledWidth);
+	    (this->*drawRowFunc)(&dd, tmpLine,
+				 xMin, yMax - 1 - y, scaledWidth);
 	  }
-	  if (x1 >= srcWidth) {
-	    x1 = srcWidth - 1;
+	} else {            // bottom-up
+	  for (int y = 0; y < scaledHeight; ++y) {
+	    scaler.nextLine();
+	    (this->*drawRowFunc)(&dd, scaler.data(),
+				 xMin, yMax - 1 - y, scaledWidth);
 	  }
-	  if (y0 < 0) {
-	    y0 = 0;
+	}
+      } else {
+	if (horizFlip) {    // top-down, mirrored
+	  for (int y = 0; y < scaledHeight; ++y) {
+	    scaler.nextLine();
+	    mirrorImageMaskRow(scaler.data(), tmpLine, scaledWidth);
+	    (this->*drawRowFunc)(&dd, tmpLine,
+				 xMin, yMin + y, scaledWidth);
 	  }
-	  if (y1 >= srcHeight) {
-	    y1 = srcHeight - 1;
+	} else {            // top-down
+	  for (int y = 0; y < scaledHeight; ++y) {
+	    scaler.nextLine();
+	    (this->*drawRowFunc)(&dd, scaler.data(),
+				 xMin, yMin + y, scaledWidth);
 	  }
-	  pix0 = ((SplashCoord)1 - sx)
-	           * (SplashCoord)unscaledImage[y0 * srcWidth + x0]
-	         + sx * (SplashCoord)unscaledImage[y0 * srcWidth + x1];
-	  pix1 = ((SplashCoord)1 - sx)
-	           * (SplashCoord)unscaledImage[y1 * srcWidth + x0]
-	         + sx * (SplashCoord)unscaledImage[y1 * srcWidth + x1];
-	  scanBuf[x] = (Guchar)splashRound(((SplashCoord)1 - sy) * pix0
-					   + sy * pix1);
-	} else {
-	  scanBuf[x] = 0;
 	}
-      } else {
-	x0 = splashFloor(ix);
-	y0 = splashFloor(iy);
-	if (x0 >= 0 && x0 < srcWidth && y0 >= 0 && y0 < srcHeight) {
-	  scanBuf[x] = unscaledImage[y0 * srcWidth + x0];
-	} else {
-	  scanBuf[x] = 0;
-	}
       }
+      gfree(tmpLine);
     }
-    if (clipRes != splashClipAllInside) {
-      if (vectorAntialias) {
-	state->clip->clipSpan(scanBuf, y, xMinI, xMaxI - 1,
-			      state->strokeAdjust);
-      } else {
-	state->clip->clipSpanBinary(scanBuf, y, xMinI, xMaxI - 1,
-				    state->strokeAdjust);
-      }
-    }
-    (this->*pipe.run)(&pipe, xMinI, xMaxI - 1, y, scanBuf + xMinI, NULL);
-  }
 
-  gfree(unscaledImage);
-}
-
-// The glyphMode flag is not currently used, but may be useful if the
-// stroke adjustment behavior is changed.
-void Splash::arbitraryTransformMask(GString *imageTag,
-				    SplashImageMaskSource src, void *srcData,
-				    int srcWidth, int srcHeight,
-				    SplashCoord *mat, GBool glyphMode,
-				    GBool interpolate) {
-  SplashBitmap *scaledMask;
-  SplashClipResult clipRes;
-  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 bw, 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 = splashRound(vx[0]);
-  xMax = splashRound(vx[0]);
-  yMin = splashRound(vy[0]);
-  yMax = splashRound(vy[0]);
-  for (i = 1; i < 4; ++i) {
-    t0 = splashRound(vx[i]);
-    if (t0 < xMin) {
-      xMin = t0;
-    } else if (t0 > xMax) {
-      xMax = t0;
+  //--- arbitrary transform
+  } else {
+    // estimate of size of scaled image
+    int scaledWidth = splashRound(splashSqrt(mat[0] * mat[0]
+					     + mat[1] * mat[1]));
+    int scaledHeight = splashRound(splashSqrt(mat[2] * mat[2]
+					      + mat[3] * mat[3]));
+    if (scaledWidth < 1) {
+      scaledWidth = 1;
     }
-    t1 = splashRound(vy[i]);
-    if (t1 < yMin) {
-      yMin = t1;
-    } else if (t1 > yMax) {
-      yMax = t1;
+    if (scaledHeight < 1) {
+      scaledHeight = 1;
     }
-  }
-  clipRes = state->clip->testRect(xMin, yMin, xMax - 1, yMax - 1,
-				  state->strokeAdjust);
-  opClipRes = clipRes;
-  if (clipRes == splashClipAllOutside) {
-    return;
-  }
+    GBool downscaling = gTrue;
+    if (veryLarge || (scaledWidth >= w && scaledHeight >= h)) {
+      downscaling = gFalse;
+      scaledWidth = w;
+      scaledHeight = h;
+    }
 
-  // compute the scale factors
-  if (mat[0] >= 0) {
-    t0 = splashRound(mat[0] + mat[4]) - splashRound(mat[4]);
-  } else {
-    t0 = splashRound(mat[4]) - splashRound(mat[0] + mat[4]);
-  }
-  if (mat[1] >= 0) {
-    t1 = splashRound(mat[1] + mat[5]) - splashRound(mat[5]);
-  } else {
-    t1 = splashRound(mat[5]) - splashRound(mat[1] + mat[5]);
-  }
-  scaledWidth = t0 > t1 ? t0 : t1;
-  if (mat[2] >= 0) {
-    t0 = splashRound(mat[2] + mat[4]) - splashRound(mat[4]);
-  } else {
-    t0 = splashRound(mat[4]) - splashRound(mat[2] + mat[4]);
-  }
-  if (mat[3] >= 0) {
-    t1 = splashRound(mat[3] + mat[5]) - splashRound(mat[5]);
-  } else {
-    t1 = splashRound(mat[5]) - splashRound(mat[3] + mat[5]);
-  }
-  scaledHeight = t0 > t1 ? t0 : t1;
-  if (scaledWidth == 0) {
-    scaledWidth = 1;
-  }
-  if (scaledHeight == 0) {
-    scaledHeight = 1;
-  }
+    // compute mapping from device space to scaled image space
+    SplashCoord mat1[6];
+    mat1[0] = mat[0] / scaledWidth;
+    mat1[1] = mat[1] / scaledWidth;
+    mat1[2] = mat[2] / scaledHeight;
+    mat1[3] = mat[3] / scaledHeight;
+    mat1[4] = mat[4];
+    mat1[5] = mat[5];
+    SplashCoord det = mat1[0] * mat1[3] - mat1[1] * mat1[2];
+    if (splashAbs(det) < 1e-6) {
+      // this should be caught by the singular matrix check in drawImage
+      return splashErrSingularMatrix;
+    }
+    SplashCoord invMat[6];
+    invMat[0] = mat1[3] / det;
+    invMat[1] = -mat1[1] / det;
+    invMat[2] = -mat1[2] / det;
+    invMat[3] = mat1[0] / det;
+    // the extra "+ 0.5 * (...)" terms are here because the
+    // drawImageArbitrary(No)Interp functions multiply by pixel
+    // centers, (x + 0.5, y + 0.5)
+    invMat[4] = (mat1[2] * mat1[5] - mat1[3] * mat1[4]) / det
+                + (invMat[0] + invMat[2]) * 0.5;
+    invMat[5] = (mat1[1] * mat1[4] - mat1[0] * mat1[5]) / det
+                + (invMat[1] + invMat[3]) * 0.5;
 
-  // 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(imageTag, src, srcData, srcWidth, srcHeight,
-			 scaledWidth, scaledHeight, interpolate);
-  if (imageCache->vertFlip) {
-    vertFlipImage(scaledMask, scaledWidth, scaledHeight, 1);
-    imageCache->vertFlip = gFalse;
-  }
-  if (imageCache->horizFlip) {
-    horizFlipImage(scaledMask, scaledWidth, scaledHeight, 1);
-    imageCache->horizFlip = gFalse;
-  }
-
-  // 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 = splashRound(vy[i]);
-    section[0].y1 = splashRound(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 = splashRound(vy[i]);
-    section[2].y1 = splashRound(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 = splashRound(vy[(i+1) & 3]);
-      section[2].y0 = splashRound(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;
+    // if downscaling: store the downscaled image mask
+    // if upscaling: store the unscaled image mask
+    Guchar *scaledMask = (Guchar *)gmallocn(scaledHeight, scaledWidth);
+    if (downscaling) {
+      ImageMaskScaler scaler(src, srcData, w, h,
+			     scaledWidth, scaledHeight, interpolate);
+      Guchar *ptr = scaledMask;
+      for (int y = 0; y < scaledHeight; ++y) {
+	scaler.nextLine();
+	memcpy(ptr, scaler.data(), scaledWidth);
+	ptr += scaledWidth;
       }
     } else {
-      section[1].y0 = splashRound(vy[(i+3) & 3]);
-      section[2].y0 = splashRound(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;
+      Guchar *ptr = scaledMask;
+      for (int y = 0; y < scaledHeight; ++y) {
+	(*src)(srcData, ptr);
+	for (int x = 0; x < scaledWidth; ++x) {
+	  *ptr = (Guchar)(*ptr * 255);
+	  ++ptr;
+	}
       }
     }
-    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, state->fillPattern,
-	   (Guchar)splashRound(state->fillAlpha * 255),
-	   gTrue, gFalse);
+    // draw it
+    if (interpolate) {
+      drawImageMaskArbitraryInterp(scaledMask,
+				   &dd, drawRowFunc, invMat,
+				   scaledWidth, scaledHeight,
+				   xMin, yMin, xMax, yMax);
+    } else {
+      drawImageMaskArbitraryNoInterp(scaledMask,
+				     &dd, drawRowFunc, invMat,
+				     scaledWidth, scaledHeight,
+				     xMin, yMin, xMax, yMax);
+    }
 
-  // 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;
-    }
+    // free the downscaled/unscaled image
+    gfree(scaledMask);
   }
 
-  // scan all pixels inside the target region
-  bw = bitmap->width;
-  for (i = 0; i < nSections; ++i) {
-    for (y = section[i].y0; y <= section[i].y1; ++y) {
-      xa = splashRound(section[i].xa0 +
-		         ((SplashCoord)y + 0.5 - section[i].ya0) *
-		           section[i].dxdya);
-      xb = splashRound(section[i].xb0 +
-		         ((SplashCoord)y + 0.5 - section[i].yb0) *
-		           section[i].dxdyb);
-      if (xa > xb) {
-	continue;
-      }
-      // make sure narrow images cover at least one pixel
-      if (xa == xb) {
-	++xb;
-      }
-      // check the scanBuf bounds
-      if (xa >= bw || xb < 0) {
-	continue;
-      }
-      if (xa < 0) {
-	xa = 0;
-      }
-      if (xb > bw) {
-	xb = bw;
-      }
-      // get the scan line
-      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;
-	}
-	scanBuf[x] = scaledMask->data[yy * scaledWidth + xx];
-      }
-      // clip the scan line
-      if (clipRes != splashClipAllInside) {
-	if (vectorAntialias) {
-	  state->clip->clipSpan(scanBuf, y, xa, xb - 1, state->strokeAdjust);
-	} else {
-	  state->clip->clipSpanBinary(scanBuf, y, xa, xb - 1,
-				      state->strokeAdjust);
-	}
-      }
-      // draw the scan line
-      (this->*pipe.run)(&pipe, xa, xb - 1, y, scanBuf + xa, NULL);
-    }
-  }
+  return splashOk;
 }
 
-// Scale an image mask into a SplashBitmap.
-SplashBitmap *Splash::scaleMask(GString *imageTag,
-				SplashImageMaskSource src, void *srcData,
-				int srcWidth, int srcHeight,
-				int scaledWidth, int scaledHeight,
-				GBool interpolate) {
-  if (imageCache->tag && imageTag &&
-      !imageCache->tag->cmp(imageTag) &&
-      imageCache->isMask &&
-      imageCache->width == scaledWidth &&
-      imageCache->height == scaledHeight &&
-      imageCache->interpolate == interpolate) {
-    return imageCache->image;
+void Splash::drawImageMaskArbitraryNoInterp(
+				   Guchar *scaledMask,
+				   SplashDrawImageMaskRowData *dd,
+				   SplashDrawImageMaskRowFunc drawRowFunc,
+				   SplashCoord *invMat,
+				   int scaledWidth, int scaledHeight,
+				   int xMin, int yMin, int xMax, int yMax) {
+  int tt = state->clip->getXMinI(state->strokeAdjust);
+  if (tt > xMin) {
+    xMin = tt;
   }
-  if (imageCache->tag) {
-    delete imageCache->tag;
+  tt = state->clip->getXMaxI(state->strokeAdjust) + 1;
+  if (tt < xMax) {
+    xMax = tt;
   }
-  if (imageCache->image) {
-    delete imageCache->image;
+  tt = state->clip->getYMinI(state->strokeAdjust);
+  if (tt > yMin) {
+    yMin = tt;
   }
-  imageCache->tag = imageTag ? imageTag->copy() : (GString *)NULL;
-  imageCache->isMask = gTrue;
-  imageCache->width = scaledWidth;
-  imageCache->height = scaledHeight;
-  imageCache->interpolate = interpolate;
-  imageCache->vertFlip = gFalse;
-  imageCache->horizFlip = gFalse;
-  imageCache->image = new SplashBitmap(scaledWidth, scaledHeight,
-				       1, splashModeMono8, gFalse,
-				       gTrue, NULL);
-  if (scaledHeight < srcHeight) {
-    if (scaledWidth < srcWidth) {
-      scaleMaskYdXd(src, srcData, srcWidth, srcHeight,
-		    scaledWidth, scaledHeight, imageCache->image);
-    } else {
-      scaleMaskYdXu(src, srcData, srcWidth, srcHeight,
-		    scaledWidth, scaledHeight, imageCache->image);
-    }
-  } else {
-    if (scaledWidth < srcWidth) {
-      scaleMaskYuXd(src, srcData, srcWidth, srcHeight,
-		    scaledWidth, scaledHeight, imageCache->image);
-    } else {
-      if (interpolate) {
-	scaleMaskYuXuI(src, srcData, srcWidth, srcHeight,
-		       scaledWidth, scaledHeight, imageCache->image);
-      } else {
-	scaleMaskYuXu(src, srcData, srcWidth, srcHeight,
-		      scaledWidth, scaledHeight, imageCache->image);
-      }
-    }
+  tt = state->clip->getYMaxI(state->strokeAdjust) + 1;
+  if (tt < yMax) {
+    yMax = tt;
   }
-  return imageCache->image;
-}
+  if (xMax <= xMin || yMax <= yMin) {
+    return;
+  }
 
-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;
+  Guchar *buf = (Guchar *)gmalloc(xMax - xMin);
 
-  // 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];
+  for (int y = yMin; y < yMax; ++y) {
+    int rowMin = xMax;
+    int rowMax = 0;
+    for (int x = xMin; x < xMax; ++x) {
+      // note: invMat includes a "+0.5" factor so that this is really
+      // a multiply by (x+0.5, y+0.5)
+      int xx = splashFloor((SplashCoord)x * invMat[0]
+			   + (SplashCoord)y * invMat[2] + invMat[4]);
+      int yy = splashFloor((SplashCoord)x * invMat[1]
+			   + (SplashCoord)y * invMat[3] + invMat[5]);
+      if (xx >= 0 && xx < scaledWidth &&
+	  yy >= 0 && yy < scaledHeight) {
+	Guchar *p = scaledMask + (yy * scaledWidth + xx);
+	Guchar *q = buf + (x - xMin);
+	*q = *p;
+	if (x < rowMin) {
+	  rowMin = x;
+	}
+	rowMax = x + 1;
       }
     }
-
-    // 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 + (1 << 22)) >> 23;
-
-      // store the pixel
-      *destPtr++ = (Guchar)pix;
+    if (rowMin < rowMax) {
+      (this->*drawRowFunc)(dd, buf + (rowMin - xMin),
+			   rowMin, y, rowMax - rowMin);
     }
   }
 
-  gfree(pixBuf);
-  gfree(lineBuf);
+  gfree(buf);
 }
 
-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;
+void Splash::drawImageMaskArbitraryInterp(
+				   Guchar *scaledMask,
+				   SplashDrawImageMaskRowData *dd,
+				   SplashDrawImageMaskRowFunc drawRowFunc,
+				   SplashCoord *invMat,
+				   int scaledWidth, int scaledHeight,
+				   int xMin, int yMin, int xMax, int yMax) {
+  int tt = state->clip->getXMinI(state->strokeAdjust);
+  if (tt > xMin) {
+    xMin = tt;
+  }
+  tt = state->clip->getXMaxI(state->strokeAdjust) + 1;
+  if (tt < xMax) {
+    xMax = tt;
+  }
+  tt = state->clip->getYMinI(state->strokeAdjust);
+  if (tt > yMin) {
+    yMin = tt;
+  }
+  tt = state->clip->getYMaxI(state->strokeAdjust) + 1;
+  if (tt < yMax) {
+    yMax = tt;
+  }
+  if (xMax <= xMin || yMax <= yMin) {
+    return;
+  }
 
-  // Bresenham parameters for y scale
-  yp = srcHeight / scaledHeight;
-  yq = srcHeight % scaledHeight;
+  Guchar *buf = (Guchar *)gmalloc(xMax - xMin);
 
-  // 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;
-
-  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];
+  for (int y = yMin; y < yMax; ++y) {
+    int rowMin = xMax;
+    int rowMax = 0;
+    for (int x = xMin; x < xMax; ++x) {
+      // note: invMat includes a "+0.5" factor so that this is really
+      // a multiply by (x+0.5, y+0.5)
+      SplashCoord xs = (SplashCoord)x * invMat[0]
+	               + (SplashCoord)y * invMat[2] + invMat[4];
+      SplashCoord ys = (SplashCoord)x * invMat[1]
+	               + (SplashCoord)y * invMat[3] + invMat[5];
+      int x0 = splashFloor(xs - 0.5);
+      int x1 = x0 + 1;
+      int y0 = splashFloor(ys - 0.5);
+      int y1 = y0 + 1;
+      if (x1 >= 0 && x0 < scaledWidth && y1 >= 0 && y0 < scaledHeight) {
+	SplashCoord sx0 = (SplashCoord)x1 + 0.5 - xs;
+	SplashCoord sx1 = (SplashCoord)1 - sx0;
+	SplashCoord sy0 = (SplashCoord)y1 + 0.5 - ys;
+	SplashCoord sy1 = (SplashCoord)1 - sy0;
+	if (x0 < 0) {
+	  x0 = 0;
+	}
+	if (x1 >= scaledWidth) {
+	  x1 = scaledWidth - 1;
+	}
+	if (y0 < 0) {
+	  y0 = 0;
+	}
+	if (y1 >= scaledHeight) {
+	  y1 = scaledHeight - 1;
+	}
+	Guchar *p00 = scaledMask + (y0 * scaledWidth + x0);
+	Guchar *p10 = scaledMask + (y0 * scaledWidth + x1);
+	Guchar *p01 = scaledMask + (y1 * scaledWidth + x0);
+	Guchar *p11 = scaledMask + (y1 * scaledWidth + x1);
+	Guchar *q = buf + (x - xMin);
+	*q = (Guchar)(int)(sx0 * (sy0 * (int)*p00 + sy1 * (int)*p01) +
+			   sx1 * (sy0 * (int)*p10 + sy1 * (int)*p11));
+	if (x < rowMin) {
+	  rowMin = x;
+	}
+	rowMax = x + 1;
       }
     }
-
-    // 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 + (1 << 22)) >> 23;
-
-      // store the pixel
-      for (i = 0; i < xStep; ++i) {
-	*destPtr++ = (Guchar)pix;
-      }
+    if (rowMin < rowMax) {
+      (this->*drawRowFunc)(dd, buf + (rowMin - xMin),
+			   rowMin, y, rowMax - rowMin);
     }
   }
 
-  gfree(pixBuf);
-  gfree(lineBuf);
+  gfree(buf);
 }
 
-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;
+void Splash::mirrorImageMaskRow(Guchar *maskIn, Guchar *maskOut, int width) {
+  Guchar *p, *q;
 
-  // 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;
-
-  destPtr0 = dest->data;
-  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 + (1 << 22)) >> 23;
-
-      // store the pixel
-      for (i = 0; i < yStep; ++i) {
-	destPtr = destPtr0 + i * scaledWidth + x;
-	*destPtr = (Guchar)pix;
-      }
-    }
-
-    destPtr0 += yStep * scaledWidth;
+  p = maskIn;
+  q = maskOut + (width - 1);
+  for (int i = 0; i < width; ++i) {
+    *q = *p;
+    ++p;
+    --q;
   }
+}
 
-  gfree(lineBuf);
+void Splash::drawImageMaskRowNoClip(SplashDrawImageMaskRowData *data,
+				    Guchar *maskData,
+				    int x, int y, int width) {
+  (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y, maskData, NULL);
 }
 
-void Splash::scaleMaskYuXu(SplashImageMaskSource src, void *srcData,
-			   int srcWidth, int srcHeight,
-			   int scaledWidth, int scaledHeight,
-			   SplashBitmap *dest) {
-  Guchar *lineBuf;
-  Guchar pix;
-  Guchar *srcPtr, *destPtr;
-  int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep;
-  int i;
-
-  // 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;
-
-  destPtr = dest->data;
-  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;
-
-    // generate one row
-    srcPtr = lineBuf;
-    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 = *srcPtr ? 255 : 0;
-      ++srcPtr;
-
-      // duplicate the pixel horizontally
-      for (i = 0; i < xStep; ++i) {
-	*destPtr++ = pix;
-      }
-    }
-
-    // duplicate the row vertically
-    for (i = 1 ; i < yStep; ++i) {
-      memcpy(destPtr, destPtr - scaledWidth, scaledWidth);
-      destPtr += scaledWidth;
-    }
+void Splash::drawImageMaskRowClipNoAA(SplashDrawImageMaskRowData *data,
+				      Guchar *maskData,
+				      int x, int y, int width) {
+  if (y < 0 || y >= bitmap->height) {
+    return;
   }
-
-  gfree(lineBuf);
+  if (x < 0) {
+    maskData -= x;
+    width += x;
+    x = 0;
+  }
+  if (x + width > bitmap->width) {
+    width = bitmap->width - x;
+  }
+  if (width <= 0) {
+    return;
+  }
+  memcpy(scanBuf + x, maskData, width);
+  state->clip->clipSpanBinary(scanBuf, y, x, x + width - 1,
+			      state->strokeAdjust);
+  (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y,
+			  scanBuf + x, NULL);
 }
 
-void Splash::scaleMaskYuXuI(SplashImageMaskSource src, void *srcData,
-			    int srcWidth, int srcHeight,
-			    int scaledWidth, int scaledHeight,
-			    SplashBitmap *dest) {
-  Guchar *lineBuf0, *lineBuf1, *tBuf;
-  Guchar pix;
-  SplashCoord yr, xr, ys, xs, ySrc, xSrc;
-  int ySrc0, ySrc1, yBuf, xSrc0, xSrc1, y, x;
-  Guchar *destPtr;
-
-  // ratios
-  yr = (SplashCoord)srcHeight / (SplashCoord)scaledHeight;
-  xr = (SplashCoord)srcWidth / (SplashCoord)scaledWidth;
-
-  // allocate buffers
-  lineBuf0 = (Guchar *)gmalloc(scaledWidth);
-  lineBuf1 = (Guchar *)gmalloc(scaledWidth);
-
-  // read first two rows
-  (*src)(srcData, lineBuf0);
-  if (srcHeight > 1) {
-    (*src)(srcData, lineBuf1);
-    yBuf = 1;
-  } else {
-    memcpy(lineBuf1, lineBuf0, srcWidth);
-    yBuf = 0;
+void Splash::drawImageMaskRowClipAA(SplashDrawImageMaskRowData *data,
+				    Guchar *maskData,
+				    int x, int y, int width) {
+  if (y < 0 || y >= bitmap->height) {
+    return;
   }
-
-  // interpolate first two rows
-  for (x = scaledWidth - 1; x >= 0; --x) {
-    xSrc = xr * x;
-    xSrc0 = splashFloor(xSrc + xr * 0.5 - 0.5);
-    xSrc1 = xSrc0 + 1;
-    xs = ((SplashCoord)xSrc1 + 0.5) - (xSrc + xr * 0.5);
-    if (xSrc0 < 0) {
-      xSrc0 = 0;
-    }
-    if (xSrc1 >= srcWidth) {
-      xSrc1 = srcWidth - 1;
-    }
-    lineBuf0[x] = (Guchar)(int)
-          ((xs * (int)lineBuf0[xSrc0] +
-	    ((SplashCoord)1 - xs) * (int)lineBuf0[xSrc1]) * 255);
-    lineBuf1[x] = (Guchar)(int)
-          ((xs * (int)lineBuf1[xSrc0] +
-	    ((SplashCoord)1 - xs) * (int)lineBuf1[xSrc1]) * 255);
+  if (x < 0) {
+    maskData -= x;
+    width += x;
+    x = 0;
   }
-
-  destPtr = dest->data;
-  for (y = 0; y < scaledHeight; ++y) {
-
-    // compute vertical interpolation parameters
-    ySrc = yr * y;
-    ySrc0 = splashFloor(ySrc + yr * 0.5 - 0.5);
-    ySrc1 = ySrc0 + 1;
-    ys = ((SplashCoord)ySrc1 + 0.5) - (ySrc + yr * 0.5);
-    if (ySrc0 < 0) {
-      ySrc0 = 0;
-      ys = 1;
-    }
-    if (ySrc1 >= srcHeight) {
-      ySrc1 = srcHeight - 1;
-      ys = 0;
-    }
-
-    // read another row (if necessary)
-    if (ySrc1 > yBuf) {
-      tBuf = lineBuf0;
-      lineBuf0 = lineBuf1;
-      lineBuf1 = tBuf;
-      (*src)(srcData, lineBuf1);
-
-      // interpolate the row
-      for (x = scaledWidth - 1; x >= 0; --x) {
-	xSrc = xr * x;
-	xSrc0 = splashFloor(xSrc + xr * 0.5 - 0.5);
-	xSrc1 = xSrc0 + 1;
-	xs = ((SplashCoord)xSrc1 + 0.5) - (xSrc + xr * 0.5);
-	if (xSrc0 < 0) {
-	  xSrc0 = 0;
-	}
-	if (xSrc1 >= srcWidth) {
-	  xSrc1 = srcWidth - 1;
-	}
-	lineBuf1[x] = (Guchar)(int)
-	              ((xs * (int)lineBuf1[xSrc0] +
-			((SplashCoord)1 - xs) * (int)lineBuf1[xSrc1]) * 255);
-      }
-
-      ++yBuf;
-    }
-
-    // do the vertical interpolation
-    for (x = 0; x < scaledWidth; ++x) {
-
-      pix = (Guchar)(int)(ys * (int)lineBuf0[x] +
-			  ((SplashCoord)1 - ys) * (int)lineBuf1[x]);
-
-      // store the pixel
-      *destPtr++ = pix;
-    }
+  if (x + width > bitmap->width) {
+    width = bitmap->width - x;
   }
-
-  gfree(lineBuf1);
-  gfree(lineBuf0);
+  if (width <= 0) {
+    return;
+  }
+  memcpy(scanBuf + x, maskData, width);
+  state->clip->clipSpan(scanBuf, y, x, x + width - 1, state->strokeAdjust);
+  (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y,
+			  scanBuf + x, NULL);
 }
 
-void Splash::blitMask(SplashBitmap *src, int xDest, int yDest,
-		      SplashClipResult clipRes) {
+struct SplashDrawImageRowData {
+  int nComps;
+  GBool srcAlpha;
   SplashPipe pipe;
-  int w, h, x0, x1, y0, y1, y, t;
+};
 
-  w = src->width;
-  h = src->height;
-  pipeInit(&pipe, state->fillPattern,
-	   (Guchar)splashRound(state->fillAlpha * 255),
-	   gTrue, gFalse);
-  if (clipRes == splashClipAllInside) {
-    for (y = 0; y < h; ++y) {
-      (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y,
-			src->data + y * (size_t)w, NULL);
-    }
-  } else {
-    x0 = xDest;
-    if ((t = state->clip->getXMinI(state->strokeAdjust)) > x0) {
-      x0 = t;
-    }
-    x1 = xDest + w;
-    if ((t = state->clip->getXMaxI(state->strokeAdjust) + 1) < x1) {
-      x1 = t;
-    }
-    y0 = yDest;
-    if ((t = state->clip->getYMinI(state->strokeAdjust)) > y0) {
-      y0 = t;
-    }
-    y1 = yDest + h;
-    if ((t = state->clip->getYMaxI(state->strokeAdjust) + 1) < y1) {
-      y1 = t;
-    }
-    if (x0 < x1 && y0 < y1) {
-      for (y = y0; y < y1; ++y) {
-	memcpy(scanBuf + x0,
-	       src->data + (y - yDest) * (size_t)w + (x0 - xDest),
-	       x1 - x0);
-	if (vectorAntialias) {
-	  state->clip->clipSpan(scanBuf, y, x0, x1 - 1,
-				state->strokeAdjust);
-	} else {
-	  state->clip->clipSpanBinary(scanBuf, y, x0, x1 - 1,
-				      state->strokeAdjust);
-	}
-	(this->*pipe.run)(&pipe, x0, x1 - 1, y, scanBuf + x0, NULL);
-      }
-    }
-  }
-}
-
 SplashError Splash::drawImage(GString *imageTag,
 			      SplashImageSource src, void *srcData,
 			      SplashColorMode srcMode, GBool srcAlpha,
 			      int w, int h, SplashCoord *mat,
 			      GBool interpolate) {
-  GBool ok;
-  SplashBitmap *scaledImg;
-  SplashClipResult clipRes;
-  GBool minorAxisZero;
-  SplashCoord wSize, hSize, t0, t1;
-  int x0, y0, x1, y1, scaledWidth, scaledHeight;
-  int nComps;
-
   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],
@@ -4970,9 +6224,9 @@
 	   (double)mat[3], (double)mat[4], (double)mat[5]);
   }
 
-  // check color modes
-  ok = gFalse; // make gcc happy
-  nComps = 0; // make gcc happy
+  //--- check color modes
+  GBool ok = gFalse;
+  int nComps = 0;
   switch (bitmap->mode) {
   case splashModeMono1:
   case splashModeMono8:
@@ -4998,1665 +6252,727 @@
     return splashErrModeMismatch;
   }
 
-  // check for singular matrix
+  //--- check for singular matrix
   if (!splashCheckDet(mat[0], mat[1], mat[2], mat[3], 0.000001)) {
     return splashErrSingularMatrix;
   }
 
-  minorAxisZero = splashAbs(mat[1]) <= 0.0001 && splashAbs(mat[2]) <= 0.0001;
-
-  // rough estimate of size of scaled image
-  t0 = splashAbs(mat[0]);
-  t1 = splashAbs(mat[1]);
-  wSize = t0 > t1 ? t0 : t1;
-  t0 = splashAbs(mat[2]);
-  t1 = splashAbs(mat[3]);
-  hSize = t0 > t1 ? t0 : t1;
-
-  // stream-mode upscaling -- this is slower, so we only use it if the
-  // upscaled image is large (in which case clipping should remove
-  // many pixels)
-#if USE_FIXEDPOINT
-  if ((wSize > 2 * w && hSize > 2 * h && (int)wSize > 1000000 / (int)hSize) ||
-      (wSize >     w && hSize >     h && (int)wSize > 10000000 / (int)hSize) ||
-      ((wSize > w || hSize > h) && (int)wSize > 25000000 / (int)hSize)) {
-#else
-  if ((wSize > 2 * w && hSize > 2 * h && wSize * hSize > 1000000) ||
-      (wSize >     w && hSize >     h && wSize * hSize > 10000000) ||
-      ((wSize > w || hSize > h) && wSize * hSize > 25000000)) {
-#endif
-    upscaleImage(src, srcData, srcMode, nComps, srcAlpha,
-		 w, h, mat, interpolate);
-
-  // scaling only
-  } else if (mat[0] > 0 && minorAxisZero && mat[3] > 0) {
-    getImageBounds(mat[4], mat[0] + mat[4], &x0, &x1);
-    getImageBounds(mat[5], mat[3] + mat[5], &y0, &y1);
-    clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1,
-				    state->strokeAdjust);
-    opClipRes = clipRes;
-    if (clipRes != splashClipAllOutside) {
-      scaledWidth = x1 - x0;
-      scaledHeight = y1 - y0;
-      scaledImg = scaleImage(imageTag,
-			     src, srcData, srcMode, nComps, srcAlpha, w, h,
-			     scaledWidth, scaledHeight, interpolate);
-      if (imageCache->vertFlip) {
-	vertFlipImage(scaledImg, scaledWidth, scaledHeight, nComps);
-	imageCache->vertFlip = gFalse;
+  //--- compute image bbox, check clipping
+  GBool flipsOnly = splashAbs(mat[1]) <= 0.0001 && splashAbs(mat[2]) <= 0.0001;
+  GBool horizFlip = gFalse;
+  GBool vertFlip = gFalse;
+  int xMin, yMin, xMax, yMax;
+  if (flipsOnly) {
+    horizFlip = mat[0] < 0;
+    vertFlip = mat[3] < 0;
+    if (vertFlip) {
+      if (horizFlip) {    // bottom-up, mirrored
+	getImageBounds(mat[0] + mat[4], mat[4], &xMin, &xMax);
+	getImageBounds(mat[3] + mat[5], mat[5], &yMin, &yMax);
+      } else {            // bottom-up
+	getImageBounds(mat[4], mat[0] + mat[4], &xMin, &xMax);
+	getImageBounds(mat[3] + mat[5], mat[5], &yMin, &yMax);
       }
-      if (imageCache->horizFlip) {
-	horizFlipImage(scaledImg, scaledWidth, scaledHeight, nComps);
-	imageCache->horizFlip = gFalse;
+    } else {
+      if (horizFlip) {    // top-down, mirrored
+	getImageBounds(mat[0] + mat[4], mat[4], &xMin, &xMax);
+	getImageBounds(mat[5], mat[3] + mat[5], &yMin, &yMax);
+      } else {            // top-down
+	getImageBounds(mat[4], mat[0] + mat[4], &xMin, &xMax);
+	getImageBounds(mat[5], mat[3] + mat[5], &yMin, &yMax);
       }
-      blitImage(scaledImg, srcAlpha, x0, y0, clipRes);
     }
-    
-  // scaling plus vertical flip
-  } else if (mat[0] > 0 && minorAxisZero && mat[3] < 0) {
-    getImageBounds(mat[4], mat[0] + mat[4], &x0, &x1);
-    getImageBounds(mat[3] + mat[5], mat[5], &y0, &y1);
-    clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1,
-				    state->strokeAdjust);
-    opClipRes = clipRes;
-    if (clipRes != splashClipAllOutside) {
-      scaledWidth = x1 - x0;
-      scaledHeight = y1 - y0;
-      scaledImg = scaleImage(imageTag,
-			     src, srcData, srcMode, nComps, srcAlpha, w, h,
-			     scaledWidth, scaledHeight, interpolate);
-      if (!imageCache->vertFlip) {
-	vertFlipImage(scaledImg, scaledWidth, scaledHeight, nComps);
-	imageCache->vertFlip = gTrue;
-      }
-      if (imageCache->horizFlip) {
-	horizFlipImage(scaledImg, scaledWidth, scaledHeight, nComps);
-	imageCache->horizFlip = gFalse;
-      }
-      blitImage(scaledImg, srcAlpha, x0, y0, clipRes);
+  } else {
+    int xx = splashRound(mat[4]);		// (0,0)
+    int yy = splashRound(mat[5]);
+    xMin = xMax = xx;
+    yMin = yMax = yy;
+    xx = splashRound(mat[0] + mat[4]);		// (1,0)
+    yy = splashRound(mat[1] + mat[5]);
+    if (xx < xMin) {
+      xMin = xx;
+    } else if (xx > xMax) {
+      xMax = xx;
     }
-
-  // scaling plus horizontal flip
-  } else if (mat[0] < 0 && minorAxisZero && mat[3] > 0) {
-    getImageBounds(mat[0] + mat[4], mat[4], &x0, &x1);
-    getImageBounds(mat[5], mat[3] + mat[5], &y0, &y1);
-    clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1,
-				    state->strokeAdjust);
-    opClipRes = clipRes;
-    if (clipRes != splashClipAllOutside) {
-      scaledWidth = x1 - x0;
-      scaledHeight = y1 - y0;
-      scaledImg = scaleImage(imageTag,
-			     src, srcData, srcMode, nComps, srcAlpha, w, h,
-			     scaledWidth, scaledHeight, interpolate);
-      if (imageCache->vertFlip) {
-	vertFlipImage(scaledImg, scaledWidth, scaledHeight, nComps);
-	imageCache->vertFlip = gFalse;
-      }
-      if (!imageCache->horizFlip) {
-	horizFlipImage(scaledImg, scaledWidth, scaledHeight, nComps);
-	imageCache->horizFlip = gTrue;
-      }
-      blitImage(scaledImg, srcAlpha, x0, y0, clipRes);
+    if (yy < yMin) {
+      yMin = yy;
+    } else if (yy > yMax) {
+      yMax = yy;
     }
-    
-  // scaling plus horizontal and vertical flips
-  } else if (mat[0] < 0 && minorAxisZero && mat[3] < 0) {
-    getImageBounds(mat[0] + mat[4], mat[4], &x0, &x1);
-    getImageBounds(mat[3] + mat[5], mat[5], &y0, &y1);
-    clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1,
-				    state->strokeAdjust);
-    opClipRes = clipRes;
-    if (clipRes != splashClipAllOutside) {
-      scaledWidth = x1 - x0;
-      scaledHeight = y1 - y0;
-      scaledImg = scaleImage(imageTag,
-			     src, srcData, srcMode, nComps, srcAlpha, w, h,
-			     scaledWidth, scaledHeight, interpolate);
-      if (!imageCache->vertFlip) {
-	vertFlipImage(scaledImg, scaledWidth, scaledHeight, nComps);
-	imageCache->vertFlip = gTrue;
-      }
-      if (!imageCache->horizFlip) {
-	horizFlipImage(scaledImg, scaledWidth, scaledHeight, nComps);
-	imageCache->horizFlip = gTrue;
-      }
-      blitImage(scaledImg, srcAlpha, x0, y0, clipRes);
+    xx = splashRound(mat[2] + mat[4]);		// (0,1)
+    yy = splashRound(mat[3] + mat[5]);
+    if (xx < xMin) {
+      xMin = xx;
+    } else if (xx > xMax) {
+      xMax = xx;
     }
-
-  // all other cases
-  } else {
-    arbitraryTransformImage(imageTag, src, srcData, srcMode, nComps, srcAlpha,
-			    w, h, mat, interpolate);
-  }
-
-  return splashOk;
-}
-
-void Splash::upscaleImage(SplashImageSource src, void *srcData,
-			  SplashColorMode srcMode, int nComps,
-			  GBool srcAlpha, int srcWidth, int srcHeight,
-			  SplashCoord *mat, GBool interpolate) {
-  SplashClipResult clipRes;
-  SplashPipe pipe;
-  SplashColorPtr unscaledImage, pixelBuf, p, q, q00, q01, q10, q11;
-  Guchar *unscaledAlpha, *alphaPtr;
-  SplashCoord xMin, yMin, xMax, yMax, t;
-  SplashCoord mi0, mi1, mi2, mi3, mi4, mi5, det;
-  SplashCoord ix, iy, sx, sy, pix0, pix1;
-  SplashBitmapRowSize rowSize;
-  int xMinI, yMinI, xMaxI, yMaxI, x, y, x0, y0, x1, y1, tt, i;
-
-  // compute the bbox of the target quadrilateral
-  xMin = xMax = mat[4];
-  t = mat[2] + mat[4];
-  if (t < xMin) {
-    xMin = t;
-  } else if (t > xMax) {
-    xMax = t;
-  }
-  t = mat[0] + mat[2] + mat[4];
-  if (t < xMin) {
-    xMin = t;
-  } else if (t > xMax) {
-    xMax = t;
-  }
-  t = mat[0] + mat[4];
-  if (t < xMin) {
-    xMin = t;
-  } else if (t > xMax) {
-    xMax = t;
-  }
-  getImageBounds(xMin, xMax, &xMinI, &xMaxI);
-  yMin = yMax = mat[5];
-  t = mat[3] + mat[5];
-  if (t < yMin) {
-    yMin = t;
-  } else if (t > yMax) {
-    yMax = t;
-  }
-  t = mat[1] + mat[3] + mat[5];
-  if (t < yMin) {
-    yMin = t;
-  } else if (t > yMax) {
-    yMax = t;
-  }
-  t = mat[1] + mat[5];
-  if (t < yMin) {
-    yMin = t;
-  } else if (t > yMax) {
-    yMax = t;
-  }
-  getImageBounds(yMin, yMax, &yMinI, &yMaxI);
-
-  // clipping
-  clipRes = state->clip->testRect(xMinI, yMinI, xMaxI - 1, yMaxI - 1,
-				  state->strokeAdjust);
-  opClipRes = clipRes;
-  if (clipRes == splashClipAllOutside) {
-    return;
-  }
-  if (clipRes != splashClipAllInside) {
-    if ((tt = state->clip->getXMinI(state->strokeAdjust)) > xMinI) {
-      xMinI = tt;
+    if (yy < yMin) {
+      yMin = yy;
+    } else if (yy > yMax) {
+      yMax = yy;
     }
-    if ((tt = state->clip->getXMaxI(state->strokeAdjust) + 1) < xMaxI) {
-      xMaxI = tt;
+    xx = splashRound(mat[0] + mat[2] + mat[4]);	// (1,1)
+    yy = splashRound(mat[1] + mat[3] + mat[5]);
+    if (xx < xMin) {
+      xMin = xx;
+    } else if (xx > xMax) {
+      xMax = xx;
     }
-    if ((tt = state->clip->getYMinI(state->strokeAdjust)) > yMinI) {
-      yMinI = tt;
+    if (yy < yMin) {
+      yMin = yy;
+    } else if (yy > yMax) {
+      yMax = yy;
     }
-    if ((tt = state->clip->getYMaxI(state->strokeAdjust) + 1) < yMaxI) {
-      yMaxI = tt;
+    if (xMax <= xMin) {
+      xMax = xMin + 1;
     }
-  }
-
-  // invert the matrix
-  det = mat[0] * mat[3] - mat[1] * mat[2];
-  if (splashAbs(det) < 1e-6) {
-    // this should be caught by the singular matrix check in fillImageMask
-    return;
-  }
-  det = (SplashCoord)1 / det;
-  mi0 = det * mat[3] * srcWidth;
-  mi1 = -det * mat[1] * srcHeight;
-  mi2 = -det * mat[2] * srcWidth;
-  mi3 = det * mat[0] * srcHeight;
-  mi4 = det * (mat[2] * mat[5] - mat[3] * mat[4]) * srcWidth;
-  mi5 = -det * (mat[0] * mat[5] - mat[1] * mat[4]) * srcHeight;
-
-  // grab the image
-  if (srcWidth > INT_MAX / nComps) {
-    rowSize = -1;
-  } else {
-    rowSize = srcWidth * nComps;
-  }
-  unscaledImage = (SplashColorPtr)gmallocn64(srcHeight, rowSize);
-  if (srcAlpha) {
-    unscaledAlpha = (Guchar *)gmallocn(srcHeight, srcWidth);
-    for (y = 0, p = unscaledImage, alphaPtr = unscaledAlpha;
-	 y < srcHeight;
-	 ++y, p += rowSize, alphaPtr += srcWidth) {
-      (*src)(srcData, p, alphaPtr);
+    if (yMax <= yMin) {
+      yMax = yMin + 1;
     }
-  } else {
-    unscaledAlpha = NULL;
-    for (y = 0, p = unscaledImage; y < srcHeight; ++y, p += rowSize) {
-      (*src)(srcData, p, NULL);
-    }
   }
+  SplashClipResult clipRes =
+      state->clip->testRect(xMin, yMin, xMax - 1, yMax - 1,
+			    state->strokeAdjust);
+  // If the scaled image is much wider and/or taller than the clip
+  // region, we use the arbitrary transform path, to avoid a
+  // potentially very slow loop in the flips-only path (which scans
+  // the full width and height of the scaled image, regardless of the
+  // clip region).
+  int clipW = state->clip->getXMaxI(state->strokeAdjust)
+	      - state->clip->getXMinI(state->strokeAdjust);
+  int clipH = state->clip->getYMaxI(state->strokeAdjust)
+	      - state->clip->getYMinI(state->strokeAdjust);
+  GBool veryLarge = ((xMax - xMin) / 8 > clipW && xMax - xMin > 1000) ||
+                    ((yMax - yMin) / 8 > clipH && yMax - yMin > 1000);
 
-  // draw it
-  pixelBuf = (SplashColorPtr)gmallocn(xMaxI - xMinI, nComps);
-  pipeInit(&pipe, NULL,
+  //--- set up the SplashDrawImageRowData object and the pipes
+  SplashDrawImageRowData dd;
+  dd.nComps = nComps;
+  dd.srcAlpha = srcAlpha;
+  pipeInit(&dd.pipe, NULL,
 	   (Guchar)splashRound(state->fillAlpha * 255),
-	   gTrue, gFalse);
-  for (y = yMinI; y < yMaxI; ++y) {
-    p = pixelBuf;
-    for (x = xMinI; x < xMaxI; ++x) {
-      ix = ((SplashCoord)x + 0.5) * mi0 + ((SplashCoord)y + 0.5) * mi2 + mi4;
-      iy = ((SplashCoord)x + 0.5) * mi1 + ((SplashCoord)y + 0.5) * mi3 + mi5;
-      if (interpolate) {
-	if (ix >= 0 && ix < srcWidth && iy >= 0 && iy < srcHeight) {
-	  x0 = splashFloor(ix - 0.5);
-	  x1 = x0 + 1;
-	  sx = (ix - 0.5) - x0;
-	  y0 = splashFloor(iy - 0.5);
-	  y1 = y0 + 1;
-	  sy = (iy - 0.5) - y0;
-	  if (x0 < 0) {
-	    x0 = 0;
-	  }
-	  if (x1 >= srcWidth) {
-	    x1 = srcWidth - 1;
-	  }
-	  if (y0 < 0) {
-	    y0 = 0;
-	  }
-	  if (y1 >= srcHeight) {
-	    y1 = srcHeight - 1;
-	  }
-	  q00 = &unscaledImage[y0 * rowSize + (SplashBitmapRowSize)x0 * nComps];
-	  q01 = &unscaledImage[y0 * rowSize + (SplashBitmapRowSize)x1 * nComps];
-	  q10 = &unscaledImage[y1 * rowSize + (SplashBitmapRowSize)x0 * nComps];
-	  q11 = &unscaledImage[y1 * rowSize + (SplashBitmapRowSize)x1 * nComps];
-	  for (i = 0; i < nComps; ++i) {
-	    pix0 = ((SplashCoord)1 - sx) * (int)*q00++ + sx * (int)*q01++;
-	    pix1 = ((SplashCoord)1 - sx) * (int)*q10++ + sx * (int)*q11++;
-	    *p++ = (Guchar)splashRound(((SplashCoord)1 - sy) * pix0
-				       + sy * pix1);
-	  }
-	  if (srcAlpha) {
-	    pix0 = ((SplashCoord)1 - sx)
-	             * (SplashCoord)unscaledAlpha[y0 * srcWidth + x0]
-	           + sx * (SplashCoord)unscaledAlpha[y0 * srcWidth + x1];
-	    pix1 = ((SplashCoord)1 - sx)
-	             * (SplashCoord)unscaledAlpha[y1 * srcWidth + x0]
-	           + sx * (SplashCoord)unscaledAlpha[y1 * srcWidth + x1];
-	    scanBuf[x] = (Guchar)splashRound(((SplashCoord)1 - sy) * pix0
-					     + sy * pix1);
-	  } else {
-	    scanBuf[x] = 0xff;
-	  }
-	} else {
-	  for (i = 0; i < nComps; ++i) {
-	    *p++ = 0;
-	  }
-	  scanBuf[x] = 0;
-	}
-      } else {
-	x0 = splashFloor(ix);
-	y0 = splashFloor(iy);
-	if (x0 >= 0 && x0 < srcWidth && y0 >= 0 && y0 < srcHeight) {
-	  q = &unscaledImage[y0 * rowSize + (SplashBitmapRowSize)x0 * nComps];
-	  for (i = 0; i < nComps; ++i) {
-	    *p++ = *q++;
-	  }
-	  if (srcAlpha) {
-	    scanBuf[x] = unscaledAlpha[y0 * srcWidth + x0];
-	  } else {
-	    scanBuf[x] = 0xff;
-	  }
-	} else {
-	  for (i = 0; i < nComps; ++i) {
-	    *p++ = 0;
-	  }
-	  scanBuf[x] = 0;
-	}
-      }
-    }
-    if (clipRes != splashClipAllInside) {
-      if (vectorAntialias) {
-	state->clip->clipSpan(scanBuf, y, xMinI, xMaxI - 1,
-			      state->strokeAdjust);
-      } else {
-	state->clip->clipSpanBinary(scanBuf, y, xMinI, xMaxI - 1,
-				    state->strokeAdjust);
-      }
-    }
-    (this->*pipe.run)(&pipe, xMinI, xMaxI - 1, y, scanBuf + xMinI, pixelBuf);
-  }
+	   clipRes != splashClipAllInside || srcAlpha,
+	   gFalse);
 
-  gfree(pixelBuf);
-  gfree(unscaledImage);
-  gfree(unscaledAlpha);
-}
-
-void Splash::arbitraryTransformImage(GString *imageTag,
-				     SplashImageSource src, void *srcData,
-				     SplashColorMode srcMode, int nComps,
-				     GBool srcAlpha,
-				     int srcWidth, int srcHeight,
-				     SplashCoord *mat, GBool interpolate) {
-  SplashBitmap *scaledImg;
-  SplashClipResult clipRes;
-  SplashPipe pipe;
-  SplashColorPtr pixelBuf;
-  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 = splashRound(vx[0]);
-  xMax = splashRound(vx[0]);
-  yMin = splashRound(vy[0]);
-  yMax = splashRound(vy[0]);
-  for (i = 1; i < 4; ++i) {
-    t0 = splashRound(vx[i]);
-    if (t0 < xMin) {
-      xMin = t0;
-    } else if (t0 > xMax) {
-      xMax = t0;
-    }
-    t1 = splashRound(vy[i]);
-    if (t1 < yMin) {
-      yMin = t1;
-    } else if (t1 > yMax) {
-      yMax = t1;
-    }
-  }
-  clipRes = state->clip->testRect(xMin, yMin, xMax - 1, yMax - 1,
-				  state->strokeAdjust);
-  opClipRes = clipRes;
-  if (clipRes == splashClipAllOutside) {
-    return;
-  }
-
-  // compute the scale factors
-  if (mat[0] >= 0) {
-    t0 = splashRound(mat[0] + mat[4]) - splashRound(mat[4]);
-  } else {
-    t0 = splashRound(mat[4]) - splashRound(mat[0] + mat[4]);
-  }
-  if (mat[1] >= 0) {
-    t1 = splashRound(mat[1] + mat[5]) - splashRound(mat[5]);
-  } else {
-    t1 = splashRound(mat[5]) - splashRound(mat[1] + mat[5]);
-  }
-  scaledWidth = t0 > t1 ? t0 : t1;
-  if (mat[2] >= 0) {
-    t0 = splashRound(mat[2] + mat[4]) - splashRound(mat[4]);
-  } else {
-    t0 = splashRound(mat[4]) - splashRound(mat[2] + mat[4]);
-  }
-  if (mat[3] >= 0) {
-    t1 = splashRound(mat[3] + mat[5]) - splashRound(mat[5]);
-  } else {
-    t1 = splashRound(mat[5]) - splashRound(mat[3] + mat[5]);
-  }
-  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;
-  }
-  ir00 = r11 / det;
-  ir01 = -r01 / det;
-  ir10 = -r10 / det;
-  ir11 = r00 / det;
-
-  // scale the input image
-  scaledImg = scaleImage(imageTag, src, srcData, srcMode, nComps, srcAlpha,
-			 srcWidth, srcHeight, scaledWidth, scaledHeight,
-			 interpolate);
-  if (imageCache->vertFlip) {
-    vertFlipImage(scaledImg, scaledWidth, scaledHeight, nComps);
-    imageCache->vertFlip = gFalse;
-  }
-  if (imageCache->horizFlip) {
-    horizFlipImage(scaledImg, scaledWidth, scaledHeight, nComps);
-    imageCache->horizFlip = gFalse;
-  }
-
-  // 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 = splashRound(vy[i]);
-    section[0].y1 = splashRound(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;
+  //--- choose the drawRow function
+  SplashDrawImageRowFunc drawRowFunc;
+  if (clipRes == splashClipAllInside) {
+    if (srcAlpha) {
+      drawRowFunc = &Splash::drawImageRowNoClipAlpha;
     } else {
-      section[0].ia0 = (i+1) & 3;
-      section[0].ia1 = (i+2) & 3;
-      section[0].ib0 = i;
-      section[0].ib1 = (i+3) & 3;
+      drawRowFunc = &Splash::drawImageRowNoClipNoAlpha;
     }
-    nSections = 1;
   } else {
-    section[0].y0 = splashRound(vy[i]);
-    section[2].y1 = splashRound(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 = splashRound(vy[(i+1) & 3]);
-      section[2].y0 = splashRound(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;
+    if (srcAlpha) {
+      if (vectorAntialias) {
+	drawRowFunc = &Splash::drawImageRowClipAlphaAA;
       } else {
-	section[1].ia0 = i;
-	section[1].ia1 = (i+3) & 3;
-	section[1].ib0 = (i+1) & 3;
-	section[1].ib1 = (i+2) & 3;
+	drawRowFunc = &Splash::drawImageRowClipAlphaNoAA;
       }
     } else {
-      section[1].y0 = splashRound(vy[(i+3) & 3]);
-      section[2].y0 = splashRound(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;
+      if (vectorAntialias) {
+	drawRowFunc = &Splash::drawImageRowClipNoAlphaAA;
       } else {
-	section[1].ia0 = (i+3) & 3;
-	section[1].ia1 = (i+2) & 3;
-	section[1].ib0 = i;
-	section[1].ib1 = (i+1) & 3;
+	drawRowFunc = &Splash::drawImageRowClipNoAlphaNoAA;
       }
     }
-    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, NULL,
-	   (Guchar)splashRound(state->fillAlpha * 255),
-	   gTrue, gFalse);
-
-  // 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;
-    }
-  }
-
-  pixelBuf = (SplashColorPtr)gmallocn(xMax - xMin + 1, bitmapComps);
-
-  // scan all pixels inside the target region
-  for (i = 0; i < nSections; ++i) {
-    for (y = section[i].y0; y <= section[i].y1; ++y) {
-      xa = splashRound(section[i].xa0 +
-		         ((SplashCoord)y + 0.5 - section[i].ya0) *
-		           section[i].dxdya);
-      xb = splashRound(section[i].xb0 +
-		         ((SplashCoord)y + 0.5 - section[i].yb0) *
-		           section[i].dxdyb);
-      if (xa > xb) {
-	continue;
-      }
-      // make sure narrow images cover at least one pixel
-      if (xa == xb) {
-	++xb;
-      }
-      // check the scanBuf bounds
-      if (xa >= bitmap->width || xb < 0) {
-	continue;
-      }
-      if (xa < 0) {
-	xa = 0;
-      }
-      if (xb > bitmap->width) {
-	xb = bitmap->width;
-      }
-      // clip the scan line
-      memset(scanBuf + xa, 0xff, xb - xa);
-      if (clipRes != splashClipAllInside) {
-	if (vectorAntialias) {
-	  state->clip->clipSpan(scanBuf, y, xa, xb - 1,
-				state->strokeAdjust);
-	} else {
-	  state->clip->clipSpanBinary(scanBuf, y, xa, xb - 1,
-				      state->strokeAdjust);
+  //--- horizontal/vertical flips only
+  if (flipsOnly && !veryLarge) {
+    if (clipRes != splashClipAllOutside) {
+      int scaledWidth = xMax - xMin;
+      int scaledHeight = yMax - yMin;
+      ImageScaler *scaler = getImageScaler(imageTag, src, srcData,
+					   w, h, nComps,
+					   scaledWidth, scaledHeight,
+					   srcMode, srcAlpha, interpolate);
+      Guchar *tmpLine = NULL;
+      Guchar *tmpAlphaLine = NULL;
+      if (horizFlip) {
+	tmpLine = (Guchar *)gmallocn(scaledWidth, nComps);
+	if (srcAlpha) {
+	  tmpAlphaLine = (Guchar *)gmalloc(scaledWidth);
 	}
       }
-      // draw the scan line
-      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 (vertFlip) {
+	if (horizFlip) {    // bottom-up, mirrored
+	  for (int y = 0; y < scaledHeight; ++y) {
+	    scaler->nextLine();
+	    mirrorImageRow(scaler->colorData(), scaler->alphaData(),
+			   tmpLine, tmpAlphaLine,
+			   scaledWidth, nComps, srcAlpha);
+	    (this->*drawRowFunc)(&dd, tmpLine, tmpAlphaLine,
+				 xMin, yMax - 1 - y, scaledWidth);
+	  }
+	} else {            // bottom-up
+	  for (int y = 0; y < scaledHeight; ++y) {
+	    scaler->nextLine();
+	    (this->*drawRowFunc)(&dd, scaler->colorData(), scaler->alphaData(),
+				 xMin, yMax - 1 - y, scaledWidth);
+	  }
 	}
-	if (yy < 0) {
-	  yy = 0;
-	} else if (yy >= scaledHeight) {
-	  yy = scaledHeight - 1;
+      } else {
+	if (horizFlip) {    // top-down, mirrored
+	  for (int y = 0; y < scaledHeight; ++y) {
+	    scaler->nextLine();
+	    mirrorImageRow(scaler->colorData(), scaler->alphaData(),
+			   tmpLine, tmpAlphaLine,
+			   scaledWidth, nComps, srcAlpha);
+	    (this->*drawRowFunc)(&dd, tmpLine, tmpAlphaLine,
+				 xMin, yMin + y, scaledWidth);
+	  }
+	} else {            // top-down
+	  for (int y = 0; y < scaledHeight; ++y) {
+	    scaler->nextLine();
+	    (this->*drawRowFunc)(&dd, scaler->colorData(), scaler->alphaData(),
+				 xMin, yMin + y, scaledWidth);
+	  }
 	}
-	// get the color
-	scaledImg->getPixel(xx, yy, pixelBuf + (x - xa) * bitmapComps);
-	// apply alpha
-	if (srcAlpha) {
-	  scanBuf[x] = div255(scanBuf[x] *
-			      scaledImg->alpha[yy * scaledWidth + xx]);
-	}
       }
-      (this->*pipe.run)(&pipe, xa, xb - 1, y, scanBuf + xa, pixelBuf);
+      gfree(tmpLine);
+      gfree(tmpAlphaLine);
+      delete scaler;
     }
-  }
 
-  gfree(pixelBuf);
-}
-
-// Scale an image into a SplashBitmap.
-SplashBitmap *Splash::scaleImage(GString *imageTag,
-				 SplashImageSource src, void *srcData,
-				 SplashColorMode srcMode, int nComps,
-				 GBool srcAlpha, int srcWidth, int srcHeight,
-				 int scaledWidth, int scaledHeight,
-				 GBool interpolate) {
-  if (imageCache->tag && imageTag &&
-      !imageCache->tag->cmp(imageTag) &&
-      !imageCache->isMask &&
-      imageCache->width == scaledWidth &&
-      imageCache->height == scaledHeight &&
-      imageCache->mode == srcMode &&
-      imageCache->alpha == srcAlpha &&
-      imageCache->interpolate == interpolate) {
-    return imageCache->image;
-  }
-  if (imageCache->tag) {
-    delete imageCache->tag;
-  }
-  if (imageCache->image) {
-    delete imageCache->image;
-  }
-  imageCache->tag = imageTag ? imageTag->copy() : (GString *)NULL;
-  imageCache->isMask = gFalse;
-  imageCache->width = scaledWidth;
-  imageCache->height = scaledHeight;
-  imageCache->mode = srcMode;
-  imageCache->alpha = srcAlpha;
-  imageCache->interpolate = interpolate;
-  imageCache->vertFlip = gFalse;
-  imageCache->horizFlip = gFalse;
-  imageCache->image = new SplashBitmap(scaledWidth, scaledHeight, 1,
-				       srcMode, srcAlpha, gTrue, NULL);
-  if (scaledHeight < srcHeight) {
-    if (scaledWidth < srcWidth) {
-      scaleImageYdXd(src, srcData, srcMode, nComps, srcAlpha,
-		     srcWidth, srcHeight, scaledWidth, scaledHeight,
-		     imageCache->image);
-    } else {
-      scaleImageYdXu(src, srcData, srcMode, nComps, srcAlpha,
-		     srcWidth, srcHeight, scaledWidth, scaledHeight,
-		     imageCache->image);
-    }
+  //--- arbitrary transform
   } else {
-    if (scaledWidth < srcWidth) {
-      scaleImageYuXd(src, srcData, srcMode, nComps, srcAlpha,
-		     srcWidth, srcHeight, scaledWidth, scaledHeight,
-		     imageCache->image);
-    } else {
-      if (interpolate) {
-	scaleImageYuXuI(src, srcData, srcMode, nComps, srcAlpha,
-			srcWidth, srcHeight, scaledWidth, scaledHeight,
-			imageCache->image);
-      } else {
-	scaleImageYuXu(src, srcData, srcMode, nComps, srcAlpha,
-		       srcWidth, srcHeight, scaledWidth, scaledHeight,
-		       imageCache->image);
-      }
+    // estimate of size of scaled image
+    int scaledWidth = splashRound(splashSqrt(mat[0] * mat[0]
+					     + mat[1] * mat[1]));
+    int scaledHeight = splashRound(splashSqrt(mat[2] * mat[2]
+					      + mat[3] * mat[3]));
+    if (scaledWidth < 1) {
+      scaledWidth = 1;
     }
-  }
-  return imageCache->image;
-}
+    if (scaledHeight < 1) {
+      scaledHeight = 1;
+    }
+    if (veryLarge || (scaledWidth >= w && scaledHeight >= h)) {
+      scaledWidth = w;
+      scaledHeight = h;
+    }
 
-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;
-#if SPLASH_CMYK
-  Guint pix3;
-#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;
+    // compute mapping from device space to scaled image space
+    SplashCoord mat1[6];
+    mat1[0] = mat[0] / scaledWidth;
+    mat1[1] = mat[1] / scaledWidth;
+    mat1[2] = mat[2] / scaledHeight;
+    mat1[3] = mat[3] / scaledHeight;
+    mat1[4] = mat[4];
+    mat1[5] = mat[5];
+    SplashCoord det = mat1[0] * mat1[3] - mat1[1] * mat1[2];
+    if (splashAbs(det) < 1e-6) {
+      // this should be caught by the singular matrix check in drawImage
+      return splashErrSingularMatrix;
+    }
+    SplashCoord invMat[6];
+    invMat[0] = mat1[3] / det;
+    invMat[1] = -mat1[1] / det;
+    invMat[2] = -mat1[2] / det;
+    invMat[3] = mat1[0] / det;
+    // the extra "+ 0.5 * (...)" terms are here because the
+    // drawImageArbitrary(No)Interp functions multiply by pixel
+    // centers, (x + 0.5, y + 0.5)
+    invMat[4] = (mat1[2] * mat1[5] - mat1[3] * mat1[4]) / det
+                + (invMat[0] + invMat[2]) * 0.5;
+    invMat[5] = (mat1[1] * mat1[4] - mat1[0] * mat1[5]) / det
+                + (invMat[1] + invMat[3]) * 0.5;
 
-  // Bresenham parameters for y scale
-  yp = srcHeight / scaledHeight;
-  yq = srcHeight % scaledHeight;
+    Guchar *scaledColor, *scaledAlpha;
+    GBool freeScaledImage;
+    getScaledImage(imageTag, src, srcData, w, h, nComps,
+		   scaledWidth, scaledHeight, srcMode, srcAlpha, interpolate,
+		   &scaledColor, &scaledAlpha, &freeScaledImage);
 
-  // Bresenham parameters for x scale
-  xp = srcWidth / scaledWidth;
-  xq = srcWidth % scaledWidth;
-
-  // allocate buffers
-  lineBuf = (Guchar *)gmallocn(srcWidth, nComps);
-  pixBuf = (Guint *)gmallocn(srcWidth, (int)(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;
+    // draw it
+    if (interpolate) {
+      drawImageArbitraryInterp(scaledColor, scaledAlpha,
+			       &dd, drawRowFunc, invMat,
+			       scaledWidth, scaledHeight,
+			       xMin, yMin, xMax, yMax,
+			       nComps, srcAlpha);
     } else {
-      yStep = yp;
+      drawImageArbitraryNoInterp(scaledColor, scaledAlpha,
+				 &dd, drawRowFunc, invMat,
+				 scaledWidth, scaledHeight,
+				 xMin, yMin, xMax, yMax,
+				 nComps, srcAlpha);
     }
 
-    // read rows from image
-    memset(pixBuf, 0, srcWidth * nComps * sizeof(int));
-    if (srcAlpha) {
-      memset(alphaPixBuf, 0, srcWidth * sizeof(int));
+    // free the downscaled/unscaled image
+    if (freeScaledImage) {
+      gfree(scaledColor);
+      gfree(scaledAlpha);
     }
-    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));
+  return splashOk;
+}
 
-    xx = xxa = 0;
-    for (x = 0; x < scaledWidth; ++x) {
+ImageScaler *Splash::getImageScaler(GString *imageTag,
+				    SplashImageSource src, void *srcData,
+				    int w, int h, int nComps,
+				    int scaledWidth, int scaledHeight,
+				    SplashColorMode srcMode,
+				    GBool srcAlpha, GBool interpolate) {
+  // Notes:
+  //
+  // * If the scaled image width or height is greater than 2000, we
+  //   don't cache it.
+  //
+  // * Caching is done on the third consecutive use (second
+  //   consecutive reuse) of an image; this avoids overhead on the
+  //   common case of single-use images.
 
-      // x scale Bresenham
-      if ((xt += xq) >= scaledWidth) {
-	xt -= scaledWidth;
-	xStep = xp + 1;
-	d = d1;
+  if (scaledWidth < 2000 && scaledHeight < 2000 &&
+      imageCache->match(imageTag, scaledWidth, scaledHeight,
+			srcMode, srcAlpha, interpolate)) {
+    if (imageCache->colorData) {
+      return new ReplayImageScaler(nComps, srcAlpha, scaledWidth,
+				   imageCache->colorData,
+				   imageCache->alphaData);
+    } else {
+      int lineSize;
+      if (scaledWidth < INT_MAX / nComps) {
+	lineSize = scaledWidth * nComps;
       } else {
-	xStep = xp;
-	d = d0;
+	lineSize = -1;
       }
-
-      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 + (1 << 22)) >> 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 + (1 << 22)) >> 23;
-	pix1 = (pix1 * d + (1 << 22)) >> 23;
-	pix2 = (pix2 * d + (1 << 22)) >> 23;
-
-	// store the pixel
-	*destPtr++ = (Guchar)pix0;
-	*destPtr++ = (Guchar)pix1;
-	*destPtr++ = (Guchar)pix2;
-	break;
-
-#if 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 + (1 << 22)) >> 23;
-	pix1 = (pix1 * d + (1 << 22)) >> 23;
-	pix2 = (pix2 * d + (1 << 22)) >> 23;
-	pix3 = (pix3 * d + (1 << 22)) >> 23;
-
-	// store the pixel
-	*destPtr++ = (Guchar)pix0;
-	*destPtr++ = (Guchar)pix1;
-	*destPtr++ = (Guchar)pix2;
-	*destPtr++ = (Guchar)pix3;
-	break;
-#endif
-
-
-      case splashModeMono1: // mono1 is not allowed
-      case splashModeBGR8: // bgr8 is not allowed
-      default:
-	break;
-      }
-
-      // process alpha
+      imageCache->colorData = (Guchar *)gmallocn(scaledHeight, lineSize);
       if (srcAlpha) {
-	alpha = 0;
-	for (i = 0; i < xStep; ++i, ++xxa) {
-	  alpha += alphaPixBuf[xxa];
-	}
-	// alpha / xStep * yStep
-	alpha = (alpha * d + (1 << 22)) >> 23;
-	*destAlphaPtr++ = (Guchar)alpha;
+	imageCache->alphaData = (Guchar *)gmallocn(scaledHeight, scaledWidth);
       }
+      return new SavingImageScaler(src, srcData,
+				   w, h, nComps, srcAlpha,
+				   scaledWidth, scaledHeight,
+				   interpolate,
+				   imageCache->colorData,
+				   imageCache->alphaData);
     }
+  } else {
+    imageCache->reset(imageTag, scaledWidth, scaledHeight,
+		      srcMode, srcAlpha, interpolate);
+    return new BasicImageScaler(src, srcData,
+				w, h, nComps, srcAlpha,
+				scaledWidth, scaledHeight,
+				interpolate);
   }
-
-  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,
+void Splash::getScaledImage(GString *imageTag,
+			    SplashImageSource src, void *srcData,
+			    int w, int h, int nComps,
 			    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;
+			    SplashColorMode srcMode,
+			    GBool srcAlpha, GBool interpolate,
+			    Guchar **scaledColor, Guchar **scaledAlpha,
+			    GBool *freeScaledImage) {
+  // Notes:
+  //
+  // * If the scaled image width or height is greater than 2000, we
+  //   don't cache it.
+  //
+  // * This buffers the whole image anyway, so there's no reason to
+  //   skip caching on the first reuse.
 
-  // 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, (int)(nComps * sizeof(int)));
-  if (srcAlpha) {
-    alphaLineBuf = (Guchar *)gmalloc(srcWidth);
-    alphaPixBuf = (Guint *)gmallocn(srcWidth, sizeof(int));
-  } else {
-    alphaLineBuf = NULL;
-    alphaPixBuf = NULL;
-  }
-
-  // make gcc happy
-  pix[0] = pix[1] = pix[2] = 0;
-#if SPLASH_CMYK
-  pix[3] = 0;
-#endif
-
-  // 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;
+  if (scaledWidth >= 2000 || scaledHeight >= 2000) {
+    int lineSize;
+    if (scaledWidth < INT_MAX / nComps) {
+      lineSize = scaledWidth * nComps;
     } else {
-      yStep = yp;
+      lineSize = -1;
     }
-
-    // read rows from image
-    memset(pixBuf, 0, srcWidth * nComps * sizeof(int));
+    *scaledColor = (Guchar *)gmallocn(scaledHeight, lineSize);
     if (srcAlpha) {
-      memset(alphaPixBuf, 0, srcWidth * sizeof(int));
+      *scaledAlpha = (Guchar *)gmallocn(scaledHeight, scaledWidth);
+    } else {
+      *scaledAlpha = NULL;
     }
-    for (i = 0; i < yStep; ++i) {
-      (*src)(srcData, lineBuf, alphaLineBuf);
-      for (j = 0; j < srcWidth * nComps; ++j) {
-	pixBuf[j] += lineBuf[j];
+    *freeScaledImage = gTrue;
+    if (scaledWidth == w && scaledHeight == h) {
+      Guchar *colorPtr = *scaledColor;
+      Guchar *alphaPtr = *scaledAlpha;
+      for (int y = 0; y < scaledHeight; ++y) {
+	(*src)(srcData, colorPtr, alphaPtr);
+	colorPtr += scaledWidth * nComps;
+	if (srcAlpha) {
+	  alphaPtr += scaledWidth;
+	}
       }
-      if (srcAlpha) {
-	for (j = 0; j < srcWidth; ++j) {
-	  alphaPixBuf[j] += alphaLineBuf[j];
+    } else {
+      BasicImageScaler scaler(src, srcData, w, h, nComps, srcAlpha,
+			      scaledWidth, scaledHeight, interpolate);
+      Guchar *colorPtr = *scaledColor;
+      Guchar *alphaPtr = *scaledAlpha;
+      for (int y = 0; y < scaledHeight; ++y) {
+	scaler.nextLine();
+	memcpy(colorPtr, scaler.colorData(), scaledWidth * nComps);
+	colorPtr += scaledWidth * nComps;
+	if (srcAlpha) {
+	  memcpy(alphaPtr, scaler.alphaData(), scaledWidth);
+	  alphaPtr += scaledWidth;
 	}
       }
     }
-
-    // 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 {
+    if (!imageCache->match(imageTag, scaledWidth, scaledHeight,
+			  srcMode, srcAlpha, interpolate) ||
+	!imageCache->colorData) {
+      imageCache->reset(imageTag, scaledWidth, scaledHeight,
+			srcMode, srcAlpha, interpolate);
+      int lineSize;
+      if (scaledWidth < INT_MAX / nComps) {
+	lineSize = scaledWidth * nComps;
       } else {
-	xStep = xp;
+	lineSize = -1;
       }
-
-      // compute the final pixel
-      for (i = 0; i < nComps; ++i) {
-	// pixBuf[] / yStep
-	pix[i] = (pixBuf[x * nComps + i] * d + (1 << 22)) >> 23;
+      imageCache->colorData = (Guchar *)gmallocn(scaledHeight, lineSize);
+      if (srcAlpha) {
+	imageCache->alphaData = (Guchar *)gmallocn(scaledHeight, scaledWidth);
       }
-
-      // store the pixel
-      switch (srcMode) {
-      case splashModeMono8:
-	for (i = 0; i < xStep; ++i) {
-	  *destPtr++ = (Guchar)pix[0];
+      if (scaledWidth == w && scaledHeight == h) {
+	Guchar *colorPtr = imageCache->colorData;
+	Guchar *alphaPtr = imageCache->alphaData;
+	for (int y = 0; y < scaledHeight; ++y) {
+	  (*src)(srcData, colorPtr, alphaPtr);
+	  colorPtr += scaledWidth * nComps;
+	  if (srcAlpha) {
+	    alphaPtr += scaledWidth;
+	  }
 	}
-	break;
-      case splashModeRGB8:
-	for (i = 0; i < xStep; ++i) {
-	  *destPtr++ = (Guchar)pix[0];
-	  *destPtr++ = (Guchar)pix[1];
-	  *destPtr++ = (Guchar)pix[2];
+      } else {
+	SavingImageScaler scaler(src, srcData, w, h, nComps, srcAlpha,
+				 scaledWidth, scaledHeight, interpolate,
+				 imageCache->colorData, imageCache->alphaData);
+	Guchar *colorPtr = imageCache->colorData;
+	Guchar *alphaPtr = imageCache->alphaData;
+	for (int y = 0; y < scaledHeight; ++y) {
+	  scaler.nextLine();
+	  memcpy(colorPtr, scaler.colorData(), scaledWidth * nComps);
+	  colorPtr += scaledWidth * nComps;
+	  if (srcAlpha) {
+	    memcpy(alphaPtr, scaler.alphaData(), scaledWidth);
+	    alphaPtr += scaledWidth;
+	  }
 	}
-	break;
-#if 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;
-#endif
-      case splashModeMono1: // mono1 is not allowed
-      case splashModeBGR8: // BGR8 is not allowed
-      default:
-	break;
       }
-
-      // process alpha
-      if (srcAlpha) {
-	// alphaPixBuf[] / yStep
-	alpha = (alphaPixBuf[x] * d + (1 << 22)) >> 23;
-	for (i = 0; i < xStep; ++i) {
-	  *destAlphaPtr++ = (Guchar)alpha;
-	}
-      }
     }
+    *scaledColor = imageCache->colorData;
+    *scaledAlpha = imageCache->alphaData;
+    *freeScaledImage = gFalse;
   }
-
-  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;
+void Splash::drawImageArbitraryNoInterp(Guchar *scaledColor,
+					Guchar *scaledAlpha,
+					SplashDrawImageRowData *dd,
+					SplashDrawImageRowFunc drawRowFunc,
+					SplashCoord *invMat,
+					int scaledWidth, int scaledHeight,
+					int xMin, int yMin, int xMax, int yMax,
+					int nComps, GBool srcAlpha) {
+  int tt = state->clip->getXMinI(state->strokeAdjust);
+  if (tt > xMin) {
+    xMin = tt;
+  }
+  tt = state->clip->getXMaxI(state->strokeAdjust) + 1;
+  if (tt < xMax) {
+    xMax = tt;
+  }
+  tt = state->clip->getYMinI(state->strokeAdjust);
+  if (tt > yMin) {
+    yMin = tt;
+  }
+  tt = state->clip->getYMaxI(state->strokeAdjust) + 1;
+  if (tt < yMax) {
+    yMax = tt;
+  }
+  if (xMax <= xMin || yMax <= yMin) {
+    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 *)gmallocn(srcWidth, nComps);
+  Guchar *colorBuf = (Guchar *)gmallocn(xMax - xMin, nComps);
+  Guchar *alphaBuf = NULL;
   if (srcAlpha) {
-    alphaLineBuf = (Guchar *)gmalloc(srcWidth);
-  } else {
-    alphaLineBuf = NULL;
+    alphaBuf = (Guchar *)gmalloc(xMax - xMin);
   }
 
-  // make gcc happy
-  pix[0] = pix[1] = pix[2] = 0;
-#if SPLASH_CMYK
-  pix[3] = 0;
-#endif
-
-  // 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 (int y = yMin; y < yMax; ++y) {
+    int rowMin = xMax;
+    int rowMax = 0;
+    for (int x = xMin; x < xMax; ++x) {
+      // note: invMat includes a "+0.5" factor so that this is really
+      // a multiply by (x+0.5, y+0.5)
+      int xx = splashFloor((SplashCoord)x * invMat[0]
+			   + (SplashCoord)y * invMat[2] + invMat[4]);
+      int yy = splashFloor((SplashCoord)x * invMat[1]
+			   + (SplashCoord)y * invMat[3] + invMat[5]);
+      if (xx >= 0 && xx < scaledWidth &&
+	  yy >= 0 && yy < scaledHeight) {
+	Guchar *p = scaledColor + (yy * scaledWidth + xx) * nComps;
+	Guchar *q = colorBuf + (x - xMin) * nComps;
+	for (int i = 0; i < nComps; ++i) {
+	  *q++ = *p++;
 	}
-      }
-      for (i = 0; i < nComps; ++i) {
-	// pix[] / xStep
-	pix[i] = (pix[i] * d + (1 << 22)) >> 23;
-      }
-
-      // store the pixel
-      switch (srcMode) {
-      case splashModeMono8:
-	for (i = 0; i < yStep; ++i) {
-	  destPtr = destPtr0 + (i * scaledWidth + x) * nComps;
-	  *destPtr++ = (Guchar)pix[0];
+	if (srcAlpha) {
+	  alphaBuf[x - xMin] = scaledAlpha[yy * scaledWidth + xx];
 	}
-	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];
+	if (x < rowMin) {
+	  rowMin = x;
 	}
-	break;
-#if 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;
-#endif
-      case splashModeMono1: // mono1 is not allowed
-      case splashModeBGR8: // BGR8 is not allowed
-      default:
-	break;
+	rowMax = x + 1;
       }
-
-      // process alpha
-      if (srcAlpha) {
-	alpha = 0;
-	for (i = 0; i < xStep; ++i, ++xxa) {
-	  alpha += alphaLineBuf[xxa];
-	}
-	// alpha / xStep
-	alpha = (alpha * d + (1 << 22)) >> 23;
-	for (i = 0; i < yStep; ++i) {
-	  destAlphaPtr = destAlphaPtr0 + i * scaledWidth + x;
-	  *destAlphaPtr = (Guchar)alpha;
-	}
-      }
     }
-
-    destPtr0 += yStep * scaledWidth * nComps;
-    if (srcAlpha) {
-      destAlphaPtr0 += yStep * scaledWidth;
+    if (rowMin < rowMax) {
+      (this->*drawRowFunc)(dd,
+			   colorBuf + (rowMin - xMin) * nComps,
+			   alphaBuf + (rowMin - xMin),
+			   rowMin, y, rowMax - rowMin);
     }
   }
 
-  gfree(alphaLineBuf);
-  gfree(lineBuf);
+  gfree(colorBuf);
+  gfree(alphaBuf);
 }
 
-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;
-  Guchar pix0, pix1, pix2;
-#if SPLASH_CMYK
-  Guchar pix3;
-#endif
-  Guchar alpha;
-  Guchar *srcPtr, *srcAlphaPtr;
-  Guchar *destPtr, *destAlphaPtr;
-  int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep;
-  int i;
+void Splash::drawImageArbitraryInterp(Guchar *scaledColor, Guchar *scaledAlpha,
+				      SplashDrawImageRowData *dd,
+				      SplashDrawImageRowFunc drawRowFunc,
+				      SplashCoord *invMat,
+				      int scaledWidth, int scaledHeight,
+				      int xMin, int yMin, int xMax, int yMax,
+				      int nComps, GBool srcAlpha) {
+  int tt = state->clip->getXMinI(state->strokeAdjust);
+  if (tt > xMin) {
+    xMin = tt;
+  }
+  tt = state->clip->getXMaxI(state->strokeAdjust) + 1;
+  if (tt < xMax) {
+    xMax = tt;
+  }
+  tt = state->clip->getYMinI(state->strokeAdjust);
+  if (tt > yMin) {
+    yMin = tt;
+  }
+  tt = state->clip->getYMaxI(state->strokeAdjust) + 1;
+  if (tt < yMax) {
+    yMax = tt;
+  }
+  if (xMax <= xMin || yMax <= yMin) {
+    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 *)gmallocn(srcWidth, nComps);
+  Guchar *colorBuf = (Guchar *)gmallocn(xMax - xMin, nComps);
+  Guchar *alphaBuf = NULL;
   if (srcAlpha) {
-    alphaLineBuf = (Guchar *)gmalloc(srcWidth);
-  } else {
-    alphaLineBuf = NULL;
+    alphaBuf = (Guchar *)gmalloc(xMax - xMin);
   }
 
-  // init y scale Bresenham
-  yt = 0;
-
-  destPtr = dest->data;
-  destAlphaPtr = 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;
-
-    // generate one row
-    srcPtr = lineBuf;
-    srcAlphaPtr = alphaLineBuf;
-    for (x = 0; x < srcWidth; ++x) {
-
-      // x scale Bresenham
-      if ((xt += xq) >= srcWidth) {
-	xt -= srcWidth;
-	xStep = xp + 1;
-      } else {
-	xStep = xp;
-      }
-
-      // duplicate the pixel horizontally
-      switch (srcMode) {
-      case splashModeMono8:
-	pix0 = *srcPtr++;
-	for (i = 0; i < xStep; ++i) {
-	  *destPtr++ = pix0;
+  for (int y = yMin; y < yMax; ++y) {
+    int rowMin = xMax;
+    int rowMax = 0;
+    for (int x = xMin; x < xMax; ++x) {
+      // note: invMat includes a "+0.5" factor so that this is really
+      // a multiply by (x+0.5, y+0.5)
+      SplashCoord xs = (SplashCoord)x * invMat[0]
+	               + (SplashCoord)y * invMat[2] + invMat[4];
+      SplashCoord ys = (SplashCoord)x * invMat[1]
+	               + (SplashCoord)y * invMat[3] + invMat[5];
+      int x0 = splashFloor(xs - 0.5);
+      int x1 = x0 + 1;
+      int y0 = splashFloor(ys - 0.5);
+      int y1 = y0 + 1;
+      if (x1 >= 0 && x0 < scaledWidth && y1 >= 0 && y0 < scaledHeight) {
+	SplashCoord sx0 = (SplashCoord)x1 + 0.5 - xs;
+	SplashCoord sx1 = (SplashCoord)1 - sx0;
+	SplashCoord sy0 = (SplashCoord)y1 + 0.5 - ys;
+	SplashCoord sy1 = (SplashCoord)1 - sy0;
+	if (x0 < 0) {
+	  x0 = 0;
 	}
-	break;
-      case splashModeRGB8:
-	pix0 = *srcPtr++;
-	pix1 = *srcPtr++;
-	pix2 = *srcPtr++;
-	for (i = 0; i < xStep; ++i) {
-	  *destPtr++ = pix0;
-	  *destPtr++ = pix1;
-	  *destPtr++ = pix2;
+	if (x1 >= scaledWidth) {
+	  x1 = scaledWidth - 1;
 	}
-	break;
-#if SPLASH_CMYK
-      case splashModeCMYK8:
-	pix0 = *srcPtr++;
-	pix1 = *srcPtr++;
-	pix2 = *srcPtr++;
-	pix3 = *srcPtr++;
-	for (i = 0; i < xStep; ++i) {
-	  *destPtr++ = pix0;
-	  *destPtr++ = pix1;
-	  *destPtr++ = pix2;
-	  *destPtr++ = pix3;
+	if (y0 < 0) {
+	  y0 = 0;
 	}
-	break;
-#endif
-      case splashModeMono1: // mono1 is not allowed
-      case splashModeBGR8: // BGR8 is not allowed
-      default:
-	break;
-      }
-
-      // duplicate the alpha value horizontally
-      if (srcAlpha) {
-	alpha = *srcAlphaPtr++;
-	for (i = 0; i < xStep; ++i) {
-	  *destAlphaPtr++ = alpha;
+	if (y1 >= scaledHeight) {
+	  y1 = scaledHeight - 1;
 	}
+	Guchar *p00 = scaledColor + (y0 * scaledWidth + x0) * nComps;
+	Guchar *p10 = scaledColor + (y0 * scaledWidth + x1) * nComps;
+	Guchar *p01 = scaledColor + (y1 * scaledWidth + x0) * nComps;
+	Guchar *p11 = scaledColor + (y1 * scaledWidth + x1) * nComps;
+	Guchar *q = colorBuf + (x - xMin) * nComps;
+	for (int i = 0; i < nComps; ++i) {
+	  *q++ = (Guchar)(int)(sx0 * (sy0 * (int)*p00++ + sy1 * (int)*p01++) +
+			       sx1 * (sy0 * (int)*p10++ + sy1 * (int)*p11++));
+	}
+	if (srcAlpha) {
+	  p00 = scaledAlpha + (y0 * scaledWidth + x0);
+	  p10 = scaledAlpha + (y0 * scaledWidth + x1);
+	  p01 = scaledAlpha + (y1 * scaledWidth + x0);
+	  p11 = scaledAlpha + (y1 * scaledWidth + x1);
+	  q = alphaBuf + (x - xMin);
+	  *q = (Guchar)(int)(sx0 * (sy0 * (int)*p00 + sy1 * (int)*p01) +
+			     sx1 * (sy0 * (int)*p10 + sy1 * (int)*p11));
+	}
+	if (x < rowMin) {
+	  rowMin = x;
+	}
+	rowMax = x + 1;
       }
     }
-
-    // duplicate the row vertically
-    for (i = 1; i < yStep; ++i) {
-      memcpy(destPtr, destPtr - scaledWidth * nComps,
-	     scaledWidth * nComps);
-      destPtr += scaledWidth * nComps;
+    if (rowMin < rowMax) {
+      (this->*drawRowFunc)(dd,
+			   colorBuf + (rowMin - xMin) * nComps,
+			   alphaBuf + (rowMin - xMin),
+			   rowMin, y, rowMax - rowMin);
     }
-    if (srcAlpha) {
-      for (i = 1; i < yStep; ++i) {
-	memcpy(destAlphaPtr, destAlphaPtr - scaledWidth, scaledWidth);
-	destAlphaPtr += scaledWidth;
-      }
-    }
   }
 
-  gfree(alphaLineBuf);
-  gfree(lineBuf);
+  gfree(colorBuf);
+  gfree(alphaBuf);
 }
 
-void Splash::scaleImageYuXuI(SplashImageSource src, void *srcData,
-			     SplashColorMode srcMode, int nComps,
-			     GBool srcAlpha, int srcWidth, int srcHeight,
-			     int scaledWidth, int scaledHeight,
-			     SplashBitmap *dest) {
-  Guchar *lineBuf0, *lineBuf1, *alphaLineBuf0, *alphaLineBuf1, *tBuf;
-  Guchar pix[splashMaxColorComps];
-  SplashCoord yr, xr, ys, xs, ySrc, xSrc;
-  int ySrc0, ySrc1, yBuf, xSrc0, xSrc1, y, x, i;
-  Guchar *destPtr, *destAlphaPtr;
+void Splash::mirrorImageRow(Guchar *colorIn, Guchar *alphaIn,
+			    Guchar *colorOut, Guchar *alphaOut,
+			    int width, int nComps, GBool srcAlpha) {
+  Guchar *p, *q;
 
-  // ratios
-  yr = (SplashCoord)srcHeight / (SplashCoord)scaledHeight;
-  xr = (SplashCoord)srcWidth / (SplashCoord)scaledWidth;
-
-  // allocate buffers
-  lineBuf0 = (Guchar *)gmallocn(scaledWidth, nComps);
-  lineBuf1 = (Guchar *)gmallocn(scaledWidth, nComps);
-  if (srcAlpha) {
-    alphaLineBuf0 = (Guchar *)gmalloc(scaledWidth);
-    alphaLineBuf1 = (Guchar *)gmalloc(scaledWidth);
-  } else {
-    alphaLineBuf0 = NULL;
-    alphaLineBuf1 = NULL;
-  }
-
-  // read first two rows
-  (*src)(srcData, lineBuf0, alphaLineBuf0);
-  if (srcHeight > 1) {
-    (*src)(srcData, lineBuf1, alphaLineBuf1);
-    yBuf = 1;
-  } else {
-    memcpy(lineBuf1, lineBuf0, srcWidth * nComps);
-    if (srcAlpha) {
-      memcpy(alphaLineBuf1, alphaLineBuf0, srcWidth);
+  p = colorIn;
+  q = colorOut + (width - 1) * nComps;
+  for (int i = 0; i < width; ++i) {
+    for (int j = 0; j < nComps; ++j) {
+      q[j] = p[j];
     }
-    yBuf = 0;
+    p += nComps;
+    q -= nComps;
   }
 
-  // interpolate first two rows
-  for (x = scaledWidth - 1; x >= 0; --x) {
-    xSrc = xr * x;
-    xSrc0 = splashFloor(xSrc + xr * 0.5 - 0.5);
-    xSrc1 = xSrc0 + 1;
-    xs = ((SplashCoord)xSrc1 + 0.5) - (xSrc + xr * 0.5);
-    if (xSrc0 < 0) {
-      xSrc0 = 0;
+  if (srcAlpha) {
+    p = alphaIn;
+    q = alphaOut + (width - 1);
+    for (int i = 0; i < width; ++i) {
+      *q = *p;
+      ++p;
+      --q;
     }
-    if (xSrc1 >= srcWidth) {
-      xSrc1 = srcWidth - 1;
-    }
-    for (i = 0; i < nComps; ++i) {
-      lineBuf0[x*nComps+i] = (Guchar)(int)
-	    (xs * (int)lineBuf0[xSrc0*nComps+i] +
-	     ((SplashCoord)1 - xs) * (int)lineBuf0[xSrc1*nComps+i]);
-      lineBuf1[x*nComps+i] = (Guchar)(int)
-	    (xs * (int)lineBuf1[xSrc0*nComps+i] +
-	     ((SplashCoord)1 - xs) * (int)lineBuf1[xSrc1*nComps+i]);
-    }
-    if (srcAlpha) {
-      alphaLineBuf0[x] = (Guchar)(int)
-	    (xs * (int)alphaLineBuf0[xSrc0] +
-	     ((SplashCoord)1 - xs) * (int)alphaLineBuf0[xSrc1]);
-      alphaLineBuf1[x] = (Guchar)(int)
-	    (xs * (int)alphaLineBuf1[xSrc0] +
-	     ((SplashCoord)1 - xs) * (int)alphaLineBuf1[xSrc1]);
-    }
   }
+}
 
-  // make gcc happy
-  pix[0] = pix[1] = pix[2] = 0;
-#if SPLASH_CMYK
-  pix[3] = 0;
-#endif
+void Splash::drawImageRowNoClipNoAlpha(SplashDrawImageRowData *data,
+				       Guchar *colorData, Guchar *alphaData,
+				       int x, int y, int width) {
+  (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y, NULL, colorData);
+}
 
-  destPtr = dest->data;
-  destAlphaPtr = dest->alpha;
-  for (y = 0; y < scaledHeight; ++y) {
-
-    // compute vertical interpolation parameters
-    ySrc = yr * y;
-    ySrc0 = splashFloor(ySrc + yr * 0.5 - 0.5);
-    ySrc1 = ySrc0 + 1;
-    ys = ((SplashCoord)ySrc1 + 0.5) - (ySrc + yr * 0.5);
-    if (ySrc0 < 0) {
-      ySrc0 = 0;
-      ys = 1;
-    }
-    if (ySrc1 >= srcHeight) {
-      ySrc1 = srcHeight - 1;
-      ys = 0;
-    }
-
-    // read another row (if necessary)
-    if (ySrc1 > yBuf) {
-      tBuf = lineBuf0;
-      lineBuf0 = lineBuf1;
-      lineBuf1 = tBuf;
-      tBuf = alphaLineBuf0;
-      alphaLineBuf0 = alphaLineBuf1;
-      alphaLineBuf1 = tBuf;
-      (*src)(srcData, lineBuf1, alphaLineBuf1);
-
-      // interpolate the row
-      for (x = scaledWidth - 1; x >= 0; --x) {
-	xSrc = xr * x;
-	xSrc0 = splashFloor(xSrc + xr * 0.5 - 0.5);
-	xSrc1 = xSrc0 + 1;
-	xs = ((SplashCoord)xSrc1 + 0.5) - (xSrc + xr * 0.5);
-	if (xSrc0 < 0) {
-	  xSrc0 = 0;
-	}
-	if (xSrc1 >= srcWidth) {
-	  xSrc1 = srcWidth - 1;
-	}
-	for (i = 0; i < nComps; ++i) {
-	  lineBuf1[x*nComps+i] = (Guchar)(int)
-	        (xs * (int)lineBuf1[xSrc0*nComps+i] +
-		 ((SplashCoord)1 - xs) * (int)lineBuf1[xSrc1*nComps+i]);
-	}
-	if (srcAlpha) {
-	  alphaLineBuf1[x] = (Guchar)(int)
-	        (xs * (int)alphaLineBuf1[xSrc0] +
-		 ((SplashCoord)1 - xs) * (int)alphaLineBuf1[xSrc1]);
-	}
-      }
-
-      ++yBuf;
-    }
-
-    // do the vertical interpolation
-    for (x = 0; x < scaledWidth; ++x) {
-
-      for (i = 0; i < nComps; ++i) {
-	pix[i] = (Guchar)(int)
-	         (ys * (int)lineBuf0[x*nComps+i] +
-		  ((SplashCoord)1 - ys) * (int)lineBuf1[x*nComps+i]);
-      }
-
-      // store the pixel
-      switch (srcMode) {
-      case splashModeMono8:
-	*destPtr++ = pix[0];
-	break;
-      case splashModeRGB8:
-	*destPtr++ = pix[0];
-	*destPtr++ = pix[1];
-	*destPtr++ = pix[2];
-	break;
-#if SPLASH_CMYK
-      case splashModeCMYK8:
-	*destPtr++ = pix[0];
-	*destPtr++ = pix[1];
-	*destPtr++ = pix[2];
-	*destPtr++ = pix[3];
-	break;
-#endif
-      case splashModeMono1: // mono1 is not allowed
-      case splashModeBGR8: // BGR8 is not allowed
-      default:
-	break;
-      }
-
-      // process alpha
-      if (srcAlpha) {
-	*destAlphaPtr++ = (Guchar)(int)
-	                  (ys * (int)alphaLineBuf0[x] +
-			   ((SplashCoord)1 - ys) * (int)alphaLineBuf1[x]);
-      }
-    }
-  }
-
-  gfree(alphaLineBuf1);
-  gfree(alphaLineBuf0);
-  gfree(lineBuf1);
-  gfree(lineBuf0);
+void Splash::drawImageRowNoClipAlpha(SplashDrawImageRowData *data,
+				     Guchar *colorData, Guchar *alphaData,
+				     int x, int y, int width) {
+  (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y,
+			  alphaData, colorData);
 }
 
-void Splash::vertFlipImage(SplashBitmap *img, int width, int height,
-			   int nComps) {
-  Guchar *lineBuf;
-  Guchar *p0, *p1;
-  int w;
-
-  w = width * nComps;
-  lineBuf = (Guchar *)gmalloc(w);
-  for (p0 = img->data, p1 = img->data + (height - 1) * (size_t)w;
-       p0 < p1;
-       p0 += w, p1 -= w) {
-    memcpy(lineBuf, p0, w);
-    memcpy(p0, p1, w);
-    memcpy(p1, lineBuf, w);
+void Splash::drawImageRowClipNoAlphaNoAA(SplashDrawImageRowData *data,
+					 Guchar *colorData,
+					 Guchar *alphaData,
+					 int x, int y, int width) {
+  if (y < 0 || y >= bitmap->height) {
+    return;
   }
-  if (img->alpha) {
-    for (p0 = img->alpha, p1 = img->alpha + (height - 1) * (size_t)width;
-	 p0 < p1;
-	 p0 += width, p1 -= width) {
-      memcpy(lineBuf, p0, width);
-      memcpy(p0, p1, width);
-      memcpy(p1, lineBuf, width);
-    }
+  if (x < 0) {
+    colorData -= x * data->nComps;
+    width += x;
+    x = 0;
   }
-  gfree(lineBuf);
-}
-
-void Splash::horizFlipImage(SplashBitmap *img, int width, int height,
-			    int nComps) {
-  Guchar *lineBuf;
-  SplashColorPtr p0, p1, p2;
-  int w, x, y, i;
-
-  w = width * nComps;
-  lineBuf = (Guchar *)gmalloc(w);
-  for (y = 0, p0 = img->data; y < height; ++y, p0 += img->rowSize) {
-    memcpy(lineBuf, p0, w);
-    p1 = p0;
-    p2 = lineBuf + (w - nComps);
-    for (x = 0; x < width; ++x) {
-      for (i = 0; i < nComps; ++i) {
-	p1[i] = p2[i];
-      }
-      p1 += nComps;
-      p2 -= nComps;
-    }
+  if (x + width > bitmap->width) {
+    width = bitmap->width - x;
   }
-  if (img->alpha) {
-    for (y = 0, p0 = img->alpha; y < height; ++y, p0 += width) {
-      memcpy(lineBuf, p0, width);
-      p1 = p0;
-      p2 = lineBuf + (width - 1);
-      for (x = 0; x < width; ++x) {
-	*p1++ = *p2--;
-      }
-    }
+  if (width <= 0) {
+    return;
   }
-  gfree(lineBuf);
+  memset(scanBuf + x, 0xff, width);
+  state->clip->clipSpanBinary(scanBuf, y, x, x + width - 1,
+			      state->strokeAdjust);
+  (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y,
+			  scanBuf + x, colorData);
 }
 
-void Splash::blitImage(SplashBitmap *src, GBool srcAlpha, int xDest, int yDest,
-		       SplashClipResult clipRes) {
-  SplashPipe pipe;
-  int w, h, x0, y0, x1, y1, y;
-
-  // split the image into clipped and unclipped regions
-  w = src->width;
-  h = src->height;
-  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;
-      }
-    }
+void Splash::drawImageRowClipNoAlphaAA(SplashDrawImageRowData *data,
+				       Guchar *colorData,
+				       Guchar *alphaData,
+				       int x, int y, int width) {
+  if (y < 0 || y >= bitmap->height) {
+    return;
   }
-
-  // draw the unclipped region
-  if (x0 < w && y0 < h && x0 < x1 && y0 < y1) {
-    pipeInit(&pipe, NULL,
-	     (Guchar)splashRound(state->fillAlpha * 255),
-	     srcAlpha, gFalse);
-    if (srcAlpha) {
-      for (y = y0; y < y1; ++y) {
-	(this->*pipe.run)(&pipe, xDest + x0, xDest + x1 - 1, yDest + y,
-			  src->alpha + y * src->alphaRowSize + x0,
-			  src->data + y * src->rowSize + x0 * bitmapComps);
-      }
-    } else {
-      for (y = y0; y < y1; ++y) {
-	(this->*pipe.run)(&pipe, xDest + x0, xDest + x1 - 1, yDest + y,
-			  NULL,
-			  src->data + y * src->getRowSize() +
-			    x0 * bitmapComps);
-      }
-    }
+  if (x < 0) {
+    colorData -= x * data->nComps;
+    width += x;
+    x = 0;
   }
+  if (x + width > bitmap->width) {
+    width = bitmap->width - x;
+  }
+  if (width <= 0) {
+    return;
+  }
+  memset(scanBuf + x, 0xff, width);
+  state->clip->clipSpan(scanBuf, y, x, x + width - 1, state->strokeAdjust);
+  (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y,
+			  scanBuf + x, colorData);
+}
 
-  // draw the clipped regions
-  if (y0 > 0) {
-    blitImageClipped(src, srcAlpha, 0, 0, xDest, yDest, w, y0);
+void Splash::drawImageRowClipAlphaNoAA(SplashDrawImageRowData *data,
+				       Guchar *colorData,
+				       Guchar *alphaData,
+				       int x, int y, int width) {
+  if (y < 0 || y >= bitmap->height) {
+    return;
   }
-  if (y1 < h) {
-    blitImageClipped(src, srcAlpha, 0, y1, xDest, yDest + y1, w, h - y1);
+  if (x < 0) {
+    colorData -= x * data->nComps;
+    alphaData -= x;
+    width += x;
+    x = 0;
   }
-  if (x0 > 0 && y0 < y1) {
-    blitImageClipped(src, srcAlpha, 0, y0, xDest, yDest + y0, x0, y1 - y0);
+  if (x + width > bitmap->width) {
+    width = bitmap->width - x;
   }
-  if (x1 < w && y0 < y1) {
-    blitImageClipped(src, srcAlpha, x1, y0, xDest + x1, yDest + y0,
-		     w - x1, y1 - y0);
+  if (width <= 0) {
+    return;
   }
+  memcpy(scanBuf + x, alphaData, width);
+  state->clip->clipSpanBinary(scanBuf, y, x, x + width - 1,
+			      state->strokeAdjust);
+  (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y,
+			  scanBuf + x, colorData);
 }
 
-void Splash::blitImageClipped(SplashBitmap *src, GBool srcAlpha,
-			      int xSrc, int ySrc, int xDest, int yDest,
-			      int w, int h) {
-  SplashPipe pipe;
-  int y;
-
-  if (xDest < 0) {
-    xSrc -= xDest;
-    w += xDest;
-    xDest = 0;
+void Splash::drawImageRowClipAlphaAA(SplashDrawImageRowData *data,
+				     Guchar *colorData,
+				     Guchar *alphaData,
+				     int x, int y, int width) {
+  if (y < 0 || y >= bitmap->height) {
+    return;
   }
-  if (xDest + w > bitmap->width) {
-    w = bitmap->width - xDest;
+  if (x < 0) {
+    colorData -= x * data->nComps;
+    alphaData -= x;
+    width += x;
+    x = 0;
   }
-  if (yDest < 0) {
-    ySrc -= yDest;
-    h += yDest;
-    yDest = 0;
+  if (x + width > bitmap->width) {
+    width = bitmap->width - x;
   }
-  if (yDest + h > bitmap->height) {
-    h = bitmap->height - yDest;
-  }
-  if (w <= 0 || h <= 0) {
+  if (width <= 0) {
     return;
   }
-
-  pipeInit(&pipe, NULL,
-	   (Guchar)splashRound(state->fillAlpha * 255),
-	   gTrue, gFalse);
-  if (srcAlpha) {
-    for (y = 0; y < h; ++y) {
-      memcpy(scanBuf + xDest,
-	     src->alpha + (ySrc + y) * src->alphaRowSize + xSrc,
-	     w);
-      if (vectorAntialias) {
-	state->clip->clipSpan(scanBuf, yDest + y, xDest, xDest + w - 1,
-			      state->strokeAdjust);
-      } else {
-	state->clip->clipSpanBinary(scanBuf, yDest + y, xDest, xDest + w - 1,
-				    state->strokeAdjust);
-      }
-      (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y,
-			scanBuf + xDest,
-			src->data + (ySrc + y) * src->rowSize +
-			  xSrc * bitmapComps);
-    }
-  } else {
-    for (y = 0; y < h; ++y) {
-      memset(scanBuf + xDest, 0xff, w);
-      if (vectorAntialias) {
-	state->clip->clipSpan(scanBuf, yDest + y, xDest, xDest + w - 1,
-			      state->strokeAdjust);
-      } else {
-	state->clip->clipSpanBinary(scanBuf, yDest + y, xDest, xDest + w - 1,
-				    state->strokeAdjust);
-      }
-      (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y,
-			scanBuf + xDest,
-			src->data + (ySrc + y) * src->rowSize +
-			  xSrc * bitmapComps);
-    }
-  }
+  memcpy(scanBuf + x, alphaData, width);
+  state->clip->clipSpan(scanBuf, y, x, x + width - 1, state->strokeAdjust);
+  (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y,
+			  scanBuf + x, colorData);
 }
 
 SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc,
@@ -6950,6 +7266,101 @@
   return splashOk;
 }
 
+SplashError Splash::compositeWithOverprint(SplashBitmap *src,
+					   Guint *srcOverprintMaskBitmap,
+					   int xSrc, int ySrc,
+					   int xDest, int yDest, int w, int h,
+					   GBool noClip, GBool nonIsolated) {
+  SplashPipe pipe;
+  int x0, x1, y0, y1, y, t;
+
+  if (!(src->mode == bitmap->mode ||
+	(src->mode == splashModeMono8 && bitmap->mode == splashModeMono1) ||
+	(src->mode == splashModeRGB8 && bitmap->mode == splashModeBGR8))) {
+    return splashErrModeMismatch;
+  }
+
+  pipeInit(&pipe, NULL,
+	   (Guchar)splashRound(state->fillAlpha * 255),
+	   !noClip || src->alpha != NULL, nonIsolated, gTrue);
+
+  if (noClip) {
+    if (src->alpha) {
+      for (y = 0; y < h; ++y) {
+	pipe.srcOverprintMaskPtr = srcOverprintMaskBitmap + y * w + xSrc;
+	// this uses shape instead of alpha, which isn't technically
+	// correct, but works out the same
+	(this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y,
+			  src->alpha +
+			    (ySrc + y) * src->alphaRowSize + xSrc,
+			  src->data + (ySrc + y) * src->rowSize +
+			    xSrc * bitmapComps);
+      }
+    } else {
+      for (y = 0; y < h; ++y) {
+	pipe.srcOverprintMaskPtr = srcOverprintMaskBitmap + y * w + xSrc;
+	(this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y,
+			  NULL,
+			  src->data + (ySrc + y) * src->rowSize +
+			    xSrc * bitmapComps);
+      }
+    }
+  } else {
+    x0 = xDest;
+    if ((t = state->clip->getXMinI(state->strokeAdjust)) > x0) {
+      x0 = t;
+    }
+    x1 = xDest + w;
+    if ((t = state->clip->getXMaxI(state->strokeAdjust) + 1) < x1) {
+      x1 = t;
+    }
+    y0 = yDest;
+    if ((t = state->clip->getYMinI(state->strokeAdjust)) > y0) {
+      y0 = t;
+    }
+    y1 = yDest + h;
+    if ((t = state->clip->getYMaxI(state->strokeAdjust) + 1) < y1) {
+      y1 = t;
+    }
+    if (x0 < x1 && y0 < y1) {
+      if (src->alpha) {
+	for (y = y0; y < y1; ++y) {
+	  memcpy(scanBuf + x0,
+		 src->alpha + (ySrc + y - yDest) * src->alphaRowSize + 
+		   (xSrc + x0 - xDest),
+		 x1 - x0);
+	  state->clip->clipSpan(scanBuf, y, x0, x1 - 1, state->strokeAdjust);
+	  pipe.srcOverprintMaskPtr = srcOverprintMaskBitmap
+	                             + (ySrc + y - yDest) * w
+	                             + (xSrc + x0 - xDest);
+	  // this uses shape instead of alpha, which isn't technically
+	  // correct, but works out the same
+	  (this->*pipe.run)(&pipe, x0, x1 - 1, y,
+			    scanBuf + x0,
+			    src->data +
+			      (ySrc + y - yDest) * src->rowSize +
+			      (xSrc + x0 - xDest) * bitmapComps);
+	}
+      } else {
+	for (y = y0; y < y1; ++y) {
+	  memset(scanBuf + x0, 0xff, x1 - x0);
+	  state->clip->clipSpan(scanBuf, y, x0, x1 - 1, state->strokeAdjust);
+	  pipe.srcOverprintMaskPtr = srcOverprintMaskBitmap
+	                             + (ySrc + y - yDest) * w
+	                             + (xSrc + x0 - xDest);
+	  (this->*pipe.run)(&pipe, x0, x1 - 1, y,
+			    scanBuf + x0,
+			    src->data +
+			      (ySrc + y - yDest) * src->rowSize +
+			      (xSrc + x0 - xDest) * bitmapComps);
+	}
+      }
+    }
+  }
+
+  return splashOk;
+}
+
 void Splash::compositeBackground(SplashColorPtr color) {
   SplashColorPtr p;
   Guchar *q;

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/splash/Splash.h
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/splash/Splash.h	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/splash/Splash.h	2021-02-15 19:17:20 UTC (rev 845)
@@ -29,6 +29,17 @@
 class SplashXPath;
 class SplashFont;
 struct SplashPipe;
+struct SplashDrawImageMaskRowData;
+class ImageScaler;
+typedef void (Splash::*SplashDrawImageMaskRowFunc)(
+				      SplashDrawImageMaskRowData *data,
+				      Guchar *maskData,
+				      int x, int y, int width);
+struct SplashDrawImageRowData;
+typedef void (Splash::*SplashDrawImageRowFunc)(SplashDrawImageRowData *data,
+					       Guchar *colorData,
+					       Guchar *alphaData,
+					       int x, int y, int width);
 
 //------------------------------------------------------------------------
 
@@ -66,6 +77,15 @@
 };
 
 //------------------------------------------------------------------------
+
+// Transparency group destination bitmap initialization control.
+enum SplashGroupDestInitMode {
+  splashGroupDestPreInit,	// dest is already initialized
+  splashGroupDestInitZero,	// initialize to zero (isolated group)
+  splashGroupDestInitCopy	// copy backdrop (non-isolated group)
+};
+
+//------------------------------------------------------------------------
 // SplashImageCache
 //------------------------------------------------------------------------
 
@@ -76,19 +96,23 @@
 
   SplashImageCache();
   ~SplashImageCache();
+  GBool match(GString *aTag, int aWidth, int aHeight,
+	      SplashColorMode aMode, GBool aAlpha,
+	      GBool aInterpolate);
+  void reset(GString *aTag, int aWidth, int aHeight,
+	     SplashColorMode aMode, GBool aAlpha,
+	     GBool aInterpolate);
   void incRefCount();
   void decRefCount();
 
   GString *tag;
-  GBool isMask;
   int width;
   int height;
   SplashColorMode mode;
   GBool alpha;
   GBool interpolate;
-  GBool vertFlip;
-  GBool horizFlip;
-  SplashBitmap *image;
+  Guchar *colorData;
+  Guchar *alphaData;
 
   int refCount;
 };
@@ -161,7 +185,9 @@
   void setSoftMask(SplashBitmap *softMask);
   void setInTransparencyGroup(SplashBitmap *groupBackBitmapA,
 			      int groupBackXA, int groupBackYA,
+			      SplashGroupDestInitMode groupDestInitModeA,
 			      GBool nonIsolated, GBool knockout);
+  void forceDeferredInit(int y, int h);
   void setTransfer(Guchar *red, Guchar *green, Guchar *blue, Guchar *gray);
   void setOverprintMask(Guint overprintMask);
   void setEnablePathSimplification(GBool en);
@@ -234,6 +260,15 @@
 			int xDest, int yDest, int w, int h,
 			GBool noClip, GBool nonIsolated);
 
+  // Composite a rectangular region from <src> onto this Splash
+  // object, using <srcOverprintMaskBitmap> as the overprint mask per
+  // pixel.  This is only supported for CMYK and DeviceN bitmaps.
+  SplashError compositeWithOverprint(SplashBitmap *src,
+				     Guint *srcOverprintMaskBitmap,
+				     int xSrc, int ySrc,
+				     int xDest, int yDest, int w, int h,
+				     GBool noClip, GBool nonIsolated);
+
   // Composite this Splash object onto a background color.  The
   // background alpha is assumed to be 1.
   void compositeBackground(SplashColorPtr color);
@@ -269,6 +304,10 @@
   // Return the associated bitmap.
   SplashBitmap *getBitmap() { return bitmap; }
 
+  // Enable writing the per-pixel overprint mask to a separate bitmap.
+  void setOverprintMaskBitmap(Guint *overprintMaskBitmapA)
+    { overprintMaskBitmap = overprintMaskBitmapA; }
+
   // Set the minimum line width.
   void setMinLineWidth(SplashCoord w) { minLineWidth = w; }
 
@@ -298,7 +337,7 @@
 
   void pipeInit(SplashPipe *pipe, SplashPattern *pattern,
 		Guchar aInput, GBool usesShape,
-		GBool nonIsolatedGroup);
+		GBool nonIsolatedGroup, GBool usesSrcOverprint = gFalse);
   void pipeRun(SplashPipe *pipe, int x0, int x1, int y,
 	       Guchar *shapePtr, SplashColorPtr cSrcPtr);
   void pipeRunSimpleMono1(SplashPipe *pipe, int x0, int x1, int y,
@@ -325,6 +364,8 @@
   void pipeRunShapeCMYK8(SplashPipe *pipe, int x0, int x1, int y,
 			 Guchar *shapePtr, SplashColorPtr cSrcPtr);
 #endif
+  void pipeRunShapeNoAlphaMono8(SplashPipe *pipe, int x0, int x1, int y,
+                                Guchar *shapePtr, SplashColorPtr cSrcPtr);
   void pipeRunAAMono1(SplashPipe *pipe, int x0, int x1, int y,
 		      Guchar *shapePtr, SplashColorPtr cSrcPtr);
   void pipeRunAAMono8(SplashPipe *pipe, int x0, int x1, int y,
@@ -337,6 +378,16 @@
   void pipeRunAACMYK8(SplashPipe *pipe, int x0, int x1, int y,
 		      Guchar *shapePtr, SplashColorPtr cSrcPtr);
 #endif
+  void pipeRunSoftMaskMono8(SplashPipe *pipe, int x0, int x1, int y,
+			    Guchar *shapePtr, SplashColorPtr cSrcPtr);
+  void pipeRunSoftMaskRGB8(SplashPipe *pipe, int x0, int x1, int y,
+                           Guchar *shapePtr, SplashColorPtr cSrcPtr);
+  void pipeRunSoftMaskBGR8(SplashPipe *pipe, int x0, int x1, int y,
+                           Guchar *shapePtr, SplashColorPtr cSrcPtr);
+#if SPLASH_CMYK
+  void pipeRunSoftMaskCMYK8(SplashPipe *pipe, int x0, int x1, int y,
+			    Guchar *shapePtr, SplashColorPtr cSrcPtr);
+#endif
   void pipeRunNonIsoMono8(SplashPipe *pipe, int x0, int x1, int y,
 			  Guchar *shapePtr, SplashColorPtr cSrcPtr);
   void pipeRunNonIsoRGB8(SplashPipe *pipe, int x0, int x1, int y,
@@ -347,6 +398,8 @@
   void pipeRunNonIsoCMYK8(SplashPipe *pipe, int x0, int x1, int y,
 			  Guchar *shapePtr, SplashColorPtr cSrcPtr);
 #endif
+  void useDestRow(int y);
+  void copyGroupBackdropRow(int y);
   void transform(SplashCoord *matrix, SplashCoord xi, SplashCoord yi,
 		 SplashCoord *xo, SplashCoord *yo);
   void updateModX(int x);
@@ -371,92 +424,81 @@
   SplashError fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph);
   void getImageBounds(SplashCoord xyMin, SplashCoord xyMax,
 		      int *xyMinI, int *xyMaxI);
-  void upscaleMask(SplashImageMaskSource src, void *srcData,
-		   int srcWidth, int srcHeight,
-		   SplashCoord *mat, GBool glyphMode,
-		   GBool interpolate);
-  void arbitraryTransformMask(GString *imageTag,
-			      SplashImageMaskSource src, void *srcData,
-			      int srcWidth, int srcHeight,
-			      SplashCoord *mat, GBool glyphMode,
-			      GBool interpolate);
-  SplashBitmap *scaleMask(GString *imageTag,
-			  SplashImageMaskSource src, void *srcData,
-			  int srcWidth, int srcHeight,
-			  int scaledWidth, int scaledHeight,
-			  GBool interpolate);
-  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 scaleMaskYuXuI(SplashImageMaskSource src, void *srcData,
-		      int srcWidth, int srcHeight,
+  void drawImageMaskArbitraryNoInterp(Guchar *scaledMask,
+				      SplashDrawImageMaskRowData *dd,
+				      SplashDrawImageMaskRowFunc drawRowFunc,
+				      SplashCoord *invMat,
+				      int scaledWidth, int scaledHeight,
+				      int xMin, int yMin, int xMax, int yMax);
+  void drawImageMaskArbitraryInterp(Guchar *scaledMask,
+				    SplashDrawImageMaskRowData *dd,
+				    SplashDrawImageMaskRowFunc drawRowFunc,
+				    SplashCoord *invMat,
+				    int scaledWidth, int scaledHeight,
+				    int xMin, int yMin, int xMax, int yMax);
+  void mirrorImageMaskRow(Guchar *maskIn, Guchar *maskOut, int width);
+  void drawImageMaskRowNoClip(SplashDrawImageMaskRowData *data,
+			      Guchar *maskData,
+			      int x, int y, int width);
+  void drawImageMaskRowClipNoAA(SplashDrawImageMaskRowData *data,
+				Guchar *maskData,
+				int x, int y, int width);
+  void drawImageMaskRowClipAA(SplashDrawImageMaskRowData *data,
+			      Guchar *maskData,
+			      int x, int y, int width);
+  ImageScaler *getImageScaler(GString *imageTag,
+			      SplashImageSource src, void *srcData,
+			      int w, int h, int nComps,
+			      int scaledWidth, int scaledHeight,
+			      SplashColorMode srcMode,
+			      GBool srcAlpha, GBool interpolate);
+  void getScaledImage(GString *imageTag,
+		      SplashImageSource src, void *srcData,
+		      int w, int h, int nComps,
 		      int scaledWidth, int scaledHeight,
-		      SplashBitmap *dest);
-  void blitMask(SplashBitmap *src, int xDest, int yDest,
-		SplashClipResult clipRes);
-  void upscaleImage(SplashImageSource src, void *srcData,
-		    SplashColorMode srcMode, int nComps,
-		    GBool srcAlpha, int srcWidth, int srcHeight,
-		    SplashCoord *mat, GBool interpolate);
-  void arbitraryTransformImage(GString *imageTag,
-			       SplashImageSource src, void *srcData,
-			       SplashColorMode srcMode, int nComps,
-			       GBool srcAlpha,
-			       int srcWidth, int srcHeight,
-			       SplashCoord *mat, GBool interpolate);
-  SplashBitmap *scaleImage(GString *imageTag,
-			   SplashImageSource src, void *srcData,
-			   SplashColorMode srcMode, int nComps,
-			   GBool srcAlpha, int srcWidth, int srcHeight,
-			   int scaledWidth, int scaledHeight,
-			   GBool interpolate);
-  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 scaleImageYuXuI(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 horizFlipImage(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);
+		      SplashColorMode srcMode,
+		      GBool srcAlpha, GBool interpolate,
+		      Guchar **scaledColor, Guchar **scaledAlpha,
+		      GBool *freeScaledImage);
+  void drawImageArbitraryNoInterp(Guchar *scaledColor, Guchar *scaledAlpha,
+				  SplashDrawImageRowData *dd,
+				  SplashDrawImageRowFunc drawRowFunc,
+				  SplashCoord *invMat,
+				  int scaledWidth, int scaledHeight,
+				  int xMin, int yMin, int xMax, int yMax,
+				  int nComps, GBool srcAlpha);
+  void drawImageArbitraryInterp(Guchar *scaledColor, Guchar *scaledAlpha,
+				SplashDrawImageRowData *dd,
+				SplashDrawImageRowFunc drawRowFunc,
+				SplashCoord *invMat,
+				int scaledWidth, int scaledHeight,
+				int xMin, int yMin, int xMax, int yMax,
+				int nComps, GBool srcAlpha);
+  void mirrorImageRow(Guchar *colorIn, Guchar *alphaIn,
+		      Guchar *colorOut, Guchar *alphaOut,
+		      int width, int nComps, GBool srcAlpha);
+  void drawImageRowNoClipNoAlpha(SplashDrawImageRowData *data,
+				 Guchar *colorData, Guchar *alphaData,
+				 int x, int y, int width);
+  void drawImageRowNoClipAlpha(SplashDrawImageRowData *data,
+			       Guchar *colorData, Guchar *alphaData,
+			       int x, int y, int width);
+  void drawImageRowClipNoAlphaNoAA(SplashDrawImageRowData *data,
+				   Guchar *colorData,
+				   Guchar *alphaData,
+				   int x, int y, int width);
+  void drawImageRowClipNoAlphaAA(SplashDrawImageRowData *data,
+				 Guchar *colorData,
+				 Guchar *alphaData,
+				 int x, int y, int width);
+  void drawImageRowClipAlphaNoAA(SplashDrawImageRowData *data,
+				 Guchar *colorData,
+				 Guchar *alphaData,
+				 int x, int y, int width);
+  void drawImageRowClipAlphaAA(SplashDrawImageRowData *data,
+			       Guchar *colorData,
+			       Guchar *alphaData,
+			       int x, int y, int width);
   void dumpPath(SplashPath *path);
   void dumpXPath(SplashXPath *path);
 
@@ -474,6 +516,9 @@
   SplashBitmap			// for transparency groups, this is the bitmap
     *groupBackBitmap;		//   containing the alpha0/color0 values
   int groupBackX, groupBackY;	// offset within groupBackBitmap
+  SplashGroupDestInitMode groupDestInitMode;
+  int groupDestInitYMin, groupDestInitYMax;
+  Guint *overprintMaskBitmap;
   SplashCoord minLineWidth;
   int modXMin, modYMin, modXMax, modYMax;
   SplashClipResult opClipRes;

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/splash/SplashBitmap.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/splash/SplashBitmap.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/splash/SplashBitmap.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -16,6 +16,8 @@
 #include <limits.h>
 #include "gmem.h"
 #include "gmempp.h"
+#include "gfile.h"
+#include "Trace.h"
 #include "SplashErrorCodes.h"
 #include "SplashBitmap.h"
 
@@ -64,6 +66,11 @@
   rowSize += rowPad - 1;
   rowSize -= rowSize % rowPad;
 
+  traceAlloc(this, "alloc bitmap: %d x %d x %d %s -> %lld bytes",
+	     width, height, splashColorModeNComps[mode],
+	     alphaA ? "with alpha" : "without alpha",
+	     height * rowSize + (alphaA ? height * width : 0));
+
   parent = parentA;
   oldData = NULL;
   oldAlpha = NULL;
@@ -75,8 +82,14 @@
       parent->oldHeight == height) {
     data = parent->oldData;
     parent->oldData = NULL;
+    traceMessage("reusing bitmap memory");
   } else {
     data = (SplashColorPtr)gmallocn64(height, rowSize);
+    traceMessage("not reusing bitmap memory"
+		 " (parent=%p parent->oldData=%p same-size=%d)",
+		 parent, parent ? parent->oldData : NULL,
+		 parent ? (parent->oldRowSize == rowSize &&
+			   parent->oldHeight == height) : 0);
   }
   if (!topDown) {
     data += (height - 1) * rowSize;
@@ -99,11 +112,12 @@
 }
 
 SplashBitmap::~SplashBitmap() {
+  traceFree(this, "free bitmap");
   if (data && rowSize < 0) {
     rowSize = -rowSize;
     data -= (height - 1) * rowSize;
   }
-  if (parent && rowSize > 10000000 / height) {
+  if (parent && rowSize > 4000000 / height) {
     gfree(parent->oldData);
     gfree(parent->oldAlpha);
     parent->oldData = data;
@@ -123,7 +137,7 @@
   FILE *f;
   SplashError err;
 
-  if (!(f = fopen(fileName, "wb"))) {
+  if (!(f = openFile(fileName, "wb"))) {
     return splashErrOpenFile;
   }
   err = writePNMFile(f);
@@ -211,7 +225,7 @@
   if (!alpha) {
     return splashErrModeMismatch;
   }
-  if (!(f = fopen(fileName, "wb"))) {
+  if (!(f = openFile(fileName, "wb"))) {
     return splashErrOpenFile;
   }
   fprintf(f, "P5\n%d %d\n255\n", width, height);

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/splash/SplashBitmap.h
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/splash/SplashBitmap.h	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/splash/SplashBitmap.h	2021-02-15 19:17:20 UTC (rev 845)
@@ -17,6 +17,10 @@
 
 #include <stdio.h>
 #include <limits.h>
+// older compilers won't define SIZE_MAX in stdint.h without this
+#ifndef __STDC_LIMIT_MACROS
+#  define __STDC_LIMIT_MACROS 1
+#endif
 #include <stdint.h>
 #include "SplashTypes.h"
 

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/splash/SplashFont.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/splash/SplashFont.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/splash/SplashFont.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -71,7 +71,11 @@
     // if the glyphs are too large, don't cache them -- setting the
     // cache bitmap size to something tiny will cause getGlyph() to
     // fall back to the uncached case
-    glyphW = glyphH = 1;
+    glyphW = glyphH = 0;
+    glyphSize = 0;
+    cacheSets = 0;
+    cacheAssoc = 0;
+    return;
   }
   if (aa) {
     glyphSize = glyphW * glyphH;
@@ -117,29 +121,33 @@
   }
 
   // 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) <
+  if (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+k].mru;
+	  }
 	}
+	cacheTags[i+j].mru = 0x80000000;
+	bitmap->aa = aa;
+	bitmap->data = cache + (i+j) * glyphSize;
+	bitmap->freeData = gFalse;
+	return gTrue;
       }
-      cacheTags[i+j].mru = 0x80000000;
-      bitmap->aa = aa;
-      bitmap->data = cache + (i+j) * glyphSize;
-      bitmap->freeData = gFalse;
-      return gTrue;
     }
+  } else {
+    i = 0; // make gcc happy
   }
 
   // generate the glyph bitmap
@@ -149,7 +157,7 @@
 
   // if the glyph doesn't fit in the bounding box, return a temporary
   // uncached bitmap
-  if (bitmap2.w > glyphW || bitmap2.h > glyphH) {
+  if (!cache || bitmap2.w > glyphW || bitmap2.h > glyphH) {
     *bitmap = bitmap2;
     return gTrue;
   }

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/splash/SplashFontEngine.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/splash/SplashFontEngine.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/splash/SplashFontEngine.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -20,6 +20,7 @@
 #include "gmem.h"
 #include "gmempp.h"
 #include "GString.h"
+#include "GList.h"
 #include "SplashMath.h"
 #include "SplashFTFontEngine.h"
 #include "SplashFontFile.h"
@@ -48,6 +49,7 @@
   for (i = 0; i < splashFontCacheSize; ++i) {
     fontCache[i] = NULL;
   }
+  badFontFiles = new GList();
 
 #if HAVE_FREETYPE_H
   if (enableFreeType) {
@@ -66,6 +68,7 @@
       delete fontCache[i];
     }
   }
+  deleteGList(badFontFiles, SplashFontFileID);
 
 #if HAVE_FREETYPE_H
   if (ftEngine) {
@@ -89,6 +92,15 @@
   return NULL;
 }
 
+GBool SplashFontEngine::checkForBadFontFile(SplashFontFileID *id) {
+  for (int i = 0; i < badFontFiles->getLength(); ++i) {
+    if (((SplashFontFileID *)badFontFiles->get(i))->matches(id)) {
+      return gTrue;
+    }
+  }
+  return gFalse;
+}
+
 SplashFontFile *SplashFontEngine::loadType1Font(SplashFontFileID *idA,
 #if LOAD_FONTS_FROM_MEM
 						GString *fontBuf,
@@ -122,6 +134,10 @@
   }
 #endif
 
+  if (!fontFile) {
+    badFontFiles->append(idA);
+  }
+
   return fontFile;
 }
 
@@ -162,6 +178,10 @@
   }
 #endif
 
+  if (!fontFile) {
+    badFontFiles->append(idA);
+  }
+
   return fontFile;
 }
 
@@ -202,6 +222,10 @@
   }
 #endif
 
+  if (!fontFile) {
+    badFontFiles->append(idA);
+  }
+
   return fontFile;
 }
 
@@ -243,6 +267,10 @@
   }
 #endif
 
+  if (!fontFile) {
+    badFontFiles->append(idA);
+  }
+
   return fontFile;
 }
 
@@ -284,6 +312,10 @@
   }
 #endif
 
+  if (!fontFile) {
+    badFontFiles->append(idA);
+  }
+
   return fontFile;
 }
 
@@ -327,6 +359,10 @@
   }
 #endif
 
+  if (!fontFile) {
+    badFontFiles->append(idA);
+  }
+
   return fontFile;
 }
 

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/splash/SplashFontEngine.h
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/splash/SplashFontEngine.h	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/splash/SplashFontEngine.h	2021-02-15 19:17:20 UTC (rev 845)
@@ -17,6 +17,7 @@
 
 #include "gtypes.h"
 class GString;
+class GList;
 
 class SplashFTFontEngine;
 class SplashDTFontEngine;
@@ -54,6 +55,10 @@
   // matching entry in the cache.
   SplashFontFile *getFontFile(SplashFontFileID *id);
 
+  // Returns true if [id] refers to a bad font file, i.e., if one of
+  // the loadXXXFont functions has returned NULL for that ID.
+  GBool checkForBadFontFile(SplashFontFileID *id);
+
   // Load fonts - these create new SplashFontFile objects.
   SplashFontFile *loadType1Font(SplashFontFileID *idA,
 #if LOAD_FONTS_FROM_MEM
@@ -114,6 +119,7 @@
 private:
 
   SplashFont *fontCache[splashFontCacheSize];
+  GList *badFontFiles;		// [SplashFontFileID]
 
 #if HAVE_FREETYPE_H
   SplashFTFontEngine *ftEngine;

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/splash/SplashXPath.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/splash/SplashXPath.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/splash/SplashXPath.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -593,7 +593,8 @@
       seg->dydx = 0;
     }
 #else
-    if (seg->y0 == seg->y1 || seg->x0 == seg->x1) {
+    if (splashAbs(seg->y1 - seg->y0) < 1e-200 ||
+	splashAbs(seg->x1 - seg->x0) < 1e-200) {
       seg->dxdy = 0;
       seg->dydx = 0;
     } else {

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/AcroForm.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/AcroForm.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/AcroForm.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -27,6 +27,9 @@
 #include "OptionalContent.h"
 #include "Annot.h"
 #include "Lexer.h"
+#include "XFAScanner.h"
+#include "UTF8.h"
+#include "PDF417Barcode.h"
 #include "AcroForm.h"
 
 //------------------------------------------------------------------------
@@ -55,6 +58,11 @@
 #define acroFormQuadCenter 1
 #define acroFormQuadRight  2
 
+#define acroFormVAlignTop               0
+#define acroFormVAlignMiddle            1
+#define acroFormVAlignMiddleNoDescender 2
+#define acroFormVAlignBottom            3
+
 #define annotFlagHidden    0x0002
 #define annotFlagPrint     0x0004
 #define annotFlagNoView    0x0020
@@ -63,8 +71,258 @@
 // = (4 * (sqrt(2) - 1) / 3) * r
 #define bezierCircle 0.55228475
 
+// limit recursive field-parent lookups to avoid infinite loops
+#define maxFieldObjectDepth 50
+
 //------------------------------------------------------------------------
 
+// 5 bars + 5 spaces -- each can be wide (1) or narrow (0)
+// (there are always exactly 3 wide elements;
+// the last space is always narrow)
+static Guchar code3Of9Data[128][10] = {
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // 0x00
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // 0x10
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 1, 1, 0, 0, 0, 1, 0, 0, 0 }, // ' ' = 0x20
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 1, 0, 1, 0, 1, 0, 0, 0, 0 }, // '$' = 0x24
+  { 0, 0, 0, 1, 0, 1, 0, 1, 0, 0 }, // '%' = 0x25
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 1, 0, 0, 1, 0, 1, 0, 0, 0 }, // '*' = 0x2a
+  { 0, 1, 0, 0, 0, 1, 0, 1, 0, 0 }, // '+' = 0x2b
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 1, 0, 0, 0, 0, 1, 0, 1, 0 }, // '-' = 0x2d
+  { 1, 1, 0, 0, 0, 0, 1, 0, 0, 0 }, // '.' = 0x2e
+  { 0, 1, 0, 1, 0, 0, 0, 1, 0, 0 }, // '/' = 0x2f
+  { 0, 0, 0, 1, 1, 0, 1, 0, 0, 0 }, // '0' = 0x30
+  { 1, 0, 0, 1, 0, 0, 0, 0, 1, 0 }, // '1'
+  { 0, 0, 1, 1, 0, 0, 0, 0, 1, 0 }, // '2'
+  { 1, 0, 1, 1, 0, 0, 0, 0, 0, 0 }, // '3'
+  { 0, 0, 0, 1, 1, 0, 0, 0, 1, 0 }, // '4'
+  { 1, 0, 0, 1, 1, 0, 0, 0, 0, 0 }, // '5'
+  { 0, 0, 1, 1, 1, 0, 0, 0, 0, 0 }, // '6'
+  { 0, 0, 0, 1, 0, 0, 1, 0, 1, 0 }, // '7'
+  { 1, 0, 0, 1, 0, 0, 1, 0, 0, 0 }, // '8'
+  { 0, 0, 1, 1, 0, 0, 1, 0, 0, 0 }, // '9'
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // 0x40
+  { 1, 0, 0, 0, 0, 1, 0, 0, 1, 0 }, // 'A' = 0x41
+  { 0, 0, 1, 0, 0, 1, 0, 0, 1, 0 }, // 'B'
+  { 1, 0, 1, 0, 0, 1, 0, 0, 0, 0 }, // 'C'
+  { 0, 0, 0, 0, 1, 1, 0, 0, 1, 0 }, // 'D'
+  { 1, 0, 0, 0, 1, 1, 0, 0, 0, 0 }, // 'E'
+  { 0, 0, 1, 0, 1, 1, 0, 0, 0, 0 }, // 'F'
+  { 0, 0, 0, 0, 0, 1, 1, 0, 1, 0 }, // 'G'
+  { 1, 0, 0, 0, 0, 1, 1, 0, 0, 0 }, // 'H'
+  { 0, 0, 1, 0, 0, 1, 1, 0, 0, 0 }, // 'I'
+  { 0, 0, 0, 0, 1, 1, 1, 0, 0, 0 }, // 'J'
+  { 1, 0, 0, 0, 0, 0, 0, 1, 1, 0 }, // 'K'
+  { 0, 0, 1, 0, 0, 0, 0, 1, 1, 0 }, // 'L'
+  { 1, 0, 1, 0, 0, 0, 0, 1, 0, 0 }, // 'M'
+  { 0, 0, 0, 0, 1, 0, 0, 1, 1, 0 }, // 'N'
+  { 1, 0, 0, 0, 1, 0, 0, 1, 0, 0 }, // 'O'
+  { 0, 0, 1, 0, 1, 0, 0, 1, 0, 0 }, // 'P' = 0x50
+  { 0, 0, 0, 0, 0, 0, 1, 1, 1, 0 }, // 'Q'
+  { 1, 0, 0, 0, 0, 0, 1, 1, 0, 0 }, // 'R'
+  { 0, 0, 1, 0, 0, 0, 1, 1, 0, 0 }, // 'S'
+  { 0, 0, 0, 0, 1, 0, 1, 1, 0, 0 }, // 'T'
+  { 1, 1, 0, 0, 0, 0, 0, 0, 1, 0 }, // 'U'
+  { 0, 1, 1, 0, 0, 0, 0, 0, 1, 0 }, // 'V'
+  { 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 }, // 'W'
+  { 0, 1, 0, 0, 1, 0, 0, 0, 1, 0 }, // 'X'
+  { 1, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, // 'Y'
+  { 0, 1, 1, 0, 1, 0, 0, 0, 0, 0 }, // 'Z'
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // 0x60
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // 0x70
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+};
+
+// 3 bars + 3 spaces -- each can be 1, 2, 3, or 4 units wide
+static Guchar code128Data[107][6] = {
+  { 2, 1, 2, 2, 2, 2 },
+  { 2, 2, 2, 1, 2, 2 },
+  { 2, 2, 2, 2, 2, 1 },
+  { 1, 2, 1, 2, 2, 3 },
+  { 1, 2, 1, 3, 2, 2 },
+  { 1, 3, 1, 2, 2, 2 },
+  { 1, 2, 2, 2, 1, 3 },
+  { 1, 2, 2, 3, 1, 2 },
+  { 1, 3, 2, 2, 1, 2 },
+  { 2, 2, 1, 2, 1, 3 },
+  { 2, 2, 1, 3, 1, 2 },
+  { 2, 3, 1, 2, 1, 2 },
+  { 1, 1, 2, 2, 3, 2 },
+  { 1, 2, 2, 1, 3, 2 },
+  { 1, 2, 2, 2, 3, 1 },
+  { 1, 1, 3, 2, 2, 2 },
+  { 1, 2, 3, 1, 2, 2 },
+  { 1, 2, 3, 2, 2, 1 },
+  { 2, 2, 3, 2, 1, 1 },
+  { 2, 2, 1, 1, 3, 2 },
+  { 2, 2, 1, 2, 3, 1 },
+  { 2, 1, 3, 2, 1, 2 },
+  { 2, 2, 3, 1, 1, 2 },
+  { 3, 1, 2, 1, 3, 1 },
+  { 3, 1, 1, 2, 2, 2 },
+  { 3, 2, 1, 1, 2, 2 },
+  { 3, 2, 1, 2, 2, 1 },
+  { 3, 1, 2, 2, 1, 2 },
+  { 3, 2, 2, 1, 1, 2 },
+  { 3, 2, 2, 2, 1, 1 },
+  { 2, 1, 2, 1, 2, 3 },
+  { 2, 1, 2, 3, 2, 1 },
+  { 2, 3, 2, 1, 2, 1 },
+  { 1, 1, 1, 3, 2, 3 },
+  { 1, 3, 1, 1, 2, 3 },
+  { 1, 3, 1, 3, 2, 1 },
+  { 1, 1, 2, 3, 1, 3 },
+  { 1, 3, 2, 1, 1, 3 },
+  { 1, 3, 2, 3, 1, 1 },
+  { 2, 1, 1, 3, 1, 3 },
+  { 2, 3, 1, 1, 1, 3 },
+  { 2, 3, 1, 3, 1, 1 },
+  { 1, 1, 2, 1, 3, 3 },
+  { 1, 1, 2, 3, 3, 1 },
+  { 1, 3, 2, 1, 3, 1 },
+  { 1, 1, 3, 1, 2, 3 },
+  { 1, 1, 3, 3, 2, 1 },
+  { 1, 3, 3, 1, 2, 1 },
+  { 3, 1, 3, 1, 2, 1 },
+  { 2, 1, 1, 3, 3, 1 },
+  { 2, 3, 1, 1, 3, 1 },
+  { 2, 1, 3, 1, 1, 3 },
+  { 2, 1, 3, 3, 1, 1 },
+  { 2, 1, 3, 1, 3, 1 },
+  { 3, 1, 1, 1, 2, 3 },
+  { 3, 1, 1, 3, 2, 1 },
+  { 3, 3, 1, 1, 2, 1 },
+  { 3, 1, 2, 1, 1, 3 },
+  { 3, 1, 2, 3, 1, 1 },
+  { 3, 3, 2, 1, 1, 1 },
+  { 3, 1, 4, 1, 1, 1 },
+  { 2, 2, 1, 4, 1, 1 },
+  { 4, 3, 1, 1, 1, 1 },
+  { 1, 1, 1, 2, 2, 4 },
+  { 1, 1, 1, 4, 2, 2 },
+  { 1, 2, 1, 1, 2, 4 },
+  { 1, 2, 1, 4, 2, 1 },
+  { 1, 4, 1, 1, 2, 2 },
+  { 1, 4, 1, 2, 2, 1 },
+  { 1, 1, 2, 2, 1, 4 },
+  { 1, 1, 2, 4, 1, 2 },
+  { 1, 2, 2, 1, 1, 4 },
+  { 1, 2, 2, 4, 1, 1 },
+  { 1, 4, 2, 1, 1, 2 },
+  { 1, 4, 2, 2, 1, 1 },
+  { 2, 4, 1, 2, 1, 1 },
+  { 2, 2, 1, 1, 1, 4 },
+  { 4, 1, 3, 1, 1, 1 },
+  { 2, 4, 1, 1, 1, 2 },
+  { 1, 3, 4, 1, 1, 1 },
+  { 1, 1, 1, 2, 4, 2 },
+  { 1, 2, 1, 1, 4, 2 },
+  { 1, 2, 1, 2, 4, 1 },
+  { 1, 1, 4, 2, 1, 2 },
+  { 1, 2, 4, 1, 1, 2 },
+  { 1, 2, 4, 2, 1, 1 },
+  { 4, 1, 1, 2, 1, 2 },
+  { 4, 2, 1, 1, 1, 2 },
+  { 4, 2, 1, 2, 1, 1 },
+  { 2, 1, 2, 1, 4, 1 },
+  { 2, 1, 4, 1, 2, 1 },
+  { 4, 1, 2, 1, 2, 1 },
+  { 1, 1, 1, 1, 4, 3 },
+  { 1, 1, 1, 3, 4, 1 },
+  { 1, 3, 1, 1, 4, 1 },
+  { 1, 1, 4, 1, 1, 3 },
+  { 1, 1, 4, 3, 1, 1 },
+  { 4, 1, 1, 1, 1, 3 },
+  { 4, 1, 1, 3, 1, 1 },
+  { 1, 1, 3, 1, 4, 1 },
+  { 1, 1, 4, 1, 3, 1 },
+  { 3, 1, 1, 1, 4, 1 },
+  { 4, 1, 1, 1, 3, 1 },
+  { 2, 1, 1, 4, 1, 2 }, // start code A
+  { 2, 1, 1, 2, 1, 4 }, // start code B
+  { 2, 1, 1, 2, 3, 2 }, // start code C
+  { 2, 3, 3, 1, 1, 1 }  // stop code (without final bar)
+};
+
+//------------------------------------------------------------------------
+
 // map an annotation ref to a page number
 class AcroFormAnnotPage {
 public:
@@ -83,7 +341,7 @@
   Object acroFormObj2;
   AcroForm *acroForm;
   AcroFormField *field;
-  Object fieldsObj, annotsObj, annotRef, annotObj, obj1, obj2;
+  Object xfaObj, fieldsObj, annotsObj, annotRef, annotObj, obj1, obj2;
   int pageNum, i, j;
 
   // this is the normal case: acroFormObj is a dictionary, as expected
@@ -90,6 +348,14 @@
   if (acroFormObjA->isDict()) {
     acroForm = new AcroForm(docA, acroFormObjA);
 
+    if (!acroFormObjA->dictLookup("XFA", &xfaObj)->isNull()) {
+      acroForm->xfaScanner = XFAScanner::load(&xfaObj);
+      if (!catalog->getNeedsRendering()) {
+	acroForm->isStaticXFA = gTrue;
+      }
+    }
+    xfaObj.free();
+
     if (acroFormObjA->dictLookup("NeedAppearances", &obj1)->isBool()) {
       acroForm->needAppearances = obj1.getBool();
     }
@@ -183,11 +449,14 @@
   return acroForm;
 }
 
-AcroForm::AcroForm(PDFDoc *docA, Object *acroFormObjA): Form(docA) {
+AcroForm::AcroForm(PDFDoc *docA, Object *acroFormObjA) {
+  doc = docA;
   acroFormObjA->copy(&acroFormObj);
   needAppearances = gFalse;
   annotPages = new GList();
   fields = new GList();
+  xfaScanner = NULL;
+  isStaticXFA = gFalse;
 }
 
 AcroForm::~AcroForm() {
@@ -194,8 +463,13 @@
   acroFormObj.free();
   deleteGList(annotPages, AcroFormAnnotPage);
   deleteGList(fields, AcroFormField);
+  delete xfaScanner;
 }
 
+const char *AcroForm::getType() {
+  return isStaticXFA ? "static XFA" : "AcroForm";
+}
+
 void AcroForm::buildAnnotPageList(Catalog *catalog) {
   Object annotsObj, annotObj;
   int pageNum, i;
@@ -296,10 +570,44 @@
   return fields->getLength();
 }
 
-FormField *AcroForm::getField(int idx) {
+AcroFormField *AcroForm::getField(int idx) {
   return (AcroFormField *)fields->get(idx);
 }
 
+AcroFormField *AcroForm::findField(int pg, double x, double y) {
+  AcroFormField *field;
+  double llx, lly, urx, ury;
+  int i;
+
+  for (i = 0; i < fields->getLength(); ++i) {
+    field = (AcroFormField *)fields->get(i);
+    if (field->getPageNum() == pg) {
+      field->getBBox(&llx, &lly, &urx, &ury);
+      if (llx <= x && x <= urx && lly <= y && y <= ury) {
+	return field;
+      }
+    }
+  }
+  return NULL;
+}
+
+int AcroForm::findFieldIdx(int pg, double x, double y) {
+  AcroFormField *field;
+  double llx, lly, urx, ury;
+  int i;
+
+  for (i = 0; i < fields->getLength(); ++i) {
+    field = (AcroFormField *)fields->get(i);
+    if (field->getPageNum() == pg) {
+      field->getBBox(&llx, &lly, &urx, &ury);
+      if (llx <= x && x <= urx && lly <= y && y <= ury) {
+	return i;
+      }
+    }
+  }
+  return -1;
+}
+
 //------------------------------------------------------------------------
 // AcroFormField
 //------------------------------------------------------------------------
@@ -307,11 +615,14 @@
 AcroFormField *AcroFormField::load(AcroForm *acroFormA, Object *fieldRefA) {
   GString *typeStr;
   TextString *nameA;
+  GString *xfaName;
   Guint flagsA;
   GBool haveFlags, typeFromParentA;
   Object fieldObjA, parentObj, parentObj2, obj1, obj2;
   AcroFormFieldType typeA;
+  XFAField *xfaFieldA;
   AcroFormField *field;
+  int depth, i0, i1;
 
   fieldRefA->fetch(acroFormA->doc->getXRef(), &fieldObjA);
 
@@ -345,7 +656,8 @@
   //----- get info from parent non-terminal fields
 
   fieldObjA.dictLookup("Parent", &parentObj);
-  while (parentObj.isDict()) {
+  depth = 0;
+  while (parentObj.isDict() && depth < maxFieldObjectDepth) {
 
     if (parentObj.dictLookup("T", &obj1)->isString()) {
       if (nameA->getLength()) {
@@ -373,6 +685,8 @@
     parentObj.dictLookup("Parent", &parentObj2);
     parentObj.free();
     parentObj = parentObj2;
+
+    ++depth;
   }
   parentObj.free();
 
@@ -381,6 +695,33 @@
     goto err1;
   }
 
+  //----- get static XFA info
+
+  xfaFieldA = NULL;
+  if (acroFormA->xfaScanner) {
+    // convert field name to UTF-8, and remove segments that start
+    // with '#' -- to match the XFA field name
+    xfaName = nameA->toUTF8();
+    i0 = 0;
+    while (i0 < xfaName->getLength()) {
+      i1 = i0;
+      while (i1 < xfaName->getLength()) {
+	if (xfaName->getChar(i1) == '.') {
+	  ++i1;
+	  break;
+	}
+	++i1;
+      }
+      if (xfaName->getChar(i0) == '#') {
+	xfaName->del(i0, i1 - i0);
+      } else {
+	i0 = i1;
+      }
+    }
+    xfaFieldA = acroFormA->xfaScanner->findField(xfaName);
+    delete xfaName;
+  }
+
   //----- check for a radio button
 
   // this is a kludge: if we see a Btn-type field with kids, and the
@@ -400,7 +741,9 @@
       typeA = acroFormFieldCheckbox;
     }
   } else if (!typeStr->cmp("Tx")) {
-    if (flagsA & acroFormFlagFileSelect) {
+    if (xfaFieldA && xfaFieldA->getBarcodeInfo()) {
+      typeA = acroFormFieldBarcode;
+    } else if (flagsA & acroFormFlagFileSelect) {
       typeA = acroFormFieldFileSelect;
     } else if (flagsA & acroFormFlagMultiline) {
       typeA = acroFormFieldMultilineText;
@@ -422,7 +765,7 @@
   delete typeStr;
 
   field = new AcroFormField(acroFormA, fieldRefA, &fieldObjA,
-			    typeA, nameA, flagsA, typeFromParentA);
+			    typeA, nameA, flagsA, typeFromParentA, xfaFieldA);
   fieldObjA.free();
   return field;
 
@@ -436,7 +779,8 @@
 AcroFormField::AcroFormField(AcroForm *acroFormA,
 			     Object *fieldRefA, Object *fieldObjA,
 			     AcroFormFieldType typeA, TextString *nameA,
-			     Guint flagsA, GBool typeFromParentA) {
+			     Guint flagsA, GBool typeFromParentA,
+			     XFAField *xfaFieldA) {
   acroForm = acroFormA;
   fieldRefA->copy(&fieldRef);
   fieldObjA->copy(&fieldObj);
@@ -444,6 +788,7 @@
   name = nameA;
   flags = flagsA;
   typeFromParent = typeFromParentA;
+  xfaField = xfaFieldA;
 }
 
 AcroFormField::~AcroFormField() {
@@ -478,6 +823,7 @@
   case acroFormFieldFileSelect:    return "FileSelect";
   case acroFormFieldMultilineText: return "MultilineText";
   case acroFormFieldText:          return "Text";
+  case acroFormFieldBarcode:       return "Barcode";
   case acroFormFieldComboBox:      return "ComboBox";
   case acroFormFieldListBox:       return "ListBox";
   case acroFormFieldSignature:     return "Signature";
@@ -508,36 +854,47 @@
   u = NULL;
   *length = 0;
 
-  fieldLookup("V", &obj1);
-  if (obj1.isName()) {
-    s = obj1.getName();
-    n = (int)strlen(s);
-    u = (Unicode *)gmallocn(n, sizeof(Unicode));
-    for (i = 0; i < n; ++i) {
-      u[i] = s[i] & 0xff;
+  // if this field has a counterpart in the XFA form, take the value
+  // from the XFA field (NB: an XFA field with no value overrides the
+  // AcroForm value)
+  if (xfaField) {
+    if (xfaField->getValue()) {
+      u = utf8ToUnicode(xfaField->getValue(), length);
     }
-    *length = n;
-  } else if (obj1.isString()) {
-    ts = new TextString(obj1.getString());
-    n = ts->getLength();
-    u = (Unicode *)gmallocn(n, sizeof(Unicode));
-    memcpy(u, ts->getUnicode(), n * sizeof(Unicode));
-    *length = n;
-    delete ts;
-  } else if (obj1.isDict()) {
-    obj1.dictLookup("Contents", &obj2);
-    if (obj2.isString()) {
-      gs = obj2.getString();
-      n = gs->getLength();
+
+  // no XFA form - take the AcroForm value
+  } else {
+    fieldLookup("V", &obj1);
+    if (obj1.isName()) {
+      s = obj1.getName();
+      n = (int)strlen(s);
       u = (Unicode *)gmallocn(n, sizeof(Unicode));
       for (i = 0; i < n; ++i) {
-	u[i] = gs->getChar(i) & 0xff;
+        u[i] = s[i] & 0xff;
       }
       *length = n;
+    } else if (obj1.isString()) {
+      ts = new TextString(obj1.getString());
+      n = ts->getLength();
+      u = (Unicode *)gmallocn(n, sizeof(Unicode));
+      memcpy(u, ts->getUnicode(), n * sizeof(Unicode));
+      *length = n;
+      delete ts;
+    } else if (obj1.isDict()) {
+      obj1.dictLookup("Contents", &obj2);
+      if (obj2.isString()) {
+        gs = obj2.getString();
+        n = gs->getLength();
+        u = (Unicode *)gmallocn(n, sizeof(Unicode));
+        for (i = 0; i < n; ++i) {
+  	u[i] = gs->getChar(i) & 0xff;
+        }
+        *length = n;
+      }
+      obj2.free();
     }
-    obj2.free();
+    obj1.free();
   }
-  obj1.free();
 
   return u;
 }
@@ -818,6 +1175,8 @@
   render = gFalse;
   if (acroForm->needAppearances) {
     render = gTrue;
+  } else if (xfaField && xfaField->getValue()) {
+    render = gTrue;
   } else {
     if (!annotObj->dictLookup("AP", &obj1)->isDict()) {
       render = gTrue;
@@ -889,9 +1248,17 @@
   double borderWidth;
   double *borderDash;
   GString *appearanceState;
-  int borderDashLength, rot, quadding, comb, nOptions, topIdx, i, j;
+  int borderDashLength, rot, quadding, vAlign, comb, nOptions, topIdx, i;
 
   appearBuf = new GString();
+#if 0 //~debug
+  appearBuf->appendf("1 1 0 rg 0 0 {0:.4f} {1:.4f} re f\n",
+		     xMax - xMin, yMax - yMin);
+#endif
+#if 0 //~debug
+  appearBuf->appendf("1 1 0 RG 0 0 {0:.4f} {1:.4f} re s\n",
+		     xMax - xMin, yMax - yMin);
+#endif
 
   // get the appearance characteristics (MK) dictionary
   if (annot->lookup("MK", &mkObj)->isDict()) {
@@ -1141,6 +1508,9 @@
   asObj.free();
   apObj.free();
 
+  int valueLength;
+  Unicode *value = getValue(&valueLength);
+
   // draw the field contents
   if (ftObj.isName("Btn")) {
     caption = NULL;
@@ -1153,12 +1523,13 @@
     // radio button
     if (flags & acroFormFlagRadio) {
       //~ Acrobat doesn't draw a caption if there is no AP dict (?)
-      if (fieldLookup("V", &obj1)
-	    ->isName(appearanceState->getCString())) {
+      if (value && unicodeStringEqual(value, valueLength,
+				      appearanceState->getCString())) {
 	if (caption) {
-	  drawText(caption, da, fontDict, gFalse, 0, acroFormQuadCenter,
-		   gFalse, gTrue, rot, xMin, yMin, xMax, yMax, borderWidth,
-		   appearBuf);
+	  drawText(caption, da, fontDict, gFalse, 0,
+		   acroFormQuadCenter, acroFormVAlignMiddleNoDescender,
+		   gFalse, gTrue, rot, 0, 0, xMax - xMin, yMax - yMin,
+		   borderWidth, gFalse, appearBuf);
 	} else {
 	  if (mkDict) {
 	    if (mkDict->lookup("BC", &obj2)->isArray() &&
@@ -1173,55 +1544,112 @@
 	  }
 	}
       }
-      obj1.free();
     // pushbutton
     } else if (flags & acroFormFlagPushbutton) {
       if (caption) {
-	drawText(caption, da, fontDict, gFalse, 0, acroFormQuadCenter,
-		 gFalse, gFalse, rot, xMin, yMin, xMax, yMax, borderWidth,
-		 appearBuf);
+	drawText(caption, da, fontDict, gFalse, 0,
+		 acroFormQuadCenter, acroFormVAlignMiddle,
+		 gFalse, gFalse, rot, 0, 0, xMax - xMin, yMax - yMin,
+		 borderWidth, gFalse, appearBuf);
       }
     // checkbox
     } else {
-      fieldLookup("V", &obj1);
-      if (obj1.isName() && !(obj1.isName("Off") ||
-			     obj1.isName("No") ||
-			     obj1.isName(""))) {
+      if (value && !(unicodeStringEqual(value, valueLength, "Off") ||
+		     unicodeStringEqual(value, valueLength, "No") ||
+		     unicodeStringEqual(value, valueLength, "0") ||
+		     valueLength == 0)) {
 	if (!caption) {
 	  caption = new GString("3"); // ZapfDingbats checkmark
 	}
-	drawText(caption, da, fontDict, gFalse, 0, acroFormQuadCenter,
-		 gFalse, gTrue, rot, xMin, yMin, xMax, yMax, borderWidth,
-		 appearBuf);
+	drawText(caption, da, fontDict, gFalse, 0,
+		 acroFormQuadCenter, acroFormVAlignMiddleNoDescender,
+		 gFalse, gTrue, rot, 0, 0, xMax - xMin, yMax - yMin,
+		 borderWidth, gFalse, appearBuf);
       }
-      obj1.free();
     }
     if (caption) {
       delete caption;
     }
   } else if (ftObj.isName("Tx")) {
-    //~ value strings can be Unicode
-    fieldLookup("V", &obj1);
-    if (obj1.isString()) {
-      if (fieldLookup("Q", &obj2)->isInt()) {
-	quadding = obj2.getInt();
+    XFAFieldBarcodeInfo *barcodeInfo = xfaField ? xfaField->getBarcodeInfo()
+                                                : (XFAFieldBarcodeInfo *)NULL;
+    if (value) {
+      //~ value strings can be Unicode
+      GString *valueLatin1 = unicodeToLatin1(value, valueLength);
+      if (barcodeInfo) {
+	drawBarcode(valueLatin1, da, fontDict, rot, xMin, yMin, xMax, yMax,
+		    barcodeInfo, appearBuf);
       } else {
-	quadding = acroFormQuadLeft;
-      }
-      obj2.free();
-      comb = 0;
-      if (flags & acroFormFlagComb) {
-	if (fieldLookup("MaxLen", &obj2)->isInt()) {
-	  comb = obj2.getInt();
+	if (fieldLookup("Q", &obj2)->isInt()) {
+	  quadding = obj2.getInt();
+	} else {
+	  quadding = acroFormQuadLeft;
 	}
 	obj2.free();
+	vAlign = (flags & acroFormFlagMultiline) ? acroFormVAlignTop
+	                                         : acroFormVAlignMiddle;
+	XFAFieldLayoutInfo *layoutInfo = xfaField ? xfaField->getLayoutInfo()
+	                                          : (XFAFieldLayoutInfo *)NULL;
+	if (layoutInfo) {
+	  switch (layoutInfo->hAlign) {
+	  case xfaFieldLayoutHAlignLeft:
+	  default:
+	    quadding = acroFormQuadLeft;
+	    break;
+	  case xfaFieldLayoutHAlignCenter:
+	    quadding = acroFormQuadCenter;
+	    break;
+	  case xfaFieldLayoutHAlignRight:
+	    quadding = acroFormQuadRight;
+	    break;
+	  }
+	  switch (layoutInfo->vAlign) {
+	  case xfaFieldLayoutVAlignTop:
+	  default:
+	    vAlign = acroFormVAlignTop;
+	    break;
+	  case xfaFieldLayoutVAlignMiddle:
+	    vAlign = acroFormVAlignMiddle;
+	    break;
+	  case xfaFieldLayoutVAlignBottom:
+	    vAlign = acroFormVAlignBottom;
+	    break;
+	  }
+	}
+	comb = 0;
+	if (flags & acroFormFlagComb) {
+	  if (fieldLookup("MaxLen", &obj2)->isInt()) {
+	    comb = obj2.getInt();
+	  }
+	  obj2.free();
+	}
+	XFAFieldPictureInfo *pictureInfo =
+	    xfaField ? xfaField->getPictureInfo()
+	             : (XFAFieldPictureInfo *)NULL;
+	GString *value2 = valueLatin1;
+	if (pictureInfo) {
+	  switch (pictureInfo->subtype) {
+	  case xfaFieldPictureDateTime:
+	    value2 = pictureFormatDateTime(valueLatin1, pictureInfo->format);
+	    break;
+	  case xfaFieldPictureNumeric:
+	    value2 = pictureFormatNumber(valueLatin1, pictureInfo->format);
+	    break;
+	  case xfaFieldPictureText:
+	    value2 = pictureFormatText(valueLatin1, pictureInfo->format);
+	    break;
+	  }
+	}
+	drawText(value2, da, fontDict,
+		 flags & acroFormFlagMultiline, comb, quadding, vAlign,
+		 gTrue, gFalse, rot, 0, 0, xMax - xMin, yMax - yMin,
+		 borderWidth, gFalse, appearBuf);
+	if (value2 != valueLatin1) {
+	  delete value2;
+	}
       }
-      drawText(obj1.getString(), da, fontDict,
-	       flags & acroFormFlagMultiline, comb, quadding,
-	       gTrue, gFalse, rot, xMin, yMin, xMax, yMax, borderWidth,
-	       appearBuf);
+      delete valueLatin1;
     }
-    obj1.free();
   } else if (ftObj.isName("Ch")) {
     //~ value/option strings can be Unicode
     if (fieldLookup("Q", &obj1)->isInt()) {
@@ -1230,10 +1658,39 @@
       quadding = acroFormQuadLeft;
     }
     obj1.free();
+    vAlign = acroFormVAlignMiddle;
+    XFAFieldLayoutInfo *layoutInfo = xfaField ? xfaField->getLayoutInfo()
+                                              : (XFAFieldLayoutInfo *)NULL;
+    if (layoutInfo) {
+      switch (layoutInfo->hAlign) {
+      case xfaFieldLayoutHAlignLeft:
+      default:
+	quadding = acroFormQuadLeft;
+	break;
+      case xfaFieldLayoutHAlignCenter:
+	quadding = acroFormQuadCenter;
+	break;
+      case xfaFieldLayoutHAlignRight:
+	quadding = acroFormQuadRight;
+	break;
+      }
+      switch (layoutInfo->vAlign) {
+      case xfaFieldLayoutVAlignTop:
+      default:
+	vAlign = acroFormVAlignTop;
+	break;
+      case xfaFieldLayoutVAlignMiddle:
+	vAlign = acroFormVAlignMiddle;
+	break;
+      case xfaFieldLayoutVAlignBottom:
+	vAlign = acroFormVAlignBottom;
+	break;
+      }
+    }
     // combo box
     if (flags & acroFormFlagCombo) {
-      if (fieldLookup("V", &obj1)->isString()) {
-	val = obj1.getString()->copy();
+      if (value) {
+	val = unicodeToLatin1(value, valueLength);
 	if (fieldObj.dictLookup("Opt", &obj2)->isArray()) {
 	  for (i = 0, done = false; i < obj2.arrayGetLength() && !done; ++i) {
 	    obj2.arrayGet(i, &obj3);
@@ -1254,12 +1711,12 @@
 	}
 	obj2.free();
 	drawText(val, da, fontDict,
-		 gFalse, 0, quadding, gTrue, gFalse, rot,
-		 xMin, yMin, xMax, yMax, borderWidth, appearBuf);
+		 gFalse, 0, quadding, vAlign, gTrue, gFalse, rot,
+		 0, 0, xMax - xMin, yMax - yMin, borderWidth,
+		 gFalse, appearBuf);
 	delete val;
 	//~ Acrobat draws a popup icon on the right side
       }
-      obj1.free();
     // list box
     } else {
       if (fieldObj.dictLookup("Opt", &obj1)->isArray()) {
@@ -1285,27 +1742,15 @@
 	// get the selected option(s)
 	selection = (GBool *)gmallocn(nOptions, sizeof(GBool));
 	//~ need to use the I field in addition to the V field
-	fieldLookup("V", &obj2);
 	for (i = 0; i < nOptions; ++i) {
-	  selection[i] = gFalse;
-	  if (obj2.isString()) {
-	    if (!obj2.getString()->cmp(text[i])) {
-	      selection[i] = gTrue;
-	    }
-	  } else if (obj2.isArray()) {
-	    for (j = 0; j < obj2.arrayGetLength(); ++j) {
-	      if (obj2.arrayGet(j, &obj3)->isString() &&
-		  !obj3.getString()->cmp(text[i])) {
-		selection[i] = gTrue;
-	      }
-	      obj3.free();
-	    }
-	  }
+	  selection[i] = unicodeStringEqual(value, valueLength, text[i]);
 	}
-	obj2.free();
 	// get the top index
 	if (fieldObj.dictLookup("TI", &obj2)->isInt()) {
 	  topIdx = obj2.getInt();
+	  if (topIdx < 0 || topIdx >= nOptions) {
+	    topIdx = 0;
+	  }
 	} else {
 	  topIdx = 0;
 	}
@@ -1334,14 +1779,16 @@
       delete da;
     }
     da = new GString("/Helv 10 Tf 1 0 0 rg");
-    drawText(caption, da, fontDict,
-	     gFalse, 0, acroFormQuadLeft, gFalse, gFalse, rot,
-	     xMin, yMin, xMax, yMax, borderWidth, appearBuf);
+    drawText(caption, da, fontDict, gFalse, 0,
+	     acroFormQuadLeft, acroFormVAlignMiddle, gFalse, gFalse, rot,
+	     0, 0, xMax - xMin, yMax - yMin, borderWidth, gFalse, appearBuf);
     delete caption;
   } else {
     error(errSyntaxError, -1, "Unknown field type");
   }
 
+  gfree(value);
+
   delete appearanceState;
   if (da) {
     delete da;
@@ -1457,17 +1904,20 @@
 
 // Draw the variable text or caption for a field.
 void AcroFormField::drawText(GString *text, GString *da, GfxFontDict *fontDict,
-			     GBool multiline, int comb, int quadding,
+			     GBool multiline, int comb,
+			     int quadding, int vAlign,
 			     GBool txField, GBool forceZapfDingbats, int rot,
-			     double xMin, double yMin, double xMax, double yMax,
-			     double border, GString *appearBuf) {
+			     double x, double y, double width, double height,
+			     double border, GBool whiteBackground,
+			     GString *appearBuf) {
   GString *text2;
   GList *daToks;
   GString *tok;
   GfxFont *font;
   double dx, dy;
-  double fontSize, fontSize2, x, xPrev, y, w, w2, wMax;
-  int tfPos, tmPos, i, j, k, c;
+  double fontSize, fontSize2, topBorder, xx, xPrev, yy, w, wMax;
+  double offset, offset2, charWidth, ascent, descent;
+  int tfPos, tmPos, nLines, i, j, k, c;
 
   //~ if there is no MK entry, this should use the existing content stream,
   //~ and only replace the marked content portion of it
@@ -1501,7 +1951,7 @@
   if (da) {
     daToks = tokenize(da);
     for (i = 2; i < daToks->getLength(); ++i) {
-      if (i >= 2 && !((GString *)daToks->get(i))->cmp("Tf")) {
+      if (!((GString *)daToks->get(i))->cmp("Tf")) {
 	tfPos = i - 2;
       } else if (i >= 6 && !((GString *)daToks->get(i))->cmp("Tm")) {
 	tmPos = i - 6;
@@ -1558,23 +2008,21 @@
   }
   appearBuf->append("q\n");
   if (rot == 90) {
-    appearBuf->appendf("0 1 -1 0 {0:.4f} 0 cm\n", xMax - xMin);
-    dx = yMax - yMin;
-    dy = xMax - xMin;
+    appearBuf->appendf("0 1 -1 0 {0:.4f} 0 cm\n", width);
+    dx = height;
+    dy = width;
   } else if (rot == 180) {
-    appearBuf->appendf("-1 0 0 -1 {0:.4f} {1:.4f} cm\n",
-		       xMax - xMin, yMax - yMin);
-    dx = xMax - yMax;
-    dy = yMax - yMin;
+    appearBuf->appendf("-1 0 0 -1 {0:.4f} {1:.4f} cm\n", width, height);
+    dx = width;
+    dy = height;
   } else if (rot == 270) {
-    appearBuf->appendf("0 -1 1 0 0 {0:.4f} cm\n", yMax - yMin);
-    dx = yMax - yMin;
-    dy = xMax - xMin;
+    appearBuf->appendf("0 -1 1 0 0 {0:.4f} cm\n", height);
+    dx = height;
+    dy = width;
   } else { // assume rot == 0
-    dx = xMax - xMin;
-    dy = yMax - yMin;
+    dx = width;
+    dy = height;
   }
-  appearBuf->append("BT\n");
 
   // multi-line text
   if (multiline) {
@@ -1582,22 +2030,29 @@
 
     wMax = dx - 2 * border - 4;
 
+#if 1 //~tmp
+    // this is a kludge that appears to match Adobe's behavior
+    if (height > 15) {
+      topBorder = 5;
+    } else {
+      topBorder = 2;
+    }
+#else
+    topBorder = 5;
+#endif
+
     // compute font autosize
     if (fontSize == 0) {
       for (fontSize = 10; fontSize > 1; --fontSize) {
-	y = dy - 3;
-	w2 = 0;
+	yy = dy - topBorder;
 	i = 0;
 	while (i < text2->getLength()) {
 	  getNextLine(text2, i, font, fontSize, wMax, &j, &w, &k);
-	  if (w > w2) {
-	    w2 = w;
-	  }
 	  i = k;
-	  y -= fontSize;
+	  yy -= fontSize;
 	}
 	// approximate the descender for the last line
-	if (y >= 0.33 * fontSize && w <= wMax) {
+	if (yy >= 0.25 * fontSize && w <= wMax) {
 	  break;
 	}
       }
@@ -1609,22 +2064,54 @@
     }
 
     // starting y coordinate
-    // (note: each line of text starts with a Td operator that moves
-    // down a line)
-    if (dy > fontSize + 6) {
-      y = dy - 3;
+    nLines = 0;
+    i = 0;
+    while (i < text2->getLength()) {
+      getNextLine(text2, i, font, fontSize, wMax, &j, &w, &k);
+      i = k;
+      ++nLines;
+    }
+    if (font) {
+      ascent = font->getDeclaredAscent() * fontSize;
+      descent = font->getDescent() * fontSize;
     } else {
-      y = 0.5 * dy - 0.4 * fontSize + fontSize;
+      ascent = 0.75 * fontSize;
+      descent = -0.25 * fontSize;
     }
+    switch (vAlign) {
+    case acroFormVAlignTop:
+    default:
+      yy = dy - ascent - topBorder;
+      break;
+    case acroFormVAlignMiddle:
+      yy = 0.5 * (dy - nLines * fontSize) + (nLines - 1) * fontSize - descent;
+      break;
+    case acroFormVAlignMiddleNoDescender:
+      yy = 0.5 * (dy - nLines * fontSize) + (nLines - 1) * fontSize;
+      break;
+    case acroFormVAlignBottom:
+      yy = (nLines - 1) * fontSize - descent;
+      break;
+    }
+    // if the field is shorter than a line of text, Acrobat positions
+    // the text relative to the bottom edge
+    if (dy < fontSize + topBorder) {
+      yy = 2 - descent;
+    }
+    // each line of text starts with a Td operator that moves down a
+    // line -- so move up a line here
+    yy += fontSize;
 
+    appearBuf->append("BT\n");
+
     // set the font matrix
     if (tmPos >= 0) {
       tok = (GString *)daToks->get(tmPos + 4);
       tok->clear();
-      tok->append('0');
+      tok->appendf("{0:.4f}", x);
       tok = (GString *)daToks->get(tmPos + 5);
       tok->clear();
-      tok->appendf("{0:.4f}", y);
+      tok->appendf("{0:.4f}", y + yy);
     }
 
     // write the DA string
@@ -1636,7 +2123,7 @@
 
     // write the font matrix (if not part of the DA string)
     if (tmPos < 0) {
-      appearBuf->appendf("1 0 0 1 0 {0:.4f} Tm\n", y);
+      appearBuf->appendf("1 0 0 1 {0:.4f} {1:.4f} Tm\n", x, y + yy);
     }
 
     // write a series of lines of text
@@ -1650,18 +2137,18 @@
       switch (quadding) {
       case acroFormQuadLeft:
       default:
-	x = border + 2;
+	xx = border + 2;
 	break;
       case acroFormQuadCenter:
-	x = (dx - w) / 2;
+	xx = (dx - w) / 2;
 	break;
       case acroFormQuadRight:
-	x = dx - border - 2 - w;
+	xx = dx - border - 2 - w;
 	break;
       }
 
       // draw the line
-      appearBuf->appendf("{0:.4f} {1:.4f} Td\n", x - xPrev, -fontSize);
+      appearBuf->appendf("{0:.4f} {1:.4f} Td\n", xx - xPrev, -fontSize);
       appearBuf->append('(');
       for (; i < j; ++i) {
 	c = text2->getChar(i) & 0xff;
@@ -1678,9 +2165,11 @@
 
       // next line
       i = k;
-      xPrev = x;
+      xPrev = xx;
     }
 
+    appearBuf->append("ET\n");
+
   // single-line text
   } else {
     //~ replace newlines with spaces? - what does Acrobat do?
@@ -1689,7 +2178,7 @@
     if (comb > 0) {
 
       // compute comb spacing
-      w = (dx - 2 * border) / comb;
+      w = dx / comb;
 
       // compute font autosize
       if (fontSize == 0) {
@@ -1712,25 +2201,48 @@
       switch (quadding) {
       case acroFormQuadLeft:
       default:
-	x = border + 2;
+	xx = 0;
 	break;
       case acroFormQuadCenter:
-	x = border + 2 + 0.5 * (comb - text2->getLength()) * w;
+	xx = ((comb - text2->getLength()) / 2) * w;
 	break;
       case acroFormQuadRight:
-	x = border + 2 + (comb - text2->getLength()) * w;
+	xx = (comb - text2->getLength()) * w;
 	break;
       }
-      y = 0.5 * dy - 0.4 * fontSize;
+      if (font) {
+	ascent = font->getDeclaredAscent() * fontSize;
+	descent = font->getDescent() * fontSize;
+      } else {
+	ascent = 0.75 * fontSize;
+	descent = -0.25 * fontSize;
+      }
+      switch (vAlign) {
+      case acroFormVAlignTop:
+      default:
+	yy = dy - ascent;
+	break;
+      case acroFormVAlignMiddle:
+	yy = 0.5 * (dy - ascent - descent);
+	break;
+      case acroFormVAlignMiddleNoDescender:
+	yy = 0.5 * (dy - ascent);
+	break;
+      case acroFormVAlignBottom:
+	yy = -descent;
+	break;
+      }
 
+      appearBuf->append("BT\n");
+
       // set the font matrix
       if (tmPos >= 0) {
 	tok = (GString *)daToks->get(tmPos + 4);
 	tok->clear();
-	tok->appendf("{0:.4f}", x);
+	tok->appendf("{0:.4f}", x + xx);
 	tok = (GString *)daToks->get(tmPos + 5);
 	tok->clear();
-	tok->appendf("{0:.4f}", y);
+	tok->appendf("{0:.4f}", y + yy);
       }
 
       // write the DA string
@@ -1742,29 +2254,35 @@
 
       // write the font matrix (if not part of the DA string)
       if (tmPos < 0) {
-	appearBuf->appendf("1 0 0 1 {0:.4f} {1:.4f} Tm\n", x, y);
+	appearBuf->appendf("1 0 0 1 {0:.4f} {1:.4f} Tm\n", x + xx, y + yy);
       }
 
       // write the text string
-      //~ this should center (instead of left-justify) each character within
-      //~     its comb cell
+      offset = 0;
       for (i = 0; i < text2->getLength(); ++i) {
-	if (i > 0) {
-	  appearBuf->appendf("{0:.4f} 0 Td\n", w);
-	}
-	appearBuf->append('(');
 	c = text2->getChar(i) & 0xff;
-	if (c == '(' || c == ')' || c == '\\') {
-	  appearBuf->append('\\');
-	  appearBuf->append((char)c);
-	} else if (c < 0x20 || c >= 0x80) {
-	  appearBuf->appendf("{0:.4f} 0 Td\n", w);
+	if (c >= 0x20 && c < 0x80) {
+	  if (font && !font->isCIDFont()) {
+	    charWidth = ((Gfx8BitFont *)font)->getWidth((Guchar)c) * fontSize;
+	  } else {
+	    // otherwise, make a crude estimate
+	    charWidth = 0.5 * fontSize;
+	  }
+	  offset2 = 0.5 * (w - charWidth);
+	  appearBuf->appendf("{0:.4f} 0 Td\n", offset + offset2);
+	  if (c == '(' || c == ')' || c == '\\') {
+	    appearBuf->appendf("(\\{0:c}) Tj\n", c);
+	  } else {
+	    appearBuf->appendf("({0:c}) Tj\n", c);
+	  }
+	  offset = w - offset2;
 	} else {
-	  appearBuf->append((char)c);
+	  offset += w;
 	}
-	appearBuf->append(") Tj\n");
       }
 
+      appearBuf->append("ET\n");
+
     // regular (non-comb) formatting
     } else {
 
@@ -1802,25 +2320,54 @@
       switch (quadding) {
       case acroFormQuadLeft:
       default:
-	x = border + 2;
+	xx = border + 2;
 	break;
       case acroFormQuadCenter:
-	x = (dx - w) / 2;
+	xx = (dx - w) / 2;
 	break;
       case acroFormQuadRight:
-	x = dx - border - 2 - w;
+	xx = dx - border - 2 - w;
 	break;
       }
-      y = 0.5 * dy - 0.4 * fontSize;
+      if (font) {
+	ascent = font->getDeclaredAscent() * fontSize;
+	descent = font->getDescent() * fontSize;
+      } else {
+	ascent = 0.75 * fontSize;
+	descent = -0.25 * fontSize;
+      }
+      switch (vAlign) {
+      case acroFormVAlignTop:
+      default:
+	yy = dy - ascent;
+	break;
+      case acroFormVAlignMiddle:
+	yy = 0.5 * (dy - ascent - descent);
+	break;
+      case acroFormVAlignMiddleNoDescender:
+	yy = 0.5 * (dy - ascent);
+	break;
+      case acroFormVAlignBottom:
+	yy = -descent;
+	break;
+      }
 
+      if (whiteBackground) {
+	appearBuf->appendf("q 1 g {0:.4f} {1:.4f} {2:.4f} {3:.4f} re f Q\n",
+			   xx - 0.25 * fontSize, yy - 0.35 * fontSize,
+			   w + 0.5 * fontSize, 1.2 * fontSize);
+      }
+
+      appearBuf->append("BT\n");
+
       // set the font matrix
       if (tmPos >= 0) {
 	tok = (GString *)daToks->get(tmPos + 4);
 	tok->clear();
-	tok->appendf("{0:.4f}", x);
+	tok->appendf("{0:.4f}", x + xx);
 	tok = (GString *)daToks->get(tmPos + 5);
 	tok->clear();
-	tok->appendf("{0:.4f}", y);
+	tok->appendf("{0:.4f}", y + yy);
       }
 
       // write the DA string
@@ -1832,7 +2379,7 @@
 
       // write the font matrix (if not part of the DA string)
       if (tmPos < 0) {
-	appearBuf->appendf("1 0 0 1 {0:.4f} {1:.4f} Tm\n", x, y);
+	appearBuf->appendf("1 0 0 1 {0:.4f} {1:.4f} Tm\n", x + xx, y + yy);
       }
 
       // write the text string
@@ -1850,10 +2397,11 @@
       }
       appearBuf->append(") Tj\n");
     }
+
+    appearBuf->append("ET\n");
   }
 
   // cleanup
-  appearBuf->append("ET\n");
   appearBuf->append("Q\n");
   if (txField) {
     appearBuf->append("EMC\n");
@@ -2197,6 +2745,203 @@
   appearBuf->append("S\n");
 }
 
+void AcroFormField::drawBarcode(GString *value, GString *da,
+				GfxFontDict *fontDict, int rot,
+				double xMin, double yMin,
+				double xMax, double yMax,
+				XFAFieldBarcodeInfo *barcodeInfo,
+				GString *appearBuf) {
+  //--- handle rotation
+  double w, h;
+  appearBuf->append("q\n");
+  switch (rot) {
+  case 0:
+  default:
+    w = xMax - xMin;
+    h = yMax - yMin;
+    break;
+  case 90:
+    appearBuf->appendf("0 1 -1 0 {0:.4f} 0 cm\n", xMax - xMin);
+    w = yMax - yMin;
+    h = xMax - xMin;
+    break;
+  case 180:
+    appearBuf->appendf("0 -1 1 0 0 {0:.4f} cm\n", yMax - yMin);
+    w = yMax - yMin;
+    h = xMax - xMin;
+    break;
+  case 270:
+    appearBuf->appendf("0 -1 1 0 0 {0:.4f} cm\n", yMax - yMin);
+    w = yMax - yMin;
+    h = xMax - xMin;
+    break;
+  }
+
+  //--- get the font size
+  double fontSize = 0.2 * h;
+  if (da) {
+    GList *daToks = tokenize(da);
+    for (int i = 2; i < daToks->getLength(); ++i) {
+      if (!((GString *)daToks->get(i))->cmp("Tf")) {
+	fontSize = atof(((GString *)daToks->get(i - 1))->getCString());
+	break;
+      }
+    }
+    deleteGList(daToks, GString);
+  }
+
+  //--- compute the embedded text type position
+  GBool doText = gTrue;
+  double yText = 0;
+  int vAlign = acroFormVAlignTop;
+  double yBarcode = 0;
+  double hBarcode = 0;
+  GBool whiteBackground = gFalse;
+  //~ this uses an estimate of the font baseline position
+  if (barcodeInfo->textLocation &&
+      !barcodeInfo->textLocation->cmp("above")) {
+    yText = h;
+    vAlign = acroFormVAlignTop;
+    yBarcode = 0;
+    hBarcode = h - fontSize;
+  } else if (barcodeInfo->textLocation &&
+	     !barcodeInfo->textLocation->cmp("belowEmbedded")) {
+    yText = 0;
+    vAlign = acroFormVAlignBottom;
+    yBarcode = 0;
+    hBarcode = h;
+    whiteBackground = gTrue;
+  } else if (barcodeInfo->textLocation &&
+	     !barcodeInfo->textLocation->cmp("aboveEmbedded")) {
+    yText = h;
+    vAlign = acroFormVAlignTop;
+    yBarcode = 0;
+    hBarcode = h;
+    whiteBackground = gTrue;
+  } else if (barcodeInfo->textLocation &&
+	     !barcodeInfo->textLocation->cmp("none")) {
+    doText = gFalse;
+  } else { // default is "below"
+    yText = 0;
+    vAlign = acroFormVAlignBottom;
+    yBarcode = fontSize;
+    hBarcode = h - fontSize;
+  }
+  double wText = w;
+
+  //--- remove extraneous start/stop chars
+  GString *value2 = value->copy();
+  if (!barcodeInfo->barcodeType->cmp("code3Of9")) {
+    if (value2->getLength() >= 1 && value2->getChar(0) == '*') {
+      value2->del(0);
+    }
+    if (value2->getLength() >= 1 &&
+	value2->getChar(value2->getLength() - 1) == '*') {
+      value2->del(value2->getLength() - 1);
+    }
+  }
+
+  //--- draw the bar code
+  if (!barcodeInfo->barcodeType->cmp("code3Of9")) {
+    if (!barcodeInfo->dataLength) {
+      error(errSyntaxError, -1,
+	    "Missing 'dataLength' attribute in barcode field");
+      goto err;
+    }
+    appearBuf->append("0 g\n");
+    double wNarrow = w / ((7 + 3 * barcodeInfo->wideNarrowRatio)
+			  * (barcodeInfo->dataLength + 2));
+    double xx = 0;
+    for (int i = -1; i <= value2->getLength(); ++i) {
+      int c;
+      if (i < 0 || i >= value2->getLength()) {
+	c = '*';
+      } else {
+	c = value2->getChar(i) & 0x7f;
+      }
+      for (int j = 0; j < 10; j += 2) {
+	appearBuf->appendf("{0:.4f} {1:.4f} {2:.4f} {3:.4f} re f\n",
+			   xx, yBarcode,
+			   (code3Of9Data[c][j] ? barcodeInfo->wideNarrowRatio
+			                       : 1) * wNarrow,
+			   hBarcode);
+	xx += ((code3Of9Data[c][j] ? barcodeInfo->wideNarrowRatio : 1) +
+	       (code3Of9Data[c][j+1] ? barcodeInfo->wideNarrowRatio : 1))
+	      * wNarrow;
+      }
+    }
+    // center the text on the drawn barcode (not the max length barcode)
+    wText = (value2->getLength() + 2) * (7 + 3 * barcodeInfo->wideNarrowRatio)
+            * wNarrow;
+  } else if (!barcodeInfo->barcodeType->cmp("code128B")) {
+    if (!barcodeInfo->dataLength) {
+      error(errSyntaxError, -1,
+	    "Missing 'dataLength' attribute in barcode field");
+      goto err;
+    }
+    appearBuf->append("0 g\n");
+    double wNarrow = w / (11 * (barcodeInfo->dataLength + 3) + 2);
+    double xx = 0;
+    int checksum = 0;
+    for (int i = -1; i <= value2->getLength() + 1; ++i) {
+      int c;
+      if (i == -1) {
+	// start code B
+	c = 104;
+	checksum += c;
+      } else if (i == value2->getLength()) {
+	// checksum
+	c = checksum % 103;
+      } else if (i == value2->getLength() + 1) {
+	// stop code
+	c = 106;
+      } else {
+	c = value2->getChar(i) & 0xff;
+	if (c >= 32 && c <= 127) {
+	  c -= 32;
+	} else {
+	  c = 0;
+	}	  
+	checksum += (i + 1) * c;
+      }
+      for (int j = 0; j < 6; j += 2) {
+	appearBuf->appendf("{0:.4f} {1:.4f} {2:.4f} {3:.4f} re f\n",
+			   xx, yBarcode,
+			   code128Data[c][j] * wNarrow, hBarcode);
+	xx += (code128Data[c][j] + code128Data[c][j+1]) * wNarrow;
+      }
+    }
+    // final bar of the stop code
+    appearBuf->appendf("{0:.4f} {1:.4f} {2:.4f} {3:.4f} re f\n",
+		       xx, yBarcode, 2 * wNarrow, hBarcode);
+    // center the text on the drawn barcode (not the max length barcode)
+    wText = (11 * (value2->getLength() + 3) + 2) * wNarrow;
+  } else if (!barcodeInfo->barcodeType->cmp("pdf417")) {
+    drawPDF417Barcode(w, h, barcodeInfo->moduleWidth,
+		      barcodeInfo->moduleHeight,
+		      barcodeInfo->errorCorrectionLevel,
+		      value2, appearBuf);
+    doText = gFalse;
+  } else {
+    error(errSyntaxError, -1,
+	  "Unimplemented barcode type '{0:t}' in barcode field",
+	  barcodeInfo->barcodeType);
+  }
+  //~ add other barcode types here
+
+  //--- draw the embedded text
+  if (doText) {
+    drawText(value2, da, fontDict, gFalse, 0, acroFormQuadCenter,
+	     vAlign, gFalse, gFalse, 0, 0, yText, wText, yText + fontSize,
+	     0, whiteBackground, appearBuf);
+  }
+
+  appearBuf->append("Q\n");
+
+ err:
+  delete value2;
+}
+
 GList *AcroFormField::tokenize(GString *s) {
   GList *toks;
   int i, j;
@@ -2373,19 +3118,769 @@
 }
 
 Object *AcroFormField::fieldLookup(Dict *dict, const char *key, Object *obj) {
-  Object parent;
+  Object parent, parent2;
+  int depth;
 
   if (!dict->lookup(key, obj)->isNull()) {
     return obj;
   }
   obj->free();
-  if (dict->lookup("Parent", &parent)->isDict()) {
-    fieldLookup(parent.getDict(), key, obj);
-  } else {
-    // some fields don't specify a parent, so we check the AcroForm
-    // dictionary just in case
-    acroForm->acroFormObj.dictLookup(key, obj);
+
+  dict->lookup("Parent", &parent)->isDict();
+  depth = 0;
+  while (parent.isDict() && depth < maxFieldObjectDepth) {
+    if (!parent.dictLookup(key, obj)->isNull()) {
+      parent.free();
+      return obj;
+    }
+    obj->free();
+    parent.dictLookup("Parent", &parent2);
+    parent.free();
+    parent = parent2;
+    ++depth;
   }
   parent.free();
+
+  // some fields don't specify a parent, so we check the AcroForm
+  // dictionary just in case
+  acroForm->acroFormObj.dictLookup(key, obj);
   return obj;
 }
+
+Unicode *AcroFormField::utf8ToUnicode(GString *s, int *unicodeLength) {
+  int n = 0;
+  int i = 0;
+  Unicode u;
+  while (getUTF8(s, &i, &u)) {
+    ++n;
+  }
+  Unicode *uVec = (Unicode *)gmallocn(n, sizeof(Unicode));
+  n = 0;
+  i = 0;
+  while (getUTF8(s, &i, &uVec[n])) {
+    ++n;
+  }
+  *unicodeLength = n;
+  return uVec;
+}
+
+GString *AcroFormField::unicodeToLatin1(Unicode *u, int unicodeLength) {
+  GString *s = new GString();
+  for (int i = 0; i < unicodeLength; ++i) {
+    if (u[i] <= 0xff) {
+      s->append((char)u[i]);
+    }
+  }
+  return s;
+}
+
+GBool AcroFormField::unicodeStringEqual(Unicode *u, int unicodeLength,
+					GString *s) {
+  if (s->getLength() != unicodeLength) {
+    return gFalse;
+  }
+  for (int i = 0; i < unicodeLength; ++i) {
+    if ((s->getChar(i) & 0xff) != u[i]) {
+      return gFalse;
+    }
+  }
+  return gTrue;
+}
+
+GBool AcroFormField::unicodeStringEqual(Unicode *u, int unicodeLength,
+					const char *s) {
+  for (int i = 0; i < unicodeLength; ++i) {
+    if (!s[i] || (s[i] & 0xff) != u[i]) {
+      return gFalse;
+    }
+  }
+  return gTrue;
+}
+
+//------------------------------------------------------------------------
+// 'picture' formatting
+//------------------------------------------------------------------------
+
+class PictureNode {
+public:
+  virtual ~PictureNode() {}
+  virtual GBool isLiteral() { return gFalse; }
+  virtual GBool isSign() { return gFalse; }
+  virtual GBool isDigit() { return gFalse; }
+  virtual GBool isDecPt() { return gFalse; }
+  virtual GBool isSeparator() { return gFalse; }
+  virtual GBool isYear() { return gFalse; }
+  virtual GBool isMonth() { return gFalse; }
+  virtual GBool isDay() { return gFalse; }
+  virtual GBool isHour() { return gFalse; }
+  virtual GBool isMinute() { return gFalse; }
+  virtual GBool isSecond() { return gFalse; }
+  virtual GBool isChar() { return gFalse; }
+};
+
+class PictureLiteral: public PictureNode {
+public:
+  PictureLiteral(GString *sA) { s = sA; }
+  virtual ~PictureLiteral() { delete s; }
+  virtual GBool isLiteral() { return gTrue; }
+  GString *s;
+};
+
+class PictureSign: public PictureNode {
+public:
+  PictureSign(char cA) { c = cA; }
+  virtual GBool isSign() { return gTrue; }
+  char c;
+};
+
+class PictureDigit: public PictureNode {
+public:
+  PictureDigit(char cA) { c = cA; pos = 0; }
+  virtual GBool isDigit() { return gTrue; }
+  char c;
+  int pos;
+};
+
+class PictureDecPt: public PictureNode {
+public:
+  PictureDecPt() { }
+  virtual GBool isDecPt() { return gTrue; }
+};
+
+class PictureSeparator: public PictureNode {
+public:
+  PictureSeparator() { }
+  virtual GBool isSeparator() { return gTrue; }
+};
+
+class PictureYear: public PictureNode {
+public:
+  PictureYear(int nDigitsA) { nDigits = nDigitsA; }
+  virtual GBool isYear() { return gTrue; }
+  int nDigits;
+};
+
+class PictureMonth: public PictureNode {
+public:
+  PictureMonth(int nDigitsA) { nDigits = nDigitsA; }
+  virtual GBool isMonth() { return gTrue; }
+  int nDigits;
+};
+
+class PictureDay: public PictureNode {
+public:
+  PictureDay(int nDigitsA) { nDigits = nDigitsA; }
+  virtual GBool isDay() { return gTrue; }
+  int nDigits;
+};
+
+class PictureHour: public PictureNode {
+public:
+  PictureHour(GBool is24HourA, int nDigitsA)
+    { is24Hour = is24HourA; nDigits = nDigitsA; }
+  virtual GBool isHour() { return gTrue; }
+  GBool is24Hour;
+  int nDigits;
+};
+
+class PictureMinute: public PictureNode {
+public:
+  PictureMinute(int nDigitsA) { nDigits = nDigitsA; }
+  virtual GBool isMinute() { return gTrue; }
+  int nDigits;
+};
+
+class PictureSecond: public PictureNode {
+public:
+  PictureSecond(int nDigitsA) { nDigits = nDigitsA; }
+  virtual GBool isSecond() { return gTrue; }
+  int nDigits;
+};
+
+class PictureChar: public PictureNode {
+public:
+  PictureChar() {}
+  virtual GBool isChar() { return gTrue; }
+};
+
+GString *AcroFormField::pictureFormatDateTime(GString *value,
+					      GString *picture) {
+  GList *pic;
+  PictureNode *node;
+  GString *ret, *s;
+  char c;
+  int year, month, day, hour, min, sec;
+  int len, picStart, picEnd, u, n, i, j;
+
+  len = value->getLength();
+  if (len == 0) {
+    return value->copy();
+  }
+
+  //--- parse the value
+
+  // expected format is yyyy(-mm(-dd)?)?Thh(:mm(:ss)?)?
+  // where:
+  // - the '-'s and ':'s are optional
+  // - the 'T' is literal
+  // - we're ignoring optional time zone info at the end
+  // (if the value is not in this canonical format, we just punt and
+  // return the value string)
+  //~ another option would be to parse the value following the
+  //~   <ui><picture> element
+  year = month = day = hour = min = sec = 0;
+  i = 0;
+  if (!(i + 4 <= len && isValidInt(value, i, 4))) {
+    return value->copy();
+  }
+  year = convertInt(value, i, 4);
+  i += 4;
+  if (i < len && value->getChar(i) == '-') {
+    ++i;
+  }
+  if (i + 2 <= len && isValidInt(value, i, 2)) {
+    month = convertInt(value, i, 2);
+    i += 2;
+    if (i < len && value->getChar(i) == '-') {
+      ++i;
+    }
+    if (i + 2 <= len && isValidInt(value, i, 2)) {
+      day = convertInt(value, i, 2);
+      i += 2;
+    }
+  }
+  if (i < len) {
+    if (value->getChar(i) != 'T') {
+      return value->copy();
+    }
+    ++i;
+    if (!(i + 2 <= len && isValidInt(value, i, 2))) {
+      return value->copy();
+    }
+    hour = convertInt(value, i, 2);
+    i += 2;
+    if (i < len && value->getChar(i) == ':') {
+      ++i;
+    }
+    if (i + 2 <= len && isValidInt(value, i, 2)) {
+      min = convertInt(value, i, 2);
+      i += 2;
+      if (i < len && value->getChar(i) == ':') {
+	++i;
+      }
+      if (i + 2 <= len && isValidInt(value, i, 2)) {
+	sec = convertInt(value, i, 2);
+	i += 2;
+      }
+    }
+  }
+  if (i < len) {
+    return value->copy();
+  }
+
+  //--- skip the category and locale in the picture
+
+  picStart = 0;
+  picEnd = picture->getLength();
+  for (i = 0; i < picture->getLength(); ++i) {
+    c = picture->getChar(i);
+    if (c == '{') {
+      picStart = i + 1;
+      for (picEnd = picStart;
+	   picEnd < picture->getLength() && picture->getChar(picEnd) != '}';
+	   ++picEnd) ;
+      break;
+    } else if (!((c >= 'a' && c <= 'z') ||
+		 (c >= 'A' && c <= 'Z') ||
+		 c == '(' ||
+		 c == ')')) {
+      break;
+    }
+  }
+
+  //--- parse the picture
+
+  pic = new GList();
+  i = picStart;
+  while (i < picEnd) {
+    c = picture->getChar(i);
+    ++i;
+    if (c == '\'') {
+      s = new GString();
+      while (i < picEnd) {
+	c = picture->getChar(i);
+	if (c == '\'') {
+	  ++i;
+	  if (i < picEnd && picture->getChar(i) == '\'') {
+	    s->append('\'');
+	    ++i;
+	  } else {
+	    break;
+	  }
+	} else if (c == '\\') {
+	  ++i;
+	  if (i == picEnd) {
+	    break;
+	  }
+	  c = picture->getChar(i);
+	  ++i;
+	  if (c == 'u' && i+4 <= picEnd) {
+	    u = 0;
+	    for (j = 0; j < 4; ++j, ++i) {
+	      c = picture->getChar(i);
+	      u <<= 4;
+	      if (c >= '0' && c <= '9') {
+		u += c - '0';
+	      } else if (c >= 'a' && c <= 'f') {
+		u += c - 'a' + 10;
+	      } else if (c >= 'A' && c <= 'F') {
+		u += c - 'A' + 10;
+	      }
+	    }
+	    //~ this should convert to UTF-8 (?)
+	    if (u <= 0xff) {
+	      s->append((char)u);
+	    }
+	  } else {
+	    s->append(c);
+	  }
+	} else {
+	  s->append(c);
+	}
+      }
+      pic->append(new PictureLiteral(s));
+    } else if (c == ',' || c == '-' || c == ':' ||
+	       c == '/' || c == '.' || c == ' ') {
+      s = new GString();
+      s->append(c);
+      pic->append(new PictureLiteral(s));
+    } else if (c == 'Y') {
+      for (n = 1; n < 4 && i < picEnd && picture->getChar(i) == 'Y'; ++n, ++i) ;
+      pic->append(new PictureYear(n));
+    } else if (c == 'M') {
+      for (n = 1; n < 2 && i < picEnd && picture->getChar(i) == 'M'; ++n, ++i) ;
+      pic->append(new PictureMonth(n));
+    } else if (c == 'D') {
+      for (n = 1; n < 2 && i < picEnd && picture->getChar(i) == 'D'; ++n, ++i) ;
+      pic->append(new PictureDay(n));
+    } else if (c == 'h') {
+      for (n = 1; n < 2 && i < picEnd && picture->getChar(i) == 'h'; ++n, ++i) ;
+      pic->append(new PictureHour(gFalse, n));
+    } else if (c == 'H') {
+      for (n = 1; n < 2 && i < picEnd && picture->getChar(i) == 'H'; ++n, ++i) ;
+      pic->append(new PictureHour(gTrue, n));
+    } else if (c == 'M') {
+      for (n = 1; n < 2 && i < picEnd && picture->getChar(i) == 'M'; ++n, ++i) ;
+      pic->append(new PictureMinute(n));
+    } else if (c == 'S') {
+      for (n = 1; n < 2 && i < picEnd && picture->getChar(i) == 'S'; ++n, ++i) ;
+      pic->append(new PictureSecond(n));
+    }
+  }
+
+  //--- generate formatted text
+
+  ret = new GString();
+  for (i = 0; i < pic->getLength(); ++i) {
+    node = (PictureNode *)pic->get(i);
+    if (node->isLiteral()) {
+      ret->append(((PictureLiteral *)node)->s);
+    } else if (node->isYear()) {
+      if (((PictureYear *)node)->nDigits == 2) {
+	if (year >= 1930 && year < 2030) {
+	  ret->appendf("{0:02d}", year % 100);
+	} else {
+	  ret->append("??");
+	}
+      } else {
+	ret->appendf("{0:04d}", year);
+      }
+    } else if (node->isMonth()) {
+      if (((PictureMonth *)node)->nDigits == 1) {
+	ret->appendf("{0:d}", month);
+      } else {
+	ret->appendf("{0:02d}", month);
+      }
+    } else if (node->isDay()) {
+      if (((PictureDay *)node)->nDigits == 1) {
+	ret->appendf("{0:d}", day);
+      } else {
+	ret->appendf("{0:02d}", day);
+      }
+    } else if (node->isHour()) {
+      if (((PictureHour *)node)->is24Hour) {
+	n = hour;
+      } else {
+	n = hour % 12;
+	if (n == 0) {
+	  n = 12;
+	}
+      }
+      if (((PictureHour *)node)->nDigits == 1) {
+	ret->appendf("{0:d}", n);
+      } else {
+	ret->appendf("{0:02d}", n);
+      }
+    } else if (node->isMinute()) {
+      if (((PictureMinute *)node)->nDigits == 1) {
+	ret->appendf("{0:d}", min);
+      } else {
+	ret->appendf("{0:02d}", min);
+      }
+    } else if (node->isSecond()) {
+      if (((PictureSecond *)node)->nDigits == 1) {
+	ret->appendf("{0:d}", sec);
+      } else {
+	ret->appendf("{0:02d}", sec);
+      }
+    }
+  }
+  deleteGList(pic, PictureNode);
+
+  return ret;
+}
+
+GString *AcroFormField::pictureFormatNumber(GString *value, GString *picture) {
+  GList *pic;
+  PictureNode *node;
+  GString *ret, *s;
+  GBool neg, haveDigits;
+  char c;
+  int start, decPt, trailingZero, len;
+  int picStart, picEnd, u, pos, i, j;
+
+  len = value->getLength();
+  if (len == 0) {
+    return value->copy();
+  }
+
+  //--- parse the value
+
+  // -nnnn.nnnn0000
+  //  ^   ^    ^   ^
+  //  |   |    |   +-- len
+  //  |   |    +------ trailingZero
+  //  |   +----------- decPt
+  //  +--------------- start
+  start = 0;
+  neg = gFalse;
+  if (value->getChar(start) == '-') {
+    neg = gTrue;
+    ++start;
+  } else if (value->getChar(start) == '+') {
+    ++start;
+  }
+  for (decPt = start; decPt < len && value->getChar(decPt) != '.'; ++decPt) ;
+  for (trailingZero = len;
+       trailingZero > decPt && value->getChar(trailingZero - 1) == '0';
+       --trailingZero) ;
+
+  //--- skip the category and locale in the picture
+
+  picStart = 0;
+  picEnd = picture->getLength();
+  for (i = 0; i < picture->getLength(); ++i) {
+    c = picture->getChar(i);
+    if (c == '{') {
+      picStart = i + 1;
+      for (picEnd = picStart;
+	   picEnd < picture->getLength() && picture->getChar(picEnd) != '}';
+	   ++picEnd) ;
+      break;
+    } else if (!((c >= 'a' && c <= 'z') ||
+		 (c >= 'A' && c <= 'Z') ||
+		 c == '(' ||
+		 c == ')')) {
+      break;
+    }
+  }
+
+  //--- parse the picture
+
+  pic = new GList();
+  i = picStart;
+  while (i < picEnd) {
+    c = picture->getChar(i);
+    ++i;
+    if (c == '\'') {
+      s = new GString();
+      while (i < picEnd) {
+	c = picture->getChar(i);
+	if (c == '\'') {
+	  ++i;
+	  if (i < picEnd && picture->getChar(i) == '\'') {
+	    s->append('\'');
+	    ++i;
+	  } else {
+	    break;
+	  }
+	} else if (c == '\\') {
+	  ++i;
+	  if (i == picEnd) {
+	    break;
+	  }
+	  c = picture->getChar(i);
+	  ++i;
+	  if (c == 'u' && i+4 <= picEnd) {
+	    u = 0;
+	    for (j = 0; j < 4; ++j, ++i) {
+	      c = picture->getChar(i);
+	      u <<= 4;
+	      if (c >= '0' && c <= '9') {
+		u += c - '0';
+	      } else if (c >= 'a' && c <= 'F') {
+		u += c - 'a' + 10;
+	      } else if (c >= 'A' && c <= 'F') {
+		u += c - 'A' + 10;
+	      }
+	    }
+	    //~ this should convert to UTF-8 (?)
+	    if (u <= 0xff) {
+	      s->append((char)u);
+	    }
+	  } else {
+	    s->append(c);
+	  }
+	} else {
+	  s->append(c);
+	  ++i;
+	}
+      }
+      pic->append(new PictureLiteral(s));
+    } else if (c == '-' || c == ':' || c == '/' || c == ' ') {
+      s = new GString();
+      s->append(c);
+      pic->append(new PictureLiteral(s));
+    } else if (c == 's' || c == 'S') {
+      pic->append(new PictureSign(c));
+    } else if (c == 'Z' || c == 'z' || c == '8' || c == '9') {
+      pic->append(new PictureDigit(c));
+    } else if (c == '.') {
+      pic->append(new PictureDecPt());
+    } else if (c == ',') {
+      pic->append(new PictureSeparator());
+    }
+  }
+  for (i = 0; i < pic->getLength(); ++i) {
+    node = (PictureNode *)pic->get(i);
+    if (node->isDecPt()) {
+      break;
+    }
+  }
+  pos = 0;
+  for (j = i - 1; j >= 0; --j) {
+    node = (PictureNode *)pic->get(j);
+    if (node->isDigit()) {
+      ((PictureDigit *)node)->pos = pos;
+      ++pos;
+    }
+  }
+  pos = -1;
+  for (j = i + 1; j < pic->getLength(); ++j) {
+    node = (PictureNode *)pic->get(j);
+    if (node->isDigit()) {
+      ((PictureDigit *)node)->pos = pos;
+      --pos;
+    }
+  }
+
+  //--- generate formatted text
+
+  ret = new GString();
+  haveDigits = gFalse;
+  for (i = 0; i < pic->getLength(); ++i) {
+    node = (PictureNode *)pic->get(i);
+    if (node->isLiteral()) {
+      ret->append(((PictureLiteral *)node)->s);
+    } else if (node->isSign()) {
+      if (((PictureSign *)node)->c == 'S') {
+	ret->append(neg ? '-' : ' ');
+      } else {
+	if (neg) {
+	  ret->append('-');
+	}
+      }
+    } else if (node->isDigit()) {
+      pos = ((PictureDigit *)node)->pos;
+      c = ((PictureDigit *)node)->c;
+      if (pos >= 0 && pos < decPt - start) {
+	ret->append(value->getChar(decPt - 1 - pos));
+	haveDigits = gTrue;
+      } else if (pos < 0 && -pos <= trailingZero - decPt - 1) {
+	ret->append(value->getChar(decPt - pos));
+	haveDigits = gTrue;
+      } else if (c == '8' &&
+		 pos < 0 &&
+		 -pos <= len - decPt - 1) {
+	ret->append('0');
+	haveDigits = gTrue;
+      } else if (c == '9') {
+	ret->append('0');
+	haveDigits = gTrue;
+      } else if (c == 'Z' && pos >= 0) {
+	ret->append(' ');
+      }
+    } else if (node->isDecPt()) {
+      if (!(i+1 < pic->getLength() &&
+	    ((PictureNode *)pic->get(i+1))->isDigit() &&
+	    ((PictureDigit *)pic->get(i+1))->c == 'z') ||
+	  trailingZero > decPt + 1) {
+	ret->append('.');
+      }
+    } else if (node->isSeparator()) {
+      if (haveDigits) {
+	ret->append(',');
+      }
+    }
+  }
+  deleteGList(pic, PictureNode);
+
+  return ret;
+}
+
+GString *AcroFormField::pictureFormatText(GString *value, GString *picture) {
+  GList *pic;
+  PictureNode *node;
+  GString *ret, *s;
+  char c;
+  int len, picStart, picEnd, u, i, j;
+
+  len = value->getLength();
+  if (len == 0) {
+    return value->copy();
+  }
+
+  //--- skip the category and locale in the picture
+
+  picStart = 0;
+  picEnd = picture->getLength();
+  for (i = 0; i < picture->getLength(); ++i) {
+    c = picture->getChar(i);
+    if (c == '{') {
+      picStart = i + 1;
+      for (picEnd = picStart;
+	   picEnd < picture->getLength() && picture->getChar(picEnd) != '}';
+	   ++picEnd) ;
+      break;
+    } else if (!((c >= 'a' && c <= 'z') ||
+		 (c >= 'A' && c <= 'Z') ||
+		 c == '(' ||
+		 c == ')')) {
+      break;
+    }
+  }
+
+  //--- parse the picture
+
+  pic = new GList();
+  i = picStart;
+  while (i < picEnd) {
+    c = picture->getChar(i);
+    ++i;
+    if (c == '\'') {
+      s = new GString();
+      while (i < picEnd) {
+	c = picture->getChar(i);
+	if (c == '\'') {
+	  ++i;
+	  if (i < picEnd && picture->getChar(i) == '\'') {
+	    s->append('\'');
+	    ++i;
+	  } else {
+	    break;
+	  }
+	} else if (c == '\\') {
+	  ++i;
+	  if (i == picEnd) {
+	    break;
+	  }
+	  c = picture->getChar(i);
+	  ++i;
+	  if (c == 'u' && i+4 <= picEnd) {
+	    u = 0;
+	    for (j = 0; j < 4; ++j, ++i) {
+	      c = picture->getChar(i);
+	      u <<= 4;
+	      if (c >= '0' && c <= '9') {
+		u += c - '0';
+	      } else if (c >= 'a' && c <= 'F') {
+		u += c - 'a' + 10;
+	      } else if (c >= 'A' && c <= 'F') {
+		u += c - 'A' + 10;
+	      }
+	    }
+	    //~ this should convert to UTF-8 (?)
+	    if (u <= 0xff) {
+	      s->append((char)u);
+	    }
+	  } else {
+	    s->append(c);
+	  }
+	} else {
+	  s->append(c);
+	  ++i;
+	}
+      }
+      pic->append(new PictureLiteral(s));
+    } else if (c == ',' || c == '-' || c == ':' ||
+	       c == '/' || c == '.' || c == ' ') {
+      s = new GString();
+      s->append(c);
+      pic->append(new PictureLiteral(s));
+    } else if (c == 'A' || c == 'X' || c == 'O' || c == '0' || c == '9') {
+      pic->append(new PictureChar());
+    }
+  }
+
+  //--- generate formatted text
+
+  ret = new GString();
+  j = 0;
+  for (i = 0; i < pic->getLength(); ++i) {
+    node = (PictureNode *)pic->get(i);
+    if (node->isLiteral()) {
+      ret->append(((PictureLiteral *)node)->s);
+    } else if (node->isChar()) {
+      // if there are more chars in the picture than in the value,
+      // Adobe renders the value as-is, without picture formatting
+      if (j >= value->getLength()) {
+	delete ret;
+	ret = value->copy();
+	break;
+      }
+      ret->append(value->getChar(j));
+      ++j;
+    }
+  }
+  deleteGList(pic, PictureNode);
+
+  return ret;
+}
+
+GBool AcroFormField::isValidInt(GString *s, int start, int len) {
+  int i;
+
+  for (i = 0; i < len; ++i) {
+    if (!(start + i < s->getLength() &&
+	  s->getChar(start + i) >= '0' &&
+	  s->getChar(start + i) <= '9')) {
+      return gFalse;
+    }
+  }
+  return gTrue;
+}
+
+int AcroFormField::convertInt(GString *s, int start, int len) {
+  char c;
+  int x, i;
+
+  x = 0;
+  for (i = 0; i < len && start + i < s->getLength(); ++i) {
+    c = s->getChar(start + i);
+    if (c < '0' || c > '9') {
+      break;
+    }
+    x = x * 10 + (c - '0');
+  }
+  return x;
+}

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/AcroForm.h
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/AcroForm.h	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/AcroForm.h	2021-02-15 19:17:20 UTC (rev 845)
@@ -15,27 +15,32 @@
 #pragma interface
 #endif
 
-#include "Form.h"
-
 class TextString;
+class Gfx;
 class GfxFont;
 class GfxFontDict;
+class AcroFormField;
+class XFAScanner;
+class XFAField;
+class XFAFieldBarcodeInfo;
 
 //------------------------------------------------------------------------
 
-class AcroForm: public Form {
+class AcroForm {
 public:
 
   static AcroForm *load(PDFDoc *docA, Catalog *catalog, Object *acroFormObjA);
 
-  virtual ~AcroForm();
+  ~AcroForm();
 
-  virtual const char *getType() { return "AcroForm"; }
+  const char *getType();
 
-  virtual void draw(int pageNum, Gfx *gfx, GBool printing);
+  void draw(int pageNum, Gfx *gfx, GBool printing);
 
-  virtual int getNumFields();
-  virtual FormField *getField(int idx);
+  int getNumFields();
+  AcroFormField *getField(int idx);
+  AcroFormField *findField(int pg, double x, double y);
+  int findFieldIdx(int pg, double x, double y);
 
 private:
 
@@ -44,10 +49,13 @@
   int lookupAnnotPage(Object *annotRef);
   void scanField(Object *fieldRef);
 
+  PDFDoc *doc;
   Object acroFormObj;
   GBool needAppearances;
   GList *annotPages;		// [AcroFormAnnotPage]
   GList *fields;		// [AcroFormField]
+  XFAScanner *xfaScanner;
+  GBool isStaticXFA;
 
   friend class AcroFormField;
 };
@@ -61,28 +69,29 @@
   acroFormFieldFileSelect,
   acroFormFieldMultilineText,
   acroFormFieldText,
+  acroFormFieldBarcode,
   acroFormFieldComboBox,
   acroFormFieldListBox,
   acroFormFieldSignature
 };
 
-class AcroFormField: public FormField {
+class AcroFormField {
 public:
 
   static AcroFormField *load(AcroForm *acroFormA, Object *fieldRefA);
 
-  virtual ~AcroFormField();
+  ~AcroFormField();
 
-  virtual int getPageNum();
-  virtual const char *getType();
-  virtual Unicode *getName(int *length);
-  virtual Unicode *getValue(int *length);
-  virtual void getBBox(double *llx, double *lly, double *urx, double *ury);
-  virtual void getFont(Ref *fontID, double *fontSize);
-  virtual void getColor(double *red, double *green, double *blue);
+  int getPageNum();
+  const char *getType();
+  Unicode *getName(int *length);
+  Unicode *getValue(int *length);
+  void getBBox(double *llx, double *lly, double *urx, double *ury);
+  void getFont(Ref *fontID, double *fontSize);
+  void getColor(double *red, double *green, double *blue);
   int getMaxLen();
 
-  virtual Object *getResources(Object *res);
+  Object *getResources(Object *res);
 
   AcroFormFieldType getAcroFormFieldType() { return type; }
   Object *getFieldRef(Object *ref);
@@ -94,7 +103,7 @@
 
   AcroFormField(AcroForm *acroFormA, Object *fieldRefA, Object *fieldObjA,
 		AcroFormFieldType typeA, TextString *nameA,
-		Guint flagsA, GBool typeFromParentA);
+		Guint flagsA, GBool typeFromParentA, XFAField *xfaFieldA);
   Ref findFontName(char *fontTag);
   void draw(int pageNum, Gfx *gfx, GBool printing);
   void drawAnnot(int pageNum, Gfx *gfx, GBool printing,
@@ -107,10 +116,10 @@
 			 double xMax, double yMax);
   void setColor(Array *a, GBool fill, int adjust, GString *appearBuf);
   void drawText(GString *text, GString *da, GfxFontDict *fontDict,
-		GBool multiline, int comb, int quadding,
+		GBool multiline, int comb, int quadding, int vAlign,
 		GBool txField, GBool forceZapfDingbats, int rot,
-		double xMin, double yMin, double xMax, double yMax,
-		double border, GString *appearBuf);
+		double x, double y, double width, double height,
+		double border, GBool whiteBackground, GString *appearBuf);
   void drawListBox(GString **text, GBool *selection,
 		   int nOptions, int topIdx,
 		   GString *da, GfxFontDict *fontDict,
@@ -126,6 +135,9 @@
 			 GString *appearBuf);
   void drawCircleBottomRight(double cx, double cy, double r,
 			     GString *appearBuf);
+  void drawBarcode(GString *value, GString *da, GfxFontDict *fontDict, int rot,
+		   double xMin, double yMin, double xMax, double yMax,
+		   XFAFieldBarcodeInfo *barcodeInfo, GString *appearBuf);
   GList *tokenize(GString *s);
   Object *getAnnotObj(Object *annotObj);
   Object *getAnnotResources(Dict *annot, Object *res);
@@ -132,6 +144,15 @@
   void buildDefaultResourceDict(Object *dr);
   Object *fieldLookup(const char *key, Object *obj);
   Object *fieldLookup(Dict *dict, const char *key, Object *obj);
+  Unicode *utf8ToUnicode(GString *s, int *unicodeLength);
+  GString *unicodeToLatin1(Unicode *u, int unicodeLength);
+  GBool unicodeStringEqual(Unicode *u, int unicodeLength, GString *s);
+  GBool unicodeStringEqual(Unicode *u, int unicodeLength, const char *s);
+  GString *pictureFormatDateTime(GString *value, GString *picture);
+  GString *pictureFormatNumber(GString *value, GString *picture);
+  GString *pictureFormatText(GString *value, GString *picture);
+  GBool isValidInt(GString *s, int start, int len);
+  int convertInt(GString *s, int start, int len);
 
   AcroForm *acroForm;
   Object fieldRef;
@@ -140,6 +161,7 @@
   TextString *name;
   Guint flags;
   GBool typeFromParent;
+  XFAField *xfaField;
 
   friend class AcroForm;
 };

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Annot.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Annot.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Annot.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -25,7 +25,7 @@
 #include "Lexer.h"
 #include "PDFDoc.h"
 #include "OptionalContent.h"
-#include "Form.h"
+#include "AcroForm.h"
 #include "BuiltinFontTables.h"
 #include "FontEncodingTables.h"
 #include "Annot.h"

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/CMakeLists.txt
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/CMakeLists.txt	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/CMakeLists.txt	2021-02-15 19:17:20 UTC (rev 845)
@@ -38,7 +38,6 @@
   Dict.cc
   Error.cc
   FontEncodingTables.cc
-  Form.cc
   Function.cc
   Gfx.cc
   GfxFont.cc
@@ -67,7 +66,7 @@
   UnicodeRemapping.cc
   UnicodeTypeTable.cc
   UTF8.cc
-  XFAForm.cc
+  XFAScanner.cc
   XRef.cc
   Zoox.cc
 )
@@ -88,6 +87,7 @@
     PDFCore.cc
     PreScanOutputDev.cc
     PSOutputDev.cc
+    ShadingImage.cc
     SplashOutputDev.cc
     TextOutputDev.cc
     TileCache.cc
@@ -104,6 +104,7 @@
     $<TARGET_OBJECTS:xpdf_objs>
     PreScanOutputDev.cc
     PSOutputDev.cc
+    ShadingImage.cc
     SplashOutputDev.cc
     pdftops.cc
   )
@@ -151,6 +152,7 @@
   add_executable(pdftohtml
     $<TARGET_OBJECTS:xpdf_objs>
     HTMLGen.cc
+    ShadingImage.cc
     SplashOutputDev.cc
     TextOutputDev.cc
     WebFont.cc
@@ -215,6 +217,7 @@
 if (HAVE_SPLASH)
   add_executable(pdftoppm
     $<TARGET_OBJECTS:xpdf_objs>
+    ShadingImage.cc
     SplashOutputDev.cc
     pdftoppm.cc
   )
@@ -234,6 +237,7 @@
 if (HAVE_SPLASH AND PNG_FOUND)
   add_executable(pdftopng
     $<TARGET_OBJECTS:xpdf_objs>
+    ShadingImage.cc
     SplashOutputDev.cc
     pdftopng.cc
   )

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Catalog.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Catalog.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Catalog.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -28,7 +28,7 @@
 #include "Page.h"
 #include "Error.h"
 #include "Link.h"
-#include "Form.h"
+#include "AcroForm.h"
 #include "TextString.h"
 #include "Catalog.h"
 
@@ -159,6 +159,7 @@
   baseURI = NULL;
   form = NULL;
   embeddedFiles = NULL;
+  pageLabels = NULL;
 #if MULTITHREADED
   gInitMutex(&pageMutex);
 #endif
@@ -222,7 +223,7 @@
   catDict.dictLookup("AcroForm", &acroForm);
 
   // get the NeedsRendering flag
-  // NB: Form::load() uses this value
+  // NB: AcroForm::load() uses this value
   needsRendering = catDict.dictLookup("NeedsRendering", &obj)->isBool() &&
                    obj.getBool();
   obj.free();
@@ -230,7 +231,7 @@
   // create the Form
   // (if acroForm is a null object, this will still create an AcroForm
   // if there are unattached Widget-type annots)
-  form = Form::load(doc, this, &acroForm);
+  form = AcroForm::load(doc, this, &acroForm);
 
   // get the OCProperties dictionary
   catDict.dictLookup("OCProperties", &ocProperties);
@@ -241,7 +242,6 @@
   // get the ViewerPreferences object
   catDict.dictLookupNF("ViewerPreferences", &viewerPrefs);
 
-  pageLabels = NULL;
   if (catDict.dictLookup("PageLabels", &obj)->isDict()) {
     readPageLabelTree(&obj);
   }
@@ -1190,7 +1190,7 @@
 	return gFalse;
       }
     }
-    *n = (len - prefixLength - 1) * 26 + (u[i] - (Unicode)style) + 1;
+    *n = (len - prefixLength - 1) * 26 + (u[prefixLength] - (Unicode)style) + 1;
     return gTrue;
   }
   return gFalse;

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Catalog.h
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Catalog.h	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Catalog.h	2021-02-15 19:17:20 UTC (rev 845)
@@ -30,7 +30,7 @@
 class LinkDest;
 class PageTreeNode;
 class PageLabelNode;
-class Form;
+class AcroForm;
 class TextString;
 
 //------------------------------------------------------------------------
@@ -88,7 +88,7 @@
 
   Object *getAcroForm() { return &acroForm; }
 
-  Form *getForm() { return form; }
+  AcroForm *getForm() { return form; }
 
   GBool getNeedsRendering() { return needsRendering; }
 
@@ -137,7 +137,7 @@
   Object outline;		// outline dictionary
   Object acroForm;		// AcroForm dictionary
   GBool needsRendering;		// NeedsRendering flag
-  Form *form;			// parsed form
+  AcroForm *form;		// parsed form
   Object ocProperties;		// OCProperties dictionary
   GList *embeddedFiles;		// embedded file list [EmbeddedFile]
   GList *pageLabels;		// page labels [PageLabelNode]

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/CharCodeToUnicode.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/CharCodeToUnicode.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/CharCodeToUnicode.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -470,8 +470,13 @@
 void CharCodeToUnicode::addMapping(CharCode code, char *uStr, int n,
 				   int offset) {
   CharCode oldLen, i;
+#if 1 //~utf16
+  Unicode u[maxUnicodeString];
+  int uLen, j;
+#else
   Unicode u;
   int j;
+#endif
 
   if (code > 0xffffff) {
     // This is an arbitrary limit to avoid integer overflow issues.
@@ -478,6 +483,11 @@
     // (I've seen CMaps with mappings for <ffffffff>.)
     return;
   }
+#if 1 //~utf16
+  if ((uLen = parseUTF16String(uStr, n, u)) == 0) {
+    return;
+  }
+#endif
   if (code >= mapLen) {
     oldLen = mapLen;
     mapLen = mapLen ? 2 * mapLen : 256;
@@ -489,6 +499,25 @@
       map[i] = 0;
     }
   }
+#if 1 //~utf16
+  if (uLen == 1) {
+    map[code] = u[0] + offset;
+  } else {
+    if (sMapLen >= sMapSize) {
+      sMapSize = sMapSize + 16;
+      sMap = (CharCodeToUnicodeString *)
+	       greallocn(sMap, sMapSize, sizeof(CharCodeToUnicodeString));
+    }
+    map[code] = 0;
+    sMap[sMapLen].c = code;
+    for (j = 0; j < uLen; ++j) {
+      sMap[sMapLen].u[j] = u[j];
+    }
+    sMap[sMapLen].u[uLen - 1] += offset;
+    sMap[sMapLen].len = uLen;
+    ++sMapLen;
+  }
+#else //~utf16
   if (n <= 4) {
     if (!parseHex(uStr, n, &u)) {
       error(errSyntaxWarning, -1, "Illegal entry in ToUnicode CMap");
@@ -515,8 +544,38 @@
     sMap[sMapLen].u[sMap[sMapLen].len - 1] += offset;
     ++sMapLen;
   }
+#endif //~utf16
 }
 
+// Convert a UTF-16BE hex string into a sequence of up to
+// maxUnicodeString Unicode chars.
+int CharCodeToUnicode::parseUTF16String(char *uStr, int n, Unicode *uOut) {
+  int i = 0;
+  int uLen = 0;
+  while (i < n) {
+    Unicode u;
+    int j = n;
+    if (j - i > 4) {
+      j = i + 4;
+    }
+    if (!parseHex(uStr + i, j - i, &u)) {
+      error(errSyntaxWarning, -1, "Illegal entry in ToUnicode CMap");
+      return 0;
+    }
+    // look for a UTF-16 pair
+    if (uLen > 0 && uOut[uLen-1] >= 0xd800 && uOut[uLen-1] <= 0xdbff &&
+	u >= 0xdc00 && u <= 0xdfff) {
+      uOut[uLen-1] = 0x10000 + ((uOut[uLen-1] & 0x03ff) << 10) + (u & 0x03ff);
+    } else {
+      if (uLen < maxUnicodeString) {
+	uOut[uLen++] = u;
+      }
+    }
+    i = j;
+  }
+  return uLen;
+}
+
 void CharCodeToUnicode::addMappingInt(CharCode code, Unicode u) {
   CharCode oldLen, i;
 

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/CharCodeToUnicode.h
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/CharCodeToUnicode.h	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/CharCodeToUnicode.h	2021-02-15 19:17:20 UTC (rev 845)
@@ -80,6 +80,7 @@
 
   GBool parseCMap1(int (*getCharFunc)(void *), void *data, int nBits);
   void addMapping(CharCode code, char *uStr, int n, int offset);
+  int parseUTF16String(char *uStr, int n, Unicode *uOut);
   void addMappingInt(CharCode code, Unicode u);
   CharCodeToUnicode();
   CharCodeToUnicode(GString *tagA);

Deleted: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Form.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Form.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Form.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,99 +0,0 @@
-//========================================================================
-//
-// Form.cc
-//
-// Copyright 2012 Glyph & Cog, LLC
-//
-//========================================================================
-
-#include <aconf.h>
-
-#ifdef USE_GCC_PRAGMAS
-#pragma implementation
-#endif
-
-#include "gmempp.h"
-#include "GlobalParams.h"
-#include "Error.h"
-#include "Object.h"
-#include "PDFDoc.h"
-#include "AcroForm.h"
-#include "XFAForm.h"
-#include "Form.h"
-
-//------------------------------------------------------------------------
-// Form
-//------------------------------------------------------------------------
-
-Form *Form::load(PDFDoc *docA, Catalog *catalog, Object *acroFormObj) {
-  Form *form;
-  Object xfaObj;
-
-  if (acroFormObj->isDict()) {
-    //~ temporary: create an XFAForm only for XFAF, not for dynamic XFA
-    acroFormObj->dictLookup("XFA", &xfaObj);
-    if (globalParams->getEnableXFA() &&
-	!xfaObj.isNull() &&
-	!catalog->getNeedsRendering()) {
-      form = XFAForm::load(docA, catalog, acroFormObj, &xfaObj);
-      xfaObj.free();
-      return form;
-    }
-    xfaObj.free();
-  }
-
-  // if acroFormObj is a null object, this will still create an
-  // AcroForm if there are unattached Widget-type annots
-  return AcroForm::load(docA, catalog, acroFormObj);
-}
-
-Form::Form(PDFDoc *docA) {
-  doc = docA;
-}
-
-Form::~Form() {
-}
-
-FormField *Form::findField(int pg, double x, double y) {
-  FormField *field;
-  double llx, lly, urx, ury;
-  int i;
-
-  for (i = 0; i < getNumFields(); ++i) {
-    field = getField(i);
-    if (field->getPageNum() == pg) {
-      field->getBBox(&llx, &lly, &urx, &ury);
-      if (llx <= x && x <= urx && lly <= y && y <= ury) {
-	return field;
-      }
-    }
-  }
-  return NULL;
-}
-
-int Form::findFieldIdx(int pg, double x, double y) {
-  FormField *field;
-  double llx, lly, urx, ury;
-  int i;
-
-  for (i = 0; i < getNumFields(); ++i) {
-    field = getField(i);
-    if (field->getPageNum() == pg) {
-      field->getBBox(&llx, &lly, &urx, &ury);
-      if (llx <= x && x <= urx && lly <= y && y <= ury) {
-	return i;
-      }
-    }
-  }
-  return -1;
-}
-
-//------------------------------------------------------------------------
-// FormField
-//------------------------------------------------------------------------
-
-FormField::FormField() {
-}
-
-FormField::~FormField() {
-}

Deleted: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Form.h
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Form.h	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Form.h	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,77 +0,0 @@
-//========================================================================
-//
-// Form.h
-//
-// Copyright 2012 Glyph & Cog, LLC
-//
-//========================================================================
-
-#ifndef FORM_H
-#define FORM_H
-
-#include <aconf.h>
-
-#ifdef USE_GCC_PRAGMAS
-#pragma interface
-#endif
-
-#include "gtypes.h"
-
-class Gfx;
-class FormField;
-
-//------------------------------------------------------------------------
-
-class Form {
-public:
-
-  static Form *load(PDFDoc *docA, Catalog *catalog, Object *acroFormObj);
-
-  virtual ~Form();
-
-  virtual const char *getType() = 0;
-
-  virtual void draw(int pageNum, Gfx *gfx, GBool printing) = 0;
-
-  virtual int getNumFields() = 0;
-  virtual FormField *getField(int idx) = 0;
-
-  FormField *findField(int pg, double x, double y);
-  int findFieldIdx(int pg, double x, double y);
-
-protected:
-
-  Form(PDFDoc *docA);
-
-  PDFDoc *doc;
-};
-
-//------------------------------------------------------------------------
-
-class FormField {
-public:
-
-  FormField();
-  virtual ~FormField();
-
-  virtual int getPageNum() = 0;
-  virtual const char *getType() = 0;
-
-  // Return the field name.  This never returns NULL.
-  virtual Unicode *getName(int *length) = 0;
-
-  // Return the field value.  This returns NULL if the field does not
-  // have a value.
-  virtual Unicode *getValue(int *length) = 0;
-
-  virtual void getBBox(double *llx, double *lly, double *urx, double *ury) = 0;
-  virtual void getFont(Ref *fontID, double *fontSize) = 0;
-  virtual void getColor(double *red, double *green, double *blue) = 0;
-
-  // Return the resource dictionaries used to draw this field.  The
-  // returned object must be either a dictionary or an array of
-  // dictonaries.
-  virtual Object *getResources(Object *res) = 0;
-};
-
-#endif

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Gfx.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Gfx.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Gfx.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -21,6 +21,7 @@
 #include "gmempp.h"
 #include "GString.h"
 #include "GList.h"
+#include "Trace.h"
 #include "GlobalParams.h"
 #include "CharTypes.h"
 #include "Object.h"
@@ -146,7 +147,15 @@
           &Gfx::opSetStrokeRGBColor},
   {"S",   0, {tchkNone},
           &Gfx::opStroke},
-  {"SC",  -4, {tchkNum,   tchkNum,    tchkNum,    tchkNum},
+  {"SC",  -4, {tchkNum,   tchkNum,    tchkNum,    tchkNum,
+	       tchkNum,   tchkNum,    tchkNum,    tchkNum,
+	       tchkNum,   tchkNum,    tchkNum,    tchkNum,
+	       tchkNum,   tchkNum,    tchkNum,    tchkNum,
+	       tchkNum,   tchkNum,    tchkNum,    tchkNum,
+	       tchkNum,   tchkNum,    tchkNum,    tchkNum,
+	       tchkNum,   tchkNum,    tchkNum,    tchkNum,
+	       tchkNum,   tchkNum,    tchkNum,    tchkNum,
+	       tchkNum},
           &Gfx::opSetStrokeColor},
   {"SCN", -33, {tchkSCN,   tchkSCN,    tchkSCN,    tchkSCN,
 	        tchkSCN,   tchkSCN,    tchkSCN,    tchkSCN,
@@ -240,7 +249,15 @@
           &Gfx::opSetRenderingIntent},
   {"s",   0, {tchkNone},
           &Gfx::opCloseStroke},
-  {"sc",  -4, {tchkNum,   tchkNum,    tchkNum,    tchkNum},
+  {"sc",  -4, {tchkNum,   tchkNum,    tchkNum,    tchkNum,
+	       tchkNum,   tchkNum,    tchkNum,    tchkNum,
+	       tchkNum,   tchkNum,    tchkNum,    tchkNum,
+	       tchkNum,   tchkNum,    tchkNum,    tchkNum,
+	       tchkNum,   tchkNum,    tchkNum,    tchkNum,
+	       tchkNum,   tchkNum,    tchkNum,    tchkNum,
+	       tchkNum,   tchkNum,    tchkNum,    tchkNum,
+	       tchkNum,   tchkNum,    tchkNum,    tchkNum,
+	       tchkNum},
           &Gfx::opSetFillColor},
   {"scn", -33, {tchkSCN,   tchkSCN,    tchkSCN,    tchkSCN,
 	        tchkSCN,   tchkSCN,    tchkSCN,    tchkSCN,
@@ -277,6 +294,7 @@
   Ref r;
 
   if (resDict) {
+    valid = gTrue;
 
     // build font dictionary
     fonts = NULL;
@@ -312,6 +330,7 @@
     resDict->lookup("Properties", &propsDict);
 
   } else {
+    valid = gFalse;
     fonts = NULL;
     xObjDict.initNull();
     colorSpaceDict.initNull();
@@ -394,7 +413,8 @@
   return gFalse;
 }
 
-void GfxResources::lookupColorSpace(const char *name, Object *obj) {
+void GfxResources::lookupColorSpace(const char *name, Object *obj,
+				    GBool inherit) {
   GfxResources *resPtr;
 
   //~ should also test for G, RGB, and CMYK - but only in inline images (?)
@@ -411,6 +431,9 @@
       }
       obj->free();
     }
+    if (!inherit && valid) {
+      break;
+    }
   }
   obj->initNull();
 }
@@ -692,7 +715,7 @@
   aborted = gFalse;
   errCount = 0;
   numArgs = 0;
-  parser->getObj(&obj);
+  getContentObj(&obj);
   while (!obj.isEOF()) {
 
     // check for an abort
@@ -748,7 +771,7 @@
     }
 
     // grab the next object
-    parser->getObj(&obj);
+    getContentObj(&obj);
   }
   obj.free();
 
@@ -772,6 +795,15 @@
   }
 }
 
+void Gfx::getContentObj(Object *obj) {
+  parser->getObj(obj);
+  if (obj->isRef()) {
+    error(errSyntaxError, getPos(), "Indirect reference in content stream");
+    obj->free();
+    obj->initError();
+  }
+}
+
 // Returns true if successful, false on error.
 GBool Gfx::execOp(Object *cmd, Object args[], int numArgs) {
   Operator *op;
@@ -807,10 +839,9 @@
     }
   } else {
     if (numArgs > -op->numArgs) {
-      error(errSyntaxError, getPos(),
+      error(errSyntaxWarning, getPos(),
 	    "Too many ({0:d}) args to '{1:s}' operator",
 	    numArgs, name);
-      return gFalse;
     }
   }
   for (i = 0; i < numArgs; ++i) {
@@ -951,14 +982,11 @@
 }
 
 void Gfx::opSetExtGState(Object args[], int numArgs) {
-  Object obj1, obj2, obj3, objRef3, obj4, obj5;
+  Object obj1, obj2, obj3, objRef3, obj4, obj5, backdropColorObj;
   Object args2[2];
   GfxBlendMode mode;
   GBool haveFillOP;
   Function *funcs[4];
-  GfxColor backdropColor;
-  GBool haveBackdropColor;
-  GfxColorSpace *blendingColorSpace;
   GBool alpha, knockout;
   double opac;
   int i;
@@ -1167,48 +1195,20 @@
 	}
       }
       obj3.free();
-      if ((haveBackdropColor = obj2.dictLookup("BC", &obj3)->isArray())) {
-	for (i = 0; i < gfxColorMaxComps; ++i) {
-	  backdropColor.c[i] = 0;
-	}
-	for (i = 0; i < obj3.arrayGetLength() && i < gfxColorMaxComps; ++i) {
-	  obj3.arrayGet(i, &obj4);
-	  if (obj4.isNum()) {
-	    backdropColor.c[i] = dblToCol(obj4.getNum());
-	  }
-	  obj4.free();
-	}
-      }
-      obj3.free();
+      obj2.dictLookup("BC", &backdropColorObj);
       if (obj2.dictLookup("G", &obj3)->isStream()) {
 	if (obj3.streamGetDict()->lookup("Group", &obj4)->isDict()) {
-	  blendingColorSpace = NULL;
 	  knockout = gFalse;
-	  if (!obj4.dictLookup("CS", &obj5)->isNull()) {
-	    blendingColorSpace = GfxColorSpace::parse(&obj5
-						      );
-	  }
-	  obj5.free();
 	  if (obj4.dictLookup("K", &obj5)->isBool()) {
 	    knockout = obj5.getBool();
 	  }
 	  obj5.free();
-	  if (!haveBackdropColor) {
-	    if (blendingColorSpace) {
-	      blendingColorSpace->getDefaultColor(&backdropColor);
-	    } else {
-	      //~ need to get the parent or default color space (?)
-	      for (i = 0; i < gfxColorMaxComps; ++i) {
-		backdropColor.c[i] = 0;
-	      }
-	    }
-	  }
 	  obj2.dictLookupNF("G", &objRef3);
 	  // it doesn't make sense for softmasks to be non-isolated,
 	  // because they're blended with a backdrop color, rather
 	  // than the original backdrop
-	  doSoftMask(&obj3, &objRef3, alpha, blendingColorSpace,
-		     gTrue, knockout, funcs[0], &backdropColor);
+	  doSoftMask(&obj3, &objRef3, alpha, gTrue, knockout, funcs[0],
+		     &backdropColorObj);
 	  objRef3.free();
 	  if (funcs[0]) {
 	    delete funcs[0];
@@ -1223,6 +1223,7 @@
 	      "Invalid soft mask in ExtGState - missing group");
       }
       obj3.free();
+      backdropColorObj.free();
     } else if (!obj2.isNull()) {
       error(errSyntaxError, getPos(), "Invalid soft mask in ExtGState");
     }
@@ -1233,9 +1234,8 @@
 }
 
 void Gfx::doSoftMask(Object *str, Object *strRef, GBool alpha,
-		     GfxColorSpace *blendingColorSpace,
 		     GBool isolated, GBool knockout,
-		     Function *transferFunc, GfxColor *backdropColor) {
+		     Function *transferFunc, Object *backdropColorObj) {
   Dict *dict, *resDict;
   double m[6], bbox[4];
   Object obj1, obj2;
@@ -1291,14 +1291,10 @@
 
   // draw it
   ++formDepth;
-  drawForm(strRef, resDict, m, bbox, gTrue, gTrue,
-	   blendingColorSpace, isolated, knockout,
-	   alpha, transferFunc, backdropColor);
+  drawForm(strRef, resDict, m, bbox, gTrue, gTrue, isolated, knockout,
+	   alpha, transferFunc, backdropColorObj);
   --formDepth;
 
-  if (blendingColorSpace) {
-    delete blendingColorSpace;
-  }
   obj1.free();
 }
 
@@ -1502,6 +1498,10 @@
   }
 }
 
+// Technically, per the PDF spec, the 'sc' operator can only be used
+// with device, CIE, and Indexed color spaces.  Some buggy PDF
+// generators use it for DeviceN, so we also allow that (same as
+// 'scn', minus the optional pattern name argument).
 void Gfx::opSetFillColor(Object args[], int numArgs) {
   GfxColor color;
   int i;
@@ -1524,6 +1524,10 @@
   out->updateFillColor(state);
 }
 
+// Technically, per the PDF spec, the 'SC' operator can only be used
+// with device, CIE, and Indexed color spaces.  Some buggy PDF
+// generators use it for DeviceN, so we also allow that (same as
+// 'SCN', minus the optional pattern name argument).
 void Gfx::opSetStrokeColor(Object args[], int numArgs) {
   GfxColor color;
   int i;
@@ -1998,6 +2002,7 @@
   state->lineTo(0, 1);
   state->closePath();
   doPatternFill(gTrue);
+  state->clearPath();
 
   restoreState();
 }
@@ -2318,35 +2323,9 @@
     state->clearPath();
   }
 
-#if 1 //~tmp: turn off anti-aliasing temporarily
-  out->setInShading(gTrue);
-#endif
+  // perform the fill
+  doShFill(shading);
 
-  // do shading type-specific operations
-  switch (shading->getType()) {
-  case 1:
-    doFunctionShFill((GfxFunctionShading *)shading);
-    break;
-  case 2:
-    doAxialShFill((GfxAxialShading *)shading);
-    break;
-  case 3:
-    doRadialShFill((GfxRadialShading *)shading);
-    break;
-  case 4:
-  case 5:
-    doGouraudTriangleShFill((GfxGouraudTriangleShading *)shading);
-    break;
-  case 6:
-  case 7:
-    doPatchMeshShFill((GfxPatchMeshShading *)shading);
-    break;
-  }
-
-#if 1 //~tmp: turn off anti-aliasing temporarily
-  out->setInShading(gFalse);
-#endif
-
   // restore graphics state
   restoreStateStack(savedState);
 }
@@ -2395,10 +2374,20 @@
   state->setFillColorSpace(shading->getColorSpace()->copy());
   out->updateFillColorSpace(state);
 
-#if 1 //~tmp: turn off anti-aliasing temporarily
-  out->setInShading(gTrue);
-#endif
+  // perform the fill
+  doShFill(shading);
 
+  // restore graphics state
+  restoreStateStack(savedState);
+
+  delete shading;
+}
+
+void Gfx::doShFill(GfxShading *shading) {
+  if (out->shadedFill(state, shading)) {
+    return;
+  }
+
   // do shading type-specific operations
   switch (shading->getType()) {
   case 1:
@@ -2419,15 +2408,6 @@
     doPatchMeshShFill((GfxPatchMeshShading *)shading);
     break;
   }
-
-#if 1 //~tmp: turn off anti-aliasing temporarily
-  out->setInShading(gFalse);
-#endif
-
-  // restore graphics state
-  restoreStateStack(savedState);
-
-  delete shading;
 }
 
 void Gfx::doFunctionShFill(GfxFunctionShading *shading) {
@@ -2434,11 +2414,6 @@
   double x0, y0, x1, y1;
   GfxColor colors[4];
 
-  if (out->useShadedFills() &&
-      out->functionShadedFill(state, shading)) {
-    return;
-  }
-
   shading->getDomain(&x0, &y0, &x1, &y1);
   shading->getColor(x0, y0, &colors[0]);
   shading->getColor(x0, y1, &colors[1]);
@@ -2567,11 +2542,6 @@
   GfxColor colors[axialSplits];
   int abortCheckCounter, nComps, i, j, k;
 
-  if (out->useShadedFills() &&
-      out->axialShadedFill(state, shading)) {
-    return;
-  }
-
   // get the clip region bbox
   state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
 
@@ -2872,11 +2842,6 @@
   double theta, alpha, angle, t;
   int abortCheckCounter, ia, ib, k, n;
 
-  if (out->useShadedFills() &&
-      out->radialShadedFill(state, shading)) {
-    return;
-  }
-
   // get the shading info
   shading->getCoords(&x0, &y0, &r0, &x1, &y1, &r1);
   t0 = shading->getDomain0();
@@ -3515,8 +3480,8 @@
     }
     for (i = 0; i < shading->getNComps(); ++i) {
       patch00.color[0][0][i] = patch->color[0][0][i];
-      patch00.color[0][1][i] = 0.5  * (patch->color[0][0][i] +
-				       patch->color[0][1][i]);
+      patch00.color[0][1][i] = 0.5 * (patch->color[0][0][i] +
+				      patch->color[0][1][i]);
       patch01.color[0][0][i] = patch00.color[0][1][i];
       patch01.color[0][1][i] = patch->color[0][1][i];
       patch01.color[1][1][i] = 0.5 * (patch->color[0][1][i] +
@@ -3905,6 +3870,19 @@
       //~ the CTM concat values here are wrong (but never used)
       out->updateCTM(state, 1, 0, 0, 1, 0, 0);
       state->transformDelta(dx, dy, &ddx, &ddy);
+#if 0
+      // The PDF spec says: "the graphics state shall be inherited
+      // from the environment of the text-showing operator that caused
+      // the [Type 3] glyph description to be invoked".  However,
+      // Acrobat apparently copies the fill color to the stroke color.
+      // It looks like Ghostscript does the same.  (This is only
+      // relevant for uncached Type 3 glyphs.)  Uncomment this block
+      // to make Xpdf mimic Adobe (in violation of the PDF spec).
+      state->setStrokeColorSpace(state->getFillColorSpace()->copy());
+      out->updateStrokeColorSpace(state);
+      state->setStrokeColor(state->getFillColor());
+      out->updateStrokeColor(state);
+#endif
       if (!out->beginType3Char(state, curX + riseX, curY + riseY, ddx, ddy,
 			       code, u, uLen)) {
 	((Gfx8BitFont *)font)->getCharProcNF(code, &charProcRef);
@@ -4149,7 +4127,7 @@
   GBool mask, invert;
   GfxColorSpace *colorSpace, *maskColorSpace;
   GfxImageColorMap *colorMap, *maskColorMap;
-  Object maskObj, smaskObj;
+  Object maskObj, smaskObj, maskRef;
   GBool haveColorKeyMask, haveExplicitMask, haveSoftMask, haveMatte;
   int maskColors[2*gfxColorMaxComps];
   int maskWidth, maskHeight;
@@ -4591,15 +4569,20 @@
     // draw it
     } else {
       if (haveSoftMask) {
+	dict->lookupNF("Mask", &maskRef);
 	out->drawSoftMaskedImage(state, ref, str, width, height, colorMap,
-				 maskStr, maskWidth, maskHeight, maskColorMap,
+				 &maskRef, maskStr, maskWidth, maskHeight,
+				 maskColorMap,
 				 haveMatte ? matte : (double *)NULL,
 				 interpolate);
+	maskRef.free();
 	delete maskColorMap;
       } else if (haveExplicitMask) {
+	dict->lookupNF("Mask", &maskRef);
 	out->drawMaskedImage(state, ref, str, width, height, colorMap,
-			     maskStr, maskWidth, maskHeight, maskInvert,
-			     interpolate);
+			     &maskRef, maskStr, maskWidth, maskHeight,
+			     maskInvert, interpolate);
+	maskRef.free();
       } else {
 	out->drawImage(state, ref, str, width, height, colorMap,
 		       haveColorKeyMask ? maskColors : (int *)NULL, inlineImg,
@@ -4642,7 +4625,6 @@
 void Gfx::doForm(Object *strRef, Object *str) {
   Dict *dict;
   GBool transpGroup, isolated, knockout;
-  GfxColorSpace *blendingColorSpace;
   Object matrixObj, bboxObj;
   double m[6], bbox[4];
   Object resObj;
@@ -4705,15 +4687,9 @@
 
   // check for a transparency group
   transpGroup = isolated = knockout = gFalse;
-  blendingColorSpace = NULL;
   if (dict->lookup("Group", &obj1)->isDict()) {
     if (obj1.dictLookup("S", &obj2)->isName("Transparency")) {
       transpGroup = gTrue;
-      if (!obj1.dictLookup("CS", &obj3)->isNull()) {
-	blendingColorSpace = GfxColorSpace::parse(&obj3
-						  );
-      }
-      obj3.free();
       if (obj1.dictLookup("I", &obj3)->isBool()) {
 	isolated = obj3.getBool();
       }
@@ -4729,13 +4705,9 @@
 
   // draw it
   ++formDepth;
-  drawForm(strRef, resDict, m, bbox,
-	   transpGroup, gFalse, blendingColorSpace, isolated, knockout);
+  drawForm(strRef, resDict, m, bbox, transpGroup, gFalse, isolated, knockout);
   --formDepth;
 
-  if (blendingColorSpace) {
-    delete blendingColorSpace;
-  }
   resObj.free();
 }
 
@@ -4742,12 +4714,14 @@
 void Gfx::drawForm(Object *strRef, Dict *resDict,
 		   double *matrix, double *bbox,
 		   GBool transpGroup, GBool softMask,
-		   GfxColorSpace *blendingColorSpace,
 		   GBool isolated, GBool knockout,
 		   GBool alpha, Function *transferFunc,
-		   GfxColor *backdropColor) {
+		   Object *backdropColorObj) {
   Parser *oldParser;
   GfxState *savedState;
+  GfxColorSpace *blendingColorSpace;
+  GfxColor backdropColor;
+  Object strObj, groupAttrsObj, csObj, obj1;
   double oldBaseMatrix[6];
   int i;
 
@@ -4779,7 +4753,23 @@
   out->clip(state);
   state->clearPath();
 
+  blendingColorSpace = NULL;
   if (softMask || transpGroup) {
+    // get the blending color space
+    // NB: this must be done AFTER pushing the resource dictionary,
+    //     so that any Default*** color spaces are available
+    strRef->fetch(xref, &strObj);
+    if (strObj.streamGetDict()->lookup("Group", &groupAttrsObj)->isDict()) {
+      if (!groupAttrsObj.dictLookup("CS", &csObj)->isNull()) {
+	blendingColorSpace = GfxColorSpace::parse(&csObj
+						  );
+      }
+      csObj.free();
+    }
+    groupAttrsObj.free();
+    strObj.free();
+
+    traceBegin(oldBaseMatrix, softMask ? "begin soft mask" : "begin t-group");
     if (state->getBlendMode() != gfxBlendNormal) {
       state->setBlendMode(gfxBlendNormal);
       out->updateBlendMode(state);
@@ -4831,11 +4821,34 @@
   popResources();
 
   if (softMask) {
-    out->setSoftMask(state, bbox, alpha, transferFunc, backdropColor);
+    for (i = 0; i < gfxColorMaxComps; ++i) {
+      backdropColor.c[i] = 0;
+    }
+    if (backdropColorObj->isArray()) {
+      for (i = 0;
+	   i < backdropColorObj->arrayGetLength() && i < gfxColorMaxComps;
+	   ++i) {
+	backdropColorObj->arrayGet(i, &obj1);
+	if (obj1.isNum()) {
+	  backdropColor.c[i] = dblToCol(obj1.getNum());
+	}
+	obj1.free();
+      }
+    } else if (blendingColorSpace) {
+      blendingColorSpace->getDefaultColor(&backdropColor);
+    }
+    //~ else: need to get the parent or default color space (?)
+    out->setSoftMask(state, bbox, alpha, transferFunc, &backdropColor);
+    traceEnd(oldBaseMatrix, "end soft mask");
   } else if (transpGroup) {
     out->paintTransparencyGroup(state, bbox);
+    traceEnd(oldBaseMatrix, "end t-group");
   }
 
+  if (blendingColorSpace) {
+    delete blendingColorSpace;
+  }
+
   return;
 }
 
@@ -4911,7 +4924,7 @@
 
   // build dictionary
   dict.initDict(xref);
-  parser->getObj(&obj);
+  getContentObj(&obj);
   while (!obj.isCmd("ID") && !obj.isEOF()) {
     if (!obj.isName()) {
       error(errSyntaxError, getPos(),
@@ -4920,14 +4933,19 @@
     } else {
       key = copyString(obj.getName());
       obj.free();
-      parser->getObj(&obj);
-      if (obj.isEOF() || obj.isError()) {
+      getContentObj(&obj);
+      if (obj.isEOF()) {
 	gfree(key);
 	break;
       }
-      dict.dictAdd(key, &obj);
+      if (obj.isError()) {
+	gfree(key);
+	obj.free();
+      } else {
+	dict.dictAdd(key, &obj);
+      }
     }
-    parser->getObj(&obj);
+    getContentObj(&obj);
   }
   if (obj.isEOF()) {
     error(errSyntaxError, getPos(), "End of file in inline image");
@@ -5108,7 +5126,7 @@
 
     // get the form bounding box
     dict->lookup("BBox", &bboxObj);
-    if (!bboxObj.isArray()) {
+    if (!bboxObj.isArray() || bboxObj.arrayGetLength() != 4) {
       error(errSyntaxError, getPos(), "Bad form bounding box");
       bboxObj.free();
       str.free();
@@ -5116,7 +5134,11 @@
     }
     for (i = 0; i < 4; ++i) {
       bboxObj.arrayGet(i, &obj1);
-      bbox[i] = obj1.getNum();
+      if (obj1.isNum()) {
+	bbox[i] = obj1.getNum();
+      } else {
+	bbox[i] = 0;
+      }
       obj1.free();
     }
     bboxObj.free();

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Gfx.h
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Gfx.h	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Gfx.h	2021-02-15 19:17:20 UTC (rev 845)
@@ -76,7 +76,7 @@
   GfxFont *lookupFontByRef(Ref ref);
   GBool lookupXObject(const char *name, Object *obj);
   GBool lookupXObjectNF(const char *name, Object *obj);
-  void lookupColorSpace(const char *name, Object *obj);
+  void lookupColorSpace(const char *name, Object *obj, GBool inherit = gTrue);
   GfxPattern *lookupPattern(const char *name
 			    );
   GfxShading *lookupShading(const char *name
@@ -88,6 +88,7 @@
 
 private:
 
+  GBool valid;
   GfxFontDict *fonts;
   Object xObjDict;
   Object colorSpaceDict;
@@ -164,10 +165,9 @@
 
   void drawForm(Object *strRef, Dict *resDict, double *matrix, double *bbox,
 		GBool transpGroup = gFalse, GBool softMask = gFalse,
-		GfxColorSpace *blendingColorSpace = NULL,
 		GBool isolated = gFalse, GBool knockout = gFalse,
 		GBool alpha = gFalse, Function *transferFunc = NULL,
-		GfxColor *backdropColor = NULL);
+		Object *backdropColorObj = NULL);
 
   // Take all of the content stream stack entries from <oldGfx>.  This
   // is useful when creating a new Gfx object to handle a pattern,
@@ -214,6 +214,7 @@
 
   GBool checkForContentStreamLoop(Object *ref);
   void go(GBool topLevel);
+  void getContentObj(Object *obj);
   GBool execOp(Object *cmd, Object args[], int numArgs);
   Operator *findOp(char *name);
   GBool checkArg(Object *arg, TchkType type);
@@ -231,9 +232,8 @@
   void opSetLineWidth(Object args[], int numArgs);
   void opSetExtGState(Object args[], int numArgs);
   void doSoftMask(Object *str, Object *strRef, GBool alpha,
-		  GfxColorSpace *blendingColorSpace,
 		  GBool isolated, GBool knockout,
-		  Function *transferFunc, GfxColor *backdropColor);
+		  Function *transferFunc, Object *backdropColorObj);
   void opSetRenderingIntent(Object args[], int numArgs);
   GfxRenderingIntent parseRenderingIntent(const char *name);
 
@@ -280,6 +280,7 @@
   void doShadingPatternFill(GfxShadingPattern *sPat,
 			    GBool stroke, GBool eoFill, GBool text);
   void opShFill(Object args[], int numArgs);
+  void doShFill(GfxShading *shading);
   void doFunctionShFill(GfxFunctionShading *shading);
   void doFunctionShFill1(GfxFunctionShading *shading,
 			 double x0, double y0,

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/GfxFont.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/GfxFont.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/GfxFont.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -467,6 +467,9 @@
       } else {
 	t2 = 0;
       }
+      if (t != 0 && t < 1.9) {
+	declaredAscent = t;
+      }
       // if both Ascent and CapHeight are set, use the smaller one
       // (because the most common problem is that Ascent is too large)
       if (t2 != 0 && (t == 0 || t2 < t)) {
@@ -851,19 +854,22 @@
   }
   str = obj2.getStream();
 
-  size = 0;
-  buf = NULL;
+  size = 4096;
+  buf = (char *)gmalloc(size);
+  *len = 0;
   str->reset();
   do {
-    if (size > INT_MAX - 4096) {
-      error(errSyntaxError, -1, "Embedded font file is too large");
-      break;
+    if (*len > size - 4096) {
+      if (size > INT_MAX / 2) {
+	error(errSyntaxError, -1, "Embedded font file is too large");
+	break;
+      }
+      size *= 2;
+      buf = (char *)grealloc(buf, size);
     }
-    buf = (char *)grealloc(buf, size + 4096);
-    n = str->getBlock(buf + size, 4096);
-    size += n;
+    n = str->getBlock(buf + *len, 4096);
+    *len += n;
   } while (n == 4096);
-  *len = size;
   str->close();
 
   obj2.free();
@@ -947,6 +953,7 @@
     missingWidth = builtinFont->missingWidth;
     ascent = 0.001 * builtinFont->ascent;
     descent = 0.001 * builtinFont->descent;
+    declaredAscent = ascent;
     fontBBox[0] = 0.001 * builtinFont->bbox[0];
     fontBBox[1] = 0.001 * builtinFont->bbox[1];
     fontBBox[2] = 0.001 * builtinFont->bbox[2];
@@ -955,6 +962,7 @@
     missingWidth = 0;
     ascent = 0.75;
     descent = -0.25;
+    declaredAscent = ascent;
     fontBBox[0] = fontBBox[1] = fontBBox[2] = fontBBox[3] = 0;
   }
 
@@ -966,6 +974,7 @@
   if (builtinFont) {
     ascent = 0.001 * builtinFont->ascent;
     descent = 0.001 * builtinFont->descent;
+    declaredAscent = ascent;
     fontBBox[0] = 0.001 * builtinFont->bbox[0];
     fontBBox[1] = 0.001 * builtinFont->bbox[1];
     fontBBox[2] = 0.001 * builtinFont->bbox[2];
@@ -1459,13 +1468,20 @@
   }
 
   // reverse map the char names through MacRomanEncoding, then map the
-  // char codes through the cmap
+  // char codes through the cmap; fall back on Unicode if that doesn't
+  // work
   if (useMacRoman) {
     for (i = 0; i < 256; ++i) {
       if ((charName = enc[i])) {
 	if ((code = globalParams->getMacRomanCharCode(charName))) {
 	  map[i] = ff->mapCodeToGID(cmap, code);
+	} else if (unicodeCmap >= 0 &&
+		   (u = globalParams->mapNameToUnicode(charName))) {
+	  map[i] = ff->mapCodeToGID(unicodeCmap, u);
 	}
+      } else if (unicodeCmap >= 0 &&
+		 (n = ctu->mapToUnicode((CharCode)i, &u, 1))) {
+	map[i] = ff->mapCodeToGID(cmap, u);
       } else {
 	map[i] = -1;
       }
@@ -1631,6 +1647,7 @@
   missingWidth = 0;
   ascent = 0.95;
   descent = -0.35;
+  declaredAscent = ascent;
   fontBBox[0] = fontBBox[1] = fontBBox[2] = fontBBox[3] = 0;
   collection = NULL;
   cMap = NULL;

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/GfxFont.h
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/GfxFont.h	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/GfxFont.h	2021-02-15 19:17:20 UTC (rev 845)
@@ -185,6 +185,7 @@
   // Return the ascent and descent values.
   double getAscent() { return ascent; }
   double getDescent() { return descent; }
+  double getDeclaredAscent() { return declaredAscent; }
 
   // Return the writing mode (0=horizontal, 1=vertical).
   virtual int getWMode() { return 0; }
@@ -234,6 +235,7 @@
   double missingWidth;		// "default" width
   double ascent;		// max height above baseline
   double descent;		// max depth below baseline
+  double declaredAscent;	// ascent value, before munging
   GBool hasToUnicode;		// true if the font has a ToUnicode map
   GBool ok;
 };

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/GfxState.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/GfxState.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/GfxState.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -101,6 +101,7 @@
 
 GfxColorSpace::GfxColorSpace() {
   overprintMask = 0x0f;
+  defaultColorSpace = gFalse;
 }
 
 GfxColorSpace::~GfxColorSpace() {
@@ -2683,6 +2684,11 @@
 	  "Missing or invalid BitsPerCoordinate in shading dictionary");
     goto err2;
   }
+  if (coordBits <= 0 || coordBits > 32) {
+    error(errSyntaxError, -1,
+	  "Invalid BitsPerCoordinate in shading dictionary");
+    goto err2;
+  }
   obj1.free();
   if (dict->lookup("BitsPerComponent", &obj1)->isInt()) {
     compBits = obj1.getInt();
@@ -2691,6 +2697,11 @@
 	  "Missing or invalid BitsPerComponent in shading dictionary");
     goto err2;
   }
+  if (compBits <= 0 || compBits > 16) {
+    error(errSyntaxError, -1,
+	  "Invalid BitsPerComponent in shading dictionary");
+    goto err2;
+  }
   obj1.free();
   flagBits = vertsPerRow = 0; // make gcc happy
   if (typeA == 4) {
@@ -2701,6 +2712,10 @@
 	    "Missing or invalid BitsPerFlag in shading dictionary");
       goto err2;
     }
+    if (flagBits < 2 || flagBits > 8) {
+      error(errSyntaxError, -1, "Invalid BitsPerFlag in shading dictionary");
+      goto err2;
+    }
     obj1.free();
   } else {
     if (dict->lookup("VerticesPerRow", &obj1)->isInt()) {
@@ -2711,6 +2726,11 @@
       goto err2;
     }
     obj1.free();
+    if (vertsPerRow < 2) {
+      error(errSyntaxError, -1,
+	    "Invalid VerticesPerRow in shading dictionary");
+      goto err2;
+    }
   }
   if (dict->lookup("Decode", &obj1)->isArray() &&
       obj1.arrayGetLength() >= 6) {
@@ -2911,6 +2931,34 @@
   }
 }
 
+void GfxGouraudTriangleShading::getBBox(double *xMin, double *yMin,
+					double *xMax, double *yMax) {
+  double xxMin = 0;
+  double yyMin = 0;
+  double xxMax = 0;
+  double yyMax = 0;
+  if (nVertices > 0) {
+    xxMin = xxMax = vertices[0].x;
+    yyMin = yyMax = vertices[0].y;
+  }
+  for (int i = 1; i < nVertices; ++i) {
+    if (vertices[i].x < xxMin) {
+      xxMin = vertices[i].x;
+    } else if (vertices[i].x > xxMax) {
+      xxMax = vertices[i].x;
+    }
+    if (vertices[i].y < yyMin) {
+      yyMin = vertices[i].y;
+    } else if (vertices[i].y > yyMax) {
+      yyMax = vertices[i].y;
+    }
+  }
+  *xMin = xxMin;
+  *yMin = yyMin;
+  *xMax = xxMax;
+  *yMax = yyMax;
+}
+
 void GfxGouraudTriangleShading::getColor(double *in, GfxColor *out) {
   double c[gfxColorMaxComps];
   int i;
@@ -2996,6 +3044,10 @@
   Object obj1, obj2;
   int i, j;
 
+  nPatchesA = 0;
+  patchesA = NULL;
+  patchesSize = 0;
+
   if (dict->lookup("BitsPerCoordinate", &obj1)->isInt()) {
     coordBits = obj1.getInt();
   } else {
@@ -3003,6 +3055,11 @@
 	  "Missing or invalid BitsPerCoordinate in shading dictionary");
     goto err2;
   }
+  if (coordBits <= 0 || coordBits > 32) {
+    error(errSyntaxError, -1,
+	  "Invalid BitsPerCoordinate in shading dictionary");
+    goto err2;
+  }
   obj1.free();
   if (dict->lookup("BitsPerComponent", &obj1)->isInt()) {
     compBits = obj1.getInt();
@@ -3011,6 +3068,11 @@
 	  "Missing or invalid BitsPerComponent in shading dictionary");
     goto err2;
   }
+  if (compBits <= 0 || compBits > 16) {
+    error(errSyntaxError, -1,
+	  "Invalid BitsPerComponent in shading dictionary");
+    goto err2;
+  }
   obj1.free();
   if (dict->lookup("BitsPerFlag", &obj1)->isInt()) {
     flagBits = obj1.getInt();
@@ -3019,6 +3081,10 @@
 	  "Missing or invalid BitsPerFlag in shading dictionary");
     goto err2;
   }
+  if (flagBits < 2 || flagBits > 8) {
+    error(errSyntaxError, -1, "Invalid BitsPerFlag in shading dictionary");
+    goto err2;
+  }
   obj1.free();
   if (dict->lookup("Decode", &obj1)->isArray() &&
       obj1.arrayGetLength() >= 6) {
@@ -3076,9 +3142,6 @@
   }
   obj1.free();
 
-  nPatchesA = 0;
-  patchesA = NULL;
-  patchesSize = 0;
   bitBuf = new GfxShadingBitBuf(str);
   while (1) {
     if (!bitBuf->getBits(flagBits, &flag)) {
@@ -3506,6 +3569,9 @@
  err2:
   obj1.free();
  err1:
+  if (patchesA) {
+    gfree(patchesA);
+  }
   return NULL;
 }
 
@@ -3513,6 +3579,38 @@
   return new GfxPatchMeshShading(this);
 }
 
+void GfxPatchMeshShading::getBBox(double *xMin, double *yMin,
+				  double *xMax, double *yMax) {
+  double xxMin = 0;
+  double yyMin = 0;
+  double xxMax = 0;
+  double yyMax = 0;
+  if (nPatches > 0) {
+    xxMin = patches[0].x[0][0];
+    yyMin = patches[0].y[0][0];
+  }
+  for (int i = 0; i < nPatches; ++i) {
+    for (int j = 0; j < 4; ++j) {
+      for (int k = 0; k < 4; ++k) {
+	if (patches[i].x[j][k] < xxMin) {
+	  xxMin = patches[i].x[j][k];
+	} else if (patches[i].x[j][k] > xxMax) {
+	  xxMax = patches[i].x[j][k];
+	}
+	if (patches[i].y[j][k] < yyMin) {
+	  yyMin = patches[i].y[j][k];
+	} else if (patches[i].y[j][k] > yyMax) {
+	  yyMax = patches[i].y[j][k];
+	}
+      }
+    }
+  }
+  *xMin = xxMin;
+  *yMin = yyMin;
+  *xMax = xxMax;
+  *yMax = yyMax;
+}
+
 void GfxPatchMeshShading::getColor(double *in, GfxColor *out) {
   double c[gfxColorMaxComps];
   int i;

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/GfxState.h
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/GfxState.h	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/GfxState.h	2021-02-15 19:17:20 UTC (rev 845)
@@ -207,6 +207,11 @@
   // Return the color space's overprint mask.
   Guint getOverprintMask() { return overprintMask; }
 
+  // Return true if this color space object is the result of
+  // substituting a DefaultGray/RGB/CMYK color space for
+  // DeviceGray/RGB/CMYK.
+  GBool isDefaultColorSpace() { return defaultColorSpace; }
+
   // Return the number of color space modes
   static int getNumColorSpaceModes();
 
@@ -216,6 +221,7 @@
 protected:
 
   Guint overprintMask;
+  GBool defaultColorSpace;
 };
 
 //------------------------------------------------------------------------
@@ -877,6 +883,7 @@
   void getTriangle(int i, double *x0, double *y0, double *color0,
 		   double *x1, double *y1, double *color1,
 		   double *x2, double *y2, double *color2);
+  void getBBox(double *xMin, double *yMin, double *xMax, double *yMax);
   void getColor(double *in, GfxColor *out);
 
 private:
@@ -916,6 +923,7 @@
   int getNComps() { return nComps; }
   int getNPatches() { return nPatches; }
   GfxPatch *getPatch(int i) { return &patches[i]; }
+  void getBBox(double *xMin, double *yMin, double *xMax, double *yMax);
   void getColor(double *in, GfxColor *out);
 
 private:

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/GlobalParams.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/GlobalParams.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/GlobalParams.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -178,24 +178,21 @@
 public:
 
   GString *name;
-  GBool bold;
-  GBool italic;
   GString *path;
   SysFontType type;
   int fontNum;			// for TrueType collections
 
-  SysFontInfo(GString *nameA, GBool boldA, GBool italicA,
-	      GString *pathA, SysFontType typeA, int fontNumA);
+  SysFontInfo(GString *nameA, GString *pathA, SysFontType typeA, int fontNumA);
   ~SysFontInfo();
-  GBool match(SysFontInfo *fi);
-  GBool match(GString *nameA, GBool boldA, GBool italicA);
+  GString *mungeName1(GString *in);
+  GString *mungeName2(GString *in);
+  void mungeName3(GString *name, GBool *bold, GBool *italic);
+  int match(GString *nameA);
 };
 
-SysFontInfo::SysFontInfo(GString *nameA, GBool boldA, GBool italicA,
-			 GString *pathA, SysFontType typeA, int fontNumA) {
+SysFontInfo::SysFontInfo(GString *nameA, GString *pathA,
+			 SysFontType typeA, int fontNumA) {
   name = nameA;
-  bold = boldA;
-  italic = italicA;
   path = pathA;
   type = typeA;
   fontNum = fontNumA;
@@ -206,16 +203,152 @@
   delete path;
 }
 
-GBool SysFontInfo::match(SysFontInfo *fi) {
-  return !strcasecmp(name->getCString(), fi->name->getCString()) &&
-         bold == fi->bold && italic == fi->italic;
+// Remove space/comma/dash/underscore chars.
+// Uppercase the name.
+GString *SysFontInfo::mungeName1(GString *in) {
+  GString *out = new GString();
+  for (char *p = in->getCString(); *p; ++p) {
+    if (*p == ' ' || *p == ',' || *p == '-' || *p == '_') {
+      // skip
+    } else if (*p >= 'a' && *p <= 'z') {
+      out->append((char)(*p & 0xdf));
+    } else {
+      out->append(*p);
+    }
+  }
+  return out;
 }
 
-GBool SysFontInfo::match(GString *nameA, GBool boldA, GBool italicA) {
-  return !strcasecmp(name->getCString(), nameA->getCString()) &&
-         bold == boldA && italic == italicA;
+// Remove trailing "Identity-H"/"Identity-V" from the name.
+// Split the name into tokens at space/comma/dash/underscore.
+// Remove trailing "MT" or "BT" from tokens.
+// Remove trailing "PS" and "WGL4" from tokens.
+// Uppercase each token.
+// Concatenate tokens (dropping the space/comma/dash chars).
+GString *SysFontInfo::mungeName2(GString *in) {
+  GString *out = new GString();
+  char *p0 = in->getCString();
+  while (*p0) {
+    if (!strcmp(p0, "Identity-H") || !strcmp(p0, "Identity-V")) {
+      break;
+    }
+    char *p1;
+    for (p1 = p0 + 1;
+	 *p1 && *p1 != ' ' && *p1 != ',' && *p1 != '-' && *p1 != '_';
+	 ++p1) ;
+    char *p2 = p1;
+    if (p2 - p0 >= 2 && (p2[-2] == 'B' || p2[-2] == 'M') && p2[-1] == 'T') {
+      p2 -= 2;
+    }
+    if (p2 - p0 >= 2 && p2[-2] == 'P' && p2[-1] == 'S') {
+      p2 -= 2;
+    }
+    if (p2 - p0 >= 4 &&
+	p2[-4] == 'W' && p2[-3] == 'G' && p2[-2] == 'L' && p2[-1] == '4') {
+      p2 -= 4;
+    }
+    for (; p0 < p2; ++p0) {
+      if (*p0 >= 'a' && *p0 <= 'z') {
+	out->append((char)(*p0 & 0xdf));
+      } else {
+	out->append(*p0);
+      }
+    }
+    for (p0 = p1; *p0 == ' ' || *p0 == ',' || *p0 == '-' || *p0 == '_'; ++p0) ;
+  }
+  return out;
 }
 
+// Remove trailing bold/italic/regular/roman tags from the name.
+// (Note: the names have already been uppercased by mungeName1/2.)
+void SysFontInfo::mungeName3(GString *name, GBool *bold, GBool *italic) {
+  *bold = gFalse;
+  *italic = gFalse;
+  int n = name->getLength();
+  while (1) {
+    if (n >= 4 && !strcmp(name->getCString() + n - 4, "BOLD")) {
+      name->del(n - 4, 4);
+      n -= 4;
+      *bold = gTrue;
+    } else if (n >= 6 && !strcmp(name->getCString() + n - 6, "ITALIC")) {
+      name->del(n - 6, 6);
+      n -= 6;
+      *italic = gTrue;
+    } else if (n >= 7 && !strcmp(name->getCString() + n - 7, "REGULAR")) {
+      name->del(n - 7, 7);
+      n -= 7;
+    } else if (n >= 5 && !strcmp(name->getCString() + n - 5, "ROMAN")) {
+      name->del(n - 5, 5);
+      n -= 5;
+    } else {
+      break;
+    }
+  }
+}
+
+// Returns a score indicating how well this font matches [nameA].  A
+// higher score is better.  Zero indicates a non-match.
+int SysFontInfo::match(GString *nameA) {
+  // fast fail: check if the first two letters match
+  if (strncasecmp(name->getCString(), nameA->getCString(), 2)) {
+    return 0;
+  }
+
+  GString *pdfName1 = mungeName1(nameA);
+  GString *sysName1 = mungeName1(name);
+  if (!pdfName1->cmp(sysName1)) {
+    delete pdfName1;
+    delete sysName1;
+    return 8;
+  }
+
+  GString *pdfName2 = mungeName2(nameA);
+  GString *sysName2 = mungeName2(name);
+  if (!pdfName2->cmp(sysName2)) {
+    delete pdfName1;
+    delete sysName1;
+    delete pdfName2;
+    delete sysName2;
+    return 7;
+  }
+
+  GBool pdfBold1, pdfItalic1, sysBold1, sysItalic1;
+  mungeName3(pdfName1, &pdfBold1, &pdfItalic1);
+  mungeName3(sysName1, &sysBold1, &sysItalic1);
+  int eq1 = !pdfName1->cmp(sysName1);
+
+  GBool pdfBold2, pdfItalic2, sysBold2, sysItalic2;
+  mungeName3(pdfName2, &pdfBold2, &pdfItalic2);
+  mungeName3(sysName2, &sysBold2, &sysItalic2);
+  int eq2 =!pdfName2->cmp(sysName2);
+
+  delete pdfName1;
+  delete sysName1;
+  delete pdfName2;
+  delete sysName2;
+
+  if (eq1 && pdfBold1 == sysBold1 && pdfItalic1 == sysItalic1) {
+    return 6;
+  }
+  if (eq2 && pdfBold2 == sysBold2 && pdfItalic2 == sysItalic2) {
+    return 5;
+  }
+  if (eq1 && pdfItalic1 == sysItalic1) {
+    return 4;
+  }
+  if (eq2 && pdfItalic2 == sysItalic2) {
+    return 3;
+  }
+  if (eq1) {
+    return 2;
+  }
+  if (eq2) {
+    return 1;
+  }
+
+  return 0;
+}
+
 //------------------------------------------------------------------------
 // SysFontList
 //------------------------------------------------------------------------
@@ -254,102 +387,17 @@
 }
 
 SysFontInfo *SysFontList::find(GString *name) {
-  GString *name2;
-  GBool bold, italic;
-  SysFontInfo *fi;
-  char c;
-  int n, i;
-
-  name2 = name->copy();
-
-  // remove space, comma, dash chars
-  i = 0;
-  while (i < name2->getLength()) {
-    c = name2->getChar(i);
-    if (c == ' ' || c == ',' || c == '-') {
-      name2->del(i);
-    } else {
-      ++i;
+  SysFontInfo *match = NULL;
+  int score = 0;
+  for (int i = 0; i < fonts->getLength(); ++i) {
+    SysFontInfo *fi = (SysFontInfo *)fonts->get(i);
+    int s = fi->match(name);
+    if (s > score) {
+      match = fi;
+      score = s;
     }
   }
-  n = name2->getLength();
-
-  // font names like "Arial-BoldMT,Bold" are occasionally used,
-  // so run this loop twice
-  bold = italic = gFalse;
-  for (i = 0; i < 2; ++i) {
-
-    // remove trailing "MT" (Foo-MT, Foo-BoldMT, etc.)
-    if (n > 2 && !strcmp(name2->getCString() + n - 2, "MT")) {
-      name2->del(n - 2, 2);
-      n -= 2;
-    }
-
-    // look for "Regular"
-    if (n > 7 && !strcmp(name2->getCString() + n - 7, "Regular")) {
-      name2->del(n - 7, 7);
-      n -= 7;
-    }
-
-    // look for "Italic"
-    if (n > 6 && !strcmp(name2->getCString() + n - 6, "Italic")) {
-      name2->del(n - 6, 6);
-      italic = gTrue;
-      n -= 6;
-    }
-
-    // look for "Bold"
-    if (n > 4 && !strcmp(name2->getCString() + n - 4, "Bold")) {
-      name2->del(n - 4, 4);
-      bold = gTrue;
-      n -= 4;
-    }
-  }
-
-  // remove trailing "PS"
-  if (n > 2 && !strcmp(name2->getCString() + n - 2, "PS")) {
-    name2->del(n - 2, 2);
-    n -= 2;
-  }
-
-  // remove trailing "IdentityH"
-  if (n > 9 && !strcmp(name2->getCString() + n - 9, "IdentityH")) {
-    name2->del(n - 9, 9);
-    n -= 9;
-  }
-
-  // search for the font
-  fi = NULL;
-  for (i = 0; i < fonts->getLength(); ++i) {
-    fi = (SysFontInfo *)fonts->get(i);
-    if (fi->match(name2, bold, italic)) {
-      break;
-    }
-    fi = NULL;
-  }
-  if (!fi && bold) {
-    // try ignoring the bold flag
-    for (i = 0; i < fonts->getLength(); ++i) {
-      fi = (SysFontInfo *)fonts->get(i);
-      if (fi->match(name2, gFalse, italic)) {
-	break;
-      }
-      fi = NULL;
-    }
-  }
-  if (!fi && (bold || italic)) {
-    // try ignoring the bold and italic flags
-    for (i = 0; i < fonts->getLength(); ++i) {
-      fi = (SysFontInfo *)fonts->get(i);
-      if (fi->match(name2, gFalse, gFalse)) {
-	break;
-      }
-      fi = NULL;
-    }
-  }
-
-  delete name2;
-  return fi;
+  return match;
 }
 
 #ifdef _WIN32
@@ -421,50 +469,15 @@
 
 SysFontInfo *SysFontList::makeWindowsFont(char *name, int fontNum,
 					  char *path) {
-  int n;
-  GBool bold, italic;
-  GString *s;
-  char c;
-  int i;
-  SysFontType type;
+  int n = (int)strlen(name);
 
-  n = (int)strlen(name);
-  bold = italic = gFalse;
-
-  // remove trailing ' (TrueType)'
-  if (n > 11 && !strncmp(name + n - 11, " (TrueType)", 11)) {
+  // remove trailing ' (TrueType)' or ' (OpenType)'
+  if (n > 11 && (!strncmp(name + n - 11, " (TrueType)", 11) ||
+		 !strncmp(name + n - 11, " (OpenType)", 11))) {
     n -= 11;
   }
 
-  // remove trailing ' Italic'
-  if (n > 7 && !strncmp(name + n - 7, " Italic", 7)) {
-    n -= 7;
-    italic = gTrue;
-  }
-
-  // remove trailing ' Bold'
-  if (n > 5 && !strncmp(name + n - 5, " Bold", 5)) {
-    n -= 5;
-    bold = gTrue;
-  }
-
-  // remove trailing ' Regular'
-  if (n > 8 && !strncmp(name + n - 8, " Regular", 8)) {
-    n -= 8;
-  }
-
-  //----- normalize the font name
-  s = new GString(name, n);
-  i = 0;
-  while (i < s->getLength()) {
-    c = s->getChar(i);
-    if (c == ' ' || c == ',' || c == '-') {
-      s->del(i);
-    } else {
-      ++i;
-    }
-  }
-
+  SysFontType type;
   if (!strcasecmp(path + strlen(path) - 4, ".ttc")) {
     type = sysFontTTC;
   } else if (!strcasecmp(path + strlen(path) - 4, ".otf")) {
@@ -472,31 +485,32 @@
   } else {
     type = sysFontTTF;
   }
-  return new SysFontInfo(s, bold, italic, new GString(path), type, fontNum);
+
+  return new SysFontInfo(new GString(name, n), new GString(path),
+			 type, fontNum);
 }
-#endif
+#endif // _WIN32
 
 #if HAVE_FONTCONFIG
 void SysFontList::scanFontconfigFonts() {
+  FcConfig *cfg;
   FcPattern *pattern;
   FcObjectSet *objSet;
   FcFontSet *fontSet;
-  char *family, *file, *styleLang, *style;
-  GString *family2;
+  char *name, *file;
   SysFontType type;
-  GBool bold, italic;
-  char c;
-  int fontNum, i, j, n;
+  int fontNum, i, n;
 
-  FcInit();
+  if (!(cfg = FcInitLoadConfigAndFonts())) {
+    return;
+  }
 
   pattern = FcPatternBuild(NULL,
 			   FC_OUTLINE, FcTypeBool, FcTrue,
 			   FC_SCALABLE, FcTypeBool, FcTrue,
 			   NULL);
-  objSet = FcObjectSetBuild(FC_FAMILY, FC_STYLE, FC_STYLELANG,
-			    FC_FILE, FC_INDEX, NULL);
-  fontSet = FcFontList(NULL, pattern, objSet);
+  objSet = FcObjectSetBuild(FC_FULLNAME, FC_FILE, FC_INDEX, NULL);
+  fontSet = FcFontList(cfg, pattern, objSet);
   FcPatternDestroy(pattern);
   FcObjectSetDestroy(objSet);
 
@@ -528,54 +542,21 @@
 	fontNum = 0;
       }
 
-      //--- font family
-      if (FcPatternGetString(fontSet->fonts[i], FC_FAMILY, 0,
-			     (FcChar8 **)&family)
+      //--- font name
+      if (FcPatternGetString(fontSet->fonts[i], FC_FULLNAME, 0,
+			     (FcChar8 **)&name)
 	  != FcResultMatch) {
 	continue;
       }
 
-      //----- normalize the font name
-      family2 = new GString(family);
-      j = 0;
-      while (j < family2->getLength()) {
-	c = family2->getChar(j);
-	if (c == ' ' || c == ',' || c == '-') {
-	  family2->del(j);
-	} else {
-	  ++j;
-	}
-      }
-
-      //--- font style
-      style = NULL;
-      for (j = 0;
-	   FcPatternGetString(fontSet->fonts[i], FC_STYLELANG, j,
-			      (FcChar8 **)&styleLang)
-	     == FcResultMatch;
-	   ++j) {
-	if (!strcmp(styleLang, "en")) {
-	  if (FcPatternGetString(fontSet->fonts[i], FC_STYLE, j,
-				 (FcChar8 **)&style)
-	      != FcResultMatch) {
-	    style = NULL;
-	  }
-	  break;
-	}
-	++j;
-      }
-      bold = style && strstr(style, "Bold") != NULL;
-      italic = style && (strstr(style, "Italic") != NULL ||
-			 strstr(style, "Oblique") != NULL);
-
-      fonts->append(new SysFontInfo(family2, bold, italic,
-				    new GString(file), type, fontNum));
+      fonts->append(new SysFontInfo(new GString(name), new GString(file),
+				    type, fontNum));
     }
 
     FcFontSetDestroy(fontSet);
   }
 
-  FcFini();
+  FcConfigDestroy(cfg);
 }
 #endif // HAVE_FONTCONFIG
 
@@ -663,6 +644,8 @@
 #else
   baseDir = appendToPath(getHomeDir(), ".xpdf");
 #endif
+  configFileVars = new GHash(gTrue);
+  setDataDirVar();
   nameToUnicode = new NameToCharCode();
   cidToUnicodes = new GHash(gTrue);
   unicodeToUnicodes = new GHash(gTrue);
@@ -736,6 +719,7 @@
   initialDisplayMode = new GString("continuous");
   initialToolbarState = gTrue;
   initialSidebarState = gTrue;
+  initialSidebarWidth = 0;
   initialSelectMode = new GString("linear");
   maxTileWidth = 1500;
   maxTileHeight = 1500;
@@ -761,6 +745,7 @@
   paperColor = new GString("#ffffff");
   matteColor = new GString("#808080");
   fullScreenMatteColor = new GString("#000000");
+  selectionColor = new GString("#8080ff");
   reverseVideoInvertImages = gFalse;
   launchCommand = NULL;
   movieCommand = NULL;
@@ -769,7 +754,6 @@
   mapUnknownCharNames = gFalse;
   mapExtTrueTypeFontsViaUnicode = gTrue;
   droppedFonts = new GHash(gTrue);
-  enableXFA = gTrue;
   createDefaultKeyBindings();
   popupMenuCmds = new GList();
   tabStateFile = appendToPath(getHomeDir(), ".xpdf.tab-state");
@@ -847,6 +831,31 @@
   }
 }
 
+void GlobalParams::setDataDirVar() {
+  GString *dir;
+
+#if defined(XPDFRC_DATADIR)
+  dir = new GString(XPDFRC_DATADIR);
+#elif defined(_WIN32)
+  wchar_t buf[512];
+  DWORD n = GetModuleFileNameW(NULL, buf, sizeof(buf) / sizeof(wchar_t));
+  if (n <= 0 || n >= sizeof(buf)) {
+    // error or path too long for buffer - just use the current dir
+    buf[0] = L'\0';
+  }
+  GString *path = fileNameToUTF8(buf);
+  dir = grabPath(path->getCString());
+  delete path;
+  appendToPath(dir, "data");
+#else
+  //~ may be useful to allow the options of using the install dir
+  //~   and/or the user's home dir (?)
+  dir = new GString("./data");
+#endif
+
+  configFileVars->add(new GString("DATADIR"), dir);
+}
+
 void GlobalParams::createDefaultKeyBindings() {
   keyBindings = new GList();
 
@@ -853,8 +862,20 @@
   //----- mouse buttons
   keyBindings->append(new KeyBinding(xpdfKeyCodeMousePress1, xpdfKeyModNone,
 				     xpdfKeyContextAny, "startSelection"));
+  keyBindings->append(new KeyBinding(xpdfKeyCodeMousePress1, xpdfKeyModShift,
+				     xpdfKeyContextAny,
+				     "startExtendedSelection"));
   keyBindings->append(new KeyBinding(xpdfKeyCodeMouseRelease1, xpdfKeyModNone,
 				     xpdfKeyContextAny, "endSelection"));
+  keyBindings->append(new KeyBinding(xpdfKeyCodeMouseRelease1, xpdfKeyModShift,
+				     xpdfKeyContextAny,
+				     "endSelection"));
+  keyBindings->append(new KeyBinding(xpdfKeyCodeMouseDoubleClick1,
+				     xpdfKeyModNone, xpdfKeyContextAny,
+				     "selectWord"));
+  keyBindings->append(new KeyBinding(xpdfKeyCodeMouseTripleClick1,
+				     xpdfKeyModNone, xpdfKeyContextAny,
+				     "selectLine"));
   keyBindings->append(new KeyBinding(xpdfKeyCodeMouseClick1, xpdfKeyModNone,
 				     xpdfKeyContextAny, "followLinkNoSel"));
   keyBindings->append(new KeyBinding(xpdfKeyCodeMouseClick2, xpdfKeyModNone,
@@ -876,6 +897,10 @@
 				     xpdfKeyContextAny, "scrollLeft(16)"));
   keyBindings->append(new KeyBinding(xpdfKeyCodeMousePress7, xpdfKeyModNone,
 				     xpdfKeyContextAny, "scrollRight(16)"));
+  keyBindings->append(new KeyBinding(xpdfKeyCodeMousePress4, xpdfKeyModCtrl,
+				     xpdfKeyContextAny, "zoomIn"));
+  keyBindings->append(new KeyBinding(xpdfKeyCodeMousePress5, xpdfKeyModCtrl,
+				     xpdfKeyContextAny, "zoomOut"));
 
   //----- control keys
   keyBindings->append(new KeyBinding('o', xpdfKeyModCtrl,
@@ -1002,26 +1027,10 @@
 void GlobalParams::parseLine(char *buf, GString *fileName, int line) {
   GList *tokens;
   GString *cmd, *incFile;
-  char *p1, *p2;
   FILE *f2;
 
   // break the line into tokens
-  tokens = new GList();
-  p1 = buf;
-  while (*p1) {
-    for (; *p1 && isspace(*p1); ++p1) ;
-    if (!*p1) {
-      break;
-    }
-    if (*p1 == '"' || *p1 == '\'') {
-      for (p2 = p1 + 1; *p2 && *p2 != *p1; ++p2) ;
-      ++p1;
-    } else {
-      for (p2 = p1 + 1; *p2 && !isspace(*p2); ++p2) ;
-    }
-    tokens->append(new GString(p1, (int)(p2 - p1)));
-    p1 = *p2 ? p2 + 1 : p2;
-  }
+  tokens = parseLineTokens(buf, fileName, line);
 
   // parse the line
   if (tokens->getLength() > 0 &&
@@ -1153,6 +1162,9 @@
     } else if (!cmd->cmp("initialSidebarState")) {
       parseYesNo("initialSidebarState", &initialSidebarState,
 		 tokens, fileName, line);
+    } else if (!cmd->cmp("initialSidebarWidth")) {
+      parseInteger("initialSidebarWidth", &initialSidebarWidth,
+		   tokens, fileName, line);
     } else if (!cmd->cmp("initialSelectMode")) {
       parseString("initialSelectMode", &initialSelectMode,
 		  tokens, fileName, line);
@@ -1217,6 +1229,8 @@
     } else if (!cmd->cmp("fullScreenMatteColor")) {
       parseString("fullScreenMatteColor", &fullScreenMatteColor,
 		  tokens, fileName, line);
+    } else if (!cmd->cmp("selectionColor")) {
+      parseString("selectionColor", &selectionColor, tokens, fileName, line);
     } else if (!cmd->cmp("reverseVideoInvertImages")) {
       parseYesNo("reverseVideoInvertImages", &reverseVideoInvertImages,
 		 tokens, fileName, line);
@@ -1238,8 +1252,6 @@
 		 tokens, fileName, line);
     } else if (!cmd->cmp("dropFont")) {
       parseDropFont(tokens, fileName, line);
-    } else if (!cmd->cmp("enableXFA")) {
-      parseYesNo("enableXFA", &enableXFA, tokens, fileName, line);
     } else if (!cmd->cmp("bind")) {
       parseBind(tokens, fileName, line);
     } else if (!cmd->cmp("unbind")) {
@@ -1269,6 +1281,8 @@
       } else if (!cmd->cmp("fontpath") || !cmd->cmp("fontmap")) {
 	error(errConfig, -1,
 	      "The config file format has changed since Xpdf 0.9x");
+      } else if (!cmd->cmp("enableXFA")) {
+	error(errConfig, -1, "The enableXFA option is no longer used");
       }
     }
   }
@@ -1276,6 +1290,71 @@
   deleteGList(tokens, GString);
 }
 
+// Split a line into a sequence of tokens.  Tokens are separated by
+// whitespace.  Each token is one of:
+//   - unquoted string, which can contain any char other than
+//     whitespace, and which cannot start with a single quote, double
+//     quote, or at-double-quote (xxxx)
+//   - single-quoted string, which can contain any char other than the
+//     single quote ('xxxx')
+//   - double-quoted string, which can contain any char other than the
+//     double quote ("xxxx")
+//   - at-double-quoted string, which can contain variables and escape
+//     chars (@"xxxx")
+//     - variables look like ${name}
+//     - special chars (${}") can be escaped with %, e.g.,
+//       @"foo%"bar", @"foo%$bar", @"foo%%bar"
+GList *GlobalParams::parseLineTokens(char *buf, GString *fileName, int line) {
+  GList *tokens = new GList();
+  char *p1 = buf;
+  while (*p1) {
+    for (; *p1 && isspace(*p1); ++p1) ;
+    if (!*p1) {
+      break;
+    }
+    if (*p1 == '"' || *p1 == '\'') {
+      char *p2;
+      for (p2 = p1 + 1; *p2 && *p2 != *p1; ++p2) ;
+      ++p1;
+      tokens->append(new GString(p1, (int)(p2 - p1)));
+      p1 = *p2 ? p2 + 1 : p2;
+    } else if (*p1 == '@' && p1[1] == '"') {
+      GString *token = new GString();
+      char *p2 = p1 + 2;
+      while (*p2 && *p2 != '"') {
+	if (*p2 == '%' && p2[1]) {
+	  token->append(p2[1]);
+	  p2 += 2;
+	} else if (*p2 == '$' && p2[1] == '{') {
+	  p2 += 2;
+	  char *p3;
+	  for (p3 = p2; *p3 && *p3 != '}'; ++p3) ;
+	  GString *varName = new GString(p2, (int)(p3 - p2));
+	  GString *varValue = (GString *)configFileVars->lookup(varName);
+	  if (varValue) {
+	    token->append(varValue);
+	  } else {
+	    error(errConfig, -1, "Unknown config file variable '%t'", varName);
+	  }
+	  delete varName;
+	  p2 = *p3 ? p3 + 1 : p3;
+	} else {
+	  token->append(*p2);
+	  ++p2;
+	}
+      }
+      tokens->append(token);
+      p1 = *p2 ? p2 + 1 : p2;
+    } else {
+      char *p2;
+      for (p2 = p1 + 1; *p2 && !isspace(*p2); ++p2) ;
+      tokens->append(new GString(p1, (int)(p2 - p1)));
+      p1 = p2;
+    }
+  }
+  return tokens;
+}
+
 void GlobalParams::parseNameToUnicode(GList *tokens, GString *fileName,
 				      int line) {
   GString *name;
@@ -1738,6 +1817,8 @@
     *code = xpdfKeyCodeEnter;
   } else if (!strcmp(p0, "backspace")) {
     *code = xpdfKeyCodeBackspace;
+  } else if (!strcmp(p0, "esc")) {
+    *code = xpdfKeyCodeEsc;
   } else if (!strcmp(p0, "insert")) {
     *code = xpdfKeyCodeInsert;
   } else if (!strcmp(p0, "delete")) {
@@ -1758,8 +1839,6 @@
     *code = xpdfKeyCodeUp;
   } else if (!strcmp(p0, "down")) {
     *code = xpdfKeyCodeDown;
-  } else if (!strcmp(p0, "esc")) {
-    *code = xpdfKeyCodeEsc;
   } else if (p0[0] == 'f' && p0[1] >= '1' && p0[1] <= '9' && !p0[2]) {
     *code = xpdfKeyCodeF1 + (p0[1] - '1');
   } else if (p0[0] == 'f' &&
@@ -1782,6 +1861,16 @@
 	     (!p0[11] || (p0[11] >= '0' && p0[11] <= '9' && !p0[12])) &&
 	     (btn = atoi(p0 + 10)) >= 1 && btn <= 32) {
     *code = xpdfKeyCodeMouseClick1 + btn - 1;
+  } else if (!strncmp(p0, "mouseDoubleClick", 16) &&
+	     p0[16] >= '0' && p0[16] <= '9' &&
+	     (!p0[17] || (p0[17] >= '0' && p0[17] <= '9' && !p0[18])) &&
+	     (btn = atoi(p0 + 16)) >= 1 && btn <= 32) {
+    *code = xpdfKeyCodeMouseDoubleClick1 + btn - 1;
+  } else if (!strncmp(p0, "mouseTripleClick", 16) &&
+	     p0[16] >= '0' && p0[16] <= '9' &&
+	     (!p0[17] || (p0[17] >= '0' && p0[17] <= '9' && !p0[18])) &&
+	     (btn = atoi(p0 + 16)) >= 1 && btn <= 32) {
+    *code = xpdfKeyCodeMouseTripleClick1 + btn - 1;
   } else if (*p0 >= 0x20 && *p0 <= 0x7e && !p0[1]) {
     *code = (int)*p0;
   } else {
@@ -1981,6 +2070,7 @@
   delete macRomanReverseMap;
 
   delete baseDir;
+  deleteGHash(configFileVars, GString);
   delete nameToUnicode;
   deleteGHash(cidToUnicodes, GString);
   deleteGHash(unicodeToUnicodes, GString);
@@ -2009,6 +2099,9 @@
   if (fullScreenMatteColor) {
     delete fullScreenMatteColor;
   }
+  if (selectionColor) {
+    delete selectionColor;
+  }
   if (launchCommand) {
     delete launchCommand;
   }
@@ -2784,6 +2877,26 @@
   return s;
 }
 
+GList *GlobalParams::getAvailableTextEncodings() {
+  GList *list;       // [GString]
+  GHashIter *iter;
+  GString *key;
+  void *val;
+
+  list = new GList();
+  lockGlobalParams;
+  residentUnicodeMaps->startIter(&iter);
+  while (residentUnicodeMaps->getNext(&iter, &key, &val)) {
+    list->append(key->copy());
+  }
+  unicodeMaps->startIter(&iter);
+  while (unicodeMaps->getNext(&iter, &key, &val)) {
+    list->append(key->copy());
+  }
+  unlockGlobalParams;
+  return list;
+}
+
 EndOfLineKind GlobalParams::getTextEOL() {
   EndOfLineKind eol;
 
@@ -2856,6 +2969,15 @@
   return state;
 }
 
+int GlobalParams::getInitialSidebarWidth() {
+  int w;
+
+  lockGlobalParams;
+  w = initialSidebarWidth;
+  unlockGlobalParams;
+  return w;
+}
+
 GString *GlobalParams::getInitialSelectMode() {
   GString *s;
 
@@ -3075,6 +3197,15 @@
   return s;
 }
 
+GString *GlobalParams::getSelectionColor() {
+  GString *s;
+
+  lockGlobalParams;
+  s = selectionColor->copy();
+  unlockGlobalParams;
+  return s;
+}
+
 GBool GlobalParams::getReverseVideoInvertImages() {
   GBool invert;
 
@@ -3129,15 +3260,6 @@
   return isDropped;
 }
 
-GBool GlobalParams::getEnableXFA() {
-  GBool enable;
-
-  lockGlobalParams;
-  enable = enableXFA;
-  unlockGlobalParams;
-  return enable;
-}
-
 GList *GlobalParams::getKeyBinding(int code, int mods, int context) {
   KeyBinding *binding;
   GList *cmds;
@@ -3164,6 +3286,10 @@
   return cmds;
 }
 
+GList *GlobalParams::getAllKeyBindings() {
+  return keyBindings;
+}
+
 int GlobalParams::getNumPopupMenuCmds() {
   int n;
 
@@ -3214,7 +3340,7 @@
   return debugLogFile;
 }
 
-void GlobalParams::debugLogPrintf(char *fmt, ...) {
+void GlobalParams::debugLogPrintf(const char *fmt, ...) {
   GString *path;
   FILE *f;
   GBool needClose;
@@ -3620,12 +3746,6 @@
   unlockGlobalParams;
 }
 
-void GlobalParams::setEnableXFA(GBool enable) {
-  lockGlobalParams;
-  enableXFA = enable;
-  unlockGlobalParams;
-}
-
 void GlobalParams::setTabStateFile(char *tabStateFileA) {
   lockGlobalParams;
   delete tabStateFile;

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/GlobalParams.h
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/GlobalParams.h	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/GlobalParams.h	2021-02-15 19:17:20 UTC (rev 845)
@@ -134,50 +134,68 @@
   ~KeyBinding();
 };
 
-#define xpdfKeyCodeTab            0x1000
-#define xpdfKeyCodeReturn         0x1001
-#define xpdfKeyCodeEnter          0x1002
-#define xpdfKeyCodeBackspace      0x1003
-#define xpdfKeyCodeEsc            0x1004
-#define xpdfKeyCodeInsert         0x1005
-#define xpdfKeyCodeDelete         0x1006
-#define xpdfKeyCodeHome           0x1007
-#define xpdfKeyCodeEnd            0x1008
-#define xpdfKeyCodePgUp           0x1009
-#define xpdfKeyCodePgDn           0x100a
-#define xpdfKeyCodeLeft           0x100b
-#define xpdfKeyCodeRight          0x100c
-#define xpdfKeyCodeUp             0x100d
-#define xpdfKeyCodeDown           0x100e
-#define xpdfKeyCodeF1             0x1100
-#define xpdfKeyCodeF35            0x1122
-#define xpdfKeyCodeMousePress1    0x2001
-#define xpdfKeyCodeMousePress2    0x2002
-#define xpdfKeyCodeMousePress3    0x2003
-#define xpdfKeyCodeMousePress4    0x2004
-#define xpdfKeyCodeMousePress5    0x2005
-#define xpdfKeyCodeMousePress6    0x2006
-#define xpdfKeyCodeMousePress7    0x2007
+#define xpdfKeyCodeTab                0x1000
+#define xpdfKeyCodeReturn             0x1001
+#define xpdfKeyCodeEnter              0x1002
+#define xpdfKeyCodeBackspace          0x1003
+#define xpdfKeyCodeEsc                0x1004
+#define xpdfKeyCodeInsert             0x1005
+#define xpdfKeyCodeDelete             0x1006
+#define xpdfKeyCodeHome               0x1007
+#define xpdfKeyCodeEnd                0x1008
+#define xpdfKeyCodePgUp               0x1009
+#define xpdfKeyCodePgDn               0x100a
+#define xpdfKeyCodeLeft               0x100b
+#define xpdfKeyCodeRight              0x100c
+#define xpdfKeyCodeUp                 0x100d
+#define xpdfKeyCodeDown               0x100e
+#define xpdfKeyCodeF1                 0x1100
+#define xpdfKeyCodeF35                0x1122
+#define xpdfKeyCodeMousePress1        0x2001
+#define xpdfKeyCodeMousePress2        0x2002
+#define xpdfKeyCodeMousePress3        0x2003
+#define xpdfKeyCodeMousePress4        0x2004
+#define xpdfKeyCodeMousePress5        0x2005
+#define xpdfKeyCodeMousePress6        0x2006
+#define xpdfKeyCodeMousePress7        0x2007
 // ...
-#define xpdfKeyCodeMousePress32   0x2020
-#define xpdfKeyCodeMouseRelease1  0x2101
-#define xpdfKeyCodeMouseRelease2  0x2102
-#define xpdfKeyCodeMouseRelease3  0x2103
-#define xpdfKeyCodeMouseRelease4  0x2104
-#define xpdfKeyCodeMouseRelease5  0x2105
-#define xpdfKeyCodeMouseRelease6  0x2106
-#define xpdfKeyCodeMouseRelease7  0x2107
+#define xpdfKeyCodeMousePress32       0x2020
+#define xpdfKeyCodeMouseRelease1      0x2101
+#define xpdfKeyCodeMouseRelease2      0x2102
+#define xpdfKeyCodeMouseRelease3      0x2103
+#define xpdfKeyCodeMouseRelease4      0x2104
+#define xpdfKeyCodeMouseRelease5      0x2105
+#define xpdfKeyCodeMouseRelease6      0x2106
+#define xpdfKeyCodeMouseRelease7      0x2107
 // ...
-#define xpdfKeyCodeMouseRelease32 0x2120
-#define xpdfKeyCodeMouseClick1    0x2201
-#define xpdfKeyCodeMouseClick2    0x2202
-#define xpdfKeyCodeMouseClick3    0x2203
-#define xpdfKeyCodeMouseClick4    0x2204
-#define xpdfKeyCodeMouseClick5    0x2205
-#define xpdfKeyCodeMouseClick6    0x2206
-#define xpdfKeyCodeMouseClick7    0x2207
+#define xpdfKeyCodeMouseRelease32     0x2120
+#define xpdfKeyCodeMouseClick1        0x2201
+#define xpdfKeyCodeMouseClick2        0x2202
+#define xpdfKeyCodeMouseClick3        0x2203
+#define xpdfKeyCodeMouseClick4        0x2204
+#define xpdfKeyCodeMouseClick5        0x2205
+#define xpdfKeyCodeMouseClick6        0x2206
+#define xpdfKeyCodeMouseClick7        0x2207
 // ...
-#define xpdfKeyCodeMouseClick32   0x2220
+#define xpdfKeyCodeMouseClick32       0x2220
+#define xpdfKeyCodeMouseDoubleClick1  0x2301
+#define xpdfKeyCodeMouseDoubleClick2  0x2302
+#define xpdfKeyCodeMouseDoubleClick3  0x2303
+#define xpdfKeyCodeMouseDoubleClick4  0x2304
+#define xpdfKeyCodeMouseDoubleClick5  0x2305
+#define xpdfKeyCodeMouseDoubleClick6  0x2306
+#define xpdfKeyCodeMouseDoubleClick7  0x2307
+// ...
+#define xpdfKeyCodeMouseDoubleClick32 0x2320
+#define xpdfKeyCodeMouseTripleClick1  0x2401
+#define xpdfKeyCodeMouseTripleClick2  0x2402
+#define xpdfKeyCodeMouseTripleClick3  0x2403
+#define xpdfKeyCodeMouseTripleClick4  0x2404
+#define xpdfKeyCodeMouseTripleClick5  0x2405
+#define xpdfKeyCodeMouseTripleClick6  0x2406
+#define xpdfKeyCodeMouseTripleClick7  0x2407
+// ...
+#define xpdfKeyCodeMouseTripleClick32 0x2420
 #define xpdfKeyModNone            0
 #define xpdfKeyModShift           (1 << 0)
 #define xpdfKeyModCtrl            (1 << 1)
@@ -279,6 +297,7 @@
   GBool getPSAlwaysRasterize();
   GBool getPSNeverRasterize();
   GString *getTextEncodingName();
+  GList *getAvailableTextEncodings();
   EndOfLineKind getTextEOL();
   GBool getTextPageBreaks();
   GBool getTextKeepTinyChars();
@@ -287,6 +306,7 @@
   GString *getInitialDisplayMode();
   GBool getInitialToolbarState();
   GBool getInitialSidebarState();
+  int getInitialSidebarWidth();
   GString *getInitialSelectMode();
   int getMaxTileWidth();
   int getMaxTileHeight();
@@ -312,6 +332,7 @@
   GString *getPaperColor();
   GString *getMatteColor();
   GString *getFullScreenMatteColor();
+  GString *getSelectionColor();
   GBool getReverseVideoInvertImages();
   GString *getLaunchCommand() { return launchCommand; }
   GString *getMovieCommand() { return movieCommand; }
@@ -320,8 +341,8 @@
   GBool getMapUnknownCharNames();
   GBool getMapExtTrueTypeFontsViaUnicode();
   GBool isDroppedFont(const char *fontName);
-  GBool getEnableXFA();
   GList *getKeyBinding(int code, int mods, int context);
+  GList *getAllKeyBindings();
   int getNumPopupMenuCmds();
   PopupMenuCmd *getPopupMenuCmd(int idx);
   GString *getTabStateFile();
@@ -328,7 +349,7 @@
   GBool getPrintCommands();
   GBool getErrQuiet();
   GString *getDebugLogFile();
-  void debugLogPrintf(char *fmt, ...);
+  void debugLogPrintf(const char *fmt, ...);
 
   CharCodeToUnicode *getCIDToUnicode(GString *collection);
   CharCodeToUnicode *getUnicodeToUnicode(GString *fontName);
@@ -378,7 +399,6 @@
   void setMapNumericCharNames(GBool map);
   void setMapUnknownCharNames(GBool map);
   void setMapExtTrueTypeFontsViaUnicode(GBool map);
-  void setEnableXFA(GBool enable);
   void setTabStateFile(char *tabStateFileA);
   void setPrintCommands(GBool printCommandsA);
   void setErrQuiet(GBool errQuietA);
@@ -392,8 +412,10 @@
 
 private:
 
+  void setDataDirVar();
   void createDefaultKeyBindings();
   void parseFile(GString *fileName, FILE *f);
+  GList *parseLineTokens(char *buf, GString *fileName, int line);
   void parseNameToUnicode(GList *tokens, GString *fileName, int line);
   void parseCIDToUnicode(GList *tokens, GString *fileName, int line);
   void parseUnicodeToUnicode(GList *tokens, GString *fileName, int line);
@@ -438,9 +460,14 @@
   NameToCharCode *		// mapping from char name to
     macRomanReverseMap;		//   MacRomanEncoding index
 
+  //----- meta settings
+
+  GString *baseDir;		// base directory - for plugins, etc.
+  GHash *configFileVars;	// variables for use in the config file
+				//   [GString]
+
   //----- user-modifiable settings
 
-  GString *baseDir;		// base directory - for plugins, etc.
   NameToCharCode *		// mapping from char name to Unicode
     nameToUnicode;
   GHash *cidToUnicodes;		// files for mappings from char collections
@@ -522,6 +549,7 @@
 				//   or closed (false)
   GBool initialSidebarState;	// initial sidebar state - open (true)
 				//   or closed (false)
+  int initialSidebarWidth;	// initial sidebar width
   GString *initialSelectMode;	// initial selection mode (block or linear)
   int maxTileWidth;		// maximum rasterization tile width
   int maxTileHeight;		// maximum rasterization tile height
@@ -548,6 +576,7 @@
   GString *paperColor;		// paper (page background) color
   GString *matteColor;		// matte (background outside of page) color
   GString *fullScreenMatteColor; // matte color in full-screen mode
+  GString *selectionColor;	// selection color
   GBool reverseVideoInvertImages; // invert images in reverse video mode
   GString *launchCommand;	// command executed for 'launch' links
   GString *movieCommand;	// command executed for movie annotations
@@ -558,7 +587,6 @@
   GBool mapExtTrueTypeFontsViaUnicode;  // map char codes to GID via Unicode
 				        //   for external TrueType fonts?
   GHash *droppedFonts;		// dropped fonts [int]
-  GBool enableXFA;		// enable XFA form rendering
   GList *keyBindings;		// key & mouse button bindings [KeyBinding]
   GList *popupMenuCmds;		// popup menu commands [PopupMenuCmd]
   GString *tabStateFile;	// path for the tab state save file

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/HTMLGen.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/HTMLGen.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/HTMLGen.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -214,6 +214,7 @@
   // set up the TextOutputDev
   textOutControl.mode = textOutReadingOrder;
   textOutControl.html = gTrue;
+  textOutControl.splitRotatedWords = gTrue;
   textOut = new TextOutputDev(NULL, &textOutControl, gFalse);
   if (!textOut->isOk()) {
     ok = gFalse;
@@ -492,7 +493,7 @@
        (spanDir >= 0) ? wordIdx <= lastWordIdx : wordIdx >= lastWordIdx;
        wordIdx += spanDir) {
     word1 = (TextWord *)words->get(wordIdx);
-    invisible = allTextInvisible || word1->isInvisible();
+    invisible = allTextInvisible || word1->isInvisible() || word1->isRotated();
     if (!drawInvisibleText && invisible) {
       continue;
     }
@@ -513,6 +514,7 @@
 	word1->getFontInfo() != word0->getFontInfo() ||
 	word1->getFontSize() != word0->getFontSize() ||
 	word1->isInvisible() != word0->isInvisible() ||
+	word1->isRotated() != word0->isRotated() ||
 	vertAlign1 != vertAlign0 ||
 	r1 != r0 || g1 != g0 || b1 != b0) {
       if (word0) {
@@ -717,6 +719,7 @@
       getFontDetails(font, &family, &weight, &style, &scale);
       fontSpec = GString::format("font-family:ff{0:d},{1:s}; font-weight:{2:s}; font-style:{3:s};",
 				 nextFontFaceIdx, family, weight, style);
+      ++nextFontFaceIdx;
       fontDefn = new HTMLGenFontDefn(id, fontFace, fontSpec, 1.0);
     }
     delete fontPath;

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/ImageOutputDev.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/ImageOutputDev.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/ImageOutputDev.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -29,7 +29,6 @@
 ImageOutputDev::ImageOutputDev(char *fileRootA, GBool dumpJPEGA,
 			       GBool dumpRawA, GBool listA) {
   fileRoot = copyString(fileRootA);
-  fileName = (char *)gmalloc((int)strlen(fileRoot) + 30);
   dumpJPEG = dumpJPEGA;
   dumpRaw = dumpRawA;
   list = listA;
@@ -39,7 +38,6 @@
 }
 
 ImageOutputDev::~ImageOutputDev() {
-  gfree(fileName);
   gfree(fileRoot);
 }
 
@@ -60,6 +58,7 @@
 void ImageOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
 				   int width, int height, GBool invert,
 				   GBool inlineImg, GBool interpolate) {
+  GString *fileName;
   FILE *f;
   char buf[4096];
   int size, n, i;
@@ -68,11 +67,12 @@
   if (dumpRaw && !inlineImg) {
 
     // open the image file
-    sprintf(fileName, "%s-%04d.%s",
-	    fileRoot, imgNum, getRawFileExtension(str));
+    fileName = GString::format("{0:s}-{1:04d}.{2:s}",
+			       fileRoot, imgNum, getRawFileExtension(str));
     ++imgNum;
-    if (!(f = fopen(fileName, "wb"))) {
-      error(errIO, -1, "Couldn't open image file '{0:s}'", fileName);
+    if (!(f = openFile(fileName->getCString(), "wb"))) {
+      error(errIO, -1, "Couldn't open image file '{0:t}'", fileName);
+      delete fileName;
       return;
     }
 
@@ -92,10 +92,11 @@
   } else if (dumpJPEG && str->getKind() == strDCT && !inlineImg) {
 
     // open the image file
-    sprintf(fileName, "%s-%04d.jpg", fileRoot, imgNum);
+    fileName = GString::format("{0:s}-{1:04d}.jpg", fileRoot, imgNum);
     ++imgNum;
-    if (!(f = fopen(fileName, "wb"))) {
-      error(errIO, -1, "Couldn't open image file '{0:s}'", fileName);
+    if (!(f = openFile(fileName->getCString(), "wb"))) {
+      error(errIO, -1, "Couldn't open image file '{0:t}'", fileName);
+      delete fileName;
       return;
     }
 
@@ -115,10 +116,11 @@
   } else {
 
     // open the image file and write the PBM header
-    sprintf(fileName, "%s-%04d.pbm", fileRoot, imgNum);
+    fileName = GString::format("{0:s}-{1:04d}.pbm", fileRoot, imgNum);
     ++imgNum;
-    if (!(f = fopen(fileName, "wb"))) {
-      error(errIO, -1, "Couldn't open image file '{0:s}'", fileName);
+    if (!(f = openFile(fileName->getCString(), "wb"))) {
+      error(errIO, -1, "Couldn't open image file '{0:t}'", fileName);
+      delete fileName;
       return;
     }
     fprintf(f, "P4\n");
@@ -144,8 +146,10 @@
   }
 
   if (list) {
-    writeImageInfo(width, height, state, NULL);
+    writeImageInfo(fileName, width, height, state, NULL);
   }
+
+  delete fileName;
 }
 
 void ImageOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
@@ -154,6 +158,7 @@
 			       int *maskColors, GBool inlineImg,
 			       GBool interpolate) {
   GfxColorSpaceMode csMode;
+  GString *fileName;
   FILE *f;
   ImageStream *imgStr;
   Guchar *p;
@@ -173,11 +178,12 @@
   if (dumpRaw && !inlineImg) {
 
     // open the image file
-    sprintf(fileName, "%s-%04d.%s",
-	    fileRoot, imgNum, getRawFileExtension(str));
+    fileName = GString::format("{0:s}-{1:04d}.{2:s}",
+			       fileRoot, imgNum, getRawFileExtension(str));
     ++imgNum;
-    if (!(f = fopen(fileName, "wb"))) {
-      error(errIO, -1, "Couldn't open image file '{0:s}'", fileName);
+    if (!(f = openFile(fileName->getCString(), "wb"))) {
+      error(errIO, -1, "Couldn't open image file '{0:t}'", fileName);
+      delete fileName;
       return;
     }
 
@@ -200,10 +206,11 @@
 	     !inlineImg) {
 
     // open the image file
-    sprintf(fileName, "%s-%04d.jpg", fileRoot, imgNum);
+    fileName = GString::format("{0:s}-{1:04d}.jpg", fileRoot, imgNum);
     ++imgNum;
-    if (!(f = fopen(fileName, "wb"))) {
-      error(errIO, -1, "Couldn't open image file '{0:s}'", fileName);
+    if (!(f = openFile(fileName->getCString(), "wb"))) {
+      error(errIO, -1, "Couldn't open image file '{0:t}'", fileName);
+      delete fileName;
       return;
     }
 
@@ -224,10 +231,11 @@
 	     colorMap->getBits() == 1) {
 
     // open the image file and write the PBM header
-    sprintf(fileName, "%s-%04d.pbm", fileRoot, imgNum);
+    fileName = GString::format("{0:s}-{1:04d}.pbm", fileRoot, imgNum);
     ++imgNum;
-    if (!(f = fopen(fileName, "wb"))) {
-      error(errIO, -1, "Couldn't open image file '{0:s}'", fileName);
+    if (!(f = openFile(fileName->getCString(), "wb"))) {
+      error(errIO, -1, "Couldn't open image file '{0:t}'", fileName);
+      delete fileName;
       return;
     }
     fprintf(f, "P4\n");
@@ -259,10 +267,11 @@
 	     (csMode == csDeviceGray || csMode == csCalGray)) {
 
     // open the image file and write the PGM header
-    sprintf(fileName, "%s-%04d.pgm", fileRoot, imgNum);
+    fileName = GString::format("{0:s}-{1:04d}.pgm", fileRoot, imgNum);
     ++imgNum;
-    if (!(f = fopen(fileName, "wb"))) {
-      error(errIO, -1, "Couldn't open image file '{0:s}'", fileName);
+    if (!(f = openFile(fileName->getCString(), "wb"))) {
+      error(errIO, -1, "Couldn't open image file '{0:t}'", fileName);
+      delete fileName;
       return;
     }
     fprintf(f, "P5\n");
@@ -300,10 +309,11 @@
   } else {
 
     // open the image file and write the PPM header
-    sprintf(fileName, "%s-%04d.ppm", fileRoot, imgNum);
+    fileName = GString::format("{0:s}-{1:04d}.ppm", fileRoot, imgNum);
     ++imgNum;
-    if (!(f = fopen(fileName, "wb"))) {
-      error(errIO, -1, "Couldn't open image file '{0:s}'", fileName);
+    if (!(f = openFile(fileName->getCString(), "wb"))) {
+      error(errIO, -1, "Couldn't open image file '{0:t}'", fileName);
+      delete fileName;
       return;
     }
     fprintf(f, "P6\n");
@@ -343,19 +353,21 @@
   }
 
   if (list) {
-    writeImageInfo(width, height, state, colorMap);
+    writeImageInfo(fileName, width, height, state, colorMap);
   }
+
+  delete fileName;
 }
 
 void ImageOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,
 				     int width, int height,
 				     GfxImageColorMap *colorMap,
-				     Stream *maskStr,
+				     Object *maskRef, Stream *maskStr,
 				     int maskWidth, int maskHeight,
 				     GBool maskInvert, GBool interpolate) {
   drawImage(state, ref, str, width, height, colorMap,
 	    NULL, gFalse, interpolate);
-  drawImageMask(state, ref, maskStr, maskWidth, maskHeight, maskInvert,
+  drawImageMask(state, maskRef, maskStr, maskWidth, maskHeight, maskInvert,
 		gFalse, interpolate);
 }
 
@@ -363,13 +375,13 @@
 					 Stream *str,
 					 int width, int height,
 					 GfxImageColorMap *colorMap,
-					 Stream *maskStr,
+					 Object *maskRef, Stream *maskStr,
 					 int maskWidth, int maskHeight,
 					 GfxImageColorMap *maskColorMap,
 					 double *matte, GBool interpolate) {
   drawImage(state, ref, str, width, height, colorMap,
 	    NULL, gFalse, interpolate);
-  drawImage(state, ref, maskStr, maskWidth, maskHeight, maskColorMap,
+  drawImage(state, maskRef, maskStr, maskWidth, maskHeight, maskColorMap,
 	    NULL, gFalse, interpolate);
 }
 
@@ -401,7 +413,8 @@
   }
 }
 
-void ImageOutputDev::writeImageInfo(int width, int height, GfxState *state,
+void ImageOutputDev::writeImageInfo(GString *fileName,
+				    int width, int height, GfxState *state,
 				    GfxImageColorMap *colorMap) {
   const char *mode;
   double hdpi, vdpi, x0, y0, x1, y1;
@@ -433,7 +446,7 @@
   }
 
   printf("%s: page=%d width=%d height=%d hdpi=%.2f vdpi=%.2f %s%s bpc=%d\n",
-	 fileName, curPageNum, width, height, hdpi, vdpi,
+	 fileName->getCString(), curPageNum, width, height, hdpi, vdpi,
 	 mode ? "colorspace=" : "mask",
 	 mode ? mode : "",
 	 bpc);

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/ImageOutputDev.h
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/ImageOutputDev.h	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/ImageOutputDev.h	2021-02-15 19:17:20 UTC (rev 845)
@@ -85,12 +85,13 @@
   virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str,
 			       int width, int height,
 			       GfxImageColorMap *colorMap,
-			       Stream *maskStr, int maskWidth, int maskHeight,
+			       Object *maskRef, Stream *maskStr,
+			       int maskWidth, int maskHeight,
 			       GBool maskInvert, GBool interpolate);
   virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
 				   int width, int height,
 				   GfxImageColorMap *colorMap,
-				   Stream *maskStr,
+				   Object *maskRef, Stream *maskStr,
 				   int maskWidth, int maskHeight,
 				   GfxImageColorMap *maskColorMap,
 				   double *matte, GBool interpolate);
@@ -99,11 +100,11 @@
 
   Stream *getRawStream(Stream *str);
   const char *getRawFileExtension(Stream *str);
-  void writeImageInfo(int width, int height, GfxState *state,
+  void writeImageInfo(GString *fileName,
+		      int width, int height, GfxState *state,
 		      GfxImageColorMap *colorMap);
 
   char *fileRoot;		// root of output file names
-  char *fileName;		// buffer for output file names
   GBool dumpJPEG;		// set to dump native JPEG files
   GBool dumpRaw;		// set to dump raw PDF-native image files
   GBool list;			// set to write image info to stdout

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/JBIG2Stream.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/JBIG2Stream.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/JBIG2Stream.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -1304,7 +1304,6 @@
   Guint *refSegs;
   int c1, c2, c3;
   Guint i;
-  GBool done;
 
   done = gFalse;
   while (!done && readULong(&segNum)) {
@@ -1723,17 +1722,18 @@
 	    "Bad delta-height value in JBIG2 symbol dictionary");
       goto syntaxError;
     }
-    // sanity check to avoid extremely long run-times with damaged streams
-    if (dh > 1000000) {
-      error(errSyntaxError, getPos(),
-	    "Bogus delta-height value in JBIG2 symbol dictionary");
-      goto syntaxError;
-    }
     symHeight += dh;
     symWidth = 0;
     totalWidth = 0;
     j = i;
 
+    // sanity check to avoid extremely long run-times with damaged streams
+    if (symHeight > 100000) {
+      error(errSyntaxError, getPos(),
+	    "Bogus symbol height value in JBIG2 symbol dictionary");
+      goto syntaxError;
+    }
+
     // read the symbols in this height class
     while (1) {
 
@@ -1760,6 +1760,13 @@
 	goto syntaxError;
       }
 
+      // sanity check to avoid extremely long run-times with damaged streams
+      if (symWidth > 100000) {
+	error(errSyntaxError, getPos(),
+	      "Bogus symbol width value in JBIG2 symbol dictionary");
+	goto syntaxError;
+      }
+
       // using a collective bitmap, so don't read a bitmap here
       if (huff && !refAgg) {
 	symWidths[i] = symWidth;
@@ -1977,6 +1984,15 @@
     error(errSyntaxError, getPos(), "Bad size in JBIG2 text region segment");
     return;
   }
+  // sanity check: if the w/h/x/y values are way out of range, it likely
+  // indicates a damaged JBIG2 stream
+  if (w / 10 > pageW || h / 10 > pageH ||
+      x / 10 > pageW || y / 10 > pageH) {
+    error(errSyntaxError, getPos(),
+	  "Bad size or position in JBIG2 text region segment");
+    done = gTrue;
+    return;
+  }
   extCombOp = segInfoFlags & 7;
 
   // rest of the text region header
@@ -2557,6 +2573,15 @@
       !readUByte(&segInfoFlags)) {
     goto eofError;
   }
+  // sanity check: if the w/h/x/y values are way out of range, it likely
+  // indicates a damaged JBIG2 stream
+  if (w / 10 > pageW || h / 10 > pageH ||
+      x / 10 > pageW || y / 10 > pageH) {
+    error(errSyntaxError, getPos(),
+	  "Bad size or position in JBIG2 halftone region segment");
+    done = gTrue;
+    return;
+  }
   extCombOp = segInfoFlags & 7;
 
   // rest of the halftone region header
@@ -2720,6 +2745,15 @@
 	  "Bad bitmap size in JBIG2 generic region segment");
     return;
   }
+  // sanity check: if the w/h/x/y values are way out of range, it likely
+  // indicates a damaged JBIG2 stream
+  if (w / 10 > pageW || h / 10 > pageH ||
+      x / 10 > pageW || y / 10 > pageH) {
+    error(errSyntaxError, getPos(),
+	  "Bad size or position in JBIG2 generic region segment");
+    done = gTrue;
+    return;
+  }
   extCombOp = segInfoFlags & 7;
 
   // rest of the generic region segment header
@@ -3623,6 +3657,15 @@
 	  "Bad size in JBIG2 generic refinement region segment");
     return;
   }
+  // sanity check: if the w/h/x/y values are way out of range, it likely
+  // indicates a damaged JBIG2 stream
+  if (w / 10 > pageW || h / 10 > pageH ||
+      x / 10 > pageW || y / 10 > pageH) {
+    error(errSyntaxError, getPos(),
+	  "Bad size or position in JBIG2 generic refinement region segment");
+    done = gTrue;
+    return;
+  }
   extCombOp = segInfoFlags & 7;
 
   // rest of the generic refinement region segment header

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/JBIG2Stream.h
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/JBIG2Stream.h	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/JBIG2Stream.h	2021-02-15 19:17:20 UTC (rev 845)
@@ -128,6 +128,7 @@
   Guchar *dataPtr;
   Guchar *dataEnd;
   Guint byteCounter;
+  GBool done;
 
   JArithmeticDecoder *arithDecoder;
   JArithmeticDecoderStats *genericRegionStats;

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/JPXStream.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/JPXStream.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/JPXStream.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -20,7 +20,6 @@
 #include "JPXStream.h"
 
 //~ to do:
-//  - precincts
 //  - ROI
 //  - progression order changes
 //  - packed packet headers
@@ -28,7 +27,6 @@
 //  - make sure all needed JP2/JPX subboxes are parsed (readBoxes)
 //  - can we assume that QCC segments must come after the QCD segment?
 //  - handle tilePartToEOC in readTilePartData
-//  - progression orders 2, 3, and 4
 //  - in coefficient decoding (readCodeBlockData):
 //    - selective arithmetic coding bypass
 //      (this also affects reading the cb->dataLen array)
@@ -325,7 +323,7 @@
 	    for (r = 0; r <= tileComp->nDecompLevels; ++r) {
 	      resLevel = &tileComp->resLevels[r];
 	      if (resLevel->precincts) {
-		for (pre = 0; pre < 1; ++pre) {
+		for (pre = 0; pre < resLevel->nPrecincts; ++pre) {
 		  precinct = &resLevel->precincts[pre];
 		  if (precinct->subbands) {
 		    for (sb = 0; sb < (Guint)(r == 0 ? 1 : 3); ++sb) {
@@ -350,13 +348,13 @@
 		    gfree(precinct->subbands);
 		  }
 		}
-		gfree(img.tiles[i].tileComps[comp].resLevels[r].precincts);
+		gfree(resLevel->precincts);
 	      }
 	    }
-	    gfree(img.tiles[i].tileComps[comp].resLevels);
+	    gfree(tileComp->resLevels);
 	  }
 	}
-	gfree(img.tiles[i].tileComps);
+	gfree(tile->tileComps);
       }
     }
     gfree(img.tiles);
@@ -1036,13 +1034,6 @@
 	error(errSyntaxError, getPos(), "Error in JPX COD marker segment");
 	return jpxDecodeFatalError;
       }
-#if 1 //~ progression orders 2-4 are unimplemented
-      if (progOrder >= 2) {
-	error(errUnimplemented, -1,
-	      "JPX progression order {0:d} is unimplemented",
-	      progOrder);
-      }
-#endif
       codeBlockW += 2;
       codeBlockH += 2;
       for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
@@ -1445,7 +1436,8 @@
   ok = gTrue;
   while (1) {
     if (!readTilePart()) {
-      return jpxDecodeFatalError;
+      ok = gFalse;
+      break;
     }
     if (!readMarkerHdr(&segType, &segLen)) {
       error(errSyntaxError, getPos(), "Error in JPX codestream");
@@ -1497,8 +1489,11 @@
   Guint style, progOrder, nLayers, multiComp, nDecompLevels;
   Guint codeBlockW, codeBlockH, codeBlockStyle, transform;
   Guint precinctSize, qStyle;
-  Guint n, nSBs, nx, ny, sbx0, sby0, comp, segLen;
-  Guint i, j, k, cbX, cbY, r, pre, sb, cbi, cbj;
+  Guint px0, py0, px1, py1;
+  Guint preCol0, preCol1, preRow0, preRow1, preCol, preRow;
+  Guint cbCol0, cbCol1, cbRow0, cbRow1, cbX, cbY;
+  Guint n, nSBs, nx, ny, comp, segLen;
+  Guint i, j, k, r, pre, sb, cbi, cbj;
   int segType, level;
 
   // process the SOT marker segment
@@ -1534,6 +1529,10 @@
     switch (segType) {
     case 0x52:			// COD - coding style default
       cover(34);
+      if (tilePartIdx != 0) {
+	error(errSyntaxError, getPos(), "Extraneous JPX COD marker segment");
+	return gFalse;
+      }
       if (!readUByte(&style) ||
 	  !readUByte(&progOrder) ||
 	  !readUWord(&nLayers) ||
@@ -1553,13 +1552,6 @@
 	error(errSyntaxError, getPos(), "Error in JPX COD marker segment");
 	return gFalse;
       }
-#if 1 //~ progression orders 2-4 are unimplemented
-      if (img.tiles[tileIdx].progOrder >= 2) {
-	error(errUnimplemented, -1,
-	      "JPX progression order {0:d} is unimplemented",
-	      img.tiles[tileIdx].progOrder);
-      }
-#endif
       codeBlockW += 2;
       codeBlockH += 2;
       img.tiles[tileIdx].progOrder = progOrder;
@@ -1607,6 +1599,10 @@
       break;
     case 0x53:			// COC - coding style component
       cover(35);
+      if (tilePartIdx != 0) {
+	error(errSyntaxError, getPos(), "Extraneous JPX COC marker segment");
+	return gFalse;
+      }
       if ((img.nComps > 256 && !readUWord(&comp)) ||
 	  (img.nComps <= 256 && !readUByte(&comp)) ||
 	  comp >= img.nComps ||
@@ -1623,7 +1619,7 @@
 	  nDecompLevels > 31 ||
 	  codeBlockW > 8 ||
 	  codeBlockH > 8) {
-	error(errSyntaxError, getPos(), "Error in JPX COD marker segment");
+	error(errSyntaxError, getPos(), "Error in JPX COC marker segment");
 	return gFalse;
       }
       img.tiles[tileIdx].tileComps[comp].style =
@@ -1659,6 +1655,10 @@
       break;
     case 0x5c:			// QCD - quantization default
       cover(36);
+      if (tilePartIdx != 0) {
+	error(errSyntaxError, getPos(), "Extraneous JPX QCD marker segment");
+	return gFalse;
+      }
       if (!readUByte(&img.tiles[tileIdx].tileComps[0].quantStyle)) {
 	error(errSyntaxError, getPos(), "Error in JPX QCD marker segment");
 	return gFalse;
@@ -1726,6 +1726,10 @@
       break;
     case 0x5d:			// QCC - quantization component
       cover(37);
+      if (tilePartIdx != 0) {
+	error(errSyntaxError, getPos(), "Extraneous JPX QCC marker segment");
+	return gFalse;
+      }
       if ((img.nComps > 256 && !readUWord(&comp)) ||
 	  (img.nComps <= 256 && !readUByte(&comp)) ||
 	  comp >= img.nComps ||
@@ -1786,6 +1790,10 @@
       break;
     case 0x5e:			// RGN - region of interest
       cover(38);
+      if (tilePartIdx != 0) {
+	error(errSyntaxError, getPos(), "Extraneous JPX RGN marker segment");
+	return gFalse;
+      }
 #if 1 //~ ROI is unimplemented
       error(errUnimplemented, -1, "Got a JPX RGN segment");
       if (segLen > 2 &&
@@ -1889,7 +1897,6 @@
   //----- initialize the tile, precincts, and code-blocks
   if (tilePartIdx == 0) {
     tile = &img.tiles[tileIdx];
-    tile->init = gTrue;
     i = tileIdx / img.nXTiles;
     j = tileIdx % img.nXTiles;
     if ((tile->x0 = img.xTileOffset + j * img.xTileSize) < img.xOffset) {
@@ -1919,8 +1926,6 @@
       tileComp->y0 = jpxCeilDiv(tile->y0, tileComp->vSep);
       tileComp->x1 = jpxCeilDiv(tile->x1, tileComp->hSep);
       tileComp->y1 = jpxCeilDiv(tile->y1, tileComp->vSep);
-      tileComp->cbW = 1 << tileComp->codeBlockW;
-      tileComp->cbH = 1 << tileComp->codeBlockH;
       tileComp->w = jpxCeilDivPow2(tileComp->x1, reduction)
 	            - jpxCeilDivPow2(tileComp->x0, reduction);
       tileComp->h = jpxCeilDivPow2(tileComp->y1, reduction)
@@ -1939,12 +1944,26 @@
       tileComp->buf = (int *)gmallocn(n + 8, sizeof(int));
       for (r = 0; r <= tileComp->nDecompLevels; ++r) {
 	resLevel = &tileComp->resLevels[r];
-	k = r == 0 ? tileComp->nDecompLevels
-	           : tileComp->nDecompLevels - r + 1;
-	resLevel->x0 = jpxCeilDivPow2(tileComp->x0, k);
-	resLevel->y0 = jpxCeilDivPow2(tileComp->y0, k);
-	resLevel->x1 = jpxCeilDivPow2(tileComp->x1, k);
-	resLevel->y1 = jpxCeilDivPow2(tileComp->y1, k);
+	resLevel->x0 = jpxCeilDivPow2(tileComp->x0,
+				      tileComp->nDecompLevels - r);
+	resLevel->y0 = jpxCeilDivPow2(tileComp->y0,
+				      tileComp->nDecompLevels - r);
+	resLevel->x1 = jpxCeilDivPow2(tileComp->x1,
+				      tileComp->nDecompLevels - r);
+	resLevel->y1 = jpxCeilDivPow2(tileComp->y1,
+				      tileComp->nDecompLevels - r);
+	resLevel->codeBlockW = r == 0 ? resLevel->precinctWidth
+	                              : resLevel->precinctWidth - 1;
+	if (resLevel->codeBlockW > tileComp->codeBlockW) {
+	  resLevel->codeBlockW = tileComp->codeBlockW;
+	}
+	resLevel->cbW = 1 << resLevel->codeBlockW;
+	resLevel->codeBlockH = r == 0 ? resLevel->precinctHeight
+	                              : resLevel->precinctHeight - 1;
+	if (resLevel->codeBlockH > tileComp->codeBlockH) {
+	  resLevel->codeBlockH = tileComp->codeBlockH;
+	}
+	resLevel->cbH = 1 << resLevel->codeBlockH;
 	// the JPEG 2000 spec says that packets for empty res levels
 	// should all be present in the codestream (B.6, B.9, B.10),
 	// but it appears that encoders drop packets if the res level
@@ -1952,6 +1971,7 @@
 	resLevel->empty = resLevel->x0 == resLevel->x1 ||
 	                  resLevel->y0 == resLevel->y1;
 	if (r == 0) {
+	  nSBs = 1;
 	  resLevel->bx0[0] = resLevel->x0;
 	  resLevel->by0[0] = resLevel->y0;
 	  resLevel->bx1[0] = resLevel->x1;
@@ -1960,18 +1980,19 @@
 	                    (resLevel->bx0[0] == resLevel->bx1[0] ||
 			     resLevel->by0[0] == resLevel->by1[0]);
 	} else {
-	  resLevel->bx0[0] = jpxCeilDivPow2(tileComp->x0 - (1 << (k-1)), k);
-	  resLevel->by0[0] = resLevel->y0;
-	  resLevel->bx1[0] = jpxCeilDivPow2(tileComp->x1 - (1 << (k-1)), k);
-	  resLevel->by1[0] = resLevel->y1;
-	  resLevel->bx0[1] = resLevel->x0;
-	  resLevel->by0[1] = jpxCeilDivPow2(tileComp->y0 - (1 << (k-1)), k);
-	  resLevel->bx1[1] = resLevel->x1;
-	  resLevel->by1[1] = jpxCeilDivPow2(tileComp->y1 - (1 << (k-1)), k);
-	  resLevel->bx0[2] = jpxCeilDivPow2(tileComp->x0 - (1 << (k-1)), k);
-	  resLevel->by0[2] = jpxCeilDivPow2(tileComp->y0 - (1 << (k-1)), k);
-	  resLevel->bx1[2] = jpxCeilDivPow2(tileComp->x1 - (1 << (k-1)), k);
-	  resLevel->by1[2] = jpxCeilDivPow2(tileComp->y1 - (1 << (k-1)), k);
+	  nSBs = 3;
+	  resLevel->bx0[0] = jpxCeilDivPow2(resLevel->x0 - 1, 1);
+	  resLevel->by0[0] = jpxCeilDivPow2(resLevel->y0, 1);
+	  resLevel->bx1[0] = jpxCeilDivPow2(resLevel->x1 - 1, 1);
+	  resLevel->by1[0] = jpxCeilDivPow2(resLevel->y1, 1);
+	  resLevel->bx0[1] = jpxCeilDivPow2(resLevel->x0, 1);
+	  resLevel->by0[1] = jpxCeilDivPow2(resLevel->y0 - 1, 1);
+	  resLevel->bx1[1] = jpxCeilDivPow2(resLevel->x1, 1);
+	  resLevel->by1[1] = jpxCeilDivPow2(resLevel->y1 - 1, 1);
+	  resLevel->bx0[2] = jpxCeilDivPow2(resLevel->x0 - 1, 1);
+	  resLevel->by0[2] = jpxCeilDivPow2(resLevel->y0 - 1, 1);
+	  resLevel->bx1[2] = jpxCeilDivPow2(resLevel->x1 - 1, 1);
+	  resLevel->by1[2] = jpxCeilDivPow2(resLevel->y1 - 1, 1);
 	  resLevel->empty = resLevel->empty &&
 	                    (resLevel->bx0[0] == resLevel->bx1[0] ||
 			     resLevel->by0[0] == resLevel->by1[0]) &&
@@ -1980,135 +2001,155 @@
 	                    (resLevel->bx0[2] == resLevel->bx1[2] ||
 			     resLevel->by0[2] == resLevel->by1[2]);
 	}
-	resLevel->precincts = (JPXPrecinct *)gmallocn(1, sizeof(JPXPrecinct));
-	for (pre = 0; pre < 1; ++pre) {
+	preCol0 = jpxFloorDivPow2(resLevel->x0, resLevel->precinctWidth);
+	preCol1 = jpxCeilDivPow2(resLevel->x1, resLevel->precinctWidth);
+	preRow0 = jpxFloorDivPow2(resLevel->y0, resLevel->precinctHeight);
+	preRow1 = jpxCeilDivPow2(resLevel->y1, resLevel->precinctHeight);
+	resLevel->nPrecincts = (preCol1 - preCol0) * (preRow1 - preRow0);
+	resLevel->precincts = (JPXPrecinct *)gmallocn(resLevel->nPrecincts,
+						      sizeof(JPXPrecinct));
+	for (pre = 0; pre < resLevel->nPrecincts; ++pre) {
 	  resLevel->precincts[pre].subbands = NULL;
 	}
-	for (pre = 0; pre < 1; ++pre) {
-	  precinct = &resLevel->precincts[pre];
-	  precinct->x0 = resLevel->x0;
-	  precinct->y0 = resLevel->y0;
-	  precinct->x1 = resLevel->x1;
-	  precinct->y1 = resLevel->y1;
-	  nSBs = r == 0 ? 1 : 3;
-	  precinct->subbands =
-	      (JPXSubband *)gmallocn(nSBs, sizeof(JPXSubband));
-	  for (sb = 0; sb < nSBs; ++sb) {
-	    precinct->subbands[sb].inclusion = NULL;
-	    precinct->subbands[sb].zeroBitPlane = NULL;
-	    precinct->subbands[sb].cbs = NULL;
-	  }
-	  for (sb = 0; sb < nSBs; ++sb) {
-	    subband = &precinct->subbands[sb];
-	    subband->x0 = resLevel->bx0[sb];
-	    subband->y0 = resLevel->by0[sb];
-	    subband->x1 = resLevel->bx1[sb];
-	    subband->y1 = resLevel->by1[sb];
-	    subband->nXCBs = jpxCeilDivPow2(subband->x1,
-					    tileComp->codeBlockW)
-	                     - jpxFloorDivPow2(subband->x0,
-					       tileComp->codeBlockW);
-	    subband->nYCBs = jpxCeilDivPow2(subband->y1,
-					    tileComp->codeBlockH)
-	                     - jpxFloorDivPow2(subband->y0,
-					       tileComp->codeBlockH);
-	    n = subband->nXCBs > subband->nYCBs ? subband->nXCBs
-	                                        : subband->nYCBs;
-	    for (subband->maxTTLevel = 0, --n;
-		 n;
-		 ++subband->maxTTLevel, n >>= 1) ;
-	    n = 0;
-	    for (level = subband->maxTTLevel; level >= 0; --level) {
-	      nx = jpxCeilDivPow2(subband->nXCBs, level);
-	      ny = jpxCeilDivPow2(subband->nYCBs, level);
-	      n += nx * ny;
+	precinct = resLevel->precincts;
+	for (preRow = preRow0; preRow < preRow1; ++preRow) {
+	  for (preCol = preCol0; preCol < preCol1; ++preCol) {
+	    precinct->subbands =
+	        (JPXSubband *)gmallocn(nSBs, sizeof(JPXSubband));
+	    for (sb = 0; sb < nSBs; ++sb) {
+	      precinct->subbands[sb].inclusion = NULL;
+	      precinct->subbands[sb].zeroBitPlane = NULL;
+	      precinct->subbands[sb].cbs = NULL;
 	    }
-	    subband->inclusion =
-	        (JPXTagTreeNode *)gmallocn(n, sizeof(JPXTagTreeNode));
-	    subband->zeroBitPlane =
-	        (JPXTagTreeNode *)gmallocn(n, sizeof(JPXTagTreeNode));
-	    for (k = 0; k < n; ++k) {
-	      subband->inclusion[k].finished = gFalse;
-	      subband->inclusion[k].val = 0;
-	      subband->zeroBitPlane[k].finished = gFalse;
-	      subband->zeroBitPlane[k].val = 0;
-	    }
-	    subband->cbs = (JPXCodeBlock *)gmallocn(subband->nXCBs *
-						      subband->nYCBs,
-						    sizeof(JPXCodeBlock));
-	    for (k = 0; k < subband->nXCBs * subband->nYCBs; ++k) {
-	      subband->cbs[k].dataLen = NULL;
-	      subband->cbs[k].touched = NULL;
-	      subband->cbs[k].arithDecoder = NULL;
-	      subband->cbs[k].stats = NULL;
-	    }
-	    sbx0 = jpxFloorDivPow2(subband->x0, tileComp->codeBlockW);
-	    sby0 = jpxFloorDivPow2(subband->y0, tileComp->codeBlockH);
-	    if (r == 0) { // (NL)LL
-	      sbCoeffs = tileComp->data;
-	    } else if (sb == 0) { // (NL-r+1)HL
-	      sbCoeffs = tileComp->data
-		         + resLevel->bx1[1] - resLevel->bx0[1];
-	    } else if (sb == 1) { // (NL-r+1)LH
-	      sbCoeffs = tileComp->data
-		         + (resLevel->by1[0] - resLevel->by0[0]) * tileComp->w;
-	    } else { // (NL-r+1)HH
-	      sbCoeffs = tileComp->data
-		         + (resLevel->by1[0] - resLevel->by0[0]) * tileComp->w
-		         + resLevel->bx1[1] - resLevel->bx0[1];
-	    }
-	    cb = subband->cbs;
-	    for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
-	      for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
-		cb->x0 = (sbx0 + cbX) << tileComp->codeBlockW;
-		cb->x1 = cb->x0 + tileComp->cbW;
-		if (subband->x0 > cb->x0) {
-		  cb->x0 = subband->x0;
-		}
-		if (subband->x1 < cb->x1) {
-		  cb->x1 = subband->x1;
-		}
-		cb->y0 = (sby0 + cbY) << tileComp->codeBlockH;
-		cb->y1 = cb->y0 + tileComp->cbH;
-		if (subband->y0 > cb->y0) {
-		  cb->y0 = subband->y0;
-		}
-		if (subband->y1 < cb->y1) {
-		  cb->y1 = subband->y1;
-		}
-		cb->seen = gFalse;
-		cb->lBlock = 3;
-		cb->nextPass = jpxPassCleanup;
-		cb->nZeroBitPlanes = 0;
-		cb->dataLenSize = 1;
-		cb->dataLen = (Guint *)gmalloc(sizeof(Guint));
-		if (r <= tileComp->nDecompLevels - reduction) {
-		  cb->coeffs = sbCoeffs
-		               + (cb->y0 - subband->y0) * tileComp->w
-		               + (cb->x0 - subband->x0);
-		  cb->touched = (char *)gmalloc(1 << (tileComp->codeBlockW
-						      + tileComp->codeBlockH));
-		  cb->len = 0;
-		  for (cbj = 0; cbj < cb->y1 - cb->y0; ++cbj) {
-		    for (cbi = 0; cbi < cb->x1 - cb->x0; ++cbi) {
-		      cb->coeffs[cbj * tileComp->w + cbi] = 0;
+	    for (sb = 0; sb < nSBs; ++sb) {
+	      subband = &precinct->subbands[sb];
+	      if (r == 0) {
+		px0 = preCol << resLevel->precinctWidth;
+		px1 = (preCol + 1) << resLevel->precinctWidth;
+		py0 = preRow << resLevel->precinctHeight;
+		py1 = (preRow + 1) << resLevel->precinctHeight;
+	      } else {
+		px0 = preCol << (resLevel->precinctWidth - 1);
+		px1 = (preCol + 1) << (resLevel->precinctWidth - 1);
+		py0 = preRow << (resLevel->precinctHeight - 1);
+		py1 = (preRow + 1) << (resLevel->precinctHeight - 1);
+	      }
+	      if (px0 < resLevel->bx0[sb]) {
+		px0 = resLevel->bx0[sb];
+	      }
+	      if (px1 > resLevel->bx1[sb]) {
+		px1 = resLevel->bx1[sb];
+	      }
+	      if (py0 < resLevel->by0[sb]) {
+		py0 = resLevel->by0[sb];
+	      }
+	      if (py1 > resLevel->by1[sb]) {
+		py1 = resLevel->by1[sb];
+	      }
+	      if (r == 0) { // (NL)LL
+		sbCoeffs = tileComp->data;
+	      } else if (sb == 0) { // (NL-r+1)HL
+		sbCoeffs = tileComp->data
+                           + resLevel->bx1[1] - resLevel->bx0[1];
+	      } else if (sb == 1) { // (NL-r+1)LH
+		sbCoeffs = tileComp->data
+		           + (resLevel->by1[0] - resLevel->by0[0]) * tileComp->w;
+	      } else { // (NL-r+1)HH
+		sbCoeffs = tileComp->data
+		           + (resLevel->by1[0] - resLevel->by0[0]) * tileComp->w
+		           + (resLevel->bx1[1] - resLevel->bx0[1]);
+	      }
+	      cbCol0 = jpxFloorDivPow2(px0, resLevel->codeBlockW);
+	      cbCol1 = jpxCeilDivPow2(px1, resLevel->codeBlockW);
+	      cbRow0 = jpxFloorDivPow2(py0, resLevel->codeBlockH);
+	      cbRow1 = jpxCeilDivPow2(py1, resLevel->codeBlockH);
+	      subband->nXCBs = cbCol1 - cbCol0;
+	      subband->nYCBs = cbRow1 - cbRow0;
+	      n = subband->nXCBs > subband->nYCBs ? subband->nXCBs
+	                                          : subband->nYCBs;
+	      for (subband->maxTTLevel = 0, --n;
+		   n;
+		   ++subband->maxTTLevel, n >>= 1) ;
+	      n = 0;
+	      for (level = subband->maxTTLevel; level >= 0; --level) {
+		nx = jpxCeilDivPow2(subband->nXCBs, level);
+		ny = jpxCeilDivPow2(subband->nYCBs, level);
+		n += nx * ny;
+	      }
+	      subband->inclusion =
+	          (JPXTagTreeNode *)gmallocn(n, sizeof(JPXTagTreeNode));
+	      subband->zeroBitPlane =
+	          (JPXTagTreeNode *)gmallocn(n, sizeof(JPXTagTreeNode));
+	      for (k = 0; k < n; ++k) {
+		subband->inclusion[k].finished = gFalse;
+		subband->inclusion[k].val = 0;
+		subband->zeroBitPlane[k].finished = gFalse;
+		subband->zeroBitPlane[k].val = 0;
+	      }
+	      subband->cbs = (JPXCodeBlock *)gmallocn(subband->nXCBs *
+						        subband->nYCBs,
+						      sizeof(JPXCodeBlock));
+	      for (k = 0; k < subband->nXCBs * subband->nYCBs; ++k) {
+		subband->cbs[k].dataLen = NULL;
+		subband->cbs[k].touched = NULL;
+		subband->cbs[k].arithDecoder = NULL;
+		subband->cbs[k].stats = NULL;
+	      }
+	      cb = subband->cbs;
+	      for (cbY = cbRow0; cbY < cbRow1; ++cbY) {
+		for (cbX = cbCol0; cbX < cbCol1; ++cbX) {
+		  cb->x0 = cbX << resLevel->codeBlockW;
+		  cb->x1 = cb->x0 + resLevel->cbW;
+		  if (cb->x0 < px0) {
+		    cb->x0 = px0;
+		  }
+		  if (cb->x1 > px1) {
+		    cb->x1 = px1;
+		  }
+		  cb->y0 = cbY << resLevel->codeBlockH;
+		  cb->y1 = cb->y0 + resLevel->cbH;
+		  if (cb->y0 < py0) {
+		    cb->y0 = py0;
+		  }
+		  if (cb->y1 > py1) {
+		    cb->y1 = py1;
+		  }
+		  cb->seen = gFalse;
+		  cb->lBlock = 3;
+		  cb->nextPass = jpxPassCleanup;
+		  cb->nZeroBitPlanes = 0;
+		  cb->dataLenSize = 1;
+		  cb->dataLen = (Guint *)gmalloc(sizeof(Guint));
+		  if (r <= tileComp->nDecompLevels - reduction) {
+		    cb->coeffs = sbCoeffs
+		                 + (cb->y0 - resLevel->by0[sb]) * tileComp->w
+		                 + (cb->x0 - resLevel->bx0[sb]);
+		    cb->touched = (char *)gmalloc(1 << (resLevel->codeBlockW
+							+ resLevel->codeBlockH));
+		    cb->len = 0;
+		    for (cbj = 0; cbj < cb->y1 - cb->y0; ++cbj) {
+		      for (cbi = 0; cbi < cb->x1 - cb->x0; ++cbi) {
+			cb->coeffs[cbj * tileComp->w + cbi] = 0;
+		      }
 		    }
+		    memset(cb->touched, 0,
+			   ((size_t)1 << (resLevel->codeBlockW
+					  + resLevel->codeBlockH)));
+		  } else {
+		    cb->coeffs = NULL;
+		    cb->touched = NULL;
+		    cb->len = 0;
 		  }
-		  memset(cb->touched, 0,
-			 ((size_t)1 << (tileComp->codeBlockW
-					+ tileComp->codeBlockH)));
-		} else {
-		  cb->coeffs = NULL;
-		  cb->touched = NULL;
-		  cb->len = 0;
+		  ++cb;
 		}
-		++cb;
 	      }
 	    }
+	    ++precinct;
 	  }
 	}
       }
     }
+    tile->init = gTrue;
   }
 
   return readTilePartData(tileIdx, tilePartLen, tilePartToEOC);
@@ -2384,13 +2425,17 @@
     switch (tile->progOrder) {
     case 0: // layer, resolution level, component, precinct
       cover(58);
-      if (++tile->comp == img.nComps) {
-	tile->comp = 0;
-	if (++tile->res == tile->maxNDecompLevels + 1) {
-	  tile->res = 0;
-	  if (++tile->layer == tile->nLayers) {
-	    tile->layer = 0;
-	    tile->done = gTrue;
+      resLevel = &tile->tileComps[tile->comp].resLevels[tile->res];
+      if (++tile->precinct == resLevel->nPrecincts) {
+	tile->precinct = 0;
+	if (++tile->comp == img.nComps) {
+	  tile->comp = 0;
+	  if (++tile->res == tile->maxNDecompLevels + 1) {
+	    tile->res = 0;
+	    if (++tile->layer == tile->nLayers) {
+	      tile->layer = 0;
+	      tile->done = gTrue;
+	    }
 	  }
 	}
       }
@@ -2397,34 +2442,42 @@
       break;
     case 1: // resolution level, layer, component, precinct
       cover(59);
-      if (++tile->comp == img.nComps) {
-	tile->comp = 0;
-	if (++tile->layer == tile->nLayers) {
-	  tile->layer = 0;
-	  if (++tile->res == tile->maxNDecompLevels + 1) {
-	    tile->res = 0;
-	    tile->done = gTrue;
+      resLevel = &tile->tileComps[tile->comp].resLevels[tile->res];
+      if (++tile->precinct == resLevel->nPrecincts) {
+	tile->precinct = 0;
+	if (++tile->comp == img.nComps) {
+	  tile->comp = 0;
+	  if (++tile->layer == tile->nLayers) {
+	    tile->layer = 0;
+	    if (++tile->res == tile->maxNDecompLevels + 1) {
+	      tile->res = 0;
+	      tile->done = gTrue;
+	    }
 	  }
 	}
       }
       break;
     case 2: // resolution level, precinct, component, layer
-      //~ this isn't correct -- see B.12.1.3
       cover(60);
+      //~ this is incorrect if there are subsampled components (?)
       if (++tile->layer == tile->nLayers) {
 	tile->layer = 0;
 	if (++tile->comp == img.nComps) {
 	  tile->comp = 0;
-	  if (++tile->res == tile->maxNDecompLevels + 1) {
-	    tile->res = 0;
-	    tile->done = gTrue;
+	  resLevel = &tile->tileComps[tile->comp].resLevels[tile->res];
+	  if (++tile->precinct == resLevel->nPrecincts) {
+	    tile->precinct = 0;
+	    if (++tile->res == tile->maxNDecompLevels + 1) {
+	      tile->res = 0;
+	      tile->done = gTrue;
+	    }
 	  }
 	}
       }
       break;
     case 3: // precinct, component, resolution level, layer
-      //~ this isn't correct -- see B.12.1.4
       cover(61);
+      //~ this is incorrect if there are subsampled components (?)
       if (++tile->layer == tile->nLayers) {
 	tile->layer = 0;
 	if (++tile->res == tile->maxNDecompLevels + 1) {
@@ -2431,21 +2484,28 @@
 	  tile->res = 0;
 	  if (++tile->comp == img.nComps) {
 	    tile->comp = 0;
-	    tile->done = gTrue;
+	    resLevel = &tile->tileComps[tile->comp].resLevels[tile->res];
+	    if (++tile->precinct == resLevel->nPrecincts) {
+	      tile->precinct = 0;
+	      tile->done = gTrue;
+	    }
 	  }
 	}
       }
       break;
     case 4: // component, precinct, resolution level, layer
-      //~ this isn't correct -- see B.12.1.5
       cover(62);
       if (++tile->layer == tile->nLayers) {
 	tile->layer = 0;
 	if (++tile->res == tile->maxNDecompLevels + 1) {
 	  tile->res = 0;
-	  if (++tile->comp == img.nComps) {
-	    tile->comp = 0;
-	    tile->done = gTrue;
+	  resLevel = &tile->tileComps[tile->comp].resLevels[tile->res];
+	  if (++tile->precinct == resLevel->nPrecincts) {
+	    tile->precinct = 0;
+	    if (++tile->comp == img.nComps) {
+	      tile->comp = 0;
+	      tile->done = gTrue;
+	    }
 	  }
 	}
       }
@@ -2515,13 +2575,13 @@
       for (y0 = cb->y0, coeff0 = cb->coeffs, touched0 = cb->touched;
 	   y0 < cb->y1;
 	   y0 += 4, coeff0 += 4 * tileComp->w,
-	     touched0 += 4 << tileComp->codeBlockW) {
+	     touched0 += 4 << resLevel->codeBlockW) {
 	for (x = cb->x0, coeff1 = coeff0, touched1 = touched0;
 	     x < cb->x1;
 	     ++x, ++coeff1, ++touched1) {
 	  for (y1 = 0, coeff = coeff1, touched = touched1;
 	       y1 < 4 && y0+y1 < cb->y1;
-	       ++y1, coeff += tileComp->w, touched += tileComp->cbW) {
+	       ++y1, coeff += tileComp->w, touched += resLevel->cbW) {
 	    if (!*coeff) {
 	      horiz = vert = diag = 0;
 	      horizSign = vertSign = 2;
@@ -2590,13 +2650,13 @@
       for (y0 = cb->y0, coeff0 = cb->coeffs, touched0 = cb->touched;
 	   y0 < cb->y1;
 	   y0 += 4, coeff0 += 4 * tileComp->w,
-	     touched0 += 4 << tileComp->codeBlockW) {
+	     touched0 += 4 << resLevel->codeBlockW) {
 	for (x = cb->x0, coeff1 = coeff0, touched1 = touched0;
 	     x < cb->x1;
 	     ++x, ++coeff1, ++touched1) {
 	  for (y1 = 0, coeff = coeff1, touched = touched1;
 	       y1 < 4 && y0+y1 < cb->y1;
-	       ++y1, coeff += tileComp->w, touched += tileComp->cbW) {
+	       ++y1, coeff += tileComp->w, touched += resLevel->cbW) {
 	    if (*coeff && !*touched) {
 	      if (*coeff == 1 || *coeff == -1) {
 		all = 0;
@@ -2651,7 +2711,7 @@
       for (y0 = cb->y0, coeff0 = cb->coeffs, touched0 = cb->touched;
 	   y0 < cb->y1;
 	   y0 += 4, coeff0 += 4 * tileComp->w,
-	     touched0 += 4 << tileComp->codeBlockW) {
+	     touched0 += 4 << resLevel->codeBlockW) {
 	for (x = cb->x0, coeff1 = coeff0, touched1 = touched0;
 	     x < cb->x1;
 	     ++x, ++coeff1, ++touched1) {
@@ -2658,9 +2718,9 @@
 	  y1 = 0;
 	  if (y0 + 3 < cb->y1 &&
 	      !(*touched1) &&
-	      !(touched1[tileComp->cbW]) &&
-	      !(touched1[2 * tileComp->cbW]) &&
-	      !(touched1[3 * tileComp->cbW]) &&
+	      !(touched1[resLevel->cbW]) &&
+	      !(touched1[2 * resLevel->cbW]) &&
+	      !(touched1[3 * resLevel->cbW]) &&
 	      (x == cb->x0 || y0 == cb->y0 ||
 	       !coeff1[-(int)tileComp->w - 1]) &&
 	      (y0 == cb->y0 ||
@@ -2702,9 +2762,9 @@
 	    }
 	  }
 	  for (coeff = &coeff1[y1 * tileComp->w],
-		 touched = &touched1[y1 << tileComp->codeBlockW];
+		 touched = &touched1[y1 << resLevel->codeBlockW];
 	       y1 < 4 && y0 + y1 < cb->y1;
-	       ++y1, coeff += tileComp->w, touched += tileComp->cbW) {
+	       ++y1, coeff += tileComp->w, touched += resLevel->cbW) {
 	    if (!*touched) {
 	      horiz = vert = diag = 0;
 	      horizSign = vertSign = 2;
@@ -2814,7 +2874,7 @@
   int shift2;
   double mu;
   int val;
-  Guint r, cbX, cbY, x, y;
+  Guint r, pre, cbX, cbY, x, y;
 
   cover(68);
 
@@ -2821,8 +2881,6 @@
   //----- (NL)LL subband (resolution level 0)
 
   resLevel = &tileComp->resLevels[0];
-  precinct = &resLevel->precincts[0];
-  subband = &precinct->subbands[0];
 
   // i-quant parameters
   qStyle = tileComp->quantStyle & 0x1f;
@@ -2843,44 +2901,48 @@
   }
 
   // do fixed point adjustment and dequantization on (NL)LL
-  cb = subband->cbs;
-  for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
-    for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
-      for (y = cb->y0, coeff0 = cb->coeffs, touched0 = cb->touched;
-	   y < cb->y1;
-	   ++y, coeff0 += tileComp->w, touched0 += tileComp->cbW) {
-	for (x = cb->x0, coeff = coeff0, touched = touched0;
-	     x < cb->x1;
-	     ++x, ++coeff, ++touched) {
-	  val = *coeff;
-	  if (val != 0) {
-	    shift2 = shift - (cb->nZeroBitPlanes + cb->len + *touched);
-	    if (shift2 > 0) {
-	      cover(94);
-	      if (val < 0) {
-		val = (val << shift2) - (1 << (shift2 - 1));
+  for (pre = 0; pre < resLevel->nPrecincts; ++pre) {
+    precinct = &resLevel->precincts[pre];
+    subband = &precinct->subbands[0];
+    cb = subband->cbs;
+    for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
+      for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
+	for (y = cb->y0, coeff0 = cb->coeffs, touched0 = cb->touched;
+	     y < cb->y1;
+	     ++y, coeff0 += tileComp->w, touched0 += resLevel->cbW) {
+	  for (x = cb->x0, coeff = coeff0, touched = touched0;
+	       x < cb->x1;
+	       ++x, ++coeff, ++touched) {
+	    val = *coeff;
+	    if (val != 0) {
+	      shift2 = shift - (cb->nZeroBitPlanes + cb->len + *touched);
+	      if (shift2 > 0) {
+		cover(94);
+		if (val < 0) {
+		  val = (val << shift2) - (1 << (shift2 - 1));
+		} else {
+		  val = (val << shift2) + (1 << (shift2 - 1));
+		}
 	      } else {
-		val = (val << shift2) + (1 << (shift2 - 1));
+		cover(95);
+		val >>= -shift2;
 	      }
-	    } else {
-	      cover(95);
-	      val >>= -shift2;
-	    }
-	    if (qStyle == 0) {
-	      cover(96);
-	      if (tileComp->transform == 0) {
-		cover(97);
-		val &= -1 << (fracBits - tileComp->prec);
+	      if (qStyle == 0) {
+		cover(96);
+		if (tileComp->transform == 0) {
+		  cover(97);
+		  val &= -1 << (fracBits - tileComp->prec);
+		}
+	      } else {
+		cover(98);
+		val = (int)((double)val * mu);
 	      }
-	    } else {
-	      cover(98);
-	      val = (int)((double)val * mu);
 	    }
+	    *coeff = val;
 	  }
-	  *coeff = val;
 	}
+	++cb;
       }
-      ++cb;
     }
   }
 
@@ -2914,11 +2976,10 @@
   int val;
   int *dataPtr, *bufPtr;
   Guint nx1, nx2, ny1, ny2, offset;
-  Guint x, y, sb, cbX, cbY;
+  Guint x, y, sb, pre, cbX, cbY;
 
   qStyle = tileComp->quantStyle & 0x1f;
   guard = (tileComp->quantStyle >> 5) & 7;
-  precinct = &resLevel->precincts[0];
 
   //----- compute subband bounds
 
@@ -2931,10 +2992,10 @@
   //   | LH | HH | <- ny1
   //   +----+----+
   //               <- ny2
-  nx1 = precinct->subbands[1].x1 - precinct->subbands[1].x0;
-  nx2 = nx1 + precinct->subbands[0].x1 - precinct->subbands[0].x0;
-  ny1 = precinct->subbands[0].y1 - precinct->subbands[0].y0;
-  ny2 = ny1 + precinct->subbands[1].y1 - precinct->subbands[1].y0;
+  nx1 = resLevel->bx1[1] - resLevel->bx0[1];
+  nx2 = nx1 + resLevel->bx1[0] - resLevel->bx0[0];
+  ny1 = resLevel->by1[0] - resLevel->by0[0];
+  ny2 = ny1 + resLevel->by1[1] - resLevel->by0[1];
   if (nx2 == 0 || ny2 == 0) {
     return;
   }
@@ -2965,44 +3026,48 @@
     }
 
     // fixed point adjustment and dequantization
-    subband = &precinct->subbands[sb];
-    cb = subband->cbs;
-    for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
-      for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
-	for (y = cb->y0, coeff0 = cb->coeffs, touched0 = cb->touched;
-	     y < cb->y1;
-	     ++y, coeff0 += tileComp->w, touched0 += tileComp->cbW) {
-	  for (x = cb->x0, coeff = coeff0, touched = touched0;
-	       x < cb->x1;
-	       ++x, ++coeff, ++touched) {
-	    val = *coeff;
-	    if (val != 0) {
-	      shift2 = shift - (cb->nZeroBitPlanes + cb->len + *touched);
-	      if (shift2 > 0) {
-		cover(74);
-		if (val < 0) {
-		  val = (val << shift2) - (1 << (shift2 - 1));
+
+    for (pre = 0; pre < resLevel->nPrecincts; ++pre) {
+      precinct = &resLevel->precincts[pre];
+      subband = &precinct->subbands[sb];
+      cb = subband->cbs;
+      for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
+	for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
+	  for (y = cb->y0, coeff0 = cb->coeffs, touched0 = cb->touched;
+	       y < cb->y1;
+	       ++y, coeff0 += tileComp->w, touched0 += resLevel->cbW) {
+	    for (x = cb->x0, coeff = coeff0, touched = touched0;
+		 x < cb->x1;
+		 ++x, ++coeff, ++touched) {
+	      val = *coeff;
+	      if (val != 0) {
+		shift2 = shift - (cb->nZeroBitPlanes + cb->len + *touched);
+		if (shift2 > 0) {
+		  cover(74);
+		  if (val < 0) {
+		    val = (val << shift2) - (1 << (shift2 - 1));
+		  } else {
+		    val = (val << shift2) + (1 << (shift2 - 1));
+		  }
 		} else {
-		  val = (val << shift2) + (1 << (shift2 - 1));
+		  cover(75);
+		  val >>= -shift2;
 		}
-	      } else {
-		cover(75);
-		val >>= -shift2;
-	      }
-	      if (qStyle == 0) {
-		cover(76);
-		if (tileComp->transform == 0) {
-		  val &= -1 << (fracBits - tileComp->prec);
+		if (qStyle == 0) {
+		  cover(76);
+		  if (tileComp->transform == 0) {
+		    val &= -1 << (fracBits - tileComp->prec);
+		  }
+		} else {
+		  cover(77);
+		  val = (int)((double)val * mu);
 		}
-	      } else {
-		cover(77);
-		val = (int)((double)val * mu);
 	      }
+	      *coeff = val;
 	    }
-	    *coeff = val;
 	  }
+	  ++cb;
 	}
-	++cb;
       }
     }
   }
@@ -3010,13 +3075,9 @@
   //----- inverse transform
 
   // horizontal (row) transforms
-  if (r == tileComp->nDecompLevels) {
-    offset = 3 + (tileComp->x0 & 1);
-  } else {
-    offset = 3 + (tileComp->resLevels[r+1].x0 & 1);
-  }
+  offset = 3 + (resLevel->x0 & 1);
   for (y = 0, dataPtr = tileComp->data; y < ny2; ++y, dataPtr += tileComp->w) {
-    if (precinct->subbands[0].x0 == precinct->subbands[1].x0) {
+    if (resLevel->bx0[0] == resLevel->bx0[1]) {
       // fetch LL/LH
       for (x = 0, bufPtr = tileComp->buf + offset;
 	   x < nx1;
@@ -3050,13 +3111,9 @@
   }
 
   // vertical (column) transforms
-  if (r == tileComp->nDecompLevels) {
-    offset = 3 + (tileComp->y0 & 1);
-  } else {
-    offset = 3 + (tileComp->resLevels[r+1].y0 & 1);
-  }
+  offset = 3 + (resLevel->y0 & 1);
   for (x = 0, dataPtr = tileComp->data; x < nx2; ++x, ++dataPtr) {
-    if (precinct->subbands[1].y0 == precinct->subbands[0].y0) {
+    if (resLevel->by0[0] == resLevel->by0[1]) {
       // fetch LL/HL
       for (y = 0, bufPtr = tileComp->buf + offset;
 	   y < ny1;

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/JPXStream.h
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/JPXStream.h	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/JPXStream.h	2021-02-15 19:17:20 UTC (rev 845)
@@ -135,7 +135,6 @@
 
 struct JPXSubband {
   //----- computed
-  Guint x0, y0, x1, y1;		// bounds
   Guint nXCBs, nYCBs;		// number of code-blocks in the x and y
 				//   directions
 
@@ -152,9 +151,6 @@
 //------------------------------------------------------------------------
 
 struct JPXPrecinct {
-  //----- computed
-  Guint x0, y0, x1, y1;		// bounds of the precinct
-
   //----- children
   JPXSubband *subbands;		// the subbands
 };
@@ -165,12 +161,18 @@
   //----- from the COD and COC segments (main and tile)
   Guint precinctWidth;		// log2(precinct width)
   Guint precinctHeight;		// log2(precinct height)
+  Guint nPrecincts;
 
   //----- computed
-  Guint x0, y0, x1, y1;		// bounds of the tile-comp (for this res level)
+  Guint x0, y0, x1, y1;		// bounds of this tile-comp at this res level
   Guint bx0[3], by0[3],		// subband bounds
         bx1[3], by1[3];
-  GBool empty;			// true if all subbands are zero width or height
+  Guint codeBlockW;		// log2(code-block width)
+  Guint codeBlockH;		// log2(code-block height)
+  Guint cbW;			// code-block width
+  Guint cbH;			// code-block height
+  GBool empty;			// true if all subbands and precincts are
+				//   zero width or height
 
   //---- children
   JPXPrecinct *precincts;	// the precincts
@@ -201,8 +203,6 @@
   //----- computed
   Guint x0, y0, x1, y1;		// bounds of the tile-comp, in ref coords
   Guint w, h;			// data size = {x1 - x0, y1 - y0} >> reduction
-  Guint cbW;			// code-block width
-  Guint cbH;			// code-block height
 
   //----- image data
   int *data;			// the decoded image data

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Lexer.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Lexer.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Lexer.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -237,11 +237,6 @@
       switch (c = getChar()) {
 
       case EOF:
-#if 0
-      // This breaks some PDF files, e.g., ones from Photoshop.
-      case '\r':
-      case '\n':
-#endif
 	error(errSyntaxError, getPos(), "Unterminated string");
 	done = gTrue;
 	break;
@@ -259,6 +254,16 @@
 	}
 	break;
 
+      case '\r':
+	// The PDF spec says that any literal end-of-line sequence
+	// (LF, CR, CR+LF) is translated to a single LF char.
+	c = lookChar();
+	if (c == '\n') {
+	  getChar();
+	}
+	c2 = '\n';
+	break;
+
       case '\\':
 	switch (c = getChar()) {
 	case 'n':

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Object.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Object.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Object.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -45,11 +45,12 @@
 #ifdef DEBUG_MEM
 #if MULTITHREADED
 GAtomicCounter Object::numAlloc[numObjTypes] =
+  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 #else
 long Object::numAlloc[numObjTypes] =
-#endif
   {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 #endif
+#endif // DEBUG_MEM
 
 Object *Object::initArray(XRef *xref) {
   initObj(objArray);
@@ -229,13 +230,15 @@
   long t;
 
   t = 0;
-  for (i = 0; i < numObjTypes; ++i)
+  for (i = 0; i < numObjTypes; ++i) {
     t += numAlloc[i];
+  }
   if (t > 0) {
     fprintf(f, "Allocated objects:\n");
     for (i = 0; i < numObjTypes; ++i) {
-      if (numAlloc[i] > 0)
+      if (numAlloc[i] > 0) {
 	fprintf(f, "  %-20s: %6ld\n", objTypeNames[i], numAlloc[i]);
+      }
     }
   }
 #endif

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/OptionalContent.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/OptionalContent.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/OptionalContent.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -172,6 +172,7 @@
   int policy;
   Ref ref;
   Object obj2, obj3, obj4, obj5;
+  GBool gotOCG;
   int i;
 
   if (obj->isNull()) {
@@ -224,34 +225,40 @@
 	obj2.free();
 	return gFalse;
       }
+      gotOCG = gFalse;
       for (i = 0; i < obj4.arrayGetLength(); ++i) {
 	obj4.arrayGetNF(i, &obj5);
 	if (obj5.isRef()) {
 	  ref = obj5.getRef();
-	  if (!(ocg = findOCG(&ref))) {
-	    obj5.free();
-	    obj4.free();
-	    obj3.free();
-	    obj2.free();
-	    return gFalse;
+	  if ((ocg = findOCG(&ref))) {
+	    gotOCG = gTrue;
+	    switch (policy) {
+	    case ocPolicyAllOn:
+	      *visible = *visible && ocg->getState();
+	      break;
+	    case ocPolicyAnyOn:
+	      *visible = *visible || ocg->getState();
+	      break;
+	    case ocPolicyAnyOff:
+	      *visible = *visible || !ocg->getState();
+	      break;
+	    case ocPolicyAllOff:
+	      *visible = *visible && !ocg->getState();
+	      break;
+	    }
 	  }
-	  switch (policy) {
-	  case ocPolicyAllOn:
-	    *visible = *visible && ocg->getState();
-	    break;
-	  case ocPolicyAnyOn:
-	    *visible = *visible || ocg->getState();
-	    break;
-	  case ocPolicyAnyOff:
-	    *visible = *visible || !ocg->getState();
-	    break;
-	  case ocPolicyAllOff:
-	    *visible = *visible && !ocg->getState();
-	    break;
-	  }
 	}
 	obj5.free();
       }
+      if (!gotOCG) {
+	// if the "OCGs" array is "empty or contains references only
+	// to null or deleted objects", this OCMD doesn't have any
+	// effect
+	obj4.free();
+	obj3.free();
+	obj2.free();
+	return gFalse;
+      }
       obj4.free();
     }
     obj3.free();

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/OutputDev.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/OutputDev.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/OutputDev.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -113,7 +113,7 @@
 void OutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,
 				int width, int height,
 				GfxImageColorMap *colorMap,
-				Stream *maskStr,
+				Object *maskRef, Stream *maskStr,
 				int maskWidth, int maskHeight,
 				GBool maskInvert, GBool interpolate) {
   drawImage(state, ref, str, width, height, colorMap, NULL, gFalse,
@@ -123,7 +123,7 @@
 void OutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
 				    int width, int height,
 				    GfxImageColorMap *colorMap,
-				    Stream *maskStr,
+				    Object *maskRef, Stream *maskStr,
 				    int maskWidth, int maskHeight,
 				    GfxImageColorMap *maskColorMap,
 				    double *matte, GBool interpolate) {

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/OutputDev.h
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/OutputDev.h	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/OutputDev.h	2021-02-15 19:17:20 UTC (rev 845)
@@ -24,9 +24,7 @@
 struct GfxColor;
 class GfxColorSpace;
 class GfxImageColorMap;
-class GfxFunctionShading;
-class GfxAxialShading;
-class GfxRadialShading;
+class GfxShading;
 class Stream;
 class Links;
 class Link;
@@ -61,11 +59,6 @@
   // operations.
   virtual GBool useTilingPatternFill() { return gFalse; }
 
-  // Does this device use functionShadedFill(), axialShadedFill(), and
-  // radialShadedFill()?  If this returns false, these shaded fills
-  // will be reduced to a series of other drawing operations.
-  virtual GBool useShadedFills() { return gFalse; }
-
   // Does this device use drawForm()?  If this returns false,
   // form-type XObjects will be interpreted (i.e., unrolled).
   virtual GBool useDrawForm() { return gFalse; }
@@ -166,13 +159,8 @@
 				 double *mat, double *bbox,
 				 int x0, int y0, int x1, int y1,
 				 double xStep, double yStep) {}
-  virtual GBool functionShadedFill(GfxState *state,
-				   GfxFunctionShading *shading)
+  virtual GBool shadedFill(GfxState *state, GfxShading *shading)
     { return gFalse; }
-  virtual GBool axialShadedFill(GfxState *state, GfxAxialShading *shading)
-    { return gFalse; }
-  virtual GBool radialShadedFill(GfxState *state, GfxRadialShading *shading)
-    { return gFalse; }
 
   //----- path clipping
   virtual void clip(GfxState *state) {}
@@ -212,12 +200,13 @@
   virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str,
 			       int width, int height,
 			       GfxImageColorMap *colorMap,
-			       Stream *maskStr, int maskWidth, int maskHeight,
+			       Object *maskRef, Stream *maskStr,
+			       int maskWidth, int maskHeight,
 			       GBool maskInvert, GBool interpolate);
   virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
 				   int width, int height,
 				   GfxImageColorMap *colorMap,
-				   Stream *maskStr,
+				   Object *maskRef, Stream *maskStr,
 				   int maskWidth, int maskHeight,
 				   GfxImageColorMap *maskColorMap,
 				   double *matte, GBool interpolate);
@@ -253,10 +242,6 @@
   //----- links
   virtual void processLink(Link *link) {}
 
-#if 1 //~tmp: turn off anti-aliasing temporarily
-  virtual void setInShading(GBool sh) {}
-#endif
-
 private:
 
   double defCTM[6];		// default coordinate transform matrix

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/PDFCore.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/PDFCore.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/PDFCore.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -26,7 +26,7 @@
 #include "PDFDoc.h"
 #include "Link.h"
 #include "Annot.h"
-#include "Form.h"
+#include "AcroForm.h"
 #include "OptionalContent.h"
 #include "TileMap.h"
 #include "TileCache.h"
@@ -260,9 +260,15 @@
   if (page <= 0 || page > doc->getNumPages()) {
     return;
   }
-  if (scrollToTop ||
-      state->getDisplayMode() == displayContinuous ||
-      state->getDisplayMode() == displaySideBySideContinuous) {
+  if (!scrollToTop &&
+      (state->getDisplayMode() == displayContinuous ||
+       state->getDisplayMode() == displaySideBySideContinuous)) {
+    scrollY = tileMap->getPageTopY(page)
+              + (state->getScrollY()
+		 - tileMap->getPageTopY(tileMap->getFirstPage()));
+  } else if (scrollToTop ||
+	     state->getDisplayMode() == displayContinuous ||
+	     state->getDisplayMode() == displaySideBySideContinuous) {
     scrollY = tileMap->getPageTopY(page);
   } else if (scrollToBottom) {
     scrollY = tileMap->getPageBottomY(page);
@@ -679,19 +685,23 @@
 	state->getDisplayMode() == displaySideBySideContinuous) {
       next = state->getDisplayMode() == displaySideBySideContinuous ? 2 : 1;
       topPage = tileMap->getFirstPage();
-      topPageY = tileMap->getPageTopY(topPage);
-      sy = state->getScrollY();
-      dy = sy - topPageY;
-      // note: dy can be negative here if the inter-page gap is at the
-      // top of the window
-      if (-16 < dy && dy < 16) {
-	state->setScrollPosition(state->getScrollPage(), x, topPageY);
-      } else if (topPage + next <= doc->getNumPages()) {
-	topPage += next;
+      // NB: topPage can be out of bounds here, because the scroll
+      // position isn't adjusted until finishUpdate is called, below
+      if (topPage > 0 && topPage <= doc->getNumPages()) {
 	topPageY = tileMap->getPageTopY(topPage);
+	sy = state->getScrollY();
 	dy = sy - topPageY;
-	if (-16 < dy && dy < 0) {
+	// note: dy can be negative here if the inter-page gap is at the
+	// top of the window
+	if (-16 < dy && dy < 16) {
 	  state->setScrollPosition(state->getScrollPage(), x, topPageY);
+	} else if (topPage + next <= doc->getNumPages()) {
+	  topPage += next;
+	  topPageY = tileMap->getPageTopY(topPage);
+	  dy = sy - topPageY;
+	  if (-16 < dy && dy < 0) {
+	    state->setScrollPosition(state->getScrollPage(), x, topPageY);
+	  }
 	}
       }
     }
@@ -1100,7 +1110,7 @@
 
   // build the list of rectangles
   //~ this doesn't handle RtL, vertical, or rotated text
-  loadText(selectPage);
+  loadText(page);
   rects = new GList();
   if (begin.colIdx == end.colIdx &&
       begin.parIdx == end.parIdx &&
@@ -1108,9 +1118,9 @@
     // same line
     text->convertPosToPointUpper(&begin, &x0, &y0);
     text->convertPosToPointLower(&end, &x1, &y1);
-    cvtDevToUser(selectPage, (int)(x0 + 0.5), (int)(y0 + 0.5), &ux0, &uy0);
-    cvtDevToUser(selectPage, (int)(x1 + 0.5), (int)(y1 + 0.5), &ux1, &uy1);
-    rects->append(new SelectRect(selectPage, ux0, uy0, ux1, uy1));
+    cvtDevToUser(page, (int)(x0 + 0.5), (int)(y0 + 0.5), &ux0, &uy0);
+    cvtDevToUser(page, (int)(x1 + 0.5), (int)(y1 + 0.5), &ux1, &uy1);
+    rects->append(new SelectRect(page, ux0, uy0, ux1, uy1));
   } else if (begin.colIdx == end.colIdx) {
     // same column
     text->convertPosToPointUpper(&begin, &x0, &y0);
@@ -1117,42 +1127,42 @@
     text->convertPosToPointRightEdge(&begin, &x1, &y1);
     text->convertPosToPointLeftEdge(&end, &x2, &y2);
     text->convertPosToPointLower(&end, &x3, &y3);
-    cvtDevToUser(selectPage, (int)(x0 + 0.5), (int)(y0 + 0.5), &ux0, &uy0);
-    cvtDevToUser(selectPage, (int)(x1 + 0.5), (int)(y1 + 0.5), &ux1, &uy1);
-    rects->append(new SelectRect(selectPage, ux0, uy0, ux1, uy1));
-    cvtDevToUser(selectPage, (int)(x2 + 0.5), (int)(y1 + 0.5), &ux0, &uy0);
-    cvtDevToUser(selectPage, (int)(x1 + 0.5), (int)(y2 + 0.5), &ux1, &uy1);
-    rects->append(new SelectRect(selectPage, ux0, uy0, ux1, uy1));
-    cvtDevToUser(selectPage, (int)(x2 + 0.5), (int)(y2 + 0.5), &ux0, &uy0);
-    cvtDevToUser(selectPage, (int)(x3 + 0.5), (int)(y3 + 0.5), &ux1, &uy1);
-    rects->append(new SelectRect(selectPage, ux0, uy0, ux1, uy1));
+    cvtDevToUser(page, (int)(x0 + 0.5), (int)(y0 + 0.5), &ux0, &uy0);
+    cvtDevToUser(page, (int)(x1 + 0.5), (int)(y1 + 0.5), &ux1, &uy1);
+    rects->append(new SelectRect(page, ux0, uy0, ux1, uy1));
+    cvtDevToUser(page, (int)(x2 + 0.5), (int)(y1 + 0.5), &ux0, &uy0);
+    cvtDevToUser(page, (int)(x1 + 0.5), (int)(y2 + 0.5), &ux1, &uy1);
+    rects->append(new SelectRect(page, ux0, uy0, ux1, uy1));
+    cvtDevToUser(page, (int)(x2 + 0.5), (int)(y2 + 0.5), &ux0, &uy0);
+    cvtDevToUser(page, (int)(x3 + 0.5), (int)(y3 + 0.5), &ux1, &uy1);
+    rects->append(new SelectRect(page, ux0, uy0, ux1, uy1));
   } else {
     // different columns
     text->convertPosToPointUpper(&begin, &x0, &y0);
     text->convertPosToPointRightEdge(&begin, &x1, &y1);
     text->getColumnLowerLeft(begin.colIdx, &x2, &y2);
-    cvtDevToUser(selectPage, (int)(x0 + 0.5), (int)(y0 + 0.5), &ux0, &uy0);
-    cvtDevToUser(selectPage, (int)(x1 + 0.5), (int)(y1 + 0.5), &ux1, &uy1);
-    rects->append(new SelectRect(selectPage, ux0, uy0, ux1, uy1));
-    cvtDevToUser(selectPage, (int)(x2 + 0.5), (int)(y1 + 0.5), &ux0, &uy0);
-    cvtDevToUser(selectPage, (int)(x1 + 0.5), (int)(y2 + 0.5), &ux1, &uy1);
-    rects->append(new SelectRect(selectPage, ux0, uy0, ux1, uy1));
+    cvtDevToUser(page, (int)(x0 + 0.5), (int)(y0 + 0.5), &ux0, &uy0);
+    cvtDevToUser(page, (int)(x1 + 0.5), (int)(y1 + 0.5), &ux1, &uy1);
+    rects->append(new SelectRect(page, ux0, uy0, ux1, uy1));
+    cvtDevToUser(page, (int)(x2 + 0.5), (int)(y1 + 0.5), &ux0, &uy0);
+    cvtDevToUser(page, (int)(x1 + 0.5), (int)(y2 + 0.5), &ux1, &uy1);
+    rects->append(new SelectRect(page, ux0, uy0, ux1, uy1));
     for (colIdx = begin.colIdx + 1; colIdx < end.colIdx; ++colIdx) {
       text->getColumnLowerLeft(colIdx, &x0, &y0);
       text->getColumnUpperRight(colIdx, &x1, &y1);
-      cvtDevToUser(selectPage, (int)(x0 + 0.5), (int)(y1 + 0.5), &ux0, &uy0);
-      cvtDevToUser(selectPage, (int)(x1 + 0.5), (int)(y0 + 0.5), &ux1, &uy1);
-      rects->append(new SelectRect(selectPage, ux0, uy0, ux1, uy1));
+      cvtDevToUser(page, (int)(x0 + 0.5), (int)(y1 + 0.5), &ux0, &uy0);
+      cvtDevToUser(page, (int)(x1 + 0.5), (int)(y0 + 0.5), &ux1, &uy1);
+      rects->append(new SelectRect(page, ux0, uy0, ux1, uy1));
     }
     text->getColumnUpperRight(end.colIdx, &x0, &y0);
     text->convertPosToPointLeftEdge(&end, &x1, &y1);
     text->convertPosToPointLower(&end, &x2, &y2);
-    cvtDevToUser(selectPage, (int)(x1 + 0.5), (int)(y0 + 0.5), &ux0, &uy0);
-    cvtDevToUser(selectPage, (int)(x0 + 0.5), (int)(y1 + 0.5), &ux1, &uy1);
-    rects->append(new SelectRect(selectPage, ux0, uy0, ux1, uy1));
-    cvtDevToUser(selectPage, (int)(x1 + 0.5), (int)(y1 + 0.5), &ux0, &uy0);
-    cvtDevToUser(selectPage, (int)(x2 + 0.5), (int)(y2 + 0.5), &ux1, &uy1);
-    rects->append(new SelectRect(selectPage, ux0, uy0, ux1, uy1));
+    cvtDevToUser(page, (int)(x1 + 0.5), (int)(y0 + 0.5), &ux0, &uy0);
+    cvtDevToUser(page, (int)(x0 + 0.5), (int)(y1 + 0.5), &ux1, &uy1);
+    rects->append(new SelectRect(page, ux0, uy0, ux1, uy1));
+    cvtDevToUser(page, (int)(x1 + 0.5), (int)(y1 + 0.5), &ux0, &uy0);
+    cvtDevToUser(page, (int)(x2 + 0.5), (int)(y2 + 0.5), &ux1, &uy1);
+    rects->append(new SelectRect(page, ux0, uy0, ux1, uy1));
   }
 
   // get window coord bboxes for old selection and new selection;
@@ -1264,10 +1274,33 @@
 }
 
 void PDFCore::finishSelectionDrag() {
-  selectPage = 0;
-  selectStartX = selectStartY = 0;
+  // nothing
 }
 
+void PDFCore::selectWord(int pg, int x, int y) {
+  TextPosition endPos;
+
+  loadText(pg);
+  if (text->findWordPoints(x, y, &selectStartPos, &endPos)) {
+    selectPage = pg;
+    setLinearSelection(pg, &selectStartPos, &endPos);
+  } else {
+    selectPage = 0;
+  }
+}
+
+void PDFCore::selectLine(int pg, int x, int y) {
+  TextPosition endPos;
+
+  loadText(pg);
+  if (text->findLinePoints(x, y, &selectStartPos, &endPos)) {
+    selectPage = pg;
+    setLinearSelection(pg, &selectStartPos, &endPos);
+  } else {
+    selectPage = 0;
+  }
+}
+
 GBool PDFCore::getSelection(int *pg, double *ulx, double *uly,
 			    double *lrx, double *lry) {
   SelectRect *rect;
@@ -1550,7 +1583,46 @@
   return gTrue;
 }
 
+GList *PDFCore::findAll(Unicode *u, int len, GBool caseSensitive,
+			GBool wholeWord, int firstPage, int lastPage) {
+  GList *results = new GList();
 
+  TextOutputDev *textOut = new TextOutputDev(NULL, &textOutCtrl, gFalse);
+  if (!textOut->isOk()) {
+    delete textOut;
+    return results;
+  }
+
+  for (int pg = firstPage; pg <= lastPage; ++pg) {
+    doc->displayPage(textOut, pg, 72, 72, 0, gFalse, gTrue, gFalse);
+    GBool first = gTrue;
+    while (1) {
+      double xMin, yMin, xMax, yMax;
+      if (!textOut->findText(u, len, first, gTrue, !first, gFalse,
+			    caseSensitive, gFalse, wholeWord,
+			    &xMin, &yMin, &xMax, &yMax)) {
+	break;
+      }
+      double uxMin, uyMin, uxMax, uyMax, t;
+      textOut->cvtDevToUser(xMin, yMin, &uxMin, &uyMin);
+      textOut->cvtDevToUser(xMax, yMax, &uxMax, &uyMax);
+      if (uxMin > uxMax) {
+	t = uxMin;  uxMin = uxMax;  uxMax = t;
+      }
+      if (uyMin > uyMax) {
+	t = uyMin;  uyMin = uyMax;  uyMax = t;
+      }
+      results->append(new FindResult(pg, uxMin, uyMin, uxMax, uyMax));
+      first = gFalse;
+    }
+  }
+
+  delete textOut;
+
+  return results;
+}
+
+
 GBool PDFCore::cvtWindowToUser(int xw, int yw,
 			       int *pg, double *xu, double *yu) {
   return tileMap->cvtWindowToUser(xw, yw, pg, xu, yu);
@@ -1683,7 +1755,7 @@
   return annots->getAnnot(idx);
 }
 
-FormField *PDFCore::findFormField(int pg, double x, double y) {
+AcroFormField *PDFCore::findFormField(int pg, double x, double y) {
   if (!doc->getCatalog()->getForm()) {
     return NULL;
   }
@@ -1697,7 +1769,7 @@
   return doc->getCatalog()->getForm()->findFieldIdx(pg, x, y);
 }
 
-FormField *PDFCore::getFormField(int idx) {
+AcroFormField *PDFCore::getFormField(int idx) {
   if (!doc->getCatalog()->getForm()) {
     return NULL;
   }

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/PDFCore.h
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/PDFCore.h	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/PDFCore.h	2021-02-15 19:17:20 UTC (rev 845)
@@ -32,7 +32,7 @@
 class LinkAction;
 class Annot;
 class Annots;
-class FormField;
+class AcroFormField;
 class TextPage;
 class HighlightFile;
 class OptionalContentGroup;
@@ -66,6 +66,17 @@
 };
 
 //------------------------------------------------------------------------
+// FindResult
+//------------------------------------------------------------------------
+
+struct FindResult {
+  FindResult(int pageA, double xMinA, double yMinA, double xMaxA, double yMaxA)
+    : page(pageA), xMin(xMinA), yMin(yMinA), xMax(xMaxA), yMax(yMaxA) {}
+  int page;
+  double xMin, yMin, xMax, yMax;
+};
+
+//------------------------------------------------------------------------
 // PDFCore
 //------------------------------------------------------------------------
 
@@ -176,6 +187,8 @@
   void startSelectionDrag(int pg, int x, int y);
   void moveSelectionDrag(int pg, int x, int y);
   void finishSelectionDrag();
+  void selectWord(int pg, int x, int y);
+  void selectLine(int pg, int x, int y);
 
   // Retrieve the current selection.  This function uses user
   // coordinates.  Returns false if there is no selection.
@@ -198,6 +211,8 @@
   virtual GBool findU(Unicode *u, int len, GBool caseSensitive,
 		      GBool next, GBool backward, GBool wholeWord,
 		      GBool onePageOnly);
+  GList *findAll(Unicode *u, int len, GBool caseSensitive,
+		 GBool wholeWord, int firstPage, int lastPage);
 
 
   //----- coordinate conversion
@@ -242,9 +257,9 @@
   Annot *findAnnot(int pg, double x, double y);
   int findAnnotIdx(int pg, double x, double y);
   Annot *getAnnot(int idx);
-  FormField *findFormField(int pg, double x, double y);
+  AcroFormField *findFormField(int pg, double x, double y);
   int findFormFieldIdx(int pg, double x, double y);
-  FormField *getFormField(int idx);
+  AcroFormField *getFormField(int idx);
   GBool overText(int pg, double x, double y);
   void forceRedraw();
   void setTileDoneCbk(void (*cbk)(void *data), void *data);

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/PDFDoc.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/PDFDoc.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/PDFDoc.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -21,6 +21,7 @@
 #endif
 #include "gmempp.h"
 #include "GString.h"
+#include "gfile.h"
 #include "config.h"
 #include "GlobalParams.h"
 #include "Page.h"
@@ -113,6 +114,7 @@
   ok = setup(ownerPassword, userPassword);
 }
 
+#if 0
 #ifdef _WIN32
 PDFDoc::PDFDoc(wchar_t *fileNameA, int fileNameLen, GString *ownerPassword,
 	       GString *userPassword, PDFCore *coreA) {
@@ -122,14 +124,21 @@
 
   init(coreA);
 
+  // handle a Windows shortcut
+  wchar_t wPath[MAX_PATH + 1];
+  int n = fileNameLen < MAX_PATH ? fileNameLen : MAX_PATH;
+  memcpy(wPath, fileNameA, n * sizeof(wchar_t));
+  wPath[n] = L'\0';
+  readWindowsShortcut(wPath, MAX_PATH + 1);
+  int wPathLen = (int)wcslen(wPath);
+
   // save both Unicode and 8-bit copies of the file name
   fileName = new GString();
-  fileNameU = (wchar_t *)gmallocn(fileNameLen + 1, sizeof(wchar_t));
-  for (i = 0; i < fileNameLen; ++i) {
+  fileNameU = (wchar_t *)gmallocn(wPathLen + 1, sizeof(wchar_t));
+  memcpy(fileNameU, wPath, (wPathLen + 1) * sizeof(wchar_t));
+  for (i = 0; i < wPathLen; ++i) {
     fileName->append((char)fileNameA[i]);
-    fileNameU[i] = fileNameA[i];
   }
-  fileNameU[fileNameLen] = L'\0';
 
   // try to open file
   // NB: _wfopen is only available in NT
@@ -153,6 +162,7 @@
   ok = setup(ownerPassword, userPassword);
 }
 #endif
+#endif /* 0 */
 
 PDFDoc::PDFDoc(char *fileNameA, GString *ownerPassword,
 	       GString *userPassword, PDFCore *coreA) {
@@ -165,7 +175,7 @@
 /*
 #ifdef _WIN32
   Unicode u;
-  int n, i, j;
+  int i, j;
 #endif
 */
 
@@ -175,17 +185,19 @@
 
 #if defined(_WIN32)
 #if 0
-  n = 0;
+  wchar_t wPath[MAX_PATH + 1];
   i = 0;
-  while (getUTF8(fileName, &i, &u)) {
-    ++n;
+  j = 0;
+  while (j < MAX_PATH && getUTF8(fileName, &i, &u)) {
+    wPath[j++] = (wchar_t)u;
   }
-  fileNameU = (wchar_t *)gmallocn(n + 1, sizeof(wchar_t));
-  i = j = 0;
-  while (j < n && getUTF8(fileName, &i, &u)) {
-    fileNameU[j++] = (wchar_t)u;
-  }
-  fileNameU[n] = L'\0';
+  wPath[j] = L'\0';
+  readWindowsShortcut(wPath, MAX_PATH + 1);
+  int wPathLen = (int)wcslen(wPath);
+
+  fileNameU = (wchar_t *)gmallocn(wPathLen + 1, sizeof(wchar_t));
+  memcpy(fileNameU, wPath, (wPathLen + 1) * sizeof(wchar_t));
+
   // NB: _wfopen is only available in NT
   version.dwOSVersionInfoSize = sizeof(version);
   GetVersionEx(&version);
@@ -579,6 +591,18 @@
   return ret;
 }
 
+GBool PDFDoc::saveEmbeddedFileU(int idx, const char *path) {
+  FILE *f;
+  GBool ret;
+
+  if (!(f = openFile(path, "wb"))) {
+    return gFalse;
+  }
+  ret = saveEmbeddedFile2(idx, f);
+  fclose(f);
+  return ret;
+}
+
 #ifdef _WIN32
 GBool PDFDoc::saveEmbeddedFile(int idx, const wchar_t *path, int pathLen) {
   FILE *f;

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/PDFDoc.h
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/PDFDoc.h	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/PDFDoc.h	2021-02-15 19:17:20 UTC (rev 845)
@@ -185,6 +185,7 @@
   int getEmbeddedFileNameLength(int idx)
     { return catalog->getEmbeddedFileNameLength(idx); }
   GBool saveEmbeddedFile(int idx, const char *path);
+  GBool saveEmbeddedFileU(int idx, const char *path);
 #ifdef _WIN32
   GBool saveEmbeddedFile(int idx, const wchar_t *path, int pathLen);
 #endif

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/PSOutputDev.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/PSOutputDev.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/PSOutputDev.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -40,7 +40,7 @@
 #include "XRef.h"
 #include "PreScanOutputDev.h"
 #include "CharCodeToUnicode.h"
-#include "Form.h"
+#include "AcroForm.h"
 #include "TextString.h"
 #if HAVE_SPLASH
 #  include "Splash.h"
@@ -1287,7 +1287,8 @@
 			 GBool manualCtrlA,
 			 PSOutCustomCodeCbk customCodeCbkA,
 			 void *customCodeCbkDataA,
-			 GBool honorUserUnitA) {
+			 GBool honorUserUnitA,
+			 GBool fileNameIsUTF8) {
   FILE *f;
   PSFileType fileTypeA;
 
@@ -1333,7 +1334,12 @@
 #endif
   } else {
     fileTypeA = psFile;
-    if (!(f = fopen(fileName, "w"))) {
+    if (fileNameIsUTF8) {
+      f = openFile(fileName, "w");
+    } else {
+      f = fopen(fileName, "w");
+    }
+    if (!f) {
       error(errIO, -1, "Couldn't open PostScript file '{0:s}'", fileName);
       ok = gFalse;
       return;
@@ -1737,7 +1743,7 @@
   Page *page;
   Dict *resDict;
   Annots *annots;
-  Form *form;
+  AcroForm *form;
   Object obj1, obj2, obj3;
   GString *s;
   GBool needDefaultFont;
@@ -1994,6 +2000,7 @@
   }
   patDict.free();
 
+
   //----- recursively scan SMask transparency groups in ExtGState dicts
   resDict->lookup("ExtGState", &gsDict);
   if (gsDict.isDict()) {
@@ -2211,13 +2218,15 @@
     if (fontLoc->locType == gfxFontLocResident &&
 	fontLoc->fontType >= fontCIDType0) {
       subst = gTrue;
-      if ((uMap = globalParams->getUnicodeMap(fontLoc->encoding))) {
-	fi->ff->encoding = fontLoc->encoding->copy();
-	uMap->decRefCnt();
-      } else {
-	error(errSyntaxError, -1,
-	      "Couldn't find Unicode map for 16-bit font encoding '{0:t}'",
-	      fontLoc->encoding);
+      if (!fi->ff->encoding) {
+	if ((uMap = globalParams->getUnicodeMap(fontLoc->encoding))) {
+	  fi->ff->encoding = fontLoc->encoding->copy();
+	  uMap->decRefCnt();
+	} else {
+	  error(errSyntaxError, -1,
+		"Couldn't find Unicode map for 16-bit font encoding '{0:t}'",
+		fontLoc->encoding);
+	}
       }
     }
 
@@ -2244,7 +2253,7 @@
 	if (font->getType() == fontTrueType &&
 	    !subst &&
 	    !((Gfx8BitFont *)font)->getHasEncoding()) {
-	  sprintf(buf, "c%02x", i+j);
+	  snprintf(buf, sizeof(buf), "c%02x", i+j);
 	  charName = buf;
 	} else {
 	  charName = ((Gfx8BitFont *)font)->getCharName(i+j);
@@ -2392,6 +2401,7 @@
   // open the font file
   if (!(fontFile = fopen(fileName->getCString(), "rb"))) {
     error(errIO, -1, "Couldn't open external font file");
+    delete psName;
     return NULL;
   }
 
@@ -3623,7 +3633,7 @@
 	 p[0] == 0x80 &&
 	 (p[1] == 0x01 || p[1] == 0x02)) {
     len = p[2] + (p[3] << 8) + (p[4] << 16) + (p[5] << 24);
-    if (len > remain - 6) {
+    if (len < 0 || len > remain - 6) {
       break;
     }
     if (p[1] == 0x01) {
@@ -4102,6 +4112,7 @@
   resObj.free();
 }
 
+
 GBool PSOutputDev::checkPageSlice(Page *page, double hDPI, double vDPI,
 				  int rotateA, GBool useMediaBox, GBool crop,
 				  int sliceX, int sliceY,
@@ -4441,9 +4452,17 @@
       landscape = gFalse;
     } else {
       rotate = (360 - state->getRotate()) % 360;
+      double scaledWidth = width * userUnit;
+      double scaledHeight = height * userUnit;
+      if (xScale0 > 0 && yScale0 > 0) {
+	scaledWidth *= xScale0;
+	scaledHeight *= yScale0;
+      }
       if (rotate == 0 || rotate == 180) {
-	if ((width < height && imgWidth > imgHeight && height > imgHeight) ||
-	    (width > height && imgWidth < imgHeight && width > imgWidth)) {
+	if ((scaledWidth < scaledHeight && imgWidth > imgHeight &&
+	     scaledHeight > imgHeight) ||
+	    (scaledWidth > scaledHeight && imgWidth < imgHeight &&
+	     scaledWidth > imgWidth)) {
 	  rotate += 90;
 	  landscape = gTrue;
 	} else {
@@ -4450,8 +4469,10 @@
 	  landscape = gFalse;
 	}
       } else { // rotate == 90 || rotate == 270
-	if ((height < width && imgWidth > imgHeight && width > imgHeight) ||
-	    (height > width && imgWidth < imgHeight && height > imgWidth)) {
+	if ((scaledHeight < scaledWidth && imgWidth > imgHeight &&
+	     scaledWidth > imgHeight) ||
+	    (scaledHeight > scaledWidth && imgWidth < imgHeight &&
+	     scaledHeight > imgWidth)) {
 	  rotate = 270 - rotate;
 	  landscape = gTrue;
 	} else {
@@ -5252,6 +5273,29 @@
   noStateChanges = gFalse;
 }
 
+GBool PSOutputDev::shadedFill(GfxState *state, GfxShading *shading) {
+  if (level != psLevel2 &&
+      level != psLevel2Sep &&
+      level != psLevel3 &&
+      level != psLevel3Sep) {
+    return gFalse;
+  }
+
+  switch (shading->getType()) {
+  case 1:
+    functionShadedFill(state, (GfxFunctionShading *)shading);
+    return gTrue;
+  case 2:
+    axialShadedFill(state, (GfxAxialShading *)shading);
+    return gTrue;
+  case 3:
+    radialShadedFill(state, (GfxRadialShading *)shading);
+    return gTrue;
+  default:
+    return gFalse;
+  }
+}
+
 GBool PSOutputDev::functionShadedFill(GfxState *state,
 				      GfxFunctionShading *shading) {
   double x0, y0, x1, y1;
@@ -5957,7 +6001,7 @@
 void PSOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,
 				  int width, int height,
 				  GfxImageColorMap *colorMap,
-				  Stream *maskStr,
+				  Object *maskRef, Stream *maskStr,
 				  int maskWidth, int maskHeight,
 				  GBool maskInvert, GBool interpolate) {
   int len;
@@ -8301,7 +8345,7 @@
       writePSChar((char)*p);
       line += 2;
     } else if (*p < 0x20 || *p >= 0x80) {
-      sprintf(buf, "\\%03o", *p);
+      snprintf(buf, sizeof(buf), "\\%03o", *p);
       writePS(buf);
       line += 4;
     } else {
@@ -8351,7 +8395,7 @@
 	c == '(' || c == ')' || c == '<' || c == '>' ||
 	c == '[' || c == ']' || c == '{' || c == '}' ||
 	c == '/' || c == '%') {
-      sprintf(buf, "#%02x", c & 0xff);
+      snprintf(buf, sizeof(buf), "#%02x", c & 0xff);
       name2->append(buf);
     } else {
       name2->append(c);

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/PSOutputDev.h
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/PSOutputDev.h	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/PSOutputDev.h	2021-02-15 19:17:20 UTC (rev 845)
@@ -38,6 +38,9 @@
 class GfxIndexedColorSpace;
 class GfxSeparationColorSpace;
 class GfxDeviceNColorSpace;
+class GfxFunctionShading;
+class GfxAxialShading;
+class GfxRadialShading;
 class PDFRectangle;
 class PSOutCustomColor;
 class PSOutputDev;
@@ -82,7 +85,8 @@
 	      GBool manualCtrlA = gFalse,
 	      PSOutCustomCodeCbk customCodeCbkA = NULL,
 	      void *customCodeCbkDataA = NULL,
-	      GBool honorUserUnitA = gFalse);
+	      GBool honorUserUnitA = gFalse,
+	      GBool fileNameIsUTF8 = gFalse);
 
   // Open a PSOutputDev that will write to a generic stream.
   PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA,
@@ -118,13 +122,6 @@
   // operations.
   virtual GBool useTilingPatternFill() { return gTrue; }
 
-  // Does this device use functionShadedFill(), axialShadedFill(), and
-  // radialShadedFill()?  If this returns false, these shaded fills
-  // will be reduced to a series of other drawing operations.
-  virtual GBool useShadedFills()
-    { return level == psLevel2 || level == psLevel2Sep ||
-	     level == psLevel3 || level == psLevel3Sep; }
-
   // Does this device use drawForm()?  If this returns false,
   // form-type XObjects will be interpreted (i.e., unrolled).
   virtual GBool useDrawForm() { return preload; }
@@ -214,10 +211,7 @@
 				 double *mat, double *bbox,
 				 int x0, int y0, int x1, int y1,
 				 double xStep, double yStep);
-  virtual GBool functionShadedFill(GfxState *state,
-				   GfxFunctionShading *shading);
-  virtual GBool axialShadedFill(GfxState *state, GfxAxialShading *shading);
-  virtual GBool radialShadedFill(GfxState *state, GfxRadialShading *shading);
+  virtual GBool shadedFill(GfxState *state, GfxShading *shading);
 
   //----- path clipping
   virtual void clip(GfxState *state);
@@ -238,7 +232,8 @@
   virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str,
 			       int width, int height,
 			       GfxImageColorMap *colorMap,
-			       Stream *maskStr, int maskWidth, int maskHeight,
+			       Object *maskRef, Stream *maskStr,
+			       int maskWidth, int maskHeight,
 			       GBool maskInvert, GBool interpolate);
 
 #if OPI_SUPPORT
@@ -342,6 +337,10 @@
 			   double *mat, double *bbox,
 			   int x0, int y0, int x1, int y1,
 			   double xStep, double yStep);
+  GBool functionShadedFill(GfxState *state,
+  			   GfxFunctionShading *shading);
+  GBool axialShadedFill(GfxState *state, GfxAxialShading *shading);
+  GBool radialShadedFill(GfxState *state, GfxRadialShading *shading);
   void doPath(GfxPath *path);
   void doImageL1(Object *ref, GfxState *state,
 		 GfxImageColorMap *colorMap,

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Page.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Page.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Page.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -14,6 +14,7 @@
 
 #include <stddef.h>
 #include "gmempp.h"
+#include "Trace.h"
 #include "GlobalParams.h"
 #include "Object.h"
 #include "Array.h"
@@ -26,7 +27,7 @@
 #include "Gfx.h"
 #include "GfxState.h"
 #include "Annot.h"
-#include "Form.h"
+#include "AcroForm.h"
 #endif
 #include "Error.h"
 #include "Catalog.h"
@@ -335,7 +336,7 @@
   Gfx *gfx;
   Object obj;
   Annots *annotList;
-  Form *form;
+  AcroForm *form;
   int i;
 
   if (!out->checkPageSlice(this, hDPI, vDPI, rotate, useMediaBox, crop,
@@ -344,6 +345,8 @@
     return;
   }
 
+  traceBegin(this, "begin page");
+
   rotate += getRotate();
   if (rotate >= 360) {
     rotate -= 360;
@@ -404,7 +407,9 @@
   }
 
   delete gfx;
-#endif
+#endif // PDF_PARSER_ONLY
+
+  traceEnd(this, "end page");
 }
 
 void Page::makeBox(double hDPI, double vDPI, int rotate,

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Page.h
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Page.h	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Page.h	2021-02-15 19:17:20 UTC (rev 845)
@@ -127,6 +127,7 @@
 
   // Get page parameters.
   int getNum() { return num; }
+  PageAttrs *getAttrs() { return attrs; }
   PDFRectangle *getMediaBox() { return attrs->getMediaBox(); }
   PDFRectangle *getCropBox() { return attrs->getCropBox(); }
   GBool isCropped() { return attrs->isCropped(); }

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/PreScanOutputDev.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/PreScanOutputDev.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/PreScanOutputDev.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -76,8 +76,7 @@
   }
 }
 
-GBool PreScanOutputDev::functionShadedFill(GfxState *state,
-					   GfxFunctionShading *shading) {
+GBool PreScanOutputDev::shadedFill(GfxState *state, GfxShading *shading) {
   if (shading->getColorSpace()->getMode() != csDeviceGray &&
       shading->getColorSpace()->getMode() != csCalGray) {
     gray = gFalse;
@@ -90,34 +89,6 @@
   return gTrue;
 }
 
-GBool PreScanOutputDev::axialShadedFill(GfxState *state,
-					GfxAxialShading *shading) {
-  if (shading->getColorSpace()->getMode() != csDeviceGray &&
-      shading->getColorSpace()->getMode() != csCalGray) {
-    gray = gFalse;
-  }
-  mono = gFalse;
-  if (state->getFillOpacity() != 1 ||
-      state->getBlendMode() != gfxBlendNormal) {
-    transparency = gTrue;
-  }
-  return gTrue;
-}
-
-GBool PreScanOutputDev::radialShadedFill(GfxState *state,
-					 GfxRadialShading *shading) {
-  if (shading->getColorSpace()->getMode() != csDeviceGray &&
-      shading->getColorSpace()->getMode() != csCalGray) {
-    gray = gFalse;
-  }
-  mono = gFalse;
-  if (state->getFillOpacity() != 1 ||
-      state->getBlendMode() != gfxBlendNormal) {
-    transparency = gTrue;
-  }
-  return gTrue;
-}
-
 void PreScanOutputDev::clip(GfxState *state) {
   //~ check for a rectangle "near" the edge of the page;
   //~   else set gdi to false
@@ -229,7 +200,7 @@
 				       Stream *str,
 				       int width, int height,
 				       GfxImageColorMap *colorMap,
-				       Stream *maskStr,
+				       Object *maskRef, Stream *maskStr,
 				       int maskWidth, int maskHeight,
 				       GBool maskInvert, GBool interpolate) {
   GfxColorSpace *colorSpace;
@@ -258,7 +229,7 @@
 					   Stream *str,
 					   int width, int height,
 					   GfxImageColorMap *colorMap,
-					   Stream *maskStr,
+					   Object *maskRef, Stream *maskStr,
 					   int maskWidth, int maskHeight,
 					   GfxImageColorMap *maskColorMap,
 					   double *matte, GBool interpolate) {

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/PreScanOutputDev.h
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/PreScanOutputDev.h	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/PreScanOutputDev.h	2021-02-15 19:17:20 UTC (rev 845)
@@ -46,11 +46,6 @@
   // operations.
   virtual GBool useTilingPatternFill() { return gTrue; }
 
-  // Does this device use functionShadedFill(), axialShadedFill(), and
-  // radialShadedFill()?  If this returns false, these shaded fills
-  // will be reduced to a series of other drawing operations.
-  virtual GBool useShadedFills() { return gTrue; }
-
   // Does this device use beginType3Char/endType3Char?  Otherwise,
   // text in Type 3 fonts will be drawn with drawChar/drawString.
   virtual GBool interpretType3Chars() { return gTrue; }
@@ -72,10 +67,7 @@
 				 double *mat, double *bbox,
 				 int x0, int y0, int x1, int y1,
 				 double xStep, double yStep);
-  virtual GBool functionShadedFill(GfxState *state,
-				   GfxFunctionShading *shading);
-  virtual GBool axialShadedFill(GfxState *state, GfxAxialShading *shading);
-  virtual GBool radialShadedFill(GfxState *state, GfxRadialShading *shading);
+  virtual GBool shadedFill(GfxState *state, GfxShading *shading);
 
   //----- path clipping
   virtual void clip(GfxState *state);
@@ -99,12 +91,13 @@
   virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str,
 			       int width, int height,
 			       GfxImageColorMap *colorMap,
-			       Stream *maskStr, int maskWidth, int maskHeight,
+			       Object *maskRef, Stream *maskStr,
+			       int maskWidth, int maskHeight,
 			       GBool maskInvert, GBool interpolate);
   virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
 				   int width, int height,
 				   GfxImageColorMap *colorMap,
-				   Stream *maskStr,
+				   Object *maskRef, Stream *maskStr,
 				   int maskWidth, int maskHeight,
 				   GfxImageColorMap *maskColorMap,
 				   double *matte, GBool interpolate);

Added: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/ShadingImage.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/ShadingImage.cc	                        (rev 0)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/ShadingImage.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -0,0 +1,1327 @@
+//========================================================================
+//
+// ShadingImage.cc
+//
+// Copyright 2020 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <math.h>
+#include "Trace.h"
+#include "GfxState.h"
+#include "SplashBitmap.h"
+#include "SplashPattern.h"
+#include "SplashPath.h"
+#include "Splash.h"
+#include "ShadingImage.h"
+
+// Max recursive depth for a patch mesh shading fill.
+#define patchMaxDepth 10
+
+// Max delta allowed in any color component for a patch mesh shading
+// fill.
+#define patchColorDelta (dblToCol(1 / 256.0))
+
+SplashBitmap *ShadingImage::generateBitmap(GfxState *state,
+					   GfxShading *shading,
+					   SplashColorMode mode,
+					   GBool reverseVideo,
+					   Splash *parentSplash,
+					   SplashBitmap *parentBitmap,
+					   int *xOut, int *yOut) {
+  switch (shading->getType()) {
+  case 1:
+    return generateFunctionBitmap(state, (GfxFunctionShading *)shading,
+				  mode, reverseVideo,
+				  parentSplash, parentBitmap, xOut, yOut);
+    break;
+  case 2:
+    return generateAxialBitmap(state, (GfxAxialShading *)shading,
+			       mode, reverseVideo,
+			       parentSplash, parentBitmap, xOut, yOut);
+    break;
+  case 3:
+    return generateRadialBitmap(state, (GfxRadialShading *)shading,
+				mode, reverseVideo,
+				parentSplash, parentBitmap, xOut, yOut);
+    break;
+  case 4:
+  case 5:
+    return generateGouraudTriangleBitmap(state,
+					 (GfxGouraudTriangleShading *)shading,
+					 mode, reverseVideo,
+					 parentSplash, parentBitmap,
+					 xOut, yOut);
+    break;
+  case 6:
+  case 7:
+    return generatePatchMeshBitmap(state, (GfxPatchMeshShading *)shading,
+				   mode, reverseVideo,
+				   parentSplash, parentBitmap, xOut, yOut);
+    break;
+  default:
+    return NULL;
+  }
+}
+
+SplashBitmap *ShadingImage::generateFunctionBitmap(GfxState *state,
+						   GfxFunctionShading *shading,
+						   SplashColorMode mode,
+						   GBool reverseVideo,
+						   Splash *parentSplash,
+						   SplashBitmap *parentBitmap,
+						   int *xOut, int *yOut) {
+  // get the shading parameters
+  double x0, y0, x1, y1;
+  shading->getDomain(&x0, &y0, &x1, &y1);
+  double *patternMat = shading->getMatrix();
+
+  // get the clip bbox
+  double fxMin, fyMin, fxMax, fyMax;
+  state->getClipBBox(&fxMin, &fyMin, &fxMax, &fyMax);
+  if (fxMin > fxMax || fyMin > fyMax) {
+    return NULL;
+  }
+
+  // convert to integer coords
+  int xMin = (int)floor(fxMin);
+  int yMin = (int)floor(fyMin);
+  int xMax = (int)floor(fxMax) + 1;
+  int yMax = (int)floor(fyMax) + 1;
+  int bitmapWidth = xMax - xMin;
+  int bitmapHeight = yMax - yMin;
+
+  // allocate the bitmap
+  traceMessage("function shading fill bitmap");
+  SplashBitmap *bitmap = new SplashBitmap(bitmapWidth, bitmapHeight, 1, mode,
+					  gTrue, gTrue, parentBitmap);
+  int nComps = splashColorModeNComps[mode];
+
+  // compute the domain -> device space transform = mat * CTM
+  double *ctm = state->getCTM();
+  double mat[6];
+  mat[0] = patternMat[0] * ctm[0] + patternMat[1] * ctm[2];
+  mat[1] = patternMat[0] * ctm[1] + patternMat[1] * ctm[3];
+  mat[2] = patternMat[2] * ctm[0] + patternMat[3] * ctm[2];
+  mat[3] = patternMat[2] * ctm[1] + patternMat[3] * ctm[3];
+  mat[4] = patternMat[4] * ctm[0] + patternMat[5] * ctm[2] + ctm[4];
+  mat[5] = patternMat[4] * ctm[1] + patternMat[5] * ctm[3] + ctm[5];
+
+  // compute the device space -> domain transform
+  double det = mat[0] * mat[3] - mat[1] * mat[2];
+  if (fabs(det) < 0.000001) {
+    return NULL;
+  }
+  det = 1 / det;
+  double iMat[6];
+  iMat[0] = mat[3] * det;
+  iMat[1] = -mat[1] * det;
+  iMat[2] = -mat[2] * det;
+  iMat[3] = mat[0] * det;
+  iMat[4] = (mat[2] * mat[5] - mat[3] * mat[4]) * det;
+  iMat[5] = (mat[1] * mat[4] - mat[0] * mat[5]) * det;
+
+  // fill the bitmap
+  SplashColorPtr dataPtr = bitmap->getDataPtr();
+  Guchar *alphaPtr = bitmap->getAlphaPtr();
+  for (int y = 0; y < bitmapHeight; ++y) {
+    for (int x = 0; x < bitmapWidth; ++x) {
+
+      // convert coords to the pattern domain
+      double tx = xMin + x + 0.5;
+      double ty = yMin + y + 0.5;
+      double xx = tx * iMat[0] + ty * iMat[2] + iMat[4];
+      double yy = tx * iMat[1] + ty * iMat[3] + iMat[5];
+
+      // get the color
+      if (xx >= x0 && xx <= x1 && yy >= y0 && yy <= y1) {
+	GfxColor color;
+	shading->getColor(xx, yy, &color);
+	SplashColor sColor;
+	computeShadingColor(state, mode, reverseVideo, &color, sColor);
+	for (int i = 0; i < nComps; ++i) {
+	  *dataPtr++ = sColor[i];
+	}
+	*alphaPtr++ = 0xff;
+      } else {
+	dataPtr += nComps;
+	*alphaPtr++ = 0;
+      }
+    }
+  }
+
+  *xOut = xMin;
+  *yOut = yMin;
+  return bitmap;
+}
+
+SplashBitmap *ShadingImage::generateAxialBitmap(GfxState *state,
+						GfxAxialShading *shading,
+						SplashColorMode mode,
+						GBool reverseVideo,
+						Splash *parentSplash,
+						SplashBitmap *parentBitmap,
+						int *xOut, int *yOut) {
+  // get the shading parameters
+  double x0, y0, x1, y1;
+  shading->getCoords(&x0, &y0, &x1, &y1);
+  double t0 = shading->getDomain0();
+  double t1 = shading->getDomain1();
+  GBool ext0 = shading->getExtend0();
+  GBool ext1 = shading->getExtend1();
+  double dx = x1 - x0;
+  double dy = y1 - y0;
+  double d = dx * dx + dy * dy;
+  GBool dZero = fabs(d) < 0.0001;
+  if (!dZero) {
+    d = 1 / d;
+  }
+  if (dZero && !ext0 && !ext1) {
+    return NULL;
+  }
+
+  // get the clip bbox
+  double fxMin, fyMin, fxMax, fyMax;
+  state->getClipBBox(&fxMin, &fyMin, &fxMax, &fyMax);
+  if (fxMin > fxMax || fyMin > fyMax) {
+    return NULL;
+  }
+
+  // convert to integer coords
+  int xMin = (int)floor(fxMin);
+  int yMin = (int)floor(fyMin);
+  int xMax = (int)floor(fxMax) + 1;
+  int yMax = (int)floor(fyMax) + 1;
+  int bitmapWidth = xMax - xMin;
+  int bitmapHeight = yMax - yMin;
+
+  // compute the inverse CTM
+  double *ctm = state->getCTM();
+  double det = ctm[0] * ctm[3] - ctm[1] * ctm[2];
+  if (fabs(det) < 0.000001) {
+    return NULL;
+  }
+  det = 1 / det;
+  double ictm[6];
+  ictm[0] = ctm[3] * det;
+  ictm[1] = -ctm[1] * det;
+  ictm[2] = -ctm[2] * det;
+  ictm[3] = ctm[0] * det;
+  ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
+  ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
+
+  // convert axis endpoints to device space
+  double xx0, yy0, xx1, yy1;
+  state->transform(x0, y0, &xx0, &yy0);
+  state->transform(x1, y1, &xx1, &yy1);
+
+  // allocate the bitmap
+  traceMessage("axial shading fill bitmap");
+  SplashBitmap *bitmap = new SplashBitmap(bitmapWidth, bitmapHeight, 1, mode,
+					  gTrue, gTrue, parentBitmap);
+  int nComps = splashColorModeNComps[mode];
+
+  // special case: zero-length axis
+  if (dZero) {
+    GfxColor color;
+    if (ext0) {
+      shading->getColor(t0, &color);
+    } else {
+      shading->getColor(t1, &color);
+    }
+    SplashColor sColor;
+    computeShadingColor(state, mode, reverseVideo, &color, sColor);
+    SplashColorPtr dataPtr = bitmap->getDataPtr();
+    for (int y = 0; y < bitmapHeight; ++y) {
+      for (int x = 0; x < bitmapWidth; ++x) {
+	for (int i = 0; i < nComps; ++i) {
+	  *dataPtr++ = sColor[i];
+	}
+      }
+    }
+    memset(bitmap->getAlphaPtr(), 0xff, (size_t)bitmapWidth * bitmapHeight);
+
+  // special case: horizontal axis (in device space)
+  } else if (fabs(yy0 - yy1) < 0.01) {
+    for (int x = 0; x < bitmapWidth; ++x) {
+      SplashColorPtr dataPtr = bitmap->getDataPtr() + x * nComps;
+      Guchar *alphaPtr = bitmap->getAlphaPtr() + x;
+      double tx = xMin + x + 0.5;
+      double ty = yMin + 0.5;
+      double xx = tx * ictm[0] + ty * ictm[2] + ictm[4];
+      double yy = tx * ictm[1] + ty * ictm[3] + ictm[5];
+      double s = ((xx - x0) * dx + (yy - y0) * dy) * d;
+      GBool go = gFalse;
+      if (s < 0) {
+	go = ext0;
+      } else if (s > 1) {
+	go = ext1;
+      } else {
+	go = gTrue;
+      }
+      if (go) {
+	GfxColor color;
+	if (s <= 0) {
+	  shading->getColor(t0, &color);
+	} else if (s >= 1) {
+	  shading->getColor(t1, &color);
+	} else {
+	  double t = t0 + s * (t1 - t0);
+	  shading->getColor(t, &color);
+	}
+	SplashColor sColor;
+	computeShadingColor(state, mode, reverseVideo, &color, sColor);
+	for (int y = 0; y < bitmapHeight; ++y) {
+	  for (int i = 0; i < nComps; ++i) {
+	    dataPtr[i] = sColor[i];
+	  }
+	  dataPtr += bitmap->getRowSize();
+	  *alphaPtr = 0xff;
+	  alphaPtr += bitmapWidth;
+	}
+      } else {
+	for (int y = 0; y < bitmapHeight; ++y) {
+	  *alphaPtr = 0;
+	  alphaPtr += bitmapWidth;
+	}
+      }
+    }
+
+  // special case: vertical axis (in device space)
+  } else if (fabs(xx0 - xx1) < 0.01) {
+    for (int y = 0; y < bitmapHeight; ++y) {
+      SplashColorPtr dataPtr = bitmap->getDataPtr() + y * bitmap->getRowSize();
+      Guchar *alphaPtr = bitmap->getAlphaPtr() + y * bitmapWidth;
+      double tx = xMin + 0.5;
+      double ty = yMin + y + 0.5;
+      double xx = tx * ictm[0] + ty * ictm[2] + ictm[4];
+      double yy = tx * ictm[1] + ty * ictm[3] + ictm[5];
+      double s = ((xx - x0) * dx + (yy - y0) * dy) * d;
+      GBool go = gFalse;
+      if (s < 0) {
+	go = ext0;
+      } else if (s > 1) {
+	go = ext1;
+      } else {
+	go = gTrue;
+      }
+      if (go) {
+	GfxColor color;
+	if (s <= 0) {
+	  shading->getColor(t0, &color);
+	} else if (s >= 1) {
+	  shading->getColor(t1, &color);
+	} else {
+	  double t = t0 + s * (t1 - t0);
+	  shading->getColor(t, &color);
+	}
+	SplashColor sColor;
+	computeShadingColor(state, mode, reverseVideo, &color, sColor);
+	for (int x = 0; x < bitmapWidth; ++x) {
+	  for (int i = 0; i < nComps; ++i) {
+	    dataPtr[i] = sColor[i];
+	  }
+	  dataPtr += nComps;
+	}
+	memset(alphaPtr, 0xff, bitmapWidth);
+      } else {
+	memset(alphaPtr, 0, bitmapWidth);
+      }
+    }
+
+  // general case
+  } else {
+    // pre-compute colors along the axis
+    int nColors = (int)(1.5 * sqrt((xx1 - xx0) * (xx1 - xx0)
+				   + (yy1 - yy0) * (yy1 - yy0)));
+    if (nColors < 16) {
+      nColors = 16;
+    } else if (nColors > 1024) {
+      nColors = 1024;
+    }
+    SplashColorPtr sColors = (SplashColorPtr)gmallocn(nColors, nComps);
+    SplashColorPtr sColor = sColors;
+    for (int i = 0; i < nColors; ++i) {
+      double s = (double)i / (double)(nColors - 1);
+      double t = t0 + s * (t1 - t0);
+      GfxColor color;
+      shading->getColor(t, &color);
+      computeShadingColor(state, mode, reverseVideo, &color, sColor);
+      sColor += nComps;
+    }
+
+    SplashColorPtr dataPtr = bitmap->getDataPtr();
+    Guchar *alphaPtr = bitmap->getAlphaPtr();
+    for (int y = 0; y < bitmapHeight; ++y) {
+      for (int x = 0; x < bitmapWidth; ++x) {
+
+	// convert coords to user space
+	double tx = xMin + x + 0.5;
+	double ty = yMin + y + 0.5;
+	double xx = tx * ictm[0] + ty * ictm[2] + ictm[4];
+	double yy = tx * ictm[1] + ty * ictm[3] + ictm[5];
+
+	// compute the position along the axis
+	double s = ((xx - x0) * dx + (yy - y0) * dy) * d;
+	GBool go = gFalse;
+	if (s < 0) {
+	  go = ext0;
+	} else if (s > 1) {
+	  go = ext1;
+	} else {
+	  go = gTrue;
+	}
+	if (go) {
+	  if (s <= 0) {
+	    sColor = sColors;
+	  } else if (s >= 1) {
+	    sColor = sColors + (nColors - 1) * nComps;
+	  } else {
+	    int i = (int)((nColors - 1) * s + 0.5);
+	    sColor = sColors + i * nComps;
+	  }
+	  for (int i = 0; i < nComps; ++i) {
+	    *dataPtr++ = sColor[i];
+	  }
+	  *alphaPtr++ = 0xff;
+	} else {
+	  dataPtr += nComps;
+	  *alphaPtr++ = 0;
+	}
+      }
+    }
+    gfree(sColors);
+  }
+
+  *xOut = xMin;
+  *yOut = yMin;
+  return bitmap;
+}
+
+SplashBitmap *ShadingImage::generateRadialBitmap(GfxState *state,
+						 GfxRadialShading *shading,
+						 SplashColorMode mode,
+						 GBool reverseVideo,
+						 Splash *parentSplash,
+						 SplashBitmap *parentBitmap,
+						 int *xOut, int *yOut) {
+  // get the shading parameters
+  double x0, y0, r0, x1, y1, r1;
+  shading->getCoords(&x0, &y0, &r0, &x1, &y1, &r1);
+  double t0 = shading->getDomain0();
+  double t1 = shading->getDomain1();
+  GBool ext0 = shading->getExtend0();
+  GBool ext1 = shading->getExtend1();
+  double h = sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0));
+  GBool enclosed = fabs(r1 - r0) >= h;
+
+  // get the clip bbox
+  double fxMin, fyMin, fxMax, fyMax;
+  state->getClipBBox(&fxMin, &fyMin, &fxMax, &fyMax);
+  if (fxMin > fxMax || fyMin > fyMax) {
+    return NULL;
+  }
+
+  // intersect with shading region (in user space): if the extend
+  // flags are false (or just the larger extend flag is false, in the
+  // "enclosed" case), we can use the bbox for the two circles
+  if ((!ext0 && !ext1) ||
+      (enclosed && !(r0 > r1 ? ext0 : ext1))) {
+    double uxMin = (x0 - r0) < (x1 - r1) ? (x0 - r0) : (x1 - r1);
+    double uxMax = (x0 + r0) > (x1 + r1) ? (x0 + r0) : (x1 + r1);
+    double uyMin = (y0 - r0) < (y1 - r1) ? (y0 - r0) : (y1 - r1);
+    double uyMax = (y0 + r0) > (y1 + r1) ? (y0 + r0) : (y1 + r1);
+    double dxMin, dyMin, dxMax, dyMax;
+    transformBBox(state, uxMin, uyMin, uxMax, uyMax,
+		  &dxMin, &dyMin, &dxMax, &dyMax);
+    if (dxMin > fxMin) {
+      fxMin = dxMin;
+    }
+    if (dxMax < dxMax) {
+      fxMax = dxMax;
+    }
+    if (dyMin > fyMin) {
+      fyMin = dyMin;
+    }
+    if (dyMax < fyMax) {
+      fyMax = dyMax;
+    }
+    if (fxMin > fxMax || fyMin > fyMax) {
+      return NULL;
+    }
+  }
+
+  // convert to integer coords
+  int xMin = (int)floor(fxMin);
+  int yMin = (int)floor(fyMin);
+  int xMax = (int)floor(fxMax) + 1;
+  int yMax = (int)floor(fyMax) + 1;
+  int bitmapWidth = xMax - xMin;
+  int bitmapHeight = yMax - yMin;
+
+  // compute the inverse CTM
+  double *ctm = state->getCTM();
+  double det = ctm[0] * ctm[3] - ctm[1] * ctm[2];
+  if (fabs(det) < 0.000001) {
+    return NULL;
+  }
+  det = 1 / det;
+  double ictm[6];
+  ictm[0] = ctm[3] * det;
+  ictm[1] = -ctm[1] * det;
+  ictm[2] = -ctm[2] * det;
+  ictm[3] = ctm[0] * det;
+  ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
+  ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
+
+  // allocate the bitmap
+  traceMessage("radial shading fill bitmap");
+  SplashBitmap *bitmap = new SplashBitmap(bitmapWidth, bitmapHeight, 1, mode,
+					  gTrue, gTrue, parentBitmap);
+  int nComps = splashColorModeNComps[mode];
+
+  // pre-compute colors along the axis
+  int nColors = (int)sqrt((double)(bitmapWidth * bitmapWidth
+				   + bitmapHeight * bitmapHeight));
+  if (nColors < 16) {
+    nColors = 16;
+  } else if (nColors > 1024) {
+    nColors = 1024;
+  }
+  SplashColorPtr sColors = (SplashColorPtr)gmallocn(nColors, nComps);
+  SplashColorPtr sColor = sColors;
+  for (int i = 0; i < nColors; ++i) {
+    double s = (double)i / (double)(nColors - 1);
+    double t = t0 + s * (t1 - t0);
+    GfxColor color;
+    shading->getColor(t, &color);
+    computeShadingColor(state, mode, reverseVideo, &color, sColor);
+    sColor += nComps;
+  }
+
+  // special case: in the "enclosed" + extended case, we can fill the
+  // bitmap with the outer color and just render inside the larger
+  // circle
+  int bxMin, byMin, bxMax, byMax;
+  if (enclosed &&
+      ((r0 > r1 && ext0) || (r1 > r0 && ext1))) {
+    double uxMin, uyMin, uxMax, uyMax;
+    if (r0 > r1) {
+      sColor = sColors;
+      uxMin = x0 - r0;
+      uxMax = x0 + r0;
+      uyMin = y0 - r0;
+      uyMax = y0 + r0;
+    } else {
+      sColor = sColors + (nColors - 1) * nComps;
+      uxMin = x1 - r1;
+      uxMax = x1 + r1;
+      uyMin = y1 - r1;
+      uyMax = y1 + r1;
+    }
+
+    // convert bbox of larger circle to device space
+    double dxMin, dyMin, dxMax, dyMax;
+    transformBBox(state, uxMin, uyMin, uxMax, uyMax,
+		  &dxMin, &dyMin, &dxMax, &dyMax);
+    bxMin = (int)floor(dxMin - xMin);
+    if (bxMin < 0) {
+      bxMin = 0;
+    }
+    byMin = (int)floor(dyMin - yMin);
+    if (byMin < 0) {
+      byMin = 0;
+    }
+    bxMax = (int)floor(dxMax - xMin) + 1;
+    if (bxMax > bitmapWidth) {
+      bxMax = bitmapWidth;
+    }
+    byMax = (int)floor(dyMax - yMin) + 1;
+    if (byMax > bitmapHeight) {
+      byMax = bitmapHeight;
+    }
+
+    // fill bitmap (except for the rectangle containing the larger circle)
+    SplashColorPtr dataPtr = bitmap->getDataPtr();
+    Guchar *alphaPtr = bitmap->getAlphaPtr();
+    for (int y = 0; y < bitmapHeight; ++y) {
+      for (int x = 0; x < bitmapWidth; ++x) {
+	if (y >= byMin && y < byMax && x >= bxMin && x < bxMax) {
+	  dataPtr += nComps;
+	  ++alphaPtr;
+	} else {
+	  for (int i = 0; i < nComps; ++i) {
+	    *dataPtr++ = sColor[i];
+	  }
+	  *alphaPtr++ = 0xff;
+	}
+      }
+    }
+
+  } else {
+    bxMin = 0;
+    byMin = 0;
+    bxMax = bitmapWidth;
+    byMax = bitmapHeight;
+  }
+
+  // render the shading into the bitmap
+  double dx = x1 - x0;
+  double dy = y1 - y0;
+  double dr = r1 - r0;
+  double r0dr = r0 * dr;
+  double r02 = r0 * r0;
+  double a = dx * dx + dy * dy - dr * dr;
+  GBool aIsZero;
+  double a2;
+  if (fabs(a) < 0.00001) {
+    aIsZero = gTrue;
+    a2 = 0;
+  } else {
+    aIsZero = gFalse;
+    a2 = 1 / (2 * a);
+  }
+  for (int y = byMin; y < byMax; ++y) {
+    SplashColorPtr dataPtr = bitmap->getDataPtr()
+                             + y * bitmap->getRowSize() + bxMin * nComps;
+    Guchar *alphaPtr = bitmap->getAlphaPtr()
+                       + y * bitmap->getAlphaRowSize() + bxMin;
+    for (int x = bxMin; x < bxMax; ++x) {
+
+      // convert coords to user space
+      double tx = xMin + x + 0.5;
+      double ty = yMin + y + 0.5;
+      double xx = tx * ictm[0] + ty * ictm[2] + ictm[4];
+      double yy = tx * ictm[1] + ty * ictm[3] + ictm[5];
+
+      // compute the radius of the circle at x,y
+      double b = 2 * ((xx - x0) * dx + (yy - y0) * dy + r0dr);
+      double c = (xx - x0) * (xx - x0) + (yy - y0) * (yy - y0) - r02;
+      double s = 0;
+      GBool go = gFalse;
+      if (aIsZero) {
+	if (fabs(b) < 0.000001) {
+	  if (c <= 0) {
+	    if (ext0) {
+	      s = 0;
+	      go = gTrue;
+	    }
+	  } else {
+	    if (ext1) {
+	      s = 1;
+	      go = gTrue;
+	    }
+	  }
+	} else {
+	  double s0 = c / b;
+	  double rs0 = r0 + s0 * (r1 - r0);
+	  if ((s0 >= 0 || ext0) && (s0 <= 1 || ext1) && rs0 >= 0) { 
+	    s = s0;
+	    go = gTrue;
+	  }
+	}
+      } else {
+	double e = b*b - 4*a*c;
+	if (e >= 0) {
+	  double es = sqrt(e);
+	  double s0 = (b + es) * a2;
+	  double s1 = (b - es) * a2;
+	  double rs0 = r0 + s0 * (r1 - r0);
+	  double rs1 = r0 + s1 * (r1 - r0);
+	  if (s0 > s1) {
+	    if ((s0 >= 0 || ext0) && (s0 <= 1 || ext1) && rs0 >= 0) {
+	      s = s0;
+	      go = gTrue;
+	    } else if ((s1 >= 0 || ext0) && (s1 <= 1 || ext1) && rs1 >= 0) {
+	      s = s1;
+	      go = gTrue;
+	    }
+	  } else {
+	    if ((s1 >= 0 || ext0) && (s1 <= 1 || ext1) && rs1 >= 0) {
+	      s = s1;
+	      go = gTrue;
+	    } else if ((s0 >= 0 || ext0) && (s0 <= 1 || ext1) && rs0 >= 0) {
+	      s = s0;
+	      go = gTrue;
+	    }
+	  }
+	}
+      }
+      if (!go) {
+	dataPtr += nComps;
+	*alphaPtr++ = 0x00;
+	continue;
+      }
+      if (s <= 0) {
+	sColor = sColors;
+      } else if (s >= 1) {
+	sColor = sColors + (nColors - 1) * nComps;
+      } else {
+	int i = (int)((nColors - 1) * s + 0.5);
+	sColor = sColors + i * nComps;
+      }
+      for (int i = 0; i < nComps; ++i) {
+	*dataPtr++ = sColor[i];
+      }
+      *alphaPtr++ = 0xff;
+    }
+  }
+
+  gfree(sColors);
+
+  *xOut = xMin;
+  *yOut = yMin;
+  return bitmap;
+}
+
+SplashBitmap *ShadingImage::generateGouraudTriangleBitmap(
+					GfxState *state,
+					GfxGouraudTriangleShading *shading,
+					SplashColorMode mode,
+					GBool reverseVideo,
+					Splash *parentSplash,
+					SplashBitmap *parentBitmap,
+					int *xOut, int *yOut) {
+  // get the clip bbox
+  double fxMin, fyMin, fxMax, fyMax;
+  state->getClipBBox(&fxMin, &fyMin, &fxMax, &fyMax);
+  if (fxMin > fxMax || fyMin > fyMax) {
+    return NULL;
+  }
+
+  // get the shading bbox
+  double tx0, ty0, tx1, ty1, dx, dy, txMin, tyMin, txMax, tyMax;
+  shading->getBBox(&tx0, &ty0, &tx1, &ty1);
+  state->transform(tx0, ty0, &dx, &dy);
+  txMin = txMax = dx;
+  tyMin = tyMax = dy;
+  state->transform(tx0, ty1, &dx, &dy);
+  if (dx < txMin) {
+    txMin = dx;
+  } else if (dx > txMax) {
+    txMax = dx;
+  }
+  if (dy < tyMin) {
+    tyMin = dy;
+  } else if (dy > tyMax) {
+    tyMax = dy;
+  }
+  state->transform(tx1, ty0, &dx, &dy);
+  if (dx < txMin) {
+    txMin = dx;
+  } else if (dx > txMax) {
+    txMax = dx;
+  }
+  if (dy < tyMin) {
+    tyMin = dy;
+  } else if (dy > tyMax) {
+    tyMax = dy;
+  }
+  state->transform(tx1, ty1, &dx, &dy);
+  if (dx < txMin) {
+    txMin = dx;
+  } else if (dx > txMax) {
+    txMax = dx;
+  }
+  if (dy < tyMin) {
+    tyMin = dy;
+  } else if (dy > tyMax) {
+    tyMax = dy;
+  }
+  if (txMin > fxMin) {
+    fxMin = txMin;
+  }
+  if (txMax < fxMax) {
+    fxMax = txMax;
+  }
+  if (tyMin > fyMin) {
+    fyMin = tyMin;
+  }
+  if (tyMax < fyMax) {
+    fyMax = tyMax;
+  }
+  if (fxMin > fxMax || fyMin > fyMax) {
+    return NULL;
+  }
+
+  // convert to integer coords
+  int xMin = (int)floor(fxMin);
+  int yMin = (int)floor(fyMin);
+  int xMax = (int)floor(fxMax) + 1;
+  int yMax = (int)floor(fyMax) + 1;
+  int bitmapWidth = xMax - xMin;
+  int bitmapHeight = yMax - yMin;
+
+  // allocate the bitmap
+  traceMessage("Gouraud triangle shading fill bitmap");
+  SplashBitmap *bitmap = new SplashBitmap(bitmapWidth, bitmapHeight, 1, mode,
+					  gTrue, gTrue, parentBitmap);
+
+  // clear the bitmap
+  memset(bitmap->getDataPtr(), 0, bitmap->getHeight() * bitmap->getRowSize());
+  memset(bitmap->getAlphaPtr(), 0, bitmap->getHeight() * bitmap->getWidth());
+
+  // draw the triangles
+  for (int i = 0; i < shading->getNTriangles(); ++i) {
+    double x0, y0, x1, y1, x2, y2;
+    double color0[gfxColorMaxComps];
+    double color1[gfxColorMaxComps];
+    double color2[gfxColorMaxComps];
+    shading->getTriangle(i, &x0, &y0, color0,
+			 &x1, &y1, color1,
+			 &x2, &y2, color2);
+    gouraudFillTriangle(state, bitmap, mode, reverseVideo,
+			xMin, yMin, xMax, yMax,
+			x0, y0, color0, x1, y1, color1, x2, y2, color2,
+			shading);
+  }
+
+  *xOut = xMin;
+  *yOut = yMin;
+  return bitmap;
+}
+
+void ShadingImage::gouraudFillTriangle(GfxState *state, SplashBitmap *bitmap,
+				       SplashColorMode mode,
+				       GBool reverseVideo,
+				       int xMin, int yMin, int xMax, int yMax,
+				       double x0, double y0, double *color0,
+				       double x1, double y1, double *color1,
+				       double x2, double y2, double *color2,
+				       GfxGouraudTriangleShading *shading) {
+  int nShadingComps = shading->getNComps();
+  int nBitmapComps = splashColorModeNComps[mode];
+
+  //--- transform the vertices to device space, sort by y
+  double dx0, dy0, dx1, dy1, dx2, dy2;
+  state->transform(x0, y0, &dx0, &dy0);
+  state->transform(x1, y1, &dx1, &dy1);
+  state->transform(x2, y2, &dx2, &dy2);
+  if (dy0 > dy1) {
+    double t = dx0;  dx0 = dx1;  dx1 = t;
+    t = dy0;  dy0 = dy1;  dy1 = t;
+    double *tc = color0;  color0 = color1;  color1 = tc;
+  }
+  if (dy1 > dy2) {
+    double t = dx1;  dx1 = dx2;  dx2 = t;
+    t = dy1;  dy1 = dy2;  dy2 = t;
+    double *tc = color1;  color1 = color2;  color2 = tc;
+  }
+  if (dy0 > dy1) {
+    double t = dx0;  dx0 = dx1;  dx1 = t;
+    t = dy0;  dy0 = dy1;  dy1 = t;
+    double *tc = color0;  color0 = color1;  color1 = tc;
+  }
+
+  //--- y loop
+  int syMin = (int)floor(dy0);
+  if (syMin < yMin) {
+    syMin = yMin;
+  }
+  int syMax = (int)floor(dy2) + 1;
+  if (syMax > yMax) {
+    syMax = yMax;
+  }
+  for (int sy = syMin; sy < syMax; ++sy) {
+
+    //--- vertical interpolation
+    double xx0, xx1;
+    double cc0[gfxColorMaxComps], cc1[gfxColorMaxComps];
+    if (sy <= dy0) {
+      xx0 = xx1 = dx0;
+      for (int i = 0; i < nShadingComps; ++i) {
+	cc0[i] = cc1[i] = color0[i];
+      }
+    } else if (sy >= dy2) {
+      xx0 = xx1 = dx2;
+      for (int i = 0; i < nShadingComps; ++i) {
+	cc0[i] = cc1[i] = color2[i];
+      }
+    } else {
+      if (sy <= dy1) {
+	double interp = (sy - dy0) / (dy1 - dy0);
+	xx0 = dx0 + interp * (dx1 - dx0);
+	for (int i = 0; i < nShadingComps; ++i) {
+	  cc0[i] = color0[i] + interp * (color1[i] - color0[i]);
+	}
+      } else {
+	double interp = (sy - dy1) / (dy2 - dy1);
+	xx0 = dx1 + interp * (dx2 - dx1);
+	for (int i = 0; i < nShadingComps; ++i) {
+	  cc0[i] = color1[i] + interp * (color2[i] - color1[i]);
+	}
+      }
+      double interp = (sy - dy0) / (dy2 - dy0);
+      xx1 = dx0 + interp * (dx2 - dx0);
+      for (int i = 0; i < nShadingComps; ++i) {
+	cc1[i] = color0[i] + interp * (color2[i] - color0[i]);
+      }
+    }
+
+    //--- x loop
+    if (xx0 > xx1) {
+      double t = xx0;  xx0 = xx1;  xx1 = t;
+      for (int i = 0; i < nShadingComps; ++i) {
+	t = cc0[i];  cc0[i] = cc1[i];  cc1[i] = t;
+      }
+    }
+    int sxMin = (int)floor(xx0);
+    if (sxMin < xMin) {
+      sxMin = xMin;
+    }
+    int sxMax = (int)floor(xx1) + 1;
+    if (sxMax > xMax) {
+      sxMax = xMax;
+    }
+    SplashColorPtr dataPtr = bitmap->getDataPtr()
+                             + (sy - yMin) * bitmap->getRowSize()
+                             + (sxMin - xMin) * nBitmapComps;
+    if (sxMin < sxMax) {
+      Guchar *alphaPtr = bitmap->getAlphaPtr()
+	                 + (sy - yMin) * bitmap->getWidth()
+	                 + (sxMin - xMin);
+      memset(alphaPtr, 0xff, sxMax - sxMin);
+    }
+    for (int sx = sxMin; sx < sxMax; ++sx) {
+
+      //--- horizontal interpolation
+      double cc[gfxColorMaxComps];
+      if (sx <= xx0) {
+	for (int i = 0; i < nShadingComps; ++i) {
+	  cc[i] = cc0[i];
+	}
+      } else if (sx >= xx1) {
+	for (int i = 0; i < nShadingComps; ++i) {
+	  cc[i] = cc1[i];
+	}
+      } else {
+	for (int i = 0; i < nShadingComps; ++i) {
+	  double interp = (sx - xx0) / (xx1 - xx0);
+	  cc[i] = cc0[i] + interp * (cc1[i] - cc0[i]);
+	}
+      }
+
+      //--- compute color and set pixel
+      GfxColor gColor;
+      shading->getColor(cc, &gColor);
+      SplashColor sColor;
+      computeShadingColor(state, mode, reverseVideo, &gColor, sColor);
+      for (int i = 0; i < nBitmapComps; ++i) {
+	dataPtr[i] = sColor[i];
+      }
+      dataPtr += nBitmapComps;
+    }
+  }
+}
+
+SplashBitmap *ShadingImage::generatePatchMeshBitmap(
+					GfxState *state,
+					GfxPatchMeshShading *shading,
+					SplashColorMode mode,
+					GBool reverseVideo,
+					Splash *parentSplash,
+					SplashBitmap *parentBitmap,
+					int *xOut, int *yOut) {
+  // get the clip bbox
+  double fxMin, fyMin, fxMax, fyMax;
+  state->getClipBBox(&fxMin, &fyMin, &fxMax, &fyMax);
+  if (fxMin > fxMax || fyMin > fyMax) {
+    return NULL;
+  }
+
+  // get the shading bbox
+  double tx0, ty0, tx1, ty1, dx, dy, txMin, tyMin, txMax, tyMax;
+  shading->getBBox(&tx0, &ty0, &tx1, &ty1);
+  state->transform(tx0, ty0, &dx, &dy);
+  txMin = txMax = dx;
+  tyMin = tyMax = dy;
+  state->transform(tx0, ty1, &dx, &dy);
+  if (dx < txMin) {
+    txMin = dx;
+  } else if (dx > txMax) {
+    txMax = dx;
+  }
+  if (dy < tyMin) {
+    tyMin = dy;
+  } else if (dy > tyMax) {
+    tyMax = dy;
+  }
+  state->transform(tx1, ty0, &dx, &dy);
+  if (dx < txMin) {
+    txMin = dx;
+  } else if (dx > txMax) {
+    txMax = dx;
+  }
+  if (dy < tyMin) {
+    tyMin = dy;
+  } else if (dy > tyMax) {
+    tyMax = dy;
+  }
+  state->transform(tx1, ty1, &dx, &dy);
+  if (dx < txMin) {
+    txMin = dx;
+  } else if (dx > txMax) {
+    txMax = dx;
+  }
+  if (dy < tyMin) {
+    tyMin = dy;
+  } else if (dy > tyMax) {
+    tyMax = dy;
+  }
+  if (txMin > fxMin) {
+    fxMin = txMin;
+  }
+  if (txMax < fxMax) {
+    fxMax = txMax;
+  }
+  if (tyMin > fyMin) {
+    fyMin = tyMin;
+  }
+  if (tyMax < fyMax) {
+    fyMax = tyMax;
+  }
+  if (fxMin > fxMax || fyMin > fyMax) {
+    return NULL;
+  }
+
+  // convert to integer coords
+  int xMin = (int)floor(fxMin);
+  int yMin = (int)floor(fyMin);
+  int xMax = (int)floor(fxMax) + 1;
+  int yMax = (int)floor(fyMax) + 1;
+  int bitmapWidth = xMax - xMin;
+  int bitmapHeight = yMax - yMin;
+
+  // allocate the bitmap
+  traceMessage("Gouraud triangle shading fill bitmap");
+  SplashBitmap *bitmap = new SplashBitmap(bitmapWidth, bitmapHeight, 1, mode,
+					  gTrue, gTrue, parentBitmap);
+
+  // allocate a Splash object
+  // vector antialiasing is disabled to avoid artifacts along triangle edges
+  Splash *splash = new Splash(bitmap, gFalse,
+			      parentSplash->getImageCache(),
+			      parentSplash->getScreen());
+  SplashColor zero;
+  for (int i = 0; i < splashColorModeNComps[mode]; ++i) {
+    zero[i] = 0;
+  }
+  splash->clear(zero, 0x00);
+
+  // draw the patches
+  int start;
+  if (shading->getNPatches() > 128) {
+    start = 3;
+  } else if (shading->getNPatches() > 64) {
+    start = 2;
+  } else if (shading->getNPatches() > 16) {
+    start = 1;
+  } else {
+    start = 0;
+  }
+  for (int i = 0; i < shading->getNPatches(); ++i) {
+    fillPatch(state, splash, mode, reverseVideo,
+	      xMin, yMin, shading->getPatch(i), shading, start);
+  }
+
+  delete splash;
+
+  *xOut = xMin;
+  *yOut = yMin;
+  return bitmap;
+}
+
+void ShadingImage::fillPatch(GfxState *state, Splash *splash,
+			     SplashColorMode mode, GBool reverseVideo,
+			     int xMin, int yMin,
+			     GfxPatch *patch,
+			     GfxPatchMeshShading *shading,
+			     int depth) {
+  GfxColor c00;
+  shading->getColor(patch->color[0][0], &c00);
+  GBool stop = gFalse;
+
+  // stop subdivision at max depth
+  if (depth == patchMaxDepth) {
+    stop = gTrue;
+  }
+
+  // stop subdivision if colors are close enough
+  if (!stop) {
+    int nComps = shading->getColorSpace()->getNComps();
+    GfxColor c01, c10, c11;
+    shading->getColor(patch->color[0][1], &c01);
+    shading->getColor(patch->color[1][0], &c10);
+    shading->getColor(patch->color[1][1], &c11);
+    int i;
+    for (i = 0; i < nComps; ++i) {
+      if (abs(c00.c[i] - c01.c[i]) > patchColorDelta ||
+	  abs(c01.c[i] - c11.c[i]) > patchColorDelta ||
+	  abs(c11.c[i] - c10.c[i]) > patchColorDelta ||
+	  abs(c10.c[i] - c00.c[i]) > patchColorDelta) {
+	break;
+      }
+    }
+    if (i == nComps) {
+      stop = gTrue;
+    }
+  }
+
+  // stop subdivision if patch is small enough
+  if (!stop) {
+    double xxMin = 0;
+    double yyMin = 0;
+    double xxMax = 0;
+    double yyMax = 0;
+    for (int j = 0; j < 4; ++j) {
+      for (int i = 0; i < 4; ++i) {
+	double xx, yy;
+	state->transformDelta(patch->x[i][j], patch->y[i][j], &xx, &yy);
+	if (i == 0 && j == 0) {
+	  xxMin = xxMax = xx;
+	  yyMin = yyMax = yy;
+	} else {
+	  if (xx < xxMin) {
+	    xxMin = xx;
+	  } else if (xx > xxMax) {
+	    xxMax = xx;
+	  }
+	  if (yy < yyMin) {
+	    yyMin = yy;
+	  } else if (yy > yyMax) {
+	    yyMax = yy;
+	  }
+	}
+      }
+    }
+    if (xxMax - xxMin < 1 && yyMax - yyMin < 1) {
+      stop = gTrue;
+    }
+  }
+
+  // draw the patch
+  if (stop) {
+    SplashColor sColor;
+    computeShadingColor(state, mode, reverseVideo, &c00, sColor);
+    splash->setFillPattern(new SplashSolidColor(sColor));
+    SplashPath *path = new SplashPath();
+    double xx0, yy0, xx1, yy1, xx2, yy2, xx3, yy3;
+    state->transform(patch->x[0][0], patch->y[0][0], &xx0, &yy0);
+    path->moveTo(xx0 - xMin, yy0 - yMin);
+    state->transform(patch->x[0][1], patch->y[0][1], &xx1, &yy1);
+    state->transform(patch->x[0][2], patch->y[0][2], &xx2, &yy2);
+    state->transform(patch->x[0][3], patch->y[0][3], &xx3, &yy3);
+    path->curveTo(xx1 - xMin, yy1 - yMin, xx2 - xMin, yy2 - yMin,
+		  xx3 - xMin, yy3 - yMin);
+    state->transform(patch->x[1][3], patch->y[1][3], &xx1, &yy1);
+    state->transform(patch->x[2][3], patch->y[2][3], &xx2, &yy2);
+    state->transform(patch->x[3][3], patch->y[3][3], &xx3, &yy3);
+    path->curveTo(xx1 - xMin, yy1 - yMin, xx2 - xMin, yy2 - yMin,
+		  xx3 - xMin, yy3 - yMin);
+    state->transform(patch->x[3][2], patch->y[3][2], &xx1, &yy1);
+    state->transform(patch->x[3][1], patch->y[3][1], &xx2, &yy2);
+    state->transform(patch->x[3][0], patch->y[3][0], &xx3, &yy3);
+    path->curveTo(xx1 - xMin, yy1 - yMin, xx2 - xMin, yy2 - yMin,
+		  xx3 - xMin, yy3 - yMin);
+    state->transform(patch->x[2][0], patch->y[2][0], &xx1, &yy1);
+    state->transform(patch->x[1][0], patch->y[1][0], &xx2, &yy2);
+    path->curveTo(xx1 - xMin, yy1 - yMin, xx2 - xMin, yy2 - yMin,
+		  xx0 - xMin, yy0 - yMin);
+    path->close();
+    splash->fill(path, gFalse);
+    delete path;
+
+  // subdivide the patch
+  } else {
+    double xx[4][8], yy[4][8];
+    for (int i = 0; i < 4; ++i) {
+      xx[i][0] = patch->x[i][0];
+      yy[i][0] = patch->y[i][0];
+      xx[i][1] = 0.5 * (patch->x[i][0] + patch->x[i][1]);
+      yy[i][1] = 0.5 * (patch->y[i][0] + patch->y[i][1]);
+      double xxm = 0.5 * (patch->x[i][1] + patch->x[i][2]);
+      double yym = 0.5 * (patch->y[i][1] + patch->y[i][2]);
+      xx[i][6] = 0.5 * (patch->x[i][2] + patch->x[i][3]);
+      yy[i][6] = 0.5 * (patch->y[i][2] + patch->y[i][3]);
+      xx[i][2] = 0.5 * (xx[i][1] + xxm);
+      yy[i][2] = 0.5 * (yy[i][1] + yym);
+      xx[i][5] = 0.5 * (xxm + xx[i][6]);
+      yy[i][5] = 0.5 * (yym + yy[i][6]);
+      xx[i][3] = xx[i][4] = 0.5 * (xx[i][2] + xx[i][5]);
+      yy[i][3] = yy[i][4] = 0.5 * (yy[i][2] + yy[i][5]);
+      xx[i][7] = patch->x[i][3];
+      yy[i][7] = patch->y[i][3];
+    }
+    GfxPatch patch00, patch01, patch10, patch11;
+    for (int i = 0; i < 4; ++i) {
+      patch00.x[0][i] = xx[0][i];
+      patch00.y[0][i] = yy[0][i];
+      patch00.x[1][i] = 0.5 * (xx[0][i] + xx[1][i]);
+      patch00.y[1][i] = 0.5 * (yy[0][i] + yy[1][i]);
+      double xxm = 0.5 * (xx[1][i] + xx[2][i]);
+      double yym = 0.5 * (yy[1][i] + yy[2][i]);
+      patch10.x[2][i] = 0.5 * (xx[2][i] + xx[3][i]);
+      patch10.y[2][i] = 0.5 * (yy[2][i] + yy[3][i]);
+      patch00.x[2][i] = 0.5 * (patch00.x[1][i] + xxm);
+      patch00.y[2][i] = 0.5 * (patch00.y[1][i] + yym);
+      patch10.x[1][i] = 0.5 * (xxm + patch10.x[2][i]);
+      patch10.y[1][i] = 0.5 * (yym + patch10.y[2][i]);
+      patch00.x[3][i] = 0.5 * (patch00.x[2][i] + patch10.x[1][i]);
+      patch00.y[3][i] = 0.5 * (patch00.y[2][i] + patch10.y[1][i]);
+      patch10.x[0][i] = patch00.x[3][i];
+      patch10.y[0][i] = patch00.y[3][i];
+      patch10.x[3][i] = xx[3][i];
+      patch10.y[3][i] = yy[3][i];
+    }
+    for (int i = 4; i < 8; ++i) {
+      patch01.x[0][i-4] = xx[0][i];
+      patch01.y[0][i-4] = yy[0][i];
+      patch01.x[1][i-4] = 0.5 * (xx[0][i] + xx[1][i]);
+      patch01.y[1][i-4] = 0.5 * (yy[0][i] + yy[1][i]);
+      double xxm = 0.5 * (xx[1][i] + xx[2][i]);
+      double yym = 0.5 * (yy[1][i] + yy[2][i]);
+      patch11.x[2][i-4] = 0.5 * (xx[2][i] + xx[3][i]);
+      patch11.y[2][i-4] = 0.5 * (yy[2][i] + yy[3][i]);
+      patch01.x[2][i-4] = 0.5 * (patch01.x[1][i-4] + xxm);
+      patch01.y[2][i-4] = 0.5 * (patch01.y[1][i-4] + yym);
+      patch11.x[1][i-4] = 0.5 * (xxm + patch11.x[2][i-4]);
+      patch11.y[1][i-4] = 0.5 * (yym + patch11.y[2][i-4]);
+      patch01.x[3][i-4] = 0.5 * (patch01.x[2][i-4] + patch11.x[1][i-4]);
+      patch01.y[3][i-4] = 0.5 * (patch01.y[2][i-4] + patch11.y[1][i-4]);
+      patch11.x[0][i-4] = patch01.x[3][i-4];
+      patch11.y[0][i-4] = patch01.y[3][i-4];
+      patch11.x[3][i-4] = xx[3][i];
+      patch11.y[3][i-4] = yy[3][i];
+    }
+    for (int i = 0; i < shading->getNComps(); ++i) {
+      patch00.color[0][0][i] = patch->color[0][0][i];
+      patch00.color[0][1][i] = 0.5 * (patch->color[0][0][i] +
+				      patch->color[0][1][i]);
+      patch01.color[0][0][i] = patch00.color[0][1][i];
+      patch01.color[0][1][i] = patch->color[0][1][i];
+      patch01.color[1][1][i] = 0.5 * (patch->color[0][1][i] +
+				      patch->color[1][1][i]);
+      patch11.color[0][1][i] = patch01.color[1][1][i];
+      patch11.color[1][1][i] = patch->color[1][1][i];
+      patch11.color[1][0][i] = 0.5 * (patch->color[1][1][i] +
+				      patch->color[1][0][i]);
+      patch10.color[1][1][i] = patch11.color[1][0][i];
+      patch10.color[1][0][i] = patch->color[1][0][i];
+      patch10.color[0][0][i] = 0.5 * (patch->color[1][0][i] +
+				      patch->color[0][0][i]);
+      patch00.color[1][0][i] = patch10.color[0][0][i];
+      patch00.color[1][1][i] = 0.5 * (patch00.color[1][0][i] +
+				      patch01.color[1][1][i]);
+      patch01.color[1][0][i] = patch00.color[1][1][i];
+      patch11.color[0][0][i] = patch00.color[1][1][i];
+      patch10.color[0][1][i] = patch00.color[1][1][i];
+    }
+    fillPatch(state, splash, mode, reverseVideo, xMin, yMin, &patch00,
+	      shading, depth + 1);
+    fillPatch(state, splash, mode, reverseVideo, xMin, yMin, &patch10,
+	      shading, depth + 1);
+    fillPatch(state, splash, mode, reverseVideo, xMin, yMin, &patch01,
+	      shading, depth + 1);
+    fillPatch(state, splash, mode, reverseVideo, xMin, yMin, &patch11,
+	      shading, depth + 1);
+  }
+}
+
+void ShadingImage::computeShadingColor(GfxState *state,
+				       SplashColorMode mode,
+				       GBool reverseVideo,
+				       GfxColor *color,
+				       SplashColorPtr sColor) {
+  GfxGray gray;
+  GfxRGB rgb;
+#if SPLASH_CMYK
+  GfxCMYK cmyk;
+#endif
+
+  state->setFillColor(color);
+  switch (mode) {
+  case splashModeMono8:
+    state->getFillGray(&gray);
+    if (reverseVideo) {
+      gray = gfxColorComp1 - gray;
+    }
+    sColor[0] = colToByte(gray);
+    break;
+  case splashModeRGB8:
+    state->getFillRGB(&rgb);
+    if (reverseVideo) {
+      rgb.r = gfxColorComp1 - rgb.r;
+      rgb.g = gfxColorComp1 - rgb.g;
+      rgb.b = gfxColorComp1 - rgb.b;
+    }
+    sColor[0] = colToByte(rgb.r);
+    sColor[1] = colToByte(rgb.g);
+    sColor[2] = colToByte(rgb.b);
+    break;
+#if SPLASH_CMYK
+  case splashModeCMYK8:
+    state->getFillCMYK(&cmyk);
+    sColor[0] = colToByte(cmyk.c);
+    sColor[1] = colToByte(cmyk.m);
+    sColor[2] = colToByte(cmyk.y);
+    sColor[3] = colToByte(cmyk.k);
+    break;
+#endif
+  case splashModeMono1:
+  case splashModeBGR8:
+    // mode cannot be Mono1 or BGR8
+    break;
+  }
+}
+
+// Transform a user space bbox to a device space bbox.
+void ShadingImage::transformBBox(GfxState *state,
+				 double uxMin, double uyMin,
+				 double uxMax, double uyMax,
+				 double *dxMin, double *dyMin,
+				 double *dxMax, double *dyMax) {
+  double tx, ty;
+  state->transform(uxMin, uyMin, &tx, &ty);
+  *dxMin = *dxMax = tx;
+  *dyMin = *dyMax = ty;
+  state->transform(uxMin, uyMax, &tx, &ty);
+  if (tx < *dxMin) {
+    *dxMin = tx;
+  } else if (tx > *dxMax) {
+    *dxMax = tx;
+  }
+  if (ty < *dyMin) {
+    *dyMin = ty;
+  } else if (ty > *dyMax) {
+    *dyMax = ty;
+  }
+  state->transform(uxMax, uyMin, &tx, &ty);
+  if (tx < *dxMin) {
+    *dxMin = tx;
+  } else if (tx > *dxMax) {
+    *dxMax = tx;
+  }
+  if (ty < *dyMin) {
+    *dyMin = ty;
+  } else if (ty > *dyMax) {
+    *dyMax = ty;
+  }
+  state->transform(uxMax, uyMax, &tx, &ty);
+  if (tx < *dxMin) {
+    *dxMin = tx;
+  } else if (tx > *dxMax) {
+    *dxMax = tx;
+  }
+  if (ty < *dyMin) {
+    *dyMin = ty;
+  } else if (ty > *dyMax) {
+    *dyMax = ty;
+  }
+}
+


Property changes on: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/ShadingImage.cc
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/ShadingImage.h
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/ShadingImage.h	                        (rev 0)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/ShadingImage.h	2021-02-15 19:17:20 UTC (rev 845)
@@ -0,0 +1,106 @@
+//========================================================================
+//
+// ShadingImage.h
+//
+// Convert shading patterns to bitmaps.
+//
+// Copyright 2020 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef SHADINGIMAGE_H
+#define SHADINGIMAGE_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "SplashTypes.h"
+
+class GfxState;
+class GfxShading;
+class SplashBitmap;
+class Splash;
+
+class ShadingImage {
+public:
+
+  // Generate a [mode] bitmap for [shading], using the clipping and
+  // CTM info from [state].  Returns the bitmap and sets [xOut],[yOut]
+  // to the upper-left corner of the region in device space.  Returns
+  // NULL if the clip region is empty.
+  static SplashBitmap *generateBitmap(GfxState *state, GfxShading *shading,
+				      SplashColorMode mode,
+				      GBool reverseVideo,
+				      Splash *parentSplash,
+				      SplashBitmap *parentBitmap,
+				      int *xOut, int *yOut);
+
+
+private:
+
+  static SplashBitmap *generateFunctionBitmap(GfxState *state,
+					      GfxFunctionShading *shading,
+					      SplashColorMode mode,
+					      GBool reverseVideo,
+					      Splash *parentSplash,
+					      SplashBitmap *parentBitmap,
+					      int *xOut, int *yOut);
+  static SplashBitmap *generateAxialBitmap(GfxState *state,
+					   GfxAxialShading *shading,
+					   SplashColorMode mode,
+					   GBool reverseVideo,
+					   Splash *parentSplash,
+					   SplashBitmap *parentBitmap,
+					   int *xOut, int *yOut);
+  static SplashBitmap *generateRadialBitmap(GfxState *state,
+					    GfxRadialShading *shading,
+					    SplashColorMode mode,
+					    GBool reverseVideo,
+					    Splash *parentSplash,
+					    SplashBitmap *parentBitmap,
+					    int *xOut, int *yOut);
+  static SplashBitmap *generateGouraudTriangleBitmap(
+					GfxState *state,
+					GfxGouraudTriangleShading *shading,
+					SplashColorMode mode,
+					GBool reverseVideo,
+					Splash *parentSplash,
+					SplashBitmap *parentBitmap,
+					int *xOut, int *yOut);
+  static void gouraudFillTriangle(GfxState *state, SplashBitmap *bitmap,
+				  SplashColorMode mode,
+				  GBool reverseVideo,
+				  int xMin, int yMin, int xMax, int yMax,
+				  double x0, double y0, double *color0,
+				  double x1, double y1, double *color1,
+				  double x2, double y2, double *color2,
+				  GfxGouraudTriangleShading *shading);
+  static SplashBitmap *generatePatchMeshBitmap(GfxState *state,
+					       GfxPatchMeshShading *shading,
+					       SplashColorMode mode,
+					       GBool reverseVideo,
+					       Splash *parentSplash,
+					       SplashBitmap *parentBitmap,
+					       int *xOut, int *yOut);
+  static void fillPatch(GfxState *state, Splash *splash,
+			SplashColorMode mode, GBool reverseVideo,
+			int xMin, int yMin,
+			GfxPatch *patch,
+			GfxPatchMeshShading *shading,
+			int depth);
+  static void computeShadingColor(GfxState *state,
+				  SplashColorMode mode,
+				  GBool reverseVideo,
+				  GfxColor *color,
+				  SplashColorPtr sColor);
+  static void transformBBox(GfxState *state,
+			    double uxMin, double uyMin,
+			    double uxMax, double uyMax,
+			    double *dxMin, double *dyMin,
+			    double *dxMax, double *dyMax);
+};
+
+#endif


Property changes on: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/ShadingImage.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/SplashOutputDev.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/SplashOutputDev.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/SplashOutputDev.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -17,11 +17,13 @@
 #include <limits.h>
 #include "gmempp.h"
 #include "gfile.h"
+#include "Trace.h"
 #include "GlobalParams.h"
 #include "Error.h"
 #include "Object.h"
 #include "Gfx.h"
 #include "GfxFont.h"
+#include "ShadingImage.h"
 #include "Link.h"
 #include "CharCodeToUnicode.h"
 #include "FontEncodingTables.h"
@@ -52,6 +54,18 @@
 
 //------------------------------------------------------------------------
 
+// max tile size (used in tilingPatternFill())
+// - Adobe uses a resolution-independent threshold here, of 6M sq pts
+// - xpdf uses a resolution-dependent max, but with different values
+//   on 32-bit and 64-bit systems
+#if SplashBitmapRowSizeMax == INT_MAX
+#  define maxTileSize 200000000
+#else
+#  define maxTileSize 2000000000
+#endif
+
+//------------------------------------------------------------------------
+
 // Type 3 font cache size parameters
 #define type3FontCacheAssoc   8
 #define type3FontCacheMaxSets 8
@@ -67,6 +81,11 @@
 
 //------------------------------------------------------------------------
 
+// 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 : (Guchar)x;
@@ -499,7 +518,7 @@
   int cacheAssoc;		// cache associativity (glyphs per set)
   Guchar *cacheData;		// glyph pixmap cache
   T3FontCacheTag *cacheTags;	// cache tags, i.e., char codes
-  GBool inUse;			// set while this T3 font is in active use
+  int refCount;			// active reference count for this T3 font
 };
 
 T3FontCache::T3FontCache(Ref *fontIDA, double m11A, double m12A,
@@ -541,7 +560,7 @@
   for (i = 0; i < cacheSets * cacheAssoc; ++i) {
     cacheTags[i].mru = (Gushort)(i & (cacheAssoc - 1));
   }
-  inUse = gFalse;
+  refCount = 0;
 }
 
 T3FontCache::~T3FontCache() {
@@ -565,6 +584,7 @@
   SplashBitmap *origBitmap;
   Splash *origSplash;
   double origCTM4, origCTM5;
+  SplashStrokeAdjustMode savedStrokeAdjust;
 
   T3GlyphStack *next;		// next object on stack
 };
@@ -711,6 +731,9 @@
   if (bitmap) {
     delete bitmap;
   }
+  if (textClipPath) {
+    delete textClipPath;
+  }
 }
 
 void SplashOutputDev::startDoc(XRef *xrefA) {
@@ -763,6 +786,7 @@
       delete bitmap;
       bitmap = NULL;
     }
+    traceMessage("page bitmap");
     bitmap = new SplashBitmap(w, h, bitmapRowPad, colorMode,
 			      colorMode != splashModeMono1, bitmapTopDown,
 			      NULL);
@@ -1194,18 +1218,21 @@
     goto err1;
   }
 
-  // sanity-check the font size - skip anything larger than 20 inches
-  // (this avoids problems allocating memory for the font cache)
+  // sanity-check the font size: skip anything larger than 10k x 10k,
+  // to avoid problems allocating a bitmap (note that code in
+  // SplashFont disables caching at a smaller size than this)
   state->textTransformDelta(state->getFontSize(), state->getFontSize(),
 			    &fsx, &fsy);
   state->transformDelta(fsx, fsy, &fsx, &fsy);
-  if (fabs(fsx) > 20 * state->getHDPI() ||
-      fabs(fsy) > 20 * state->getVDPI()) {
+  if (fabs(fsx) > 20000 || fabs(fsy) > 20000) {
     goto err1;
   }
 
   // check the font file cache
   id = new SplashOutFontFileID(gfxFont->getID());
+  if (fontEngine->checkForBadFontFile(id)) {
+    goto err2;
+  }
   if ((fontFile = fontEngine->getFontFile(id))) {
     delete id;
 
@@ -1308,7 +1335,7 @@
 	      gfxFont->getName() ? gfxFont->getName()->getCString()
 	                         : "(unnamed)");
 	delete fontLoc;
-	goto err2;
+	goto err1;
       }
       break;
     case fontType1C:
@@ -1337,7 +1364,7 @@
 	      gfxFont->getName() ? gfxFont->getName()->getCString()
 	                         : "(unnamed)");
 	delete fontLoc;
-	goto err2;
+	goto err1;
       }
       break;
     case fontType1COT:
@@ -1370,7 +1397,7 @@
 	      gfxFont->getName() ? gfxFont->getName()->getCString()
 	                         : "(unnamed)");
 	delete fontLoc;
-	goto err2;
+	goto err1;
       }
       break;
     case fontTrueType:
@@ -1415,7 +1442,7 @@
 	      gfxFont->getName() ? gfxFont->getName()->getCString()
 	                         : "(unnamed)");
 	delete fontLoc;
-	goto err2;
+	goto err1;
       }
       break;
     case fontCIDType0:
@@ -1443,7 +1470,7 @@
 	      gfxFont->getName() ? gfxFont->getName()->getCString()
 	                         : "(unnamed)");
 	delete fontLoc;
-	goto err2;
+	goto err1;
       }
       break;
     case fontCIDType0COT:
@@ -1513,7 +1540,7 @@
 	      gfxFont->getName() ? gfxFont->getName()->getCString()
 	                         : "(unnamed)");
 	delete fontLoc;
-	goto err2;
+	goto err1;
       }
       break;
     case fontCIDType2:
@@ -1588,7 +1615,7 @@
 	      gfxFont->getName() ? gfxFont->getName()->getCString()
 	                         : "(unnamed)");
 	delete fontLoc;
-	goto err2;
+	goto err1;
       }
       break;
     default:
@@ -1734,6 +1761,7 @@
   SplashBitmap *origBitmap, *tileBitmap;
   Splash *origSplash;
   SplashColor color;
+  Guint *overprintMaskBitmap;
   double *ctm;
   double ictm[6], tileMat[6], mat1[6], mat2[6];
   double tileXMin, tileYMin, tileXMax, tileYMax;
@@ -1818,7 +1846,7 @@
   if (tileXMax - tileXMin + 0.5 > (double)INT_MAX ||
       tileYMax - tileYMin + 0.5 > (double)INT_MAX ||
       tileW > INT_MAX / tileH ||
-      tileSize > 1000000) {
+      tileSize > maxTileSize) {
     mat1[0] = mat[0];
     mat1[1] = mat[1];
     mat1[2] = mat[2];
@@ -1969,6 +1997,7 @@
   // create a temporary bitmap
   origBitmap = bitmap;
   origSplash = splash;
+  traceMessage("tiling pattern bitmap");
   bitmap = tileBitmap = new SplashBitmap(tileW, tileH, bitmapRowPad,
 					 colorMode, gTrue, bitmapTopDown,
 					 origBitmap);
@@ -1978,6 +2007,20 @@
     color[i] = 0;
   }
   splash->clear(color);
+#if SPLASH_CMYK
+  // if we're doing overprint preview, we need to track the overprint
+  // mask at each pixel in the tile bitmap
+  if (globalParams->getOverprintPreview() &&
+      colorMode == splashModeCMYK8) {
+    overprintMaskBitmap = (Guint *)gmallocn(tileH, tileW * (int)sizeof(Guint));
+    memset(overprintMaskBitmap, 0, tileH * tileW * sizeof(Guint));
+    splash->setOverprintMaskBitmap(overprintMaskBitmap);
+  } else {
+    overprintMaskBitmap = NULL;
+  }
+#else // SPLASH_CMYK
+  overprintMaskBitmap = NULL;
+#endif // SPLASH_CMYK
   splash->setMinLineWidth(globalParams->getMinLineWidth());
   splash->setStrokeAdjust(
 		 mapStrokeAdjustMode[globalParams->getStrokeAdjust()]);
@@ -2005,434 +2048,48 @@
   splash->setOverprintMask(0xffffffff);
 
   // draw the tiles
-  for (iy = iyMin; iy < iyMax; ++iy) {
-    for (ix = ixMin; ix < ixMax; ++ix) {
-      x = (int)(adjXMin + ix * xStepX + iy * yStepX + 0.5);
-      y = (int)(adjYMin + ix * xStepY + iy * yStepY + 0.5);
-      splash->composite(tileBitmap, 0, 0, x, y, tileW, tileH,
-			gFalse, gFalse);
-    }
-  }
-
-  delete tileBitmap;
-}
-
-GBool SplashOutputDev::axialShadedFill(GfxState *state,
-				       GfxAxialShading *shading) {
-  double x0, y0, x1, y1, t0, t1;
-  GBool ext0, ext1;
-  double uxMin, uyMin, uxMax, uyMax, det;
-  double *ctm;
-  double ictm[6];
-  double xMin, yMin, xMax, yMax, tx, ty, xx, yy;
-  double xx0, yy0, xx1, yy1, dx, dy, d, s, t;
-  GBool dZero, go;
-  int ixMin, iyMin, ixMax, iyMax, bitmapWidth, bitmapHeight, nColors;
-  SplashClipResult clipRes;
-  SplashColorMode srcMode;
-  SplashBitmap *tBitmap;
-  int nComps;
-  int x, y, i;
-  SplashColorPtr dataPtr;
-  Guchar *alphaPtr;
-  GfxColor color;
-  SplashColorPtr sColors, sColor;
-  SplashColor sColor0;
-
-
-  // get the shading parameters
-  shading->getCoords(&x0, &y0, &x1, &y1);
-  t0 = shading->getDomain0();
-  t1 = shading->getDomain1();
-  ext0 = shading->getExtend0();
-  ext1 = shading->getExtend1();
-  dx = x1 - x0;
-  dy = y1 - y0;
-  d = dx * dx + dy * dy;
-  dZero = fabs(d) < 0.0001;
-  if (!dZero) {
-    d = 1 / d;
-  }
-  if (dZero && !ext0 && !ext1) {
-    return gTrue;
-  }
-
-  // get clip region (in user space)
-  state->getUserClipBBox(&uxMin, &uyMin, &uxMax, &uyMax);
-  if (uxMin > uxMax || uyMin > uyMax) {
-    return gTrue;
-  }
-
-  // convert the region to device space
-  ctm = state->getCTM();
-  tx = uxMin * ctm[0] + uyMin * ctm[2] + ctm[4];
-  ty = uxMin * ctm[1] + uyMin * ctm[3] + ctm[5];
-  xMin = xMax = tx;
-  yMin = yMax = ty;
-  tx = uxMin * ctm[0] + uyMax * ctm[2] + ctm[4];
-  ty = uxMin * ctm[1] + uyMax * ctm[3] + ctm[5];
-  if (tx < xMin) {
-    xMin = tx;
-  } else if (tx > xMax) {
-    xMax = tx;
-  }
-  if (ty < yMin) {
-    yMin = ty;
-  } else if (ty > yMax) {
-    yMax = ty;
-  }
-  tx = uxMax * ctm[0] + uyMin * ctm[2] + ctm[4];
-  ty = uxMax * ctm[1] + uyMin * ctm[3] + ctm[5];
-  if (tx < xMin) {
-    xMin = tx;
-  } else if (tx > xMax) {
-    xMax = tx;
-  }
-  if (ty < yMin) {
-    yMin = ty;
-  } else if (ty > yMax) {
-    yMax = ty;
-  }
-  tx = uxMax * ctm[0] + uyMax * ctm[2] + ctm[4];
-  ty = uxMax * ctm[1] + uyMax * ctm[3] + ctm[5];
-  if (tx < xMin) {
-    xMin = tx;
-  } else if (tx > xMax) {
-    xMax = tx;
-  }
-  if (ty < yMin) {
-    yMin = ty;
-  } else if (ty > yMax) {
-    yMax = ty;
-  }
-  ixMin = (int)floor(xMin);
-  iyMin = (int)floor(yMin);
-  ixMax = (int)floor(xMax) + 1;
-  iyMax = (int)floor(yMax) + 1;
-  clipRes = splash->limitRectToClipRect(&ixMin, &iyMin, &ixMax, &iyMax);
-  if (clipRes == splashClipAllOutside) {
-    return gTrue;
-  }
-
-  // allocate a bitmap
-  if (colorMode == splashModeMono1) {
-    srcMode = splashModeMono8;
-  } else if (colorMode == splashModeBGR8) {
-    srcMode = splashModeRGB8;
-  } else {
-    srcMode = colorMode;
-  }
-  bitmapWidth = ixMax - ixMin;
-  bitmapHeight = iyMax - iyMin;
-  tBitmap = new SplashBitmap(bitmapWidth, bitmapHeight, 1,
-			     srcMode, gTrue, gTrue, bitmap);
-  memset(tBitmap->getAlphaPtr(), 0, (size_t)bitmapWidth * bitmapHeight);
-  nComps = splashColorModeNComps[srcMode];
-
-  // compute the inverse CTM
-  det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
-  ictm[0] = ctm[3] * det;
-  ictm[1] = -ctm[1] * det;
-  ictm[2] = -ctm[2] * det;
-  ictm[3] = ctm[0] * det;
-  ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
-  ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
-
-  // render the shading into the bitmap
-  xx0 = x0 * ctm[0] + y0 * ctm[2] + ctm[4];
-  yy0 = x0 * ctm[1] + y0 * ctm[3] + ctm[5];
-  xx1 = x1 * ctm[0] + y1 * ctm[2] + ctm[4];
-  yy1 = x1 * ctm[1] + y1 * ctm[3] + ctm[5];
-  sColors = NULL;
-
-  // special case: zero-length axis
-  if (dZero) {
-    if (ext0) {
-      shading->getColor(t0, &color);
-    } else {
-      shading->getColor(t1, &color);
-    }
-    computeShadingColor(state, srcMode, &color, sColor0);
-    dataPtr = tBitmap->getDataPtr();
-    alphaPtr = tBitmap->getAlphaPtr();
-    for (y = 0; y < bitmapHeight; ++y) {
-      for (x = 0; x < bitmapWidth; ++x) {
-	for (i = 0; i < nComps; ++i) {
-	  *dataPtr++ = sColor0[i];
-	}
-	*alphaPtr++ = 0xff;
+  if (tileW == 1 && tileH == 1 &&
+      fabs(xStepX * yStepY - xStepY * yStepX) < 0.9) {
+    // if the tile is 1x1 pixel, and the stepping completely fills the
+    // area, just composite the 1x1 image across the clip region
+    // (this avoids performance problems in cases where the step size
+    // is very small) (we compare to 0.9 instead of 1.0 to avoid fp
+    // jitter issues)
+    ixMin = (int)floor(clipXMin);
+    ixMax = (int)floor(clipXMax) + 1;
+    iyMin = (int)floor(clipYMin);
+    iyMax = (int)floor(clipYMax) + 1;
+    for (iy = iyMin; iy < iyMax; ++iy) {
+      for (ix = ixMin; ix < ixMax; ++ix) {
+	splash->composite(tileBitmap, 0, 0, ix, iy, tileW, tileH,
+			  gFalse, gFalse);
       }
     }
-
-  // special case: horizontal axis (in device space)
-  } else if (fabs(yy0 - yy1) < 0.01) {
-    for (x = 0; x < bitmapWidth; ++x) {
-      dataPtr = tBitmap->getDataPtr() + x * nComps;
-      alphaPtr = tBitmap->getAlphaPtr() + x;
-      tx = ixMin + x + 0.5;
-      ty = iyMin + 0.5;
-      xx = tx * ictm[0] + ty * ictm[2] + ictm[4];
-      yy = tx * ictm[1] + ty * ictm[3] + ictm[5];
-      s = ((xx - x0) * dx + (yy - y0) * dy) * d;
-      go = gFalse;
-      if (s < 0) {
-	go = ext0;
-      } else if (s > 1) {
-	go = ext1;
-      } else {
-	go = gTrue;
-      }
-      if (!go) {
-	continue;
-      }
-      if (s <= 0) {
-	shading->getColor(t0, &color);
-      } else if (s >= 1) {
-	shading->getColor(t1, &color);
-      } else {
-	t = t0 + s * (t1 - t0);
-	shading->getColor(t, &color);
-      }
-      computeShadingColor(state, srcMode, &color, sColor0);
-      for (y = 0; y < bitmapHeight; ++y) {
-	for (i = 0; i < nComps; ++i) {
-	  dataPtr[i] = sColor0[i];
-	}
-	*alphaPtr = 0xff;
-	dataPtr += tBitmap->getRowSize();
-	alphaPtr += bitmapWidth;
-      }
-    }
-
-  // special case: vertical axis (in device space)
-  } else if (fabs(xx0 - xx1) < 0.01) {
-    dataPtr = tBitmap->getDataPtr();
-    alphaPtr = tBitmap->getAlphaPtr();
-    for (y = 0; y < bitmapHeight; ++y) {
-      tx = ixMin + 0.5;
-      ty = iyMin + y + 0.5;
-      xx = tx * ictm[0] + ty * ictm[2] + ictm[4];
-      yy = tx * ictm[1] + ty * ictm[3] + ictm[5];
-      s = ((xx - x0) * dx + (yy - y0) * dy) * d;
-      go = gFalse;
-      if (s < 0) {
-	go = ext0;
-      } else if (s > 1) {
-	go = ext1;
-      } else {
-	go = gTrue;
-      }
-      if (!go) {
-	continue;
-      }
-      if (s <= 0) {
-	shading->getColor(t0, &color);
-      } else if (s >= 1) {
-	shading->getColor(t1, &color);
-      } else {
-	t = t0 + s * (t1 - t0);
-	shading->getColor(t, &color);
-      }
-      computeShadingColor(state, srcMode, &color, sColor0);
-      for (x = 0; x < bitmapWidth; ++x) {
-	for (i = 0; i < nComps; ++i) {
-	  *dataPtr++ = sColor0[i];
-	}
-	*alphaPtr++ = 0xff;
-      }
-    }
-
-  // general case
   } else {
-    // pre-compute colors along the axis
-    nColors = (int)(1.5 * sqrt((xx1 - xx0) * (xx1 - xx0)
-			       + (yy1 - yy0) * (yy1 - yy0)));
-    if (nColors < 16) {
-      nColors = 16;
-    } else if (nColors > 1024) {
-      nColors = 1024;
-    }
-    sColors = (SplashColorPtr)gmallocn(nColors, nComps);
-    sColor = sColors;
-    for (i = 0; i < nColors; ++i) {
-      s = (double)i / (double)(nColors - 1);
-      t = t0 + s * (t1 - t0);
-      shading->getColor(t, &color);
-      computeShadingColor(state, srcMode, &color, sColor);
-      sColor += nComps;
-    }
-
-    dataPtr = tBitmap->getDataPtr();
-    alphaPtr = tBitmap->getAlphaPtr();
-    for (y = 0; y < bitmapHeight; ++y) {
-      for (x = 0; x < bitmapWidth; ++x) {
-
-	// convert coords to user space
-	tx = ixMin + x + 0.5;
-	ty = iyMin + y + 0.5;
-	xx = tx * ictm[0] + ty * ictm[2] + ictm[4];
-	yy = tx * ictm[1] + ty * ictm[3] + ictm[5];
-
-	// compute the position along the axis
-	s = ((xx - x0) * dx + (yy - y0) * dy) * d;
-	go = gFalse;
-	if (s < 0) {
-	  go = ext0;
-	} else if (s > 1) {
-	  go = ext1;
+    for (iy = iyMin; iy < iyMax; ++iy) {
+      for (ix = ixMin; ix < ixMax; ++ix) {
+	x = (int)(adjXMin + ix * xStepX + iy * yStepX + 0.5);
+	y = (int)(adjYMin + ix * xStepY + iy * yStepY + 0.5);
+	if (overprintMaskBitmap) {
+	  splash->compositeWithOverprint(tileBitmap, overprintMaskBitmap,
+					 0, 0, x, y, tileW, tileH,
+					 gFalse, gFalse);
 	} else {
-	  go = gTrue;
+	  splash->composite(tileBitmap, 0, 0, x, y, tileW, tileH,
+			    gFalse, gFalse);
 	}
-	if (!go) {
-	  dataPtr += nComps;
-	  ++alphaPtr;
-	  continue;
-	}
-	if (s <= 0) {
-	  sColor = sColors;
-	} else if (s >= 1) {
-	  sColor = sColors + (nColors - 1) * nComps;
-	} else {
-	  i = (int)((nColors - 1) * s + 0.5);
-	  sColor = sColors + i * nComps;
-	}
-	for (i = 0; i < nComps; ++i) {
-	  *dataPtr++ = sColor[i];
-	}
-	*alphaPtr++ = 0xff;
       }
     }
   }
 
-  // composite the bitmap
-  setOverprintMask(state, state->getFillColorSpace(),
-		   state->getFillOverprint(), state->getOverprintMode(),
-		   NULL);
-  splash->composite(tBitmap, 0, 0, ixMin, iyMin, bitmapWidth, bitmapHeight,
-		    clipRes == splashClipAllInside, gFalse);
+  gfree(overprintMaskBitmap);
+  delete tileBitmap;
+}
 
-  gfree(sColors);
-  delete tBitmap;
+GBool SplashOutputDev::shadedFill(GfxState *state, GfxShading *shading) {
 
-  return gTrue;
-}
-
-GBool SplashOutputDev::radialShadedFill(GfxState *state,
-					GfxRadialShading *shading) {
-  double x0, y0, r0, x1, y1, r1, t0, t1, h;
-  GBool ext0, ext1, enclosed;
-  double uxMin, uyMin, uxMax, uyMax, det;
-  double *ctm;
-  double ictm[6];
-  double xMin, yMin, xMax, yMax, tx, ty, xx, yy;
-  double dx, dy, dr, r0dr, r02, a, a2, b, c, e, es, s, s0, s1, rs0, rs1, t;
-  GBool aIsZero, go;
-  int ixMin, iyMin, ixMax, iyMax, bitmapWidth, bitmapHeight, nColors;
-  int bxMin, byMin, bxMax, byMax;
-  SplashClipResult clipRes;
+  // generate the bitmap
   SplashColorMode srcMode;
-  SplashBitmap *tBitmap;
-  int nComps;
-  int x, y, i;
-  SplashColorPtr dataPtr;
-  Guchar *alphaPtr;
-  GfxColor color;
-  SplashColorPtr sColors, sColor;
-
-
-  // get the shading parameters
-  shading->getCoords(&x0, &y0, &r0, &x1, &y1, &r1);
-  t0 = shading->getDomain0();
-  t1 = shading->getDomain1();
-  ext0 = shading->getExtend0();
-  ext1 = shading->getExtend1();
-  h = sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0));
-  enclosed = fabs(r1 - r0) >= h;
-
-  // get clip region (in user space)
-  state->getUserClipBBox(&uxMin, &uyMin, &uxMax, &uyMax);
-  if (uxMin > uxMax || uyMin > uyMax) {
-    return gTrue;
-  }
-
-  // intersect with shading region (in user space): if the extend
-  // flags are false (or just the larger extend flag is false, in the
-  // "enclosed" case), we can use the bbox for the two circles
-  if ((!ext0 && !ext1) ||
-      (enclosed && !(r0 > r1 ? ext0 : ext1))) {
-    tx = (x0 - r0) < (x1 - r1) ? (x0 - r0) : (x1 - r1);
-    if (tx > uxMin) {
-      uxMin = tx;
-    }
-    tx = (x0 + r0) > (x1 + r1) ? (x0 + r0) : (x1 + r1);
-    if (tx < uxMax) {
-      uxMax = tx;
-    }
-    ty = (y0 - r0) < (y1 - r1) ? (y0 - r0) : (y1 - r1);
-    if (ty > uyMin) {
-      uyMin = ty;
-    }
-    ty = (y0 + r0) > (y1 + r1) ? (y0 + r0) : (y1 + r1);
-    if (ty < uyMax) {
-      uyMax = ty;
-    }
-  }
-  if (uxMin > uxMax || uyMin > uyMax) {
-    return gTrue;
-  }
-
-  // convert the region to device space
-  ctm = state->getCTM();
-  tx = uxMin * ctm[0] + uyMin * ctm[2] + ctm[4];
-  ty = uxMin * ctm[1] + uyMin * ctm[3] + ctm[5];
-  xMin = xMax = tx;
-  yMin = yMax = ty;
-  tx = uxMin * ctm[0] + uyMax * ctm[2] + ctm[4];
-  ty = uxMin * ctm[1] + uyMax * ctm[3] + ctm[5];
-  if (tx < xMin) {
-    xMin = tx;
-  } else if (tx > xMax) {
-    xMax = tx;
-  }
-  if (ty < yMin) {
-    yMin = ty;
-  } else if (ty > yMax) {
-    yMax = ty;
-  }
-  tx = uxMax * ctm[0] + uyMin * ctm[2] + ctm[4];
-  ty = uxMax * ctm[1] + uyMin * ctm[3] + ctm[5];
-  if (tx < xMin) {
-    xMin = tx;
-  } else if (tx > xMax) {
-    xMax = tx;
-  }
-  if (ty < yMin) {
-    yMin = ty;
-  } else if (ty > yMax) {
-    yMax = ty;
-  }
-  tx = uxMax * ctm[0] + uyMax * ctm[2] + ctm[4];
-  ty = uxMax * ctm[1] + uyMax * ctm[3] + ctm[5];
-  if (tx < xMin) {
-    xMin = tx;
-  } else if (tx > xMax) {
-    xMax = tx;
-  }
-  if (ty < yMin) {
-    yMin = ty;
-  } else if (ty > yMax) {
-    yMax = ty;
-  }
-  ixMin = (int)floor(xMin);
-  iyMin = (int)floor(yMin);
-  ixMax = (int)floor(xMax) + 1;
-  iyMax = (int)floor(yMax) + 1;
-  clipRes = splash->limitRectToClipRect(&ixMin, &iyMin, &ixMax, &iyMax);
-  if (clipRes == splashClipAllOutside) {
-    return gTrue;
-  }
-  
-  // allocate a bitmap
   if (colorMode == splashModeMono1) {
     srcMode = splashModeMono8;
   } else if (colorMode == splashModeBGR8) {
@@ -2440,287 +2097,36 @@
   } else {
     srcMode = colorMode;
   }
-  bitmapWidth = ixMax - ixMin;
-  bitmapHeight = iyMax - iyMin;
-  tBitmap = new SplashBitmap(bitmapWidth, bitmapHeight, 1,
-			     srcMode, gTrue, gTrue, bitmap);
-  memset(tBitmap->getAlphaPtr(), 0, tBitmap->getAlphaRowSize() * bitmapHeight);
-  nComps = splashColorModeNComps[srcMode];
-
-  // compute the inverse CTM
-  det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
-  ictm[0] = ctm[3] * det;
-  ictm[1] = -ctm[1] * det;
-  ictm[2] = -ctm[2] * det;
-  ictm[3] = ctm[0] * det;
-  ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
-  ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
-
-  // pre-compute colors along the axis
-  nColors = (int)sqrt((double)(bitmapWidth * bitmapWidth
-			       + bitmapHeight * bitmapHeight));
-  if (nColors < 16) {
-    nColors = 16;
-  } else if (nColors > 1024) {
-    nColors = 1024;
+  int x, y;
+  SplashBitmap *tBitmap = ShadingImage::generateBitmap(state, shading, srcMode,
+						       reverseVideo,
+						       splash, bitmap, &x, &y);
+  if (!tBitmap) {
+    // clip region is empty - nothing to draw
+    return gTrue;
   }
-  sColors = (SplashColorPtr)gmallocn(nColors, nComps);
-  sColor = sColors;
-  for (i = 0; i < nColors; ++i) {
-    s = (double)i / (double)(nColors - 1);
-    t = t0 + s * (t1 - t0);
-    shading->getColor(t, &color);
-    computeShadingColor(state, srcMode, &color, sColor);
-    sColor += nComps;
-  }
 
-  // special case: in the "enclosed" + extended case, we can fill the
-  // bitmap with the outer color and just render inside the larger
-  // circle
-  if (enclosed &&
-      ((r0 > r1 && ext0) || (r1 > r0 && ext1))) {
-    if (r0 > r1) {
-      sColor = sColors;
-      uxMin = x0 - r0;
-      uxMax = x0 + r0;
-      uyMin = y0 - r0;
-      uyMax = y0 + r0;
-    } else {
-      sColor = sColors + (nColors - 1) * nComps;
-      uxMin = x1 - r1;
-      uxMax = x1 + r1;
-      uyMin = y1 - r1;
-      uyMax = y1 + r1;
-    }
-
-    // convert bbox of larger circle to device space
-    tx = uxMin * ctm[0] + uyMin * ctm[2] + ctm[4];
-    ty = uxMin * ctm[1] + uyMin * ctm[3] + ctm[5];
-    xMin = xMax = tx;
-    yMin = yMax = ty;
-    tx = uxMin * ctm[0] + uyMax * ctm[2] + ctm[4];
-    ty = uxMin * ctm[1] + uyMax * ctm[3] + ctm[5];
-    if (tx < xMin) {
-      xMin = tx;
-    } else if (tx > xMax) {
-      xMax = tx;
-    }
-    if (ty < yMin) {
-      yMin = ty;
-    } else if (ty > yMax) {
-      yMax = ty;
-    }
-    tx = uxMax * ctm[0] + uyMin * ctm[2] + ctm[4];
-    ty = uxMax * ctm[1] + uyMin * ctm[3] + ctm[5];
-    if (tx < xMin) {
-      xMin = tx;
-    } else if (tx > xMax) {
-      xMax = tx;
-    }
-    if (ty < yMin) {
-      yMin = ty;
-    } else if (ty > yMax) {
-      yMax = ty;
-    }
-    tx = uxMax * ctm[0] + uyMax * ctm[2] + ctm[4];
-    ty = uxMax * ctm[1] + uyMax * ctm[3] + ctm[5];
-    if (tx < xMin) {
-      xMin = tx;
-    } else if (tx > xMax) {
-      xMax = tx;
-    }
-    if (ty < yMin) {
-      yMin = ty;
-    } else if (ty > yMax) {
-      yMax = ty;
-    }
-    bxMin = (int)floor(xMin - ixMin);
-    if (bxMin < 0) {
-      bxMin = 0;
-    }
-    byMin = (int)floor(yMin - iyMin);
-    if (byMin < 0) {
-      byMin = 0;
-    }
-    bxMax = (int)floor(xMax - ixMin) + 1;
-    if (bxMax > bitmapWidth) {
-      bxMax = bitmapWidth;
-    }
-    byMax = (int)floor(yMax - iyMin) + 1;
-    if (byMax > bitmapHeight) {
-      byMax = bitmapHeight;
-    }
-
-    // fill bitmap (except for the rectangle containing the larger circle)
-    dataPtr = tBitmap->getDataPtr();
-    alphaPtr = tBitmap->getAlphaPtr();
-    for (y = 0; y < bitmapHeight; ++y) {
-      for (x = 0; x < bitmapWidth; ++x) {
-	if (y >= byMin && y < byMax && x >= bxMin && x < bxMax) {
-	  dataPtr += nComps;
-	  ++alphaPtr;
-	} else {
-	  for (i = 0; i < nComps; ++i) {
-	    *dataPtr++ = sColor[i];
-	  }
-	  *alphaPtr++ = 0xff;
-	}
-      }
-    }
-
-  } else {
-    bxMin = 0;
-    byMin = 0;
-    bxMax = bitmapWidth;
-    byMax = bitmapHeight;
+  // check clipping and composite the bitmap
+  int xMin = x;
+  int yMin = y;
+  int xMax = x + tBitmap->getWidth();
+  int yMax = y + tBitmap->getHeight();
+  SplashClipResult clipRes = splash->limitRectToClipRect(&xMin, &yMin,
+							 &xMax, &yMax);
+  if (clipRes != splashClipAllOutside) {
+    setOverprintMask(state, state->getFillColorSpace(),
+		     state->getFillOverprint(), state->getOverprintMode(),
+		     NULL);
+    splash->composite(tBitmap, xMin - x, yMin - y, xMin, yMin,
+		      xMax - xMin, yMax - yMin,
+		      clipRes == splashClipAllInside, gFalse);
   }
 
-  // render the shading into the bitmap
-  dx = x1 - x0;
-  dy = y1 - y0;
-  dr = r1 - r0;
-  r0dr = r0 * dr;
-  r02 = r0 * r0;
-  a = dx * dx + dy * dy - dr * dr;
-  if (fabs(a) < 0.00001) {
-    aIsZero = gTrue;
-    a2 = 0;
-  } else {
-    aIsZero = gFalse;
-    a2 = 1 / (2 * a);
-  }
-  for (y = byMin; y < byMax; ++y) {
-    dataPtr = tBitmap->getDataPtr()
-              + y * tBitmap->getRowSize() + bxMin * nComps;
-    alphaPtr = tBitmap->getAlphaPtr() + y * tBitmap->getAlphaRowSize() + bxMin;
-    for (x = bxMin; x < bxMax; ++x) {
-
-      // convert coords to user space
-      tx = ixMin + x + 0.5;
-      ty = iyMin + y + 0.5;
-      xx = tx * ictm[0] + ty * ictm[2] + ictm[4];
-      yy = tx * ictm[1] + ty * ictm[3] + ictm[5];
-
-      // compute the radius of the circle at x,y
-      b = 2 * ((xx - x0) * dx + (yy - y0) * dy + r0dr);
-      c = (xx - x0) * (xx - x0) + (yy - y0) * (yy - y0) - r02;
-      s = 0;
-      go = gFalse;
-      if (aIsZero) {
-	if (fabs(b) < 0.000001) {
-	  if (c <= 0) {
-	    if (ext0) {
-	      s = 0;
-	      go = gTrue;
-	    }
-	  } else {
-	    if (ext1) {
-	      s = 1;
-	      go = gTrue;
-	    }
-	  }
-	} else {
-	  s0 = c / b;
-	  rs0 = r0 + s0 * (r1 - r0);
-	  if ((s0 >= 0 || ext0) && (s0 <= 1 || ext1) && rs0 >= 0) { 
-	    s = s0;
-	    go = gTrue;
-	  }
-	}
-      } else {
-	e = b*b -  4*a*c;
-	if (e >= 0) {
-	  es = sqrt(e);
-	  s0 = (b + es) * a2;
-	  s1 = (b - es) * a2;
-	  rs0 = r0 + s0 * (r1 - r0);
-	  rs1 = r0 + s1 * (r1 - r0);
-	  if (s0 > s1) {
-	    if ((s0 >= 0 || ext0) && (s0 <= 1 || ext1) && rs0 >= 0) {
-	      s = s0;
-	      go = gTrue;
-	    } else if ((s1 >= 0 || ext0) && (s1 <= 1 || ext1) && rs1 >= 0) {
-	      s = s1;
-	      go = gTrue;
-	    }
-	  } else {
-	    if ((s1 >= 0 || ext0) && (s1 <= 1 || ext1) && rs1 >= 0) {
-	      s = s1;
-	      go = gTrue;
-	    } else if ((s0 >= 0 || ext0) && (s0 <= 1 || ext1) && rs0 >= 0) {
-	      s = s0;
-	      go = gTrue;
-	    }
-	  }
-	}
-      }
-      if (!go) {
-	dataPtr += nComps;
-	++alphaPtr;
-	continue;
-      }
-      if (s <= 0) {
-	sColor = sColors;
-      } else if (s >= 1) {
-	sColor = sColors + (nColors - 1) * nComps;
-      } else {
-	i = (int)((nColors - 1) * s + 0.5);
-	sColor = sColors + i * nComps;
-      }
-      for (i = 0; i < nComps; ++i) {
-	*dataPtr++ = sColor[i];
-      }
-      *alphaPtr++ = 0xff;
-    }
-  }
-
-  // composite the bitmap
-  setOverprintMask(state, state->getFillColorSpace(),
-		   state->getFillOverprint(), state->getOverprintMode(),
-		   NULL);
-  splash->composite(tBitmap, 0, 0, ixMin, iyMin, bitmapWidth, bitmapHeight,
-		    clipRes == splashClipAllInside, gFalse);
-
-  gfree(sColors);
   delete tBitmap;
 
   return gTrue;
 }
 
-void SplashOutputDev::computeShadingColor(GfxState *state,
-					  SplashColorMode mode,
-					  GfxColor *color,
-					  SplashColorPtr sColor) {
-  GfxGray gray;
-  GfxRGB rgb;
-#if SPLASH_CMYK
-  GfxCMYK cmyk;
-#endif
-
-  state->setFillColor(color);
-  switch (mode) {
-  case splashModeMono8:
-    state->getFillGray(&gray);
-    getColor(gray, sColor);
-    break;
-  case splashModeRGB8:
-    state->getFillRGB(&rgb);
-    getColor(&rgb, sColor);
-    break;
-#if SPLASH_CMYK
-  case splashModeCMYK8:
-    state->getFillCMYK(&cmyk);
-    getColor(&cmyk, sColor);
-    break;
-#endif
-  case splashModeMono1:
-  case splashModeBGR8:
-    // mode cannot be Mono1 or BGR8
-    break;
-  }
-}
-
-
 void SplashOutputDev::clip(GfxState *state) {
   SplashPath *path;
 
@@ -2799,6 +2205,7 @@
 
   if (skipHorizText || skipRotatedText) {
     state->getFontTransMat(&m[0], &m[1], &m[2], &m[3]);
+    // this matches the 'diagonal' test in TextPage::updateFont()
     horiz = m[0] > 0 && fabs(m[1]) < 0.001 &&
             fabs(m[2]) < 0.001 && m[3] < 0;
     if ((skipHorizText && horiz) || (skipRotatedText && !horiz)) {
@@ -2924,7 +2331,7 @@
   }
 
   if (!(gfxFont = state->getFont())) {
-    return gFalse;
+    return gTrue;
   }
   fontID = gfxFont->getID();
   ctm = state->getCTM();
@@ -2954,7 +2361,7 @@
 	}
       } else {
 	for (j = nT3Fonts - 1; j >= 0; --j) {
-	  if (!t3FontCache[j]->inUse) {
+	  if (t3FontCache[j]->refCount == 0) {
 	    break;
 	  }
 	}
@@ -3038,7 +2445,11 @@
     }
   }
 
-  t3Font->inUse = gTrue;
+  if (t3Font->refCount > 1000) {
+    error(errSyntaxError, -1, "Type 3 CharProcs nested too deeply");
+    return gTrue;
+  }
+  ++t3Font->refCount;
 
   // push a new Type 3 glyph record
   t3gs = new T3GlyphStack();
@@ -3050,6 +2461,10 @@
   t3GlyphStack->cacheData = NULL;
   t3GlyphStack->haveDx = gFalse;
   t3GlyphStack->doNotCache = gFalse;
+#if 1 //~t3-sa
+  t3GlyphStack->savedStrokeAdjust = splash->getStrokeAdjust();
+  splash->setStrokeAdjust(splashStrokeAdjustOff);
+#endif
 
   return gFalse;
 }
@@ -3074,9 +2489,12 @@
     drawType3Glyph(state, t3GlyphStack->cache,
 		   t3GlyphStack->cacheTag, t3GlyphStack->cacheData);
   }
+#if 1 //~t3-sa
+  splash->setStrokeAdjust(t3GlyphStack->savedStrokeAdjust);
+#endif
   t3gs = t3GlyphStack;
   t3GlyphStack = t3gs->next;
-  t3gs->cache->inUse = gFalse;
+  --t3gs->cache->refCount;
   delete t3gs;
 }
 
@@ -3186,6 +2604,7 @@
   // create the temporary bitmap
   if (colorMode == splashModeMono1) {
     colorMode = splashModeMono1;
+    traceMessage("T3 glyph bitmap");
     bitmap = new SplashBitmap(t3Font->glyphW, t3Font->glyphH, 1,
 			      splashModeMono1, gFalse, gTrue, bitmap);
     splash = new Splash(bitmap, gFalse,
@@ -3196,6 +2615,7 @@
     color[0] = 0xff;
   } else {
     colorMode = splashModeMono8;
+    traceMessage("T3 glyph bitmap");
     bitmap = new SplashBitmap(t3Font->glyphW, t3Font->glyphH, 1,
 			      splashModeMono8, gFalse, gTrue, bitmap);
     splash = new Splash(bitmap, vectorAntialias,
@@ -3299,7 +2719,7 @@
   imgMaskData.height = height;
   imgMaskData.y = 0;
 
-  imgTag = makeImageTag(ref);
+  imgTag = makeImageTag(ref, gfxRenderingIntentRelativeColorimetric, NULL);
   splash->fillImageMask(imgTag,
 			&imageMaskSrc, &imgMaskData, width, height, mat,
 			t3GlyphStack != NULL, interpolate);
@@ -3344,6 +2764,7 @@
   imgMaskData.width = width;
   imgMaskData.height = height;
   imgMaskData.y = 0;
+  traceMessage("image mask soft mask bitmap");
   maskBitmap = new SplashBitmap(bitmap->getWidth(), bitmap->getHeight(),
 				1, splashModeMono8, gFalse, gTrue, bitmap);
   maskSplash = new Splash(maskBitmap, gTrue, splash->getImageCache());
@@ -3354,7 +2775,7 @@
   clearMaskRegion(state, maskSplash, 0, 0, 1, 1);
   maskColor[0] = 0xff;
   maskSplash->setFillPattern(new SplashSolidColor(maskColor));
-  imgTag = makeImageTag(ref);
+  imgTag = makeImageTag(ref, gfxRenderingIntentRelativeColorimetric, NULL);
   maskSplash->fillImageMask(imgTag, &imageMaskSrc, &imgMaskData,
 			    width, height, mat, gFalse, interpolate);
   delete imgTag;
@@ -3643,7 +3064,8 @@
     srcMode = colorMode;
   }
   src = maskColors ? &alphaImageSrc : &imageSrc;
-  imgTag = makeImageTag(ref);
+  imgTag = makeImageTag(ref, state->getRenderingIntent(),
+			colorMap->getColorSpace());
   splash->drawImage(imgTag,
 		    src, &imgData, srcMode, maskColors ? gTrue : gFalse,
 		    width, height, mat, interpolate);
@@ -3775,9 +3197,9 @@
 void SplashOutputDev::drawMaskedImage(GfxState *state, Object *ref,
 				      Stream *str, int width, int height,
 				      GfxImageColorMap *colorMap,
-				      Stream *maskStr, int maskWidth,
-				      int maskHeight, GBool maskInvert,
-				      GBool interpolate) {
+				      Object *maskRef, Stream *maskStr,
+				      int maskWidth, int maskHeight,
+				      GBool maskInvert, GBool interpolate) {
   GfxImageColorMap *maskColorMap;
   Object maskDecode, decodeLow, decodeHigh;
   double *ctm;
@@ -3817,7 +3239,7 @@
 					new GfxDeviceGrayColorSpace());
     maskDecode.free();
     drawSoftMaskedImage(state, ref, str, width, height, colorMap,
-			maskStr, maskWidth, maskHeight, maskColorMap,
+			maskRef, maskStr, maskWidth, maskHeight, maskColorMap,
 			NULL, interpolate);
     delete maskColorMap;
 
@@ -3837,6 +3259,7 @@
     imgMaskData.width = maskWidth;
     imgMaskData.height = maskHeight;
     imgMaskData.y = 0;
+    traceMessage("masked image bitmap");
     maskBitmap = new SplashBitmap(width, height, 1, splashModeMono1,
 				  gFalse, gTrue, bitmap);
     maskSplash = new Splash(maskBitmap, gFalse, splash->getImageCache());
@@ -3931,7 +3354,8 @@
     } else {
       srcMode = colorMode;
     }
-    imgTag = makeImageTag(ref);
+    imgTag = makeImageTag(ref, state->getRenderingIntent(),
+			  colorMap->getColorSpace());
     splash->drawImage(imgTag,
 		      &maskedImageSrc, &imgData, srcMode, gTrue,
 		      width, height, mat, interpolate);
@@ -4055,7 +3479,7 @@
 void SplashOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref,
 					  Stream *str, int width, int height,
 					  GfxImageColorMap *colorMap,
-					  Stream *maskStr,
+					  Object *maskRef, Stream *maskStr,
 					  int maskWidth, int maskHeight,
 					  GfxImageColorMap *maskColorMap,
 					  double *matte, GBool interpolate) {
@@ -4147,18 +3571,13 @@
 #endif
     }
     //~ could add the matteImgData.lookup special case
-    if (colorMap->getBits() <= 8) {
-      n = 1 << maskColorMap->getBits();
-    } else {
-      // GfxImageColorMap and ImageStream compress 16-bit samples to 8-bit
-      n = 1 << 8;
-    }
     matteImgData.colorMode = colorMode;
     matteImgData.invert = reverseVideo && reverseVideoInvertImages;
     matteImgData.width = width;
     matteImgData.height = height;
     matteImgData.y = 0;
-    imgTag = makeImageTag(ref);
+    imgTag = makeImageTag(ref, state->getRenderingIntent(),
+			  colorMap->getColorSpace());
     splash->drawImage(imgTag, &softMaskMatteImageSrc, &matteImgData,
 		      srcMode, gTrue, width, height, mat, interpolate);
     delete imgTag;
@@ -4186,7 +3605,12 @@
     imgMaskData.width = maskWidth;
     imgMaskData.height = maskHeight;
     imgMaskData.y = 0;
-    n = 1 << maskColorMap->getBits();
+    if (maskColorMap->getBits() <= 8) {
+      n = 1 << maskColorMap->getBits();
+    } else {
+      // GfxImageColorMap and ImageStream compress 16-bit samples to 8-bit
+      n = 1 << 8;
+    }
     imgMaskData.lookup = (SplashColorPtr)gmalloc(n);
     for (i = 0; i < n; ++i) {
       pix = (Guchar)i;
@@ -4193,6 +3617,7 @@
       maskColorMap->getGray(&pix, &gray, state->getRenderingIntent());
       imgMaskData.lookup[i] = colToByte(gray);
     }
+    traceMessage("soft masked image bitmap");
     maskBitmap = new SplashBitmap(bitmap->getWidth(), bitmap->getHeight(),
 				  1, splashModeMono8, gFalse, gTrue, bitmap);
     maskSplash = new Splash(maskBitmap, vectorAntialias,
@@ -4273,7 +3698,8 @@
       }
     }
 
-    imgTag = makeImageTag(ref);
+    imgTag = makeImageTag(ref, state->getRenderingIntent(),
+			  colorMap->getColorSpace());
     splash->drawImage(imgTag,
 		      &imageSrc, &imgData, srcMode, gFalse, width, height, mat,
 		      interpolate);
@@ -4288,11 +3714,14 @@
   }
 }
 
-GString *SplashOutputDev::makeImageTag(Object *ref) {
-  if (!ref || !ref->isRef()) {
+GString *SplashOutputDev::makeImageTag(Object *ref, GfxRenderingIntent ri,
+				       GfxColorSpace *colorSpace) {
+  if (!ref || !ref->isRef() ||
+      (colorSpace && colorSpace->isDefaultColorSpace())) {
     return NULL;
   }
-  return GString::format("{0:d}_{1:d}", ref->getRefNum(), ref->getRefGen());
+  return GString::format("{0:d}_{1:d}_{2:d}",
+			 ref->getRefNum(), ref->getRefGen(), (int)ri);
 }
 
 void SplashOutputDev::reduceImageResolution(Stream *str, double *ctm,
@@ -4471,7 +3900,8 @@
     ty = bh - 1;
   }
   w = (int)ceil(xMax) - tx + 1;
-  if (tx + w > bw) {
+  // NB bw and tx are both non-negative, so 'bw - tx' can't overflow
+  if (bw - tx < w) {
     w = bw - tx;
   }
   if (w < 1) {
@@ -4478,7 +3908,8 @@
     w = 1;
   }
   h = (int)ceil(yMax) - ty + 1;
-  if (ty + h > bh) {
+  // NB bh and ty are both non-negative, so 'bh - ty' can't overflow
+  if (bh - ty < h) {
     h = bh - ty;
   }
   if (h < 1) {
@@ -4524,6 +3955,7 @@
   }
 
   // create the temporary bitmap
+  traceMessage("t-group bitmap");
   bitmap = new SplashBitmap(w, h, bitmapRowPad, colorMode, gTrue,
 			    bitmapTopDown, transpGroup->origBitmap); 
   splash = new Splash(bitmap, vectorAntialias,
@@ -4535,32 +3967,70 @@
   splash->setEnablePathSimplification(
 		 globalParams->getEnablePathSimplification());
   copyState(transpGroup->origSplash, gTrue);
+  if (!isolated || knockout) {
+    // non-isolated and knockout groups nested in another group will
+    // read the parent group bitmap, so we need to force any deferred
+    // initialization on the parent
+    transpGroup->origSplash->forceDeferredInit(ty, h);
+  }
   if (isolated) {
-    for (i = 0; i < splashMaxColorComps; ++i) {
-      color[i] = 0;
+    // isolated group
+    backdropBitmap = transpGroup->origBitmap;
+    transpGroup->backdropBitmap = NULL;
+    if (forSoftMask) {
+      // setSoftMask uses the whole bitmap, not just the mod region,
+      // so we can't use the deferred initialization optimization
+      for (i = 0; i < splashMaxColorComps; ++i) {
+	color[i] = 0;
+      }
+      splash->clear(color, 0);
+      splash->setInTransparencyGroup(backdropBitmap, tx, ty,
+				     splashGroupDestPreInit,
+				     gFalse, knockout);
+    } else {
+      splash->setInTransparencyGroup(backdropBitmap, tx, ty,
+				     splashGroupDestInitZero,
+				     gFalse, knockout);
     }
-    splash->clear(color, 0);
-  } else {
-    splash->blitTransparent(transpGroup->origBitmap, tx, ty, 0, 0, w, h);
-  }
-  if (!isolated &&
-      transpGroup->origBitmap->getAlphaPtr() &&
-      transpGroup->origSplash->getInNonIsolatedGroup() &&
-      colorMode != splashModeMono1) {
-    // when drawing a non-isolated group into another non-isolated group,
+  } else if (transpGroup->origBitmap->getAlphaPtr() &&
+	     transpGroup->origSplash->getInNonIsolatedGroup() &&
+	     colorMode != splashModeMono1) {
+    // non-isolated group drawn in another non-isolated group:
     // compute a backdrop bitmap with corrected alpha values
+    traceMessage("t-group backdrop bitmap");
     backdropBitmap = new SplashBitmap(w, h, bitmapRowPad, colorMode, gTrue,
 				      bitmapTopDown, transpGroup->origBitmap);
     transpGroup->origSplash->blitCorrectedAlpha(backdropBitmap,
 						tx, ty, 0, 0, w, h);
     transpGroup->backdropBitmap = backdropBitmap;
-    splash->setInTransparencyGroup(backdropBitmap, 0, 0,
-				   !isolated, knockout);
+    if (forSoftMask) {
+      // setSoftMask uses the whole bitmap, not just the mod region,
+      // so we can't use the deferred initialization optimization
+      splash->blitTransparent(transpGroup->origBitmap, tx, ty, 0, 0, w, h);
+      splash->setInTransparencyGroup(backdropBitmap, 0, 0,
+				     splashGroupDestPreInit,
+				     gTrue, knockout);
+    } else {
+      splash->setInTransparencyGroup(backdropBitmap, 0, 0,
+				     splashGroupDestInitCopy,
+				     gTrue, knockout);
+    }
   } else {
+    // other non-isolated group
     backdropBitmap = transpGroup->origBitmap;
     transpGroup->backdropBitmap = NULL;
-    splash->setInTransparencyGroup(backdropBitmap, tx, ty,
-				   !isolated, knockout);
+    if (forSoftMask) {
+      // setSoftMask uses the whole bitmap, not just the mod region,
+      // so we can't use the deferred initialization optimization
+      splash->blitTransparent(transpGroup->origBitmap, tx, ty, 0, 0, w, h);
+      splash->setInTransparencyGroup(backdropBitmap, tx, ty,
+				     splashGroupDestPreInit,
+				     gTrue, knockout);
+    } else {
+      splash->setInTransparencyGroup(backdropBitmap, tx, ty,
+				     splashGroupDestInitCopy,
+				     gTrue, knockout);
+    }
   }
   splash->clearModRegion();
   transpGroup->tBitmap = bitmap;
@@ -4632,7 +4102,8 @@
   Splash *tSplash;
   SplashTransparencyGroup *transpGroup;
   SplashColor color;
-  SplashColorPtr p;
+  SplashColorPtr p, colorPtr, colorPtr2;
+  Guchar *alphaPtr;
   GfxGray gray;
   GfxRGB rgb;
 #if SPLASH_CMYK
@@ -4639,7 +4110,9 @@
   GfxCMYK cmyk;
 #endif
   double backdrop, backdrop2, lum, lum2;
-  int tx, ty, x, y;
+  Guchar lum8;
+  SplashBitmapRowSize rowSize;
+  int tw, th, tNComps, tx, ty, x, y;
 
   tx = transpGroupStack->tx;
   ty = transpGroupStack->ty;
@@ -4709,6 +4182,7 @@
     backdrop2 = backdrop;
   }
 
+  traceMessage("soft mask bitmap");
   softMask = new SplashBitmap(bitmap->getWidth(), bitmap->getHeight(),
 			      1, splashModeMono8, gFalse, gTrue, bitmap);
   memset(softMask->getDataPtr(), (int)(backdrop2 * 255.0 + 0.5),
@@ -4715,45 +4189,65 @@
 	 softMask->getRowSize() * softMask->getHeight());
   if (tx < softMask->getWidth() && ty < softMask->getHeight()) {
     p = softMask->getDataPtr() + ty * softMask->getRowSize() + tx;
-    for (y = 0; y < tBitmap->getHeight(); ++y) {
-      for (x = 0; x < tBitmap->getWidth(); ++x) {
-	if (alpha) {
-	  lum = tBitmap->getAlpha(x, y) / 255.0;
-	} else {
-	  tBitmap->getPixel(x, y, color);
+    tw = tBitmap->getWidth();
+    th = tBitmap->getHeight();
+    rowSize = softMask->getRowSize();
+    if (alpha) {
+      alphaPtr = tBitmap->getAlphaPtr();
+      for (y = 0; y < th; ++y) {
+	for (x = 0; x < tw; ++x) {
+	  lum = *alphaPtr++ / 255.0;
+	  if (transferFunc) {
+	    transferFunc->transform(&lum, &lum2);
+	  } else {
+	    lum2 = lum;
+	  }
+	  p[x] = (Guchar)(lum2 * 255.0 + 0.5);
+	}
+	p += rowSize;
+      }
+    } else {
+      colorPtr = tBitmap->getDataPtr();
+      tNComps = splashColorModeNComps[tBitmap->getMode()];
+      lum8 = 0;  // make gcc happy
+      for (y = 0; y < th; ++y) {
+	colorPtr2 = colorPtr;
+	for (x = 0; x < tw; ++x) {
 	  // convert to luminosity
 	  switch (tBitmap->getMode()) {
 	  case splashModeMono1:
+	    lum8 = 0;
+	    break;
 	  case splashModeMono8:
-	    lum = color[0] / 255.0;
+	    lum8 = colorPtr2[0];
 	    break;
 	  case splashModeRGB8:
 	  case splashModeBGR8:
-	    lum = (0.3 / 255.0) * color[0] +
-	          (0.59 / 255.0) * color[1] +
-	          (0.11 / 255.0) * color[2];
+	    // [0.3, 0.59, 0.11] * 255 = [77, 150, 28]
+	    lum8 = div255(77 * colorPtr2[0] +
+			  150 * colorPtr2[1] +
+			  28 * colorPtr2[1]);
 	    break;
 #if SPLASH_CMYK
 	  case splashModeCMYK8:
-	    lum = (1 - color[3] / 255.0)
-	          - (0.3 / 255.0) * color[0]
-	          - (0.59 / 255.0) * color[1]
-	          - (0.11 / 255.0) * color[2];
-	    if (lum < 0) {
-	      lum = 0;
-	    }
+	    lum8 = clip255(255 - colorPtr2[3]
+			   - div255(77 * colorPtr2[0] +
+				    150 * colorPtr2[1] +
+				    28 * colorPtr2[2]));
 	    break;
 #endif
 	  }
+	  if (transferFunc) {
+	    lum = lum8 / 255.0;
+	    transferFunc->transform(&lum, &lum2);
+	    lum8 = (Guchar)(lum2 * 255.0 + 0.5);
+	  }
+	  p[x] = lum8;
+	  colorPtr2 += tNComps;
 	}
-	if (transferFunc) {
-	  transferFunc->transform(&lum, &lum2);
-	} else {
-	  lum2 = lum;
-	}
-	p[x] = (Guchar)(lum2 * 255.0 + 0.5);
+	p += rowSize;
+	colorPtr += tBitmap->getRowSize();
       }
-      p += softMask->getRowSize();
     }
   }
   splash->setSoftMask(softMask);
@@ -4993,6 +4487,10 @@
 }
 
 #if 1 //~tmp: turn off anti-aliasing temporarily
+// This was originally used with gradient shadings -- that's no longer
+// necessary, now that shadings are all converted to device space
+// images.  It's still used with knockout groups, however, because the
+// rasterizer doesn't properly separate opacity and shape.
 void SplashOutputDev::setInShading(GBool sh) {
   splash->setInShading(sh);
 }

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/SplashOutputDev.h
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/SplashOutputDev.h	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/SplashOutputDev.h	2021-02-15 19:17:20 UTC (rev 845)
@@ -69,11 +69,6 @@
   // operations.
   virtual GBool useTilingPatternFill() { return gTrue; }
 
-  // Does this device use functionShadedFill(), axialShadedFill(), and
-  // radialShadedFill()?  If this returns false, these shaded fills
-  // will be reduced to a series of other drawing operations.
-  virtual GBool useShadedFills() { return gTrue; }
-
   // Does this device use beginType3Char/endType3Char?  Otherwise,
   // text in Type 3 fonts will be drawn with drawChar/drawString.
   virtual GBool interpretType3Chars() { return gTrue; }
@@ -123,8 +118,7 @@
 				 double *mat, double *bbox,
 				 int x0, int y0, int x1, int y1,
 				 double xStep, double yStep);
-  virtual GBool axialShadedFill(GfxState *state, GfxAxialShading *shading);
-  virtual GBool radialShadedFill(GfxState *state, GfxRadialShading *shading);
+  virtual GBool shadedFill(GfxState *state, GfxShading *shading);
 
   //----- path clipping
   virtual void clip(GfxState *state);
@@ -156,12 +150,13 @@
   virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str,
 			       int width, int height,
 			       GfxImageColorMap *colorMap,
-			       Stream *maskStr, int maskWidth, int maskHeight,
+			       Object *maskRef, Stream *maskStr,
+			       int maskWidth, int maskHeight,
 			       GBool maskInvert, GBool interpolate);
   virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
 				   int width, int height,
 				   GfxImageColorMap *colorMap,
-				   Stream *maskStr,
+				   Object *maskRef, Stream *maskStr,
 				   int maskWidth, int maskHeight,
 				   GfxImageColorMap *maskColorMap,
 				   double *matte, GBool interpolate);
@@ -240,10 +235,6 @@
   // Get the screen parameters.
   SplashScreenParams *getScreenParams() { return &screenParams; }
 
-#if 1 //~tmp: turn off anti-aliasing temporarily
-  virtual void setInShading(GBool sh);
-#endif
-
 private:
 
   void setupScreenParams(double hDPI, double vDPI);
@@ -260,10 +251,6 @@
   void setOverprintMask(GfxState *state, GfxColorSpace *colorSpace,
 			GBool overprintFlag, int overprintMode,
 			GfxColor *singleColor);
-  void computeShadingColor(GfxState *state,
-			   SplashColorMode mode,
-			   GfxColor *color,
-			   SplashColorPtr sColor);
   SplashPath *convertPath(GfxState *state, GfxPath *path,
 			  GBool dropEmptySubpaths);
   void doUpdateFont(GfxState *state);
@@ -279,7 +266,8 @@
   static GBool softMaskMatteImageSrc(void *data,
 				     SplashColorPtr colorLine,
 				     Guchar *alphaLine);
-  GString *makeImageTag(Object *ref);
+  GString *makeImageTag(Object *ref, GfxRenderingIntent ri,
+			GfxColorSpace *colorSpace);
   void reduceImageResolution(Stream *str, double *mat,
 			     int *width, int *height);
   void clearMaskRegion(GfxState *state,
@@ -287,6 +275,9 @@
 		       double xMin, double yMin,
 		       double xMax, double yMax);
   void copyState(Splash *oldSplash, GBool copyColors);
+#if 1 //~tmp: turn off anti-aliasing temporarily
+  void setInShading(GBool sh);
+#endif
 
   SplashColorMode colorMode;
   int bitmapRowPad;

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Stream.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Stream.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Stream.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -1317,6 +1317,7 @@
   eof = gFalse;
   inputBits = 0;
   clearTable();
+  totalIn = totalOut = 0;
 }
 
 GBool LZWStream::processNextCode() {
@@ -1382,7 +1383,15 @@
       nextBits = 12;
   }
   prevCode = code;
+  totalOut += seqLength;
 
+  // check for a 'decompression bomb'
+  if (totalOut > 50000000 && totalIn < totalOut / 250) {
+    error(errSyntaxError, getPos(), "Decompression bomb in flate stream");
+    eof = gTrue;
+    return gFalse;
+  }
+
   // reset buffer
   seqIndex = 0;
 
@@ -1405,6 +1414,7 @@
       return EOF;
     inputBuf = (inputBuf << 8) | (c & 0xff);
     inputBits += 8;
+    ++totalIn;
   }
   code = (inputBuf >> (inputBits - nextBits)) & ((1 << nextBits) - 1);
   inputBits -= nextBits;
@@ -2268,7 +2278,6 @@
 GString *CCITTFaxStream::getPSFilter(int psLevel, const char *indent,
 				     GBool okToReadStream) {
   GString *s;
-  char s1[50];
 
   if (psLevel < 2) {
     return NULL;
@@ -2278,8 +2287,7 @@
   }
   s->append(indent)->append("<< ");
   if (encoding != 0) {
-    sprintf(s1, "/K %d ", encoding);
-    s->append(s1);
+    s->appendf("/K {0:d} ", encoding);
   }
   if (endOfLine) {
     s->append("/EndOfLine true ");
@@ -2287,11 +2295,9 @@
   if (byteAlign) {
     s->append("/EncodedByteAlign true ");
   }
-  sprintf(s1, "/Columns %d ", columns);
-  s->append(s1);
+  s->appendf("/Columns {0:d} ", columns);
   if (rows != 0) {
-    sprintf(s1, "/Rows %d ", rows);
-    s->append(s1);
+    s->appendf("/Rows {0:d} ", rows);
   }
   if (!endOfBlock) {
     s->append("/EndOfBlock false ");
@@ -4059,7 +4065,7 @@
       error(errSyntaxError, getPos(), "Bad DCT quantization table");
       return gFalse;
     }
-    if (index == numQuantTables) {
+    if (index >= numQuantTables) {
       numQuantTables = index + 1;
     }
     for (i = 0; i < 64; ++i) {
@@ -4951,6 +4957,8 @@
   endOfBlock = eof = gTrue;
   cmf = str->getChar();
   flg = str->getChar();
+  totalIn = 2;
+  totalOut = 0;
   if (cmf == EOF || flg == EOF)
     return;
   if ((cmf & 0x0f) != 0x08) {
@@ -5017,7 +5025,7 @@
 }
 
 int FlateStream::getBlock(char *blk, int size) {
-  int n;
+  int n, k;
 
   if (pred) {
     return pred->getBlock(blk, size);
@@ -5031,11 +5039,17 @@
       }
       readSome();
     }
-    while (remain && n < size) {
-      blk[n++] = buf[index];
-      index = (index + 1) & flateMask;
-      --remain;
+    k = remain;
+    if (size - n < k) {
+      k = size - n;
     }
+    if (flateWindow - index < k) {
+      k = flateWindow - index;
+    }
+    memcpy(blk + n, buf + index, k);
+    n += k;
+    index = (index + k) & flateMask;
+    remain -= k;
   }
   return n;
 }
@@ -5061,7 +5075,7 @@
 void FlateStream::readSome() {
   int code1, code2;
   int len, dist;
-  int i, j, k;
+  int src, dest, n1, n2, n3, i, j, k;
   int c;
 
   if (endOfBlock) {
@@ -5090,12 +5104,78 @@
       if (code2 > 0 && (code2 = getCodeWord(code2)) == EOF)
 	goto err;
       dist = distDecode[code1].first + code2;
-      i = index;
-      j = (index - dist) & flateMask;
-      for (k = 0; k < len; ++k) {
-	buf[i] = buf[j];
-	i = (i + 1) & flateMask;
-	j = (j + 1) & flateMask;
+      dest = index;
+      src = (index - dist) & flateMask;
+      // the following is an optimized version of:
+      // for (k = 0; k < len; ++k) {
+      //   buf[dest] = buf[src];
+      //   dest = (dest + 1) & flateMask;
+      //   src = (src + 1) & flateMask;
+      // }
+      if (dest + len <= flateWindow) {
+	if (src + len <= flateWindow) {
+	  for (k = 0; k < len; ++k) {
+	    buf[dest + k] = buf[src + k];
+	  }
+	} else {
+	  n1 = flateWindow - src;
+	  n2 = len - n1;
+	  for (k = 0; k < n1; ++k) {
+	    buf[dest + k] = buf[src + k];
+	  }
+	  dest = dest + n1;
+	  src = 0;
+	  for (k = 0; k < n2; ++k) {
+	    buf[dest + k] = buf[src + k];
+	  }
+	}
+      } else {
+	if (src + len <= flateWindow) {
+	  n1 = flateWindow - dest;
+	  n2 = len - n1;
+	  for (k = 0; k < n1; ++k) {
+	    buf[dest + k] = buf[src + k];
+	  }
+	  dest = 0;
+	  src = src + n1;
+	  for (k = 0; k < n2; ++k) {
+	    buf[dest + k] = buf[src + k];
+	  }
+	} else if (src < dest) {
+	  n1 = flateWindow - dest;
+	  n2 = dest - src;
+	  n3 = len - n1 - n2;
+	  for (k = 0; k < n1; ++k) {
+	    buf[dest + k] = buf[src + k];
+	  }
+	  dest = 0;
+	  src = src + n1;
+	  for (k = 0; k < n2; ++k) {
+	    buf[dest + k] = buf[src + k];
+	  }
+	  dest = n2;
+	  src = 0;
+	  for (k = 0; k < n3; ++k) {
+	    buf[dest + k] = buf[src + k];
+	  }
+	} else {
+	  n1 = flateWindow - src;
+	  n2 = src - dest;
+	  n3 = len - n1 - n2;
+	  for (k = 0; k < n1; ++k) {
+	    buf[dest + k] = buf[src + k];
+	  }
+	  dest = dest + n1;
+	  src = 0;
+	  for (k = 0; k < n2; ++k) {
+	    buf[dest + k] = buf[src + k];
+	  }
+	  dest = 0;
+	  src = n2;
+	  for (k = 0; k < n3; ++k) {
+	    buf[dest + k] = buf[src + k];
+	  }
+	}
       }
       remain = len;
     }
@@ -5113,8 +5193,17 @@
     blockLen -= len;
     if (blockLen == 0)
       endOfBlock = gTrue;
+    totalIn += remain;
   }
+  totalOut += remain;
 
+  // check for a 'decompression bomb'
+  if (totalOut > 50000000 && totalIn < totalOut / 250) {
+    error(errSyntaxError, getPos(), "Decompression bomb in flate stream");
+    endOfBlock = eof = gTrue;
+    remain = 0;
+  }
+
   return;
 
 err:
@@ -5164,6 +5253,7 @@
 	    "Bad uncompressed block length in flate stream");
     codeBuf = 0;
     codeSize = 0;
+    totalIn += 4;
 
   // compressed block with fixed codes
   } else if (blockHdr == 1) {
@@ -5358,6 +5448,7 @@
     }
     codeBuf |= (c & 0xff) << codeSize;
     codeSize += 8;
+    ++totalIn;
   }
   code = &tab->codes[codeBuf & ((1 << tab->maxLen) - 1)];
   if (codeSize == 0 || codeSize < code->len || code->len == 0) {
@@ -5376,6 +5467,7 @@
       return EOF;
     codeBuf |= (c & 0xff) << codeSize;
     codeSize += 8;
+    ++totalIn;
   }
   c = codeBuf & ((1 << bits) - 1);
   codeBuf >>= bits;

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Stream.h
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Stream.h	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Stream.h	2021-02-15 19:17:20 UTC (rev 845)
@@ -501,6 +501,8 @@
   int seqLength;		// length of current sequence
   int seqIndex;			// index into current sequence
   GBool first;			// first code after a table clear
+  unsigned long long totalIn;	// total number of encoded bytes read so far
+  unsigned long long totalOut;	// total number of bytes decoded so far
 
   GBool processNextCode();
   void clearTable();
@@ -814,6 +816,8 @@
   int blockLen;			// remaining length of uncompressed block
   GBool endOfBlock;		// set when end of block is reached
   GBool eof;			// set when end of stream is reached
+  unsigned long long totalIn;	// total number of encoded bytes read so far
+  unsigned long long totalOut;	// total number of bytes decoded so far
 
   static int			// code length code reordering
     codeLenCodeMap[flateMaxCodeLenCodes];

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/TextOutputDev.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/TextOutputDev.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/TextOutputDev.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -26,6 +26,7 @@
 #include "gmempp.h"
 #include "GString.h"
 #include "GList.h"
+#include "gfile.h"
 #include "config.h"
 #include "Error.h"
 #include "GlobalParams.h"
@@ -88,11 +89,13 @@
 // Inter-character spacing that varies by less than this multiple of
 // font size is assumed to be equivalent.
 #define uniformSpacing 0.07
+#define tableModeUniformSpacing 0.14
 
 // Typical word spacing, as a fraction of font size.  This will be
 // added to the minimum inter-character spacing, to account for wide
 // character spacing.
 #define wordSpacing 0.1
+#define tableModeWordSpacing 0.2
 
 // Minimum paragraph indent from left margin, as a fraction of font
 // size.
@@ -114,6 +117,9 @@
 // value multiplied by font size.
 #define simpleLayoutGapThreshold 0.7
 
+// Minimum overlap in simple2 mode.
+#define simple2MinOverlap 0.2
+
 // Table cells (TextColumns) are allowed to overlap by this much
 // in table layout mode (as a fraction of cell width or height).
 #define tableCellOverlapSlack 0.05
@@ -157,9 +163,28 @@
 // rectangles, in order to work around flakey ascent values in fonts.
 #define selectionAscent 0.8
 
+// Grid size used to bin sort characters for overlap detection.
+#define overlapGridWidth 20
+#define overlapGridHeight 20
+
+// Minimum character bbox overlap (horizontal and vertical) as a
+// fraction of character bbox width/height for a character to be
+// treated as overlapping.
+#define minCharOverlap 0.3
+
 #define maxUnicodeLen 16
 
 //------------------------------------------------------------------------
+
+static inline double dmin(double x, double y) {
+  return x < y ? x : y;
+}
+
+static inline double dmax(double x, double y) {
+  return x > y ? x : y;
+}
+
+//------------------------------------------------------------------------
 // TextChar
 //------------------------------------------------------------------------
 
@@ -168,31 +193,36 @@
 
   TextChar(Unicode cA, int charPosA, int charLenA,
 	   double xMinA, double yMinA, double xMaxA, double yMaxA,
-	   int rotA, GBool clippedA, GBool invisibleA,
+	   int rotA, GBool rotatedA, GBool clippedA, GBool invisibleA,
 	   TextFontInfo *fontA, double fontSizeA,
 	   double colorRA, double colorGA, double colorBA);
 
   static int cmpX(const void *p1, const void *p2);
   static int cmpY(const void *p1, const void *p2);
+  static int cmpCharPos(const void *p1, const void *p2);
 
   Unicode c;
   int charPos;
   int charLen;
   double xMin, yMin, xMax, yMax;
-  Guchar rot;
-  char clipped;
-  char invisible;
-  char spaceAfter;
   TextFontInfo *font;
   double fontSize;
   double colorR,
          colorG,
          colorB;
+
+  // group the byte-size fields to minimize object size
+  Guchar rot;
+  char rotated;
+  char clipped;
+  char invisible;
+  char spaceAfter;
+  char overlap;
 };
 
 TextChar::TextChar(Unicode cA, int charPosA, int charLenA,
 		   double xMinA, double yMinA, double xMaxA, double yMaxA,
-		   int rotA, GBool clippedA, GBool invisibleA,
+		   int rotA, GBool rotatedA, GBool clippedA, GBool invisibleA,
 		   TextFontInfo *fontA, double fontSizeA,
 		   double colorRA, double colorGA, double colorBA) {
   double t;
@@ -228,6 +258,7 @@
     yMax = 1e8;
   }
   rot = (Guchar)rotA;
+  rotated = (char)rotatedA;
   clipped = (char)clippedA;
   invisible = (char)invisibleA;
   spaceAfter = (char)gFalse;
@@ -236,6 +267,7 @@
   colorR = colorRA;
   colorG = colorGA;
   colorB = colorBA;
+  overlap = gFalse;
 }
 
 int TextChar::cmpX(const void *p1, const void *p2) {
@@ -264,6 +296,12 @@
   }
 }
 
+int TextChar::cmpCharPos(const void *p1, const void *p2) {
+  const TextChar *ch1 = *(const TextChar **)p1;
+  const TextChar *ch2 = *(const TextChar **)p2;
+  return ch1->charPos - ch2->charPos;
+}
+
 //------------------------------------------------------------------------
 // TextBlock
 //------------------------------------------------------------------------
@@ -408,6 +446,40 @@
 }
 
 //------------------------------------------------------------------------
+// TextCharLine
+//------------------------------------------------------------------------
+
+class TextCharLine {
+public:
+
+  TextCharLine(int rotA);
+  ~TextCharLine();
+  void add(TextChar *ch);
+
+  GList *chars;
+  double yMin, yMax;
+  int rot;
+  TextCharLine *next, *prev;
+};
+
+TextCharLine::TextCharLine(int rotA) {
+  chars = new GList();
+  yMin = yMax = 0;
+  rot = rotA;
+  next = prev = NULL;
+}
+
+TextCharLine::~TextCharLine() {
+  delete chars;
+}
+
+void TextCharLine::add(TextChar *ch) {
+  chars->append(ch);
+  yMin = ch->yMin;
+  yMax = ch->yMax;
+}
+
+//------------------------------------------------------------------------
 // TextGaps
 //------------------------------------------------------------------------
 
@@ -539,8 +611,12 @@
   html = gFalse;
   clipText = gFalse;
   discardDiagonalText = gFalse;
+  discardRotatedText = gFalse;
   discardInvisibleText = gFalse;
   discardClippedText = gFalse;
+  splitRotatedWords = gFalse;
+  overlapHandling = textOutIgnoreOverlaps;
+  separateLargeChars = gTrue;
   insertBOM = gFalse;
   marginLeft = 0;
   marginRight = 0;
@@ -602,13 +678,15 @@
 }
 
 GBool TextFontInfo::matches(GfxState *state) {
-  Ref *id;
+  Ref id;
 
-  if (!state->getFont()) {
-    return gFalse;
+  if (state->getFont()) {
+    id = *state->getFont()->getID();
+  } else {
+    id.num = -1;
+    id.gen = -1;
   }
-  id = state->getFont()->getID();
-  return id->num == fontID.num && id->gen == fontID.gen;
+  return id.num == fontID.num && id.gen == fontID.gen;
 }
 
 //------------------------------------------------------------------------
@@ -618,11 +696,12 @@
 // Build a TextWord object, using chars[start .. start+len-1].
 // (If rot >= 2, the chars list is in reverse order.)
 TextWord::TextWord(GList *chars, int start, int lenA,
-		   int rotA, int dirA, GBool spaceAfterA) {
+		   int rotA, GBool rotatedA, int dirA, GBool spaceAfterA) {
   TextChar *ch;
   int i;
 
-  rot = rotA;
+  rot = (char)rotA;
+  rotated = (char)rotatedA;
   len = lenA;
   text = (Unicode *)gmallocn(len, sizeof(Unicode));
   edge = (double *)gmallocn(len + 1, sizeof(double));
@@ -680,8 +759,8 @@
   ch = (TextChar *)chars->get(start);
   font = ch->font;
   fontSize = ch->fontSize;
-  dir = dirA;
-  spaceAfter = spaceAfterA;
+  dir = (char)dirA;
+  spaceAfter = (char)spaceAfterA;
   underlined = gFalse;
   link = NULL;
   colorR = ch->colorR;
@@ -1057,6 +1136,7 @@
   curFontSize = 0;
   curRot = 0;
   diagonal = gFalse;
+  rotated = gFalse;
   nTinyChars = 0;
   actualText = NULL;
   actualTextLen = 0;
@@ -1108,6 +1188,7 @@
   curFontSize = 0;
   curRot = 0;
   diagonal = gFalse;
+  rotated = gFalse;
   nTinyChars = 0;
   gfree(actualText);
   actualText = NULL;
@@ -1219,7 +1300,12 @@
     m[2] = m2[2];
     m[3] = m2[3];
   }
-  if (fabs(m[0]) >= fabs(m[1]))  {
+  if (curFontSize == 0) {
+    // special case - if the font size is zero, just assume plain
+    // horizontal text
+    curRot = 0;
+    diagonal = gFalse;
+  } else if (fabs(m[0]) >= fabs(m[1]))  {
     if (m[0] > 0) {
       curRot = 0;
     } else {
@@ -1234,6 +1320,9 @@
     }
     diagonal = fabs(m[0]) > diagonalThreshold * fabs(m[1]);
   }
+  // this matches the 'horiz' test in SplashOutputDev::drawChar()
+  rotated = !(m[0] > 0 && fabs(m[1]) < 0.001 &&
+	      fabs(m[2]) < 0.001 && m[3] < 0);
 }
 
 void TextPage::addChar(GfxState *state, double x, double y,
@@ -1260,8 +1349,9 @@
     return;
   }
 
-  // throw away diagonal chars
-  if (control.discardDiagonalText && diagonal) {
+  // throw away diagonal/rotated chars
+  if ((control.discardDiagonalText && diagonal) ||
+      (control.discardRotatedText && rotated)) {
     charPos += nBytes;
     return;
   }
@@ -1299,9 +1389,15 @@
   }
 
   // skip space, tab, and non-breaking space characters
-  if (uLen == 1 && (u[0] == (Unicode)0x20 ||
-		    u[0] == (Unicode)0x09 ||
-		    u[0] == (Unicode)0xa0)) {
+  // (ActualText spans can result in multiple space chars)
+  for (i = 0; i < uLen; ++i) {
+    if (u[i] != (Unicode)0x20 &&
+	u[i] != (Unicode)0x09 &&
+	u[i] != (Unicode)0xa0) {
+      break;
+    }
+  }
+  if (i == uLen && uLen >= 1) {
     charPos += nBytes;
     if (chars->getLength() > 0) {
       ((TextChar *)chars->get(chars->getLength() - 1))->spaceAfter =
@@ -1400,7 +1496,7 @@
       }
       chars->append(new TextChar(uBuf[j], charPos, nBytes,
 				 xMin, yMin, xMax, yMax,
-				 curRot, clipped,
+				 curRot, rotated, clipped,
 				 state->getRender() == 3 || alpha < 0.001,
 				 curFont, curFontSize,
 				 colToDbl(rgb.r), colToDbl(rgb.g),
@@ -1503,6 +1599,10 @@
     writeSimpleLayout(outputStream, outputFunc, uMap, space, spaceLen,
 		      eol, eolLen);
     break;
+  case textOutSimple2Layout:
+    writeSimple2Layout(outputStream, outputFunc, uMap, space, spaceLen,
+		       eol, eolLen);
+    break;
   case textOutLinePrinter:
     writeLinePrinter(outputStream, outputFunc, uMap, space, spaceLen,
 		     eol, eolLen);
@@ -1530,11 +1630,20 @@
   TextColumn *col;
   TextParagraph *par;
   TextLine *line;
+  GList *overlappingChars;
   GList *columns;
   GBool primaryLR;
   GString *s;
   int colIdx, parIdx, lineIdx, rot, n;
 
+#if 0 //~debug
+  dumpChars(chars);
+#endif
+  if (control.overlapHandling != textOutIgnoreOverlaps) {
+    overlappingChars = separateOverlappingText(chars);
+  } else {
+    overlappingChars = NULL;
+  }
   rot = rotateChars(chars);
   primaryLR = checkPrimaryLR(chars);
   tree = splitChars(chars);
@@ -1553,6 +1662,12 @@
     rotateUnderlinesAndLinks(rot);
     generateUnderlinesAndLinks(columns);
   }
+  if (overlappingChars) {
+    if (overlappingChars->getLength() > 0) {
+      columns->append(buildOverlappingTextColumn(overlappingChars));
+    }
+    deleteGList(overlappingChars, TextChar);
+  }
 #if 0 //~debug
   dumpColumns(columns);
 #endif
@@ -1585,24 +1700,44 @@
 
 GList *TextPage::makeColumns() {
   TextBlock *tree;
+  GList *overlappingChars;
   GList *columns;
   GBool primaryLR;
   int rot;
 
-  rot = rotateChars(chars);
-  primaryLR = checkPrimaryLR(chars);
-  if ((tree = splitChars(chars))) {
-    columns = buildColumns(tree, primaryLR);
-    delete tree;
+  if (control.mode == textOutSimple2Layout) {
+    primaryLR = checkPrimaryLR(chars);
+    rotateCharsToZero(chars);
+    columns = buildSimple2Columns(chars);
+    unrotateCharsFromZero(chars);
+    unrotateColumnsFromZero(columns);
   } else {
-    // no text
-    columns = new GList();
+    if (control.overlapHandling != textOutIgnoreOverlaps) {
+      overlappingChars = separateOverlappingText(chars);
+    } else {
+      overlappingChars = NULL;
+    }
+    rot = rotateChars(chars);
+    primaryLR = checkPrimaryLR(chars);
+    if ((tree = splitChars(chars))) {
+      columns = buildColumns(tree, primaryLR);
+      delete tree;
+    } else {
+      // no text
+      columns = new GList();
+    }
+    unrotateChars(chars, rot);
+    unrotateColumns(columns, rot);
+    if (control.html) {
+      generateUnderlinesAndLinks(columns);
+    }
+    if (overlappingChars) {
+      if (overlappingChars->getLength() > 0) {
+	columns->append(buildOverlappingTextColumn(overlappingChars));
+      }
+      deleteGList(overlappingChars, TextChar);
+    }
   }
-  unrotateChars(chars, rot);
-  unrotateColumns(columns, rot);
-  if (control.html) {
-    generateUnderlinesAndLinks(columns);
-  }
   return columns;
 }
 
@@ -1618,6 +1753,7 @@
   TextColumn *col;
   TextParagraph *par;
   TextLine *line;
+  GList *overlappingChars;
   GList *columns;
   GBool primaryLR;
   int ph, colIdx, parIdx, lineIdx, rot, y, i;
@@ -1628,6 +1764,11 @@
 #if 0 //~debug
   dumpUnderlines();
 #endif
+  if (control.overlapHandling != textOutIgnoreOverlaps) {
+    overlappingChars = separateOverlappingText(chars);
+  } else {
+    overlappingChars = NULL;
+  }
   rot = rotateChars(chars);
   primaryLR = checkPrimaryLR(chars);
   tree = splitChars(chars);
@@ -1700,6 +1841,29 @@
   gfree(outLen);
 
   deleteGList(columns, TextColumn);
+
+  if (overlappingChars) {
+    if (overlappingChars->getLength() > 0) {
+      TextColumn *col = buildOverlappingTextColumn(overlappingChars);
+      (*outputFunc)(outputStream, eol, eolLen);
+      for (parIdx = 0; parIdx < col->paragraphs->getLength(); ++parIdx) {
+	par = (TextParagraph *)col->paragraphs->get(parIdx);
+	for (lineIdx = 0; lineIdx < par->lines->getLength(); ++lineIdx) {
+	  line = (TextLine *)par->lines->get(lineIdx);
+	  GString *s = new GString();
+	  encodeFragment(line->text, line->len, uMap, primaryLR, s);
+	  s->append(eol, eolLen);
+	  (*outputFunc)(outputStream, s->getCString(), s->getLength());
+	  delete s;
+	}
+	if (parIdx < col->paragraphs->getLength() - 1) {
+	  (*outputFunc)(outputStream, eol, eolLen);
+	}
+      }
+      delete col;
+    }
+    deleteGList(overlappingChars, TextChar);
+  }
 }
 
 void TextPage::writeSimpleLayout(void *outputStream,
@@ -1762,6 +1926,46 @@
   deleteGList(superLines, TextSuperLine);
 }
 
+void TextPage::writeSimple2Layout(void *outputStream,
+				  TextOutputFunc outputFunc,
+				  UnicodeMap *uMap,
+				  char *space, int spaceLen,
+				  char *eol, int eolLen) {
+  GList *columns;
+  TextColumn *col;
+  TextParagraph *par;
+  TextLine *line;
+  GString *out;
+  GBool primaryLR;
+  int colIdx, parIdx, lineIdx;
+
+  primaryLR = checkPrimaryLR(chars);
+  rotateCharsToZero(chars);
+#if 0 //~debug
+  dumpChars(chars);
+#endif
+  columns = buildSimple2Columns(chars);
+  unrotateCharsFromZero(chars);
+  unrotateColumnsFromZero(columns);
+
+  for (colIdx = 0; colIdx < columns->getLength(); ++colIdx) {
+    col = (TextColumn *)columns->get(colIdx);
+    for (parIdx = 0; parIdx < col->paragraphs->getLength(); ++parIdx) {
+      par = (TextParagraph *)col->paragraphs->get(parIdx);
+      for (lineIdx = 0; lineIdx < par->lines->getLength(); ++lineIdx) {
+	line = (TextLine *)par->lines->get(lineIdx);
+	out = new GString();
+	encodeFragment(line->text, line->len, uMap, primaryLR, out);
+	(*outputFunc)(outputStream, out->getCString(), out->getLength());
+	delete out;
+	(*outputFunc)(outputStream, eol, eolLen);
+      }
+    }
+  }
+
+  deleteGList(columns, TextColumn);
+}
+
 void TextPage::writeLinePrinter(void *outputStream,
 				TextOutputFunc outputFunc,
 				UnicodeMap *uMap,
@@ -1778,7 +1982,8 @@
 
   rot = rotateChars(chars);
   chars->sort(&TextChar::cmpX);
-  removeDuplicates(chars, 0);
+  // don't call removeDuplicates here, because it expects to be
+  // working on a secondary list that doesn't own the TextChar objects
   chars->sort(&TextChar::cmpY);
 
   // get character pitch
@@ -1796,7 +2001,7 @@
 	    ch->yMin + ascentAdjustFactor * (ch->yMax - ch->yMin) <
 	      ch2->yMax - descentAdjustFactor * (ch2->yMax - ch2->yMin)) {
 	  delta = fabs(ch2->xMin - ch->xMin);
-	  if (delta > 0 && delta < pitch) {
+	  if (delta > 0.01 && delta < pitch) {
 	    pitch = delta;
 	  }
 	}
@@ -2135,6 +2340,53 @@
   return rot;
 }
 
+// Rotate all chars to zero rotation.  This leaves the TextChar.rot
+// fields unchanged.
+void TextPage::rotateCharsToZero(GList *charsA) {
+  TextChar *ch;
+  double xMin, yMin, xMax, yMax;
+  int i;
+
+  for (i = 0; i < charsA->getLength(); ++i) {
+    ch = (TextChar *)charsA->get(i);
+    switch (ch->rot) {
+    case 0:
+    default:
+      break;
+    case 1:
+      xMin = ch->yMin;
+      xMax = ch->yMax;
+      yMin = pageWidth - ch->xMax;
+      yMax = pageWidth - ch->xMin;
+      ch->xMin = xMin;
+      ch->xMax = xMax;
+      ch->yMin = yMin;
+      ch->yMax = yMax;
+      break;
+    case 2:
+      xMin = pageWidth - ch->xMax;
+      xMax = pageWidth - ch->xMin;
+      yMin = pageHeight - ch->yMax;
+      yMax = pageHeight - ch->yMin;
+      ch->xMin = xMin;
+      ch->xMax = xMax;
+      ch->yMin = yMin;
+      ch->yMax = yMax;
+      break;
+    case 3:
+      xMin = pageHeight - ch->yMax;
+      xMax = pageHeight - ch->yMin;
+      yMin = ch->xMin;
+      yMax = ch->xMax;
+      ch->xMin = xMin;
+      ch->xMax = xMax;
+      ch->yMin = yMin;
+      ch->yMax = yMax;
+      break;
+    }
+  }
+}
+
 // Rotate the TextUnderlines and TextLinks to match the transform
 // performed by rotateChars().
 void TextPage::rotateUnderlinesAndLinks(int rot) {
@@ -2286,6 +2538,224 @@
   }
 }
 
+// Undo the coordinate transform performed by rotateCharsToZero().
+void TextPage::unrotateCharsFromZero(GList *charsA) {
+  TextChar *ch;
+  double xMin, yMin, xMax, yMax;
+  int i;
+
+  for (i = 0; i < charsA->getLength(); ++i) {
+    ch = (TextChar *)charsA->get(i);
+    switch (ch->rot) {
+    case 0:
+    default:
+      break;
+    case 1:
+      xMin = pageWidth - ch->yMax;
+      xMax = pageWidth - ch->yMin;
+      yMin = ch->xMin;
+      yMax = ch->xMax;
+      ch->xMin = xMin;
+      ch->xMax = xMax;
+      ch->yMin = yMin;
+      ch->yMax = yMax;
+      break;
+    case 2:
+      xMin = pageWidth - ch->xMax;
+      xMax = pageWidth - ch->xMin;
+      yMin = pageHeight - ch->yMax;
+      yMax = pageHeight - ch->yMin;
+      ch->xMin = xMin;
+      ch->xMax = xMax;
+      ch->yMin = yMin;
+      ch->yMax = yMax;
+      break;
+    case 3:
+      xMin = ch->yMin;
+      xMax = ch->yMax;
+      yMin = pageHeight - ch->xMax;
+      yMax = pageHeight - ch->xMin;
+      ch->xMin = xMin;
+      ch->xMax = xMax;
+      ch->yMin = yMin;
+      ch->yMax = yMax;
+      break;
+    }
+  }
+}
+
+// Undo the coordinate transform performed by rotateCharsToZero().
+void TextPage::unrotateColumnsFromZero(GList *columns) {
+  TextColumn *col;
+  TextParagraph *par;
+  TextLine *line;
+  TextWord *word;
+  double xMin, yMin, xMax, yMax;
+  int colIdx, parIdx, lineIdx, wordIdx, i;
+
+  for (colIdx = 0; colIdx < columns->getLength(); ++colIdx) {
+    col = (TextColumn *)columns->get(colIdx);
+    switch (col->getRotation()) {
+    case 0:
+    default:
+      break;
+    case 1:
+      xMin = pageWidth - col->yMax;
+      xMax = pageWidth - col->yMin;
+      yMin = col->xMin;
+      yMax = col->xMax;
+      col->xMin = xMin;
+      col->xMax = xMax;
+      col->yMin = yMin;
+      col->yMax = yMax;
+      for (parIdx = 0;
+	   parIdx < col->paragraphs->getLength();
+	   ++parIdx) {
+	par = (TextParagraph *)col->paragraphs->get(parIdx);
+	xMin = pageWidth - par->yMax;
+	xMax = pageWidth - par->yMin;
+	yMin = par->xMin;
+	yMax = par->xMax;
+	par->xMin = xMin;
+	par->xMax = xMax;
+	par->yMin = yMin;
+	par->yMax = yMax;
+	for (lineIdx = 0;
+	     lineIdx < par->lines->getLength();
+	     ++lineIdx) {
+	  line = (TextLine *)par->lines->get(lineIdx);
+	  xMin = pageWidth - line->yMax;
+	  xMax = pageWidth - line->yMin;
+	  yMin = line->xMin;
+	  yMax = line->xMax;
+	  line->xMin = xMin;
+	  line->xMax = xMax;
+	  line->yMin = yMin;
+	  line->yMax = yMax;
+	  for (wordIdx = 0; wordIdx < line->words->getLength(); ++wordIdx) {
+	    word = (TextWord *)line->words->get(wordIdx);
+	    xMin = pageWidth - word->yMax;
+	    xMax = pageWidth - word->yMin;
+	    yMin = word->xMin;
+	    yMax = word->xMax;
+	    word->xMin = xMin;
+	    word->xMax = xMax;
+	    word->yMin = yMin;
+	    word->yMax = yMax;
+	  }
+	}
+      }
+      break;
+    case 2:
+      xMin = pageWidth - col->xMax;
+      xMax = pageWidth - col->xMin;
+      yMin = pageHeight - col->yMax;
+      yMax = pageHeight - col->yMin;
+      col->xMin = xMin;
+      col->xMax = xMax;
+      col->yMin = yMin;
+      col->yMax = yMax;
+      for (parIdx = 0;
+	   parIdx < col->paragraphs->getLength();
+	   ++parIdx) {
+	par = (TextParagraph *)col->paragraphs->get(parIdx);
+	xMin = pageWidth - par->xMax;
+	xMax = pageWidth - par->xMin;
+	yMin = pageHeight - par->yMax;
+	yMax = pageHeight - par->yMin;
+	par->xMin = xMin;
+	par->xMax = xMax;
+	par->yMin = yMin;
+	par->yMax = yMax;
+	for (lineIdx = 0;
+	     lineIdx < par->lines->getLength();
+	     ++lineIdx) {
+	  line = (TextLine *)par->lines->get(lineIdx);
+	  xMin = pageWidth - line->xMax;
+	  xMax = pageWidth - line->xMin;
+	  yMin = pageHeight - line->yMax;
+	  yMax = pageHeight - line->yMin;
+	  line->xMin = xMin;
+	  line->xMax = xMax;
+	  line->yMin = yMin;
+	  line->yMax = yMax;
+	  for (i = 0; i <= line->len; ++i) {
+	    line->edge[i] = pageWidth - line->edge[i];
+	  }
+	  for (wordIdx = 0; wordIdx < line->words->getLength(); ++wordIdx) {
+	    word = (TextWord *)line->words->get(wordIdx);
+	    xMin = pageWidth - word->xMax;
+	    xMax = pageWidth - word->xMin;
+	    yMin = pageHeight - word->yMax;
+	    yMax = pageHeight - word->yMin;
+	    word->xMin = xMin;
+	    word->xMax = xMax;
+	    word->yMin = yMin;
+	    word->yMax = yMax;
+	    for (i = 0; i <= word->len; ++i) {
+	      word->edge[i] = pageWidth - word->edge[i];
+	    }
+	  }
+	}
+      }
+      break;
+    case 3:
+      xMin = col->yMin;
+      xMax = col->yMax;
+      yMin = pageHeight - col->xMax;
+      yMax = pageHeight - col->xMin;
+      col->xMin = xMin;
+      col->xMax = xMax;
+      col->yMin = yMin;
+      col->yMax = yMax;
+      for (parIdx = 0;
+	   parIdx < col->paragraphs->getLength();
+	   ++parIdx) {
+	par = (TextParagraph *)col->paragraphs->get(parIdx);
+	xMin = par->yMin;
+	xMax = par->yMax;
+	yMin = pageHeight - par->xMax;
+	yMax = pageHeight - par->xMin;
+	par->xMin = xMin;
+	par->xMax = xMax;
+	par->yMin = yMin;
+	par->yMax = yMax;
+	for (lineIdx = 0;
+	     lineIdx < par->lines->getLength();
+	     ++lineIdx) {
+	  line = (TextLine *)par->lines->get(lineIdx);
+	  xMin = line->yMin;
+	  xMax = line->yMax;
+	  yMin = pageHeight - line->xMax;
+	  yMax = pageHeight - line->xMin;
+	  line->xMin = xMin;
+	  line->xMax = xMax;
+	  line->yMin = yMin;
+	  line->yMax = yMax;
+	  for (i = 0; i <= line->len; ++i) {
+	    line->edge[i] = pageHeight - line->edge[i];
+	  }
+	  for (wordIdx = 0; wordIdx < line->words->getLength(); ++wordIdx) {
+	    word = (TextWord *)line->words->get(wordIdx);
+	    xMin = word->yMin;
+	    xMax = word->yMax;
+	    yMin = pageHeight - word->xMax;
+	    yMax = pageHeight - word->xMin;
+	    word->xMin = xMin;
+	    word->xMax = xMax;
+	    word->yMin = yMin;
+	    word->yMax = yMax;
+	    for (i = 0; i <= word->len; ++i) {
+	      word->edge[i] = pageHeight - word->edge[i];
+	    }
+	  }
+	}
+      }
+      break;
+    }
+  }
+}
+
 // Undo the coordinate transform performed by rotateChars().
 void TextPage::unrotateColumns(GList *columns, int rot) {
   TextColumn *col;
@@ -2601,7 +3071,8 @@
   int i, j;
 
   if (rot & 1) {
-    for (i = 0; i < charsA->getLength(); ++i) {
+    i = 0;
+    while (i < charsA->getLength()) {
       ch = (TextChar *)charsA->get(i);
       xDelta = dupMaxSecDelta * ch->fontSize;
       yDelta = dupMaxPriDelta * ch->fontSize;
@@ -2615,6 +3086,11 @@
 	    fabs(ch2->xMin - ch->xMin) < xDelta &&
 	    fabs(ch2->xMax - ch->xMax) < xDelta &&
 	    fabs(ch2->yMax - ch->yMax) < yDelta) {
+	  if (ch->invisible && !ch2->invisible) {
+	    charsA->del(i);
+	    --i;
+	    break;
+	  }
 	  if (ch2->spaceAfter) {
 	    ch->spaceAfter = (char)gTrue;
 	  }
@@ -2623,9 +3099,11 @@
 	  ++j;
 	}
       }
+      ++i;
     }
   } else {
-    for (i = 0; i < charsA->getLength(); ++i) {
+    i = 0;
+    while (i < charsA->getLength()) {
       ch = (TextChar *)charsA->get(i);
       xDelta = dupMaxPriDelta * ch->fontSize;
       yDelta = dupMaxSecDelta * ch->fontSize;
@@ -2639,15 +3117,257 @@
 	    fabs(ch2->xMax - ch->xMax) < xDelta &&
 	    fabs(ch2->yMin - ch->yMin) < yDelta &&
 	    fabs(ch2->yMax - ch->yMax) < yDelta) {
+	  if (ch->invisible && !ch2->invisible) {
+	    charsA->del(i);
+	    --i;
+	    break;
+	  }
+	  if (ch2->spaceAfter) {
+	    ch->spaceAfter = (char)gTrue;
+	  }
 	  charsA->del(j);
 	} else {
 	  ++j;
 	}
       }
+      ++i;
     }
   }
 }
 
+struct TextCharNode {
+  TextCharNode(TextChar *chA, TextCharNode *nextA): ch(chA), next(nextA) {}
+  TextChar *ch;
+  TextCharNode *next;
+};
+
+// Separate out any overlapping text.  If handling is
+// textOutAppendOverlaps, return a list of the overlapping chars; else
+// delete them and return NULL.
+GList *TextPage::separateOverlappingText(GList *charsA) {
+  // bin-sort the TextChars
+  TextCharNode *grid[overlapGridHeight][overlapGridWidth];
+  for (int y = 0; y < overlapGridHeight; ++y) {
+    for (int x = 0; x < overlapGridWidth; ++x) {
+      grid[y][x] = NULL;
+    }
+  }
+  for (int i = 0; i < charsA->getLength(); ++i) {
+    TextChar *ch = (TextChar *)charsA->get(i);
+    int y0 = (int)floor(overlapGridHeight * ch->yMin / pageHeight);
+    int y1 = (int)ceil(overlapGridHeight * ch->yMax / pageHeight);
+    int x0 = (int)floor(overlapGridWidth * ch->xMin / pageWidth);
+    int x1 = (int)ceil(overlapGridWidth * ch->yMin / pageWidth);
+    if (y0 < 0) {
+      y0 = 0;
+    }
+    if (y1 >= overlapGridHeight) {
+      y1 = overlapGridHeight - 1;
+    }
+    if (x0 < 0) {
+      x0 = 0;
+    }
+    if (x1 >= overlapGridWidth) {
+      x1 = overlapGridWidth - 1;
+    }
+    for (int y = y0; y <= y1; ++y) {
+      for (int x = x0; x <= x1; ++x) {
+	grid[y][x] = new TextCharNode(ch, grid[y][x]);
+      }
+    }
+  }
+
+  // look for overlaps in each cell
+  GBool foundOverlaps = gFalse;
+  for (int y = 0; y < overlapGridHeight; ++y) {
+    for (int x = 0; x < overlapGridWidth; ++x) {
+      for (TextCharNode *p0 = grid[y][x]; p0; p0 = p0->next) {
+	for (TextCharNode *p1 = p0->next; p1; p1 = p1->next) {
+	  if (p0->ch->colorR != p1->ch->colorR ||
+	      p0->ch->colorG != p1->ch->colorG ||
+	      p0->ch->colorB != p1->ch->colorB) {
+	    double ovx = (dmin(p0->ch->xMax, p1->ch->xMax)
+			  - dmax(p0->ch->xMin, p1->ch->xMin))
+	                 / dmin(p0->ch->xMax - p0->ch->xMin,
+			       p1->ch->xMax - p1->ch->xMin);
+	    double ovy = (dmin(p0->ch->yMax, p1->ch->yMax)
+			  - dmax(p0->ch->yMin, p1->ch->yMin))
+	                 / dmin(p0->ch->yMax - p0->ch->yMin,
+			       p1->ch->yMax - p1->ch->yMin);
+	    if (ovx > minCharOverlap && ovy > minCharOverlap) {
+	      // assume the lighter colored text is extraneous
+	      if (p0->ch->colorR + p0->ch->colorG + p0->ch->colorB
+		  < p1->ch->colorR + p1->ch->colorG + p1->ch->colorB) {
+		p1->ch->overlap = gTrue;
+	      } else {
+		p0->ch->overlap = gTrue;
+	      }
+	      foundOverlaps = gTrue;
+	    }
+	  }
+	}
+      }
+    }
+  }
+
+  // find overlapped strings
+  GList *overlapChars = NULL;
+  if (control.overlapHandling == textOutAppendOverlaps) {
+    overlapChars = new GList();
+  }
+  if (foundOverlaps) {
+    charsA->sort(&TextChar::cmpCharPos);
+    int i = 0;
+    while (i < charsA->getLength()) {
+      TextChar *ch0 = (TextChar *)charsA->get(i);
+      if (ch0->overlap) {
+	int j0, j1;
+	for (j0 = i - 1; j0 >= 0; --j0) {
+	  TextChar *ch1 = (TextChar *)charsA->get(j0);
+	  if (ch1->colorR != ch0->colorR ||
+	      ch1->colorG != ch0->colorG ||
+	      ch1->colorB != ch0->colorB ||
+	      ch1->rot != ch0->rot) {
+	    break;
+	  }
+	}
+	++j0;
+	for (j1 = i + 1; j1 < charsA->getLength(); ++j1) {
+	  TextChar *ch1 = (TextChar *)charsA->get(j1);
+	  if (ch1->colorR != ch0->colorR ||
+	      ch1->colorG != ch0->colorG ||
+	      ch1->colorB != ch0->colorB ||
+	      ch1->rot != ch0->rot) {
+	    break;
+	  }
+	}
+	--j1;
+	for (int j = j0; j <= j1; ++j) {
+	  if (overlapChars) {
+	    overlapChars->append(charsA->get(j0));
+	  } else {
+	    delete (TextChar *)charsA->get(j0);
+	  }
+	  charsA->del(j0);
+	}
+	i = j0;
+      } else {
+	++i;
+      }
+    }
+  }
+
+  // free memory
+  for (int y = 0; y < overlapGridHeight; ++y) {
+    for (int x = 0; x < overlapGridWidth; ++x) {
+      TextCharNode *p0 = grid[y][x];
+      while (p0) {
+	TextCharNode *p1 = p0->next;
+	delete p0;
+	p0 = p1;
+      }
+    }
+  }
+
+  return overlapChars;
+}
+
+// Construct a TextColumn from the list of separated overlapping
+// chars.
+TextColumn *TextPage::buildOverlappingTextColumn(GList *overlappingChars) {
+  GList *pars = new GList();
+  GList *lines = new GList();
+  GList *words = new GList();
+  int wordStart = 0;
+  double lineXMin = 0, lineYMin = 0, lineXMax = 0, lineYMax = 0;
+  double colXMin = 0, colYMin = 0, colXMax = 0, colYMax = 0;
+  for (int i = 0; i < overlappingChars->getLength(); ++i) {
+    TextChar *ch = (TextChar *)overlappingChars->get(i);
+    TextChar *chNext = NULL;
+    if (i + 1 < overlappingChars->getLength()) {
+      chNext = (TextChar *)overlappingChars->get(i + 1);
+    }
+    double sp = 0;
+    double dy = 0;
+    if (chNext) {
+      switch (ch->rot) {
+      case 0:
+      default:
+	sp = chNext->xMin - ch->xMax;
+	dy = chNext->yMin - ch->yMin;
+	break;
+      case 1:
+	sp = chNext->yMin - ch->yMax;
+	dy = chNext->xMax - ch->xMax;
+	break;
+      case 2:
+	sp = ch->xMin - chNext->xMax;
+	dy = ch->yMax - chNext->yMax;
+	break;
+      case 3:
+	sp = ch->yMin - chNext->yMax;
+	dy = ch->xMin - chNext->xMin;
+	break;
+      }
+    }
+    // the +1 here allows for a space character after ch
+    GBool parBreak = !chNext ||
+                     chNext->rot != ch->rot ||
+                     chNext->charPos > ch->charPos + ch->charLen + 1;
+    GBool lineBreak = parBreak ||
+                      sp < -rawModeCharOverlap * ch->fontSize ||
+                      fabs(dy) > rawModeLineDelta * ch->fontSize;
+    GBool wordBreak = lineBreak ||
+                      ch->spaceAfter ||
+                      sp > rawModeWordSpacing * ch->fontSize;
+    if (!wordBreak) {
+      continue;
+    }
+    TextWord *word = new TextWord(overlappingChars, wordStart,
+				  i - wordStart + 1, ch->rot, ch->rotated,
+				  getCharDirection(ch), !lineBreak);
+    words->append(word);
+    if (words->getLength() == 0) {
+      lineXMin = word->xMin;
+      lineYMin = word->yMin;
+      lineXMax = word->xMax;
+      lineYMax = word->yMax;
+    } else {
+      lineXMin = dmin(lineXMin, word->xMin);
+      lineYMin = dmin(lineYMin, word->yMin);
+      lineXMax = dmax(lineXMax, word->xMax);
+      lineYMax = dmax(lineYMax, word->yMax);
+    }
+    wordStart = i + 1;
+    if (!lineBreak) {
+      continue;
+    }
+    lines->append(new TextLine(words, lineXMin, lineYMin, lineXMax, lineYMax,
+			       ((TextWord *)words->get(0))->fontSize));
+    words = new GList();
+    if (!parBreak) {
+      continue;
+    }
+    TextParagraph *par = new TextParagraph(lines, gFalse);
+    pars->append(par);
+    if (pars->getLength() == 0) {
+      colXMin = par->xMin;
+      colYMin = par->yMin;
+      colXMax = par->xMax;
+      colYMax = par->yMax;
+    } else {
+      colXMin = dmin(colXMin, par->xMin);
+      colYMin = dmin(colYMin, par->yMin);
+      colXMax = dmax(colXMax, par->xMax);
+      colYMax = dmax(colYMax, par->yMax);
+    }
+    lines = new GList();
+  }
+  delete words;
+  delete lines;
+  return new TextColumn(pars, colXMin, colYMin, colXMax, colYMax);
+}
+
 // Split the characters into trees of TextBlocks, one tree for each
 // rotation.  Merge into a single tree (with the primary rotation).
 TextBlock *TextPage::splitChars(GList *charsA) {
@@ -2860,12 +3580,15 @@
   //    largeCharSize could otherwise have slightly different values
   //    here and where it's used below to do the large char partition
   //    (because it gets truncated from 80 to 64 bits when spilled)
-  largeCharSize = (int)(largeCharThreshold * avgFontSize * 256) / 256.0;
   nLargeChars = 0;
-  for (i = 0; i < charsA->getLength(); ++i) {
-    ch = (TextChar *)charsA->get(i);
-    if (ch->fontSize > largeCharSize) {
-      ++nLargeChars;
+  largeCharSize = 0;
+  if (control.separateLargeChars) {
+    largeCharSize = (int)(largeCharThreshold * avgFontSize * 256) / 256.0;
+    for (i = 0; i < charsA->getLength(); ++i) {
+      ch = (TextChar *)charsA->get(i);
+      if (ch->fontSize > largeCharSize) {
+	++nLargeChars;
+      }
     }
   }
 
@@ -3092,7 +3815,7 @@
   if (xMin * invSplitPrecision < 0.5 * INT_MIN ||
       xMax * invSplitPrecision > 0.5 * INT_MAX ||
       yMin * invSplitPrecision < 0.5 * INT_MIN ||
-      xMax * invSplitPrecision > 0.5 * INT_MAX) {
+      yMax * invSplitPrecision > 0.5 * INT_MAX) {
     return;
   }
   // add some slack to the array bounds to avoid floating point
@@ -3543,7 +4266,7 @@
   int i;
 
   lines = new GList();
-  buildLines(blk, lines);
+  buildLines(blk, lines, gFalse);
 
   spaceThresh = paragraphSpacingThreshold * getAverageLineSpacing(lines);
 
@@ -3712,12 +4435,13 @@
   return sp;
 }
 
-void TextPage::buildLines(TextBlock *blk, GList *lines) {
+void TextPage::buildLines(TextBlock *blk, GList *lines,
+			  GBool splitSuperLines) {
   TextLine *line;
   int i;
 
-  switch (blk->tag) {
-  case blkTagLine:
+  if (blk->tag == blkTagLine ||
+      (blk->tag == blkTagSuperLine && !splitSuperLines)) {
     line = buildLine(blk);
     if (blk->rot == 1 || blk->rot == 2) {
       lines->insert(0, line);
@@ -3724,32 +4448,219 @@
     } else {
       lines->append(line);
     }
-    break;
-  case blkTagSuperLine:
-  case blkTagColumn:
-  case blkTagMulticolumn: // multicolumn should never happen here
+  } else {
     for (i = 0; i < blk->children->getLength(); ++i) {
-      buildLines((TextBlock *)blk->children->get(i), lines);
+      buildLines((TextBlock *)blk->children->get(i), lines, splitSuperLines);
     }
-    break;
   }
 }
 
+GList *TextPage::buildSimple2Columns(GList *charsA) {
+  GList *columns, *paragraphs, *lines;
+  TextParagraph *paragraph;
+  int rot;
+
+  charsA->sort(&TextChar::cmpX);
+  columns = new GList();
+  for (rot = 0; rot < 4; ++rot) {
+    lines = buildSimple2Lines(charsA, rot);
+    if (lines->getLength() == 0) {
+      delete lines;
+      continue;
+    }
+    paragraph = new TextParagraph(lines, gFalse);
+    paragraphs = new GList();
+    paragraphs->append(paragraph);
+    columns->append(new TextColumn(paragraphs,
+				   paragraph->xMin, paragraph->yMin,
+				   paragraph->xMax, paragraph->yMax));
+  }
+  return columns;
+}
+
+GList *TextPage::buildSimple2Lines(GList *charsA, int rot) {
+  GList *openCharLines, *lines;
+  TextCharLine *firstCharLine, *lastCharLine, *charLine, *p;
+  TextChar *ch;
+  TextLine *line;
+  double bestOverlap, overlap, xMin, yMin, xMax, yMax;
+  int bestLine, i, j, k, m;
+
+  firstCharLine = lastCharLine = NULL;
+  openCharLines = new GList();
+  for (i = 0; i < charsA->getLength(); ++i) {
+    ch = (TextChar *)charsA->get(i);
+    if (ch->rot != rot) {
+      continue;
+    }
+
+    // find the first open line with line.yMax > ch.yMin
+    j = -1;
+    k = openCharLines->getLength();
+    while (j < k - 1) {
+      // invariants: openLines[j].yMax <= ch.yMin (or j = -1)
+      //             openLines[k].yMax >  ch.yMin (or k = nOpenLines)
+      //             j < k - 1
+      m = j + (k - j) / 2;
+      charLine = (TextCharLine *)openCharLines->get(m);
+      if (charLine->yMax <= ch->yMin) {
+	j = m;
+      } else {
+	k = m;
+      }
+    }
+
+    // check overlap for all overlapping lines
+    // i.e., all lines with line.yMin < ch.yMax and line.yMax > ch.yMin
+    bestLine = -1;
+    bestOverlap = 0;
+    for (; k < openCharLines->getLength(); ++k) {
+      charLine = (TextCharLine *)openCharLines->get(k);
+      if (charLine->yMin >= ch->yMax) {
+	break;
+      }
+      overlap = ((ch->yMax < charLine->yMax ? ch->yMax : charLine->yMax)
+		 - (ch->yMin > charLine->yMin ? ch->yMin : charLine->yMin))
+	        / (ch->yMax - ch->yMin);
+      if (overlap > bestOverlap) {
+	bestLine = k;
+	bestOverlap = overlap;
+      }
+    }
+
+    // found an overlapping line
+    if (bestLine >= 0 && bestOverlap > simple2MinOverlap) {
+      k = bestLine;
+      charLine = (TextCharLine *)openCharLines->get(k);
+
+    // else insert a new line immediately before line k
+    } else {
+      charLine = new TextCharLine(ch->rot);
+      if (k < openCharLines->getLength()) {
+	p = (TextCharLine *)openCharLines->get(k);
+	if (p->prev) {
+	  p->prev->next = charLine;
+	  charLine->prev = p->prev;
+	} else {
+	  firstCharLine = charLine;
+	}
+	p->prev = charLine;
+	charLine->next = p;
+      } else {
+	if (lastCharLine) {
+	  lastCharLine->next = charLine;
+	  charLine->prev = lastCharLine;
+	} else {
+	  firstCharLine = charLine;
+	}
+	lastCharLine = charLine;
+      }
+      openCharLines->insert(k, charLine);
+    }
+
+    // add the char to the line
+    charLine->add(ch);
+    charLine->yMin = ch->yMin;
+    charLine->yMax = ch->yMax;
+
+    // update open lines before k
+    j = k - 1;
+    while (j >= 0) {
+      charLine = (TextCharLine *)openCharLines->get(j);
+      if (charLine->yMax <= ch->yMin) {
+	break;
+      }
+      charLine->yMax = ch->yMin;
+      if (charLine->yMin < charLine->yMax) {
+	break;
+      }
+      openCharLines->del(j);
+      --j;
+    }
+
+    // update open lines after k
+    j = k + 1;
+    while (j < openCharLines->getLength()) {
+      charLine = (TextCharLine *)openCharLines->get(j);
+      if (charLine->yMin >= ch->yMax) {
+	break;
+      }
+      charLine->yMin = ch->yMax;
+      if (charLine->yMin < charLine->yMax) {
+	break;
+      }
+      openCharLines->del(j);
+    }
+  }
+
+  // build TextLine objects
+  lines = new GList();
+  for (charLine = firstCharLine; charLine; charLine = p) {
+    xMin = yMin = xMax = yMax = 0;
+    for (j = 0; j < charLine->chars->getLength(); ++j) {
+      ch = (TextChar *)charLine->chars->get(j);
+      if (j == 0) {
+	xMin = ch->xMin;
+	yMin = ch->yMin;
+	xMax = ch->xMax;
+	yMax = ch->yMax;
+      } else {
+	if (ch->xMin < xMin) {
+	  xMin = ch->xMin;
+	}
+	if (ch->yMin < yMin) {
+	  yMin = ch->yMin;
+	}
+	if (ch->xMax < xMax) {
+	  xMax = ch->xMax;
+	}
+	if (ch->yMax < yMax) {
+	  yMax = ch->yMax;
+	}
+      }
+    }
+    // the chars have been rotated to 0, without changing the
+    // TextChar.rot values, so we need to tell buildLine to use rot=0,
+    // and then set the word and line rotation correctly afterward
+    line = buildLine(charLine->chars, 0, xMin, yMin, xMax, yMax);
+    line->rot = charLine->rot;
+    for (i = 0; i < line->words->getLength(); ++i) {
+      ((TextWord *)line->words->get(i))->rot = (char)charLine->rot;
+    }
+    lines->append(line);
+    p = charLine->next;
+    delete charLine;
+  }
+
+  delete openCharLines;
+
+  return lines;
+}
+
 TextLine *TextPage::buildLine(TextBlock *blk) {
   GList *charsA;
+
+  charsA = new GList();
+  getLineChars(blk, charsA);
+  TextLine *line = buildLine(charsA, blk->rot,
+			     blk->xMin, blk->yMin, blk->xMax, blk->yMax);
+  delete charsA;
+  return line;
+}
+
+TextLine *TextPage::buildLine(GList *charsA, int rot,
+			      double xMin, double yMin,
+			      double xMax, double yMax) {
   GList *words;
   TextChar *ch, *ch2;
   TextWord *word;
   double wordSp, lineFontSize, sp;
   int dir, dir2;
-  GBool spaceAfter, spaceBefore;
+  GBool rotated, spaceAfter, spaceBefore;
   int i, j;
 
-  charsA = new GList();
-  getLineChars(blk, charsA);
+  wordSp = computeWordSpacingThreshold(charsA, rot);
 
-  wordSp = computeWordSpacingThreshold(charsA, blk->rot);
-
   words = new GList();
   lineFontSize = 0;
   spaceBefore = gFalse;
@@ -3758,10 +4669,11 @@
     sp = wordSp - 1;
     spaceAfter = gFalse;
     dir = getCharDirection((TextChar *)charsA->get(i));
+    rotated = ((TextChar *)charsA->get(i))->rotated;
     for (j = i+1; j < charsA->getLength(); ++j) {
       ch = (TextChar *)charsA->get(j-1);
       ch2 = (TextChar *)charsA->get(j);
-      sp = (blk->rot & 1) ? (ch2->yMin - ch->yMax) : (ch2->xMin - ch->xMax);
+      sp = (rot & 1) ? (ch2->yMin - ch->yMax) : (ch2->xMin - ch->xMax);
       if (sp > wordSp) {
 	spaceAfter = gTrue;
 	break;
@@ -3775,6 +4687,7 @@
       dir2 = getCharDirection(ch2);
       if (ch->font != ch2->font ||
 	  fabs(ch->fontSize - ch2->fontSize) > 0.01 ||
+	  (control.splitRotatedWords && ch2->rotated != rotated) ||
 	  (dir && dir2 && dir2 != dir) ||
 	  (control.mode == textOutRawOrder &&
 	   ch2->charPos != ch->charPos + ch->charLen)) {
@@ -3785,11 +4698,11 @@
       }
       sp = wordSp - 1;
     }
-    word = new TextWord(charsA, i, j - i, blk->rot, dir,
-			(blk->rot >= 2) ? spaceBefore : spaceAfter);
+    word = new TextWord(charsA, i, j - i, rot, rotated, dir,
+			(rot >= 2) ? spaceBefore : spaceAfter);
     spaceBefore = spaceAfter;
     i = j;
-    if (blk->rot >= 2) {
+    if (rot >= 2) {
       words->insert(0, word);
     } else {
       words->append(word);
@@ -3799,10 +4712,7 @@
     }
   }
 
-  delete charsA;
-
-  return new TextLine(words, blk->xMin, blk->yMin, blk->xMax, blk->yMax,
-		      lineFontSize);
+  return new TextLine(words, xMin, yMin, xMax, yMax, lineFontSize);
 }
 
 void TextPage::getLineChars(TextBlock *blk, GList *charsA) {
@@ -3822,10 +4732,19 @@
 // spaces.
 double TextPage::computeWordSpacingThreshold(GList *charsA, int rot) {
   TextChar *ch, *ch2;
+  double uniformSp, wordSp;
   double avgFontSize;
   double minAdjGap, maxAdjGap, minSpGap, maxSpGap, minGap, maxGap, gap, gap2;
   int i;
 
+  if (control.mode == textOutTableLayout) {
+    uniformSp = tableModeUniformSpacing;
+    wordSp = tableModeWordSpacing;
+  } else {
+    uniformSp = uniformSpacing;
+    wordSp = wordSpacing;
+  }
+
   avgFontSize = 0;
   minGap = maxGap = 0;
   minAdjGap = minSpGap = 1;
@@ -3876,13 +4795,13 @@
   // (3) otherwise assume it's a single word (technically it could be
   //     either "ABC" or "A B C", but it's essentially impossible to
   //     tell)
-  if (maxGap - minGap < uniformSpacing * avgFontSize) {
+  if (maxGap - minGap < uniformSp * avgFontSize) {
     if (minSpGap <= maxSpGap) {
       if (minAdjGap <= maxAdjGap &&
 	  minSpGap - maxAdjGap > 0.01) {
 	return 0.5 * (maxAdjGap + minSpGap);
       } else if (minAdjGap > maxAdjGap &&
-		 maxSpGap - minSpGap < uniformSpacing * avgFontSize) {
+		 maxSpGap - minSpGap < uniformSp * avgFontSize) {
 	return minSpGap - 1;
       }
     }
@@ -3890,7 +4809,7 @@
 
   // if there is some variation in spacing, but it's small, assume
   // there are some inter-word spaces
-  } else if (maxGap - minGap < wordSpacing * avgFontSize) {
+  } else if (maxGap - minGap < wordSp * avgFontSize) {
     return 0.5 * (minGap + maxGap);
 
   // if there is a large variation in spacing, use the SpGap/AdjGap
@@ -3901,12 +4820,12 @@
   } else {
     if (minAdjGap <= maxAdjGap &&
 	minSpGap <= maxSpGap &&
-	minSpGap - maxAdjGap > uniformSpacing * avgFontSize) {
-      gap = wordSpacing * avgFontSize;
+	minSpGap - maxAdjGap > uniformSp * avgFontSize) {
+      gap = wordSp * avgFontSize;
       gap2 = 0.5 * (minSpGap - minGap);
       return minGap + (gap < gap2 ? gap : gap2);
     } else {
-      return minGap + wordSpacing * avgFontSize;
+      return minGap + wordSp * avgFontSize;
     }
   }
 }
@@ -4069,16 +4988,10 @@
   GList *lines;
   int i;
 
-  if (blk->tag == blkTagLine) {
+  if (blk->tag == blkTagLine || blk->tag == blkTagSuperLine) {
     lines = new GList();
-    buildLines(blk, lines);
+    buildLines(blk, lines, gTrue);
     superLines->append(new TextSuperLine(lines));
-  } else if (blk->tag == blkTagSuperLine) {
-    lines = new GList();
-    for (i = 0; i < blk->children->getLength(); ++i) {
-      buildLines((TextBlock *)blk->children->get(i), lines);
-    }
-    superLines->append(new TextSuperLine(lines));
   } else {
     for (i = 0; i < blk->children->getLength(); ++i) {
       buildSuperLines((TextBlock *)blk->children->get(i), superLines);
@@ -4681,6 +5594,59 @@
   return gTrue;
 }
 
+GBool TextPage::findWordPoints(double x, double y,
+			       TextPosition *startPos, TextPosition *endPos) {
+  TextPosition pos;
+  TextColumn *col;
+  TextParagraph *par;
+  TextLine *line;
+  int startCharIdx, endCharIdx;
+
+  if (!findPointInside(x, y, &pos)) {
+    return gFalse;
+  }
+  col = (TextColumn *)findCols->get(pos.colIdx);
+  par = (TextParagraph *)col->getParagraphs()->get(pos.parIdx);
+  line = (TextLine *)par->getLines()->get(pos.lineIdx);
+
+  for (startCharIdx = pos.charIdx;
+       startCharIdx > 0 && line->text[startCharIdx - 1] != 0x20;
+       --startCharIdx) ;
+  *startPos = pos;
+  startPos->charIdx = startCharIdx;
+
+  for (endCharIdx = pos.charIdx;
+       endCharIdx < line->len && line->text[endCharIdx] != 0x20;
+       ++endCharIdx) ;
+  *endPos = pos;
+  endPos->charIdx = endCharIdx;
+
+  return gTrue;
+}
+
+GBool TextPage::findLinePoints(double x, double y,
+			       TextPosition *startPos, TextPosition *endPos) {
+  TextPosition pos;
+  TextColumn *col;
+  TextParagraph *par;
+  TextLine *line;
+
+  if (!findPointInside(x, y, &pos)) {
+    return gFalse;
+  }
+  col = (TextColumn *)findCols->get(pos.colIdx);
+  par = (TextParagraph *)col->getParagraphs()->get(pos.parIdx);
+  line = (TextLine *)par->getLines()->get(pos.lineIdx);
+
+  *startPos = pos;
+  startPos->charIdx = 0;
+
+  *endPos = pos;
+  endPos->charIdx = line->len;
+
+  return gTrue;
+}
+
 // Find the position in [col] corresponding to [x],[y].  The column,
 // [col], was found by findPointInside() or findPointNear().
 void TextPage::findPointInColumn(TextColumn *col, double x, double y,
@@ -4860,33 +5826,56 @@
   TextParagraph *par;
   TextLine *line;
   TextWord *word;
+  GList *overlappingChars;
   GList *words;
   GBool primaryLR;
   int rot, colIdx, parIdx, lineIdx, wordIdx;
 
 #if 0 //~debug
-  dumpCharList(charList);
+  dumpChars(charList);
 #endif
-  rot = rotateChars(charList);
-  primaryLR = checkPrimaryLR(charList);
-  tree = splitChars(charList);
+
+  if (control.mode == textOutSimple2Layout) {
+    rot = 0;
+    primaryLR = checkPrimaryLR(chars);
+    rotateCharsToZero(chars);
+    columns = buildSimple2Columns(chars);
+    unrotateCharsFromZero(chars);
+    unrotateColumnsFromZero(columns);
+
+  } else {
+    if (control.overlapHandling != textOutIgnoreOverlaps) {
+      overlappingChars = separateOverlappingText(chars);
+    } else {
+      overlappingChars = NULL;
+    }
+    rot = rotateChars(charList);
+    primaryLR = checkPrimaryLR(charList);
+    tree = splitChars(charList);
 #if 0 //~debug
-  dumpTree(tree);
+    dumpTree(tree);
 #endif
-  if (!tree) {
-    // no text
-    unrotateChars(charList, rot);
-    return new TextWordList(new GList(), gTrue);
-  }
-  columns = buildColumns(tree, primaryLR);
+    if (!tree) {
+      // no text
+      unrotateChars(charList, rot);
+      return new TextWordList(new GList(), gTrue);
+    }
+    columns = buildColumns(tree, primaryLR);
 #if 0 //~debug
-  dumpColumns(columns, gTrue);
+    dumpColumns(columns, gTrue);
 #endif
-  delete tree;
-  unrotateChars(charList, rot);
-  if (control.html) {
-    rotateUnderlinesAndLinks(rot);
-    generateUnderlinesAndLinks(columns);
+    delete tree;
+    unrotateChars(charList, rot);
+    if (control.html) {
+      rotateUnderlinesAndLinks(rot);
+      generateUnderlinesAndLinks(columns);
+    }
+    if (overlappingChars) {
+      if (overlappingChars->getLength() > 0) {
+	columns->append(buildOverlappingTextColumn(overlappingChars));
+      }
+      deleteGList(overlappingChars, TextChar);
+    }
   }
 
   words = new GList();
@@ -4897,8 +5886,12 @@
       for (lineIdx = 0; lineIdx < par->lines->getLength(); ++lineIdx) {
 	line = (TextLine *)par->lines->get(lineIdx);
 	for (wordIdx = 0; wordIdx < line->words->getLength(); ++wordIdx) {
-	  word = (TextWord *)line->words->get(wordIdx);
-	  words->append(word->copy());
+	  word = ((TextWord *)line->words->get(wordIdx))->copy();
+	  if (wordIdx == line->words->getLength() - 1 &&
+	      !line->getHyphenated()) {
+	    word->spaceAfter = gTrue;
+	  }
+	  words->append(word);
 	}
       }
     }
@@ -4906,6 +5899,7 @@
 
   switch (control.mode) {
   case textOutReadingOrder:
+  case textOutSimple2Layout:
     // already in reading order
     break;
   case textOutPhysLayout:
@@ -4958,7 +5952,8 @@
 	 tree->type == blkLeaf ? "leaf" :
 	                 tree->type == blkHorizSplit ? "horiz" : "vert",
 	 tree->tag == blkTagMulticolumn ? "multicolumn" :
-	                tree->tag == blkTagColumn ? "column" : "line",
+	                tree->tag == blkTagColumn ? "column" :
+                        tree->tag == blkTagSuperLine ? "superline" : "line",
 	 tree->smallSplit,
 	 tree->rot, tree->xMin, tree->yMin, tree->xMax, tree->yMax);
   if (tree->type == blkLeaf) {
@@ -5001,18 +5996,18 @@
 	    word = (TextWord *)line->words->get(wordIdx);
 	    printf("      word: xMin=%g yMin=%g xMax=%g yMax=%g\n",
 		   word->xMin, word->yMin, word->xMax, word->yMax);
-	    printf("            ");
+	    printf("            '");
 	    for (i = 0; i < word->len; ++i) {
 	      printf("%c", word->text[i] & 0xff);
 	    }
-	    printf("\n");
+	    printf("'\n");
 	  }
 	} else {
-	  printf("          ");
+	  printf("          '");
 	  for (i = 0; i < line->len; ++i) {
 	    printf("%c", line->text[i] & 0xff);
 	  }
-	  printf("\n");
+	  printf("'\n");
 	}
       }
     }
@@ -5041,7 +6036,7 @@
 }
 
 TextOutputDev::TextOutputDev(char *fileName, TextOutputControl *controlA,
-			     GBool append) {
+			     GBool append, GBool fileNameIsUTF8) {
   text = NULL;
   control = *controlA;
   ok = gTrue;
@@ -5055,15 +6050,22 @@
       // keep DOS from munging the end-of-line characters
       setmode(fileno(stdout), O_BINARY);
 #endif
-    } else if ((outputStream = fopen(fileName, append ? "ab" : "wb"))) {
+    } else {
+      if (fileNameIsUTF8) {
+	outputStream = openFile(fileName, append ? "ab" : "wb");
+      } else {
+	outputStream = fopen(fileName, append ? "ab" : "wb");
+      }
+      if (!outputStream) {
+	error(errIO, -1, "Couldn't open text file '{0:s}'", fileName);
+	ok = gFalse;
+	return;
+      }
       needClose = gTrue;
-    } else {
-      error(errIO, -1, "Couldn't open text file '{0:s}'", fileName);
-      ok = gFalse;
-      return;
     }
     outputFunc = &outputToFile;
   } else {
+    outputFunc = NULL;
     outputStream = NULL;
   }
 

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/TextOutputDev.h
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/TextOutputDev.h	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/TextOutputDev.h	2021-02-15 19:17:20 UTC (rev 845)
@@ -42,6 +42,7 @@
   textOutReadingOrder,		// format into reading order
   textOutPhysLayout,		// maintain original physical layout
   textOutSimpleLayout,		// simple one-column physical layout
+  textOutSimple2Layout,		// simple one-column physical layout
   textOutTableLayout,		// similar to PhysLayout, but optimized
 				//   for tables
   textOutLinePrinter,		// strict fixed-pitch/height layout
@@ -48,6 +49,12 @@
   textOutRawOrder		// keep text in content stream order
 };
 
+enum TextOutputOverlapHandling {
+  textOutIgnoreOverlaps,	// no special handling for overlaps
+  textOutAppendOverlaps,	// append overlapping text to main text
+  textOutDiscardOverlaps	// discard overlapping text
+};
+
 class TextOutputControl {
 public:
 
@@ -66,8 +73,17 @@
 				//   in after forming columns
   GBool discardDiagonalText;	// discard all text that's not close to
 				//   0/90/180/270 degrees
+  GBool discardRotatedText;	// discard all text that's not horizontal
+				//   (0 degrees)
   GBool discardInvisibleText;	// discard all invisible characters
   GBool discardClippedText;	// discard all clipped characters
+  GBool splitRotatedWords;	// do not combine horizontal and
+				//   non-horizontal chars in a single
+				//   word
+  TextOutputOverlapHandling	// how to handle overlapping text
+               overlapHandling;
+  GBool separateLargeChars;	// separate "large" characters from
+				//   "regular" characters
   GBool insertBOM;		// insert a Unicode BOM at the start of
 				//   the text output
   double marginLeft,		// characters outside the margins are
@@ -124,7 +140,7 @@
 public:
 
   TextWord(GList *chars, int start, int lenA,
-	   int rotA, int dirA, GBool spaceAfterA);
+	   int rotA, GBool rotatedA, int dirA, GBool spaceAfterA);
   ~TextWord();
   TextWord *copy() { return new TextWord(this); }
 
@@ -144,6 +160,7 @@
 		   double *xMaxA, double *yMaxA);
   double getFontSize() { return fontSize; }
   int getRotation() { return rot; }
+  GBool isRotated() { return (GBool)rotated; }
   int getCharPos() { return charPos[0]; }
   int getCharLen() { return charPos[len] - charPos[0]; }
   int getDirection() { return dir; }
@@ -158,8 +175,6 @@
   static int cmpYX(const void *p1, const void *p2);
   static int cmpCharPos(const void *p1, const void *p2);
 
-  int rot;			// rotation, multiple of 90 degrees
-				//   (0, 1, 2, or 3)
   double xMin, xMax;		// bounding box x coordinates
   double yMin, yMax;		// bounding box y coordinates
   Unicode *text;		// the text
@@ -171,19 +186,22 @@
   int len;			// number of characters
   TextFontInfo *font;		// font information
   double fontSize;		// font size
-  int dir;			// character direction (+1 = left-to-right;
-				//   -1 = right-to-left; 0 = neither)
-  GBool spaceAfter;		// set if there is a space between this
-				//   word and the next word on the line
-
-  GBool underlined;
   TextLink *link;
-
   double colorR,		// word color
          colorG,
          colorB;
   GBool invisible;		// set for invisible text (render mode 3)
 
+  // group the byte-size fields to minimize object size
+  Guchar rot;			// rotation, multiple of 90 degrees
+				//   (0, 1, 2, or 3)
+  char rotated;			// set if this word is non-horizontal
+  char dir;			// character direction (+1 = left-to-right;
+				//   -1 = right-to-left; 0 = neither)
+  char spaceAfter;		// set if there is a space between this
+				//   word and the next word on the line
+  char underlined;
+
   friend class TextBlock;
   friend class TextLine;
   friend class TextPage;
@@ -209,6 +227,7 @@
   GList *getWords() { return words; }
   int getLength() { return len; }
   double getEdge(int idx) { return edge[idx]; }
+  GBool getHyphenated() { return hyphenated; }
 
 private:
 
@@ -407,6 +426,16 @@
   // are no columns.
   GBool findPointNear(double x, double y, TextPosition *pos);
 
+  // Find the start and end of a word inside a column.  Returns false
+  // if x,y fall outside all columns.
+  GBool findWordPoints(double x, double y,
+		       TextPosition *startPos, TextPosition *endPos);
+
+  // Find the start and end of a line inside a column.  Returns false
+  // if x,y fall outside all columns.
+  GBool findLinePoints(double x, double y,
+		       TextPosition *startPos, TextPosition *endPos);
+
   // Get the upper point of a TextPosition.
   void convertPosToPointUpper(TextPosition *pos, double *x, double *y);
 
@@ -478,6 +507,11 @@
 			 UnicodeMap *uMap,
 			 char *space, int spaceLen,
 			 char *eol, int eolLen);
+  void writeSimple2Layout(void *outputStream,
+			  TextOutputFunc outputFunc,
+			  UnicodeMap *uMap,
+			  char *space, int spaceLen,
+			  char *eol, int eolLen);
   void writeLinePrinter(void *outputStream,
 			TextOutputFunc outputFunc,
 			UnicodeMap *uMap,
@@ -493,12 +527,17 @@
 
   // analysis
   int rotateChars(GList *charsA);
+  void rotateCharsToZero(GList *charsA);
   void rotateUnderlinesAndLinks(int rot);
   void unrotateChars(GList *charsA, int rot);
+  void unrotateCharsFromZero(GList *charsA);
+  void unrotateColumnsFromZero(GList *columns);
   void unrotateColumns(GList *columns, int rot);
   void unrotateWords(GList *words, int rot);
   GBool checkPrimaryLR(GList *charsA);
   void removeDuplicates(GList *charsA, int rot);
+  GList *separateOverlappingText(GList *charsA);
+  TextColumn *buildOverlappingTextColumn(GList *overlappingChars);
   TextBlock *splitChars(GList *charsA);
   TextBlock *split(GList *charsA, int rot);
   GList *getChars(GList *charsA, double xMin, double yMin,
@@ -522,8 +561,12 @@
   double getLineIndent(TextLine *line, TextBlock *blk);
   double getAverageLineSpacing(GList *lines);
   double getLineSpacing(TextLine *line0, TextLine *line1);
-  void buildLines(TextBlock *blk, GList *lines);
+  void buildLines(TextBlock *blk, GList *lines, GBool splitSuperLines);
+  GList *buildSimple2Columns(GList *charsA);
+  GList *buildSimple2Lines(GList *charsA, int rot);
   TextLine *buildLine(TextBlock *blk);
+  TextLine *buildLine(GList *charsA, int rot,
+		      double xMin, double yMin, double xMax, double yMax);
   void getLineChars(TextBlock *blk, GList *charsA);
   double computeWordSpacingThreshold(GList *charsA, int rot);
   int getCharDirection(TextChar *ch);
@@ -563,6 +606,7 @@
   int curRot;			// current rotation
   GBool diagonal;		// set if rotation is not close to
 				//   0/90/180/270 degrees
+  GBool rotated;		// set if text is not horizontal (0 degrees)
   int nTinyChars;		// number of "tiny" chars seen so far
   Unicode *actualText;		// current "ActualText" span
   int actualTextLen;
@@ -605,7 +649,7 @@
   // is maintained.  If <rawOrder> is true, the text is kept in
   // content stream order.
   TextOutputDev(char *fileName, TextOutputControl *controlA,
-		GBool append);
+		GBool append, GBool fileNameIsUTF8 = gFalse);
 
   // Create a TextOutputDev which will write to a generic stream.  If
   // <physLayoutA> is true, the original physical layout of the text

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/TextString.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/TextString.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/TextString.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -201,3 +201,13 @@
   }
   return s;
 }
+
+GString *TextString::toUTF8() {
+  GString *s = new GString();
+  for (int i = 0; i < len; ++i) {
+    char buf[8];
+    int n = mapUTF8(u[i], buf, sizeof(buf));
+    s->append(buf, n);
+  }
+  return s;
+}

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/TextString.h
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/TextString.h	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/TextString.h	2021-02-15 19:17:20 UTC (rev 845)
@@ -56,6 +56,9 @@
   // Create a PDF text string from a TextString.
   GString *toPDFTextString();
 
+  // Convert a TextString to UTF-8.
+  GString *toUTF8();
+
 private:
 
   void expand(int delta);

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/WebFont.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/WebFont.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/WebFont.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -22,6 +22,7 @@
 
 WebFont::WebFont(GfxFont *gfxFontA, XRef *xref) {
   GfxFontType type;
+  Ref id;
 
   gfxFont = gfxFontA;
   fontBuf = NULL;
@@ -29,24 +30,26 @@
   ffType1C = NULL;
   isOpenType = gFalse;
 
-  type = gfxFont->getType();
-  if (type == fontTrueType ||
-      type == fontTrueTypeOT ||
-      type == fontCIDType2 ||
-      type == fontCIDType2OT) {
-    if ((fontBuf = gfxFont->readEmbFontFile(xref, &fontLength))) {
-      ffTrueType = FoFiTrueType::make(fontBuf, fontLength, 0);
+  if (gfxFont->getEmbeddedFontID(&id)) {
+    type = gfxFont->getType();
+    if (type == fontTrueType ||
+	type == fontTrueTypeOT ||
+	type == fontCIDType2 ||
+	type == fontCIDType2OT) {
+      if ((fontBuf = gfxFont->readEmbFontFile(xref, &fontLength))) {
+	ffTrueType = FoFiTrueType::make(fontBuf, fontLength, 0);
+      }
+    } else if (type == fontType1C ||
+	       type == fontCIDType0C) {
+      if ((fontBuf = gfxFont->readEmbFontFile(xref, &fontLength))) {
+	ffType1C = FoFiType1C::make(fontBuf, fontLength);
+      }
+    } else if (type == fontType1COT ||
+	       type == fontCIDType0COT) {
+      if ((fontBuf = gfxFont->readEmbFontFile(xref, &fontLength))) {
+	isOpenType = gTrue;
+      }
     }
-  } else if (type == fontType1C ||
-	     type == fontCIDType0C) {
-    if ((fontBuf = gfxFont->readEmbFontFile(xref, &fontLength))) {
-      ffType1C = FoFiType1C::make(fontBuf, fontLength);
-    }
-  } else if (type == fontType1COT ||
-	     type == fontCIDType0COT) {
-    if ((fontBuf = gfxFont->readEmbFontFile(xref, &fontLength))) {
-      isOpenType = gTrue;
-    }
   }
 }
 

Deleted: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/XFAForm.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/XFAForm.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/XFAForm.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,3245 +0,0 @@
-//========================================================================
-//
-// XFAForm.cc
-//
-// Copyright 2012 Glyph & Cog, LLC
-//
-//========================================================================
-
-#include <aconf.h>
-
-#ifdef USE_GCC_PRAGMAS
-#pragma implementation
-#endif
-
-#include <stdlib.h>
-#include "gmem.h"
-#include "gmempp.h"
-#include "GString.h"
-#include "GList.h"
-#include "GHash.h"
-#include "Error.h"
-#include "Object.h"
-#include "PDFDoc.h"
-#include "Gfx.h"
-#include "GfxFont.h"
-#include "Zoox.h"
-#include "PDF417Barcode.h"
-#include "UTF8.h"
-#include "XFAForm.h"
-
-#ifdef _WIN32
-#  undef strcasecmp
-#  undef strncasecmp
-#  define strcasecmp _stricmp
-#  define strncasecmp _strnicmp
-#endif
-
-//------------------------------------------------------------------------
-
-// 5 bars + 5 spaces -- each can be wide (1) or narrow (0)
-// (there are always exactly 3 wide elements;
-// the last space is always narrow)
-static Guchar code3Of9Data[128][10] = {
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // 0x00
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // 0x10
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 1, 1, 0, 0, 0, 1, 0, 0, 0 }, // ' ' = 0x20
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 1, 0, 1, 0, 1, 0, 0, 0, 0 }, // '$' = 0x24
-  { 0, 0, 0, 1, 0, 1, 0, 1, 0, 0 }, // '%' = 0x25
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 1, 0, 0, 1, 0, 1, 0, 0, 0 }, // '*' = 0x2a
-  { 0, 1, 0, 0, 0, 1, 0, 1, 0, 0 }, // '+' = 0x2b
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 1, 0, 0, 0, 0, 1, 0, 1, 0 }, // '-' = 0x2d
-  { 1, 1, 0, 0, 0, 0, 1, 0, 0, 0 }, // '.' = 0x2e
-  { 0, 1, 0, 1, 0, 0, 0, 1, 0, 0 }, // '/' = 0x2f
-  { 0, 0, 0, 1, 1, 0, 1, 0, 0, 0 }, // '0' = 0x30
-  { 1, 0, 0, 1, 0, 0, 0, 0, 1, 0 }, // '1'
-  { 0, 0, 1, 1, 0, 0, 0, 0, 1, 0 }, // '2'
-  { 1, 0, 1, 1, 0, 0, 0, 0, 0, 0 }, // '3'
-  { 0, 0, 0, 1, 1, 0, 0, 0, 1, 0 }, // '4'
-  { 1, 0, 0, 1, 1, 0, 0, 0, 0, 0 }, // '5'
-  { 0, 0, 1, 1, 1, 0, 0, 0, 0, 0 }, // '6'
-  { 0, 0, 0, 1, 0, 0, 1, 0, 1, 0 }, // '7'
-  { 1, 0, 0, 1, 0, 0, 1, 0, 0, 0 }, // '8'
-  { 0, 0, 1, 1, 0, 0, 1, 0, 0, 0 }, // '9'
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // 0x40
-  { 1, 0, 0, 0, 0, 1, 0, 0, 1, 0 }, // 'A' = 0x41
-  { 0, 0, 1, 0, 0, 1, 0, 0, 1, 0 }, // 'B'
-  { 1, 0, 1, 0, 0, 1, 0, 0, 0, 0 }, // 'C'
-  { 0, 0, 0, 0, 1, 1, 0, 0, 1, 0 }, // 'D'
-  { 1, 0, 0, 0, 1, 1, 0, 0, 0, 0 }, // 'E'
-  { 0, 0, 1, 0, 1, 1, 0, 0, 0, 0 }, // 'F'
-  { 0, 0, 0, 0, 0, 1, 1, 0, 1, 0 }, // 'G'
-  { 1, 0, 0, 0, 0, 1, 1, 0, 0, 0 }, // 'H'
-  { 0, 0, 1, 0, 0, 1, 1, 0, 0, 0 }, // 'I'
-  { 0, 0, 0, 0, 1, 1, 1, 0, 0, 0 }, // 'J'
-  { 1, 0, 0, 0, 0, 0, 0, 1, 1, 0 }, // 'K'
-  { 0, 0, 1, 0, 0, 0, 0, 1, 1, 0 }, // 'L'
-  { 1, 0, 1, 0, 0, 0, 0, 1, 0, 0 }, // 'M'
-  { 0, 0, 0, 0, 1, 0, 0, 1, 1, 0 }, // 'N'
-  { 1, 0, 0, 0, 1, 0, 0, 1, 0, 0 }, // 'O'
-  { 0, 0, 1, 0, 1, 0, 0, 1, 0, 0 }, // 'P' = 0x50
-  { 0, 0, 0, 0, 0, 0, 1, 1, 1, 0 }, // 'Q'
-  { 1, 0, 0, 0, 0, 0, 1, 1, 0, 0 }, // 'R'
-  { 0, 0, 1, 0, 0, 0, 1, 1, 0, 0 }, // 'S'
-  { 0, 0, 0, 0, 1, 0, 1, 1, 0, 0 }, // 'T'
-  { 1, 1, 0, 0, 0, 0, 0, 0, 1, 0 }, // 'U'
-  { 0, 1, 1, 0, 0, 0, 0, 0, 1, 0 }, // 'V'
-  { 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 }, // 'W'
-  { 0, 1, 0, 0, 1, 0, 0, 0, 1, 0 }, // 'X'
-  { 1, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, // 'Y'
-  { 0, 1, 1, 0, 1, 0, 0, 0, 0, 0 }, // 'Z'
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // 0x60
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // 0x70
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
-};
-
-// 3 bars + 3 spaces -- each can be 1, 2, 3, or 4 units wide
-static Guchar code128Data[107][6] = {
-  { 2, 1, 2, 2, 2, 2 },
-  { 2, 2, 2, 1, 2, 2 },
-  { 2, 2, 2, 2, 2, 1 },
-  { 1, 2, 1, 2, 2, 3 },
-  { 1, 2, 1, 3, 2, 2 },
-  { 1, 3, 1, 2, 2, 2 },
-  { 1, 2, 2, 2, 1, 3 },
-  { 1, 2, 2, 3, 1, 2 },
-  { 1, 3, 2, 2, 1, 2 },
-  { 2, 2, 1, 2, 1, 3 },
-  { 2, 2, 1, 3, 1, 2 },
-  { 2, 3, 1, 2, 1, 2 },
-  { 1, 1, 2, 2, 3, 2 },
-  { 1, 2, 2, 1, 3, 2 },
-  { 1, 2, 2, 2, 3, 1 },
-  { 1, 1, 3, 2, 2, 2 },
-  { 1, 2, 3, 1, 2, 2 },
-  { 1, 2, 3, 2, 2, 1 },
-  { 2, 2, 3, 2, 1, 1 },
-  { 2, 2, 1, 1, 3, 2 },
-  { 2, 2, 1, 2, 3, 1 },
-  { 2, 1, 3, 2, 1, 2 },
-  { 2, 2, 3, 1, 1, 2 },
-  { 3, 1, 2, 1, 3, 1 },
-  { 3, 1, 1, 2, 2, 2 },
-  { 3, 2, 1, 1, 2, 2 },
-  { 3, 2, 1, 2, 2, 1 },
-  { 3, 1, 2, 2, 1, 2 },
-  { 3, 2, 2, 1, 1, 2 },
-  { 3, 2, 2, 2, 1, 1 },
-  { 2, 1, 2, 1, 2, 3 },
-  { 2, 1, 2, 3, 2, 1 },
-  { 2, 3, 2, 1, 2, 1 },
-  { 1, 1, 1, 3, 2, 3 },
-  { 1, 3, 1, 1, 2, 3 },
-  { 1, 3, 1, 3, 2, 1 },
-  { 1, 1, 2, 3, 1, 3 },
-  { 1, 3, 2, 1, 1, 3 },
-  { 1, 3, 2, 3, 1, 1 },
-  { 2, 1, 1, 3, 1, 3 },
-  { 2, 3, 1, 1, 1, 3 },
-  { 2, 3, 1, 3, 1, 1 },
-  { 1, 1, 2, 1, 3, 3 },
-  { 1, 1, 2, 3, 3, 1 },
-  { 1, 3, 2, 1, 3, 1 },
-  { 1, 1, 3, 1, 2, 3 },
-  { 1, 1, 3, 3, 2, 1 },
-  { 1, 3, 3, 1, 2, 1 },
-  { 3, 1, 3, 1, 2, 1 },
-  { 2, 1, 1, 3, 3, 1 },
-  { 2, 3, 1, 1, 3, 1 },
-  { 2, 1, 3, 1, 1, 3 },
-  { 2, 1, 3, 3, 1, 1 },
-  { 2, 1, 3, 1, 3, 1 },
-  { 3, 1, 1, 1, 2, 3 },
-  { 3, 1, 1, 3, 2, 1 },
-  { 3, 3, 1, 1, 2, 1 },
-  { 3, 1, 2, 1, 1, 3 },
-  { 3, 1, 2, 3, 1, 1 },
-  { 3, 3, 2, 1, 1, 1 },
-  { 3, 1, 4, 1, 1, 1 },
-  { 2, 2, 1, 4, 1, 1 },
-  { 4, 3, 1, 1, 1, 1 },
-  { 1, 1, 1, 2, 2, 4 },
-  { 1, 1, 1, 4, 2, 2 },
-  { 1, 2, 1, 1, 2, 4 },
-  { 1, 2, 1, 4, 2, 1 },
-  { 1, 4, 1, 1, 2, 2 },
-  { 1, 4, 1, 2, 2, 1 },
-  { 1, 1, 2, 2, 1, 4 },
-  { 1, 1, 2, 4, 1, 2 },
-  { 1, 2, 2, 1, 1, 4 },
-  { 1, 2, 2, 4, 1, 1 },
-  { 1, 4, 2, 1, 1, 2 },
-  { 1, 4, 2, 2, 1, 1 },
-  { 2, 4, 1, 2, 1, 1 },
-  { 2, 2, 1, 1, 1, 4 },
-  { 4, 1, 3, 1, 1, 1 },
-  { 2, 4, 1, 1, 1, 2 },
-  { 1, 3, 4, 1, 1, 1 },
-  { 1, 1, 1, 2, 4, 2 },
-  { 1, 2, 1, 1, 4, 2 },
-  { 1, 2, 1, 2, 4, 1 },
-  { 1, 1, 4, 2, 1, 2 },
-  { 1, 2, 4, 1, 1, 2 },
-  { 1, 2, 4, 2, 1, 1 },
-  { 4, 1, 1, 2, 1, 2 },
-  { 4, 2, 1, 1, 1, 2 },
-  { 4, 2, 1, 2, 1, 1 },
-  { 2, 1, 2, 1, 4, 1 },
-  { 2, 1, 4, 1, 2, 1 },
-  { 4, 1, 2, 1, 2, 1 },
-  { 1, 1, 1, 1, 4, 3 },
-  { 1, 1, 1, 3, 4, 1 },
-  { 1, 3, 1, 1, 4, 1 },
-  { 1, 1, 4, 1, 1, 3 },
-  { 1, 1, 4, 3, 1, 1 },
-  { 4, 1, 1, 1, 1, 3 },
-  { 4, 1, 1, 3, 1, 1 },
-  { 1, 1, 3, 1, 4, 1 },
-  { 1, 1, 4, 1, 3, 1 },
-  { 3, 1, 1, 1, 4, 1 },
-  { 4, 1, 1, 1, 3, 1 },
-  { 2, 1, 1, 4, 1, 2 }, // start code A
-  { 2, 1, 1, 2, 1, 4 }, // start code B
-  { 2, 1, 1, 2, 3, 2 }, // start code C
-  { 2, 3, 3, 1, 1, 1 }  // stop code (without final bar)
-};
-
-//------------------------------------------------------------------------
-
-class XFATableInfo {
-public:
-
-  XFATableInfo(ZxAttr *columnWidthsAttr);
-  ~XFATableInfo();
-  void computeRowHeight(ZxElement *rowSubform);
-
-  int nColumns;			// number of columns
-  double *columnRight;		// right edge (x coord) of each column
-  int rowIdx;			// current row index
-  int columnIdx;		// current column index
-  double rowTop;		// top edge (y coord) of current row
-  double rowHeight;		// height of current row (max cell height
-				//   so far)
-};
-
-XFATableInfo::XFATableInfo(ZxAttr *columnWidthsAttr) {
-  GString *s;
-  double w;
-  int i, columnRightSize;
-
-  nColumns = 0;
-  columnRight = NULL;
-  columnRightSize = 0;
-  if (columnWidthsAttr) {
-    s = columnWidthsAttr->getValue();
-    i = 0;
-    while (1) {
-      for (;
-	   i < s->getLength() &&
-	     (s->getChar(i) == ' ' || s->getChar(i) == '\t' ||
-	      s->getChar(i) == '\r' || s->getChar(i) == '\n');
-	   ++i) ;
-      if (i == s->getLength()) {
-	break;
-      }
-      w = XFAFormField::getMeasurement(s, i);
-      if (nColumns == columnRightSize) {
-	columnRightSize = columnRightSize ? 2 * columnRightSize : 8;
-	columnRight = (double *)greallocn(columnRight, columnRightSize,
-					  sizeof(double));
-      }
-      columnRight[nColumns] = (nColumns > 0 ? columnRight[nColumns - 1] : 0) + w;
-      ++nColumns;
-      for (++i;
-	   i < s->getLength() &&
-	     !(s->getChar(i) == ' ' || s->getChar(i) == '\t' ||
-	       s->getChar(i) == '\r' || s->getChar(i) == '\n');
-	   ++i) ;
-    }
-  }
-  rowIdx = -1;
-  columnIdx = 0;
-  rowTop = rowHeight = 0;
-}
-
-XFATableInfo::~XFATableInfo() {
-  gfree(columnRight);
-}
-
-void XFATableInfo::computeRowHeight(ZxElement *rowSubform) {
-  ZxNode *child;
-  ZxAttr *attr;
-  double h;
-
-  rowHeight = 0;
-  for (child = rowSubform->getFirstChild();
-       child;
-       child = child->getNextChild()) {
-    if (child->isElement("field") || child->isElement("draw")) {
-      if (!(attr = ((ZxElement *)child)->findAttr("h"))) {
-	attr = ((ZxElement *)child)->findAttr("minH");
-      }
-      h = XFAFormField::getMeasurement(attr,  0);
-      if (h > rowHeight) {
-	rowHeight = h;
-      }
-    }
-  }
-}
-
-//------------------------------------------------------------------------
-// XFAForm
-//------------------------------------------------------------------------
-
-XFAForm *XFAForm::load(PDFDoc *docA, Catalog *catalog,
-		       Object *acroFormObj, Object *xfaObj) {
-  XFAForm *xfaForm;
-  XFAFormField *field;
-  ZxDoc *xmlA;
-  ZxElement *tmpl;
-  Object catDict, resourceDictA, obj1;
-  GString *data;
-  GBool fullXFAA;
-  GString *name, *fullName;
-  GHash *nameCount, *nameIdx, *fullNameCount, *fullNameIdx;
-  char buf[4096];
-  int n, i;
-
-  if (catalog->getNumPages() == 0) {
-    return NULL;
-  }
-
-  docA->getXRef()->getCatalog(&catDict);
-  catDict.dictLookup("NeedsRendering", &obj1);
-  fullXFAA = obj1.isBool() && obj1.getBool();
-  obj1.free();
-  catDict.free();
-
-  if (xfaObj->isStream()) {
-    data = new GString();
-    xfaObj->streamReset();
-    while ((n = xfaObj->getStream()->getBlock(buf, sizeof(buf))) > 0) {
-      data->append(buf, n);
-    }
-  } else if (xfaObj->isArray()) {
-    data = new GString();
-    for (i = 1; i < xfaObj->arrayGetLength(); i += 2) {
-      if (!xfaObj->arrayGet(i, &obj1)->isStream()) {
-	error(errSyntaxError, -1, "XFA array element is wrong type");
-	obj1.free();
-	delete data;
-	return NULL;
-      }
-      obj1.streamReset();
-      while ((n = obj1.getStream()->getBlock(buf, sizeof(buf))) > 0) {
-	data->append(buf, n);
-      }
-      obj1.free();
-    }
-  } else {
-    error(errSyntaxError, -1, "XFA object is wrong type");
-    return NULL;
-  }
-
-  xmlA = ZxDoc::loadMem(data->getCString(), data->getLength());
-  delete data;
-  if (!xmlA) {
-    error(errSyntaxError, -1, "Invalid XML in XFA form");
-    return NULL;
-  }
-
-  if (acroFormObj->isDict()) {
-    acroFormObj->dictLookup("DR", &resourceDictA);
-  }
-
-  xfaForm = new XFAForm(docA, catalog->getNumPages(),
-			xmlA, &resourceDictA, fullXFAA);
-
-  resourceDictA.free();
-
-  if (xfaForm->xml->getRoot()) {
-    if ((tmpl = xfaForm->xml->getRoot()->findFirstChildElement("template"))) {
-      xfaForm->curPageNum = 0;
-      xfaForm->curXOffset = xfaForm->curYOffset = 0;
-      name = new GString();
-      fullName = new GString();
-      nameCount = new GHash();
-      nameIdx = new GHash();
-      fullNameCount = new GHash();
-      fullNameIdx = new GHash();
-      xfaForm->scanNode(tmpl, name, fullName, gFalse, NULL,
-			nameCount, nameIdx, fullNameCount, fullNameIdx,
-			NULL, catalog);
-      delete nameCount;
-      delete nameIdx;
-      delete fullNameCount;
-      delete fullNameIdx;
-      delete name;
-      delete fullName;
-
-      // apply pageOffsetX/Y (the pageSet/pageArea/contentArea offset)
-      // to all fields
-      if (xfaForm->pageSetNPages >= 1 &&
-	  xfaForm->pageSetNPages < xfaForm->nPages) {
-	for (i = xfaForm->pageSetNPages + 1; i <= xfaForm->nPages; ++i) {
-	  xfaForm->pageOffsetX[i - 1] =
-	      xfaForm->pageOffsetX[xfaForm->pageSetNPages - 1];
-	  xfaForm->pageOffsetY[i - 1] =
-	      xfaForm->pageOffsetY[xfaForm->pageSetNPages - 1];
-	}
-      }
-      for (i = 0; i < xfaForm->fields->getLength(); ++i) {
-	field = (XFAFormField *)xfaForm->fields->get(i);
-	if (field->pageNum >= 1 && field->pageNum <= xfaForm->nPages) {
-	  field->xOffset += xfaForm->pageOffsetX[field->pageNum - 1];
-	  field->yOffset += xfaForm->pageOffsetY[field->pageNum - 1];
-	}
-      }
-    }
-  }
-
-  return xfaForm;
-}
-
-XFAForm::XFAForm(PDFDoc *docA, int nPagesA, ZxDoc *xmlA,
-		 Object *resourceDictA, GBool fullXFAA):
-  Form(docA) {
-  int pg;
-
-  xml = xmlA;
-  fields = new GList();
-  resourceDictA->copy(&resourceDict);
-  fullXFA = fullXFAA;
-  nPages = nPagesA;
-  pageSetNPages = 0;
-  pageOffsetX = (double *)gmallocn(nPages, sizeof(double));
-  pageOffsetY = (double *)gmallocn(nPages, sizeof(double));
-  for (pg = 0; pg < nPages; ++pg) {
-    pageOffsetX[pg] = pageOffsetY[pg] = 0;
-  }
-}
-
-XFAForm::~XFAForm() {
-  delete xml;
-  deleteGList(fields, XFAFormField);
-  resourceDict.free();
-  gfree(pageOffsetX);
-  gfree(pageOffsetY);
-}
-
-// Scan <elem>.  Constructs the node's name and full name.  If <elem>
-// is a field, creates an XFAFormField; else scans <elem>'s children.
-void XFAForm::scanNode(ZxElement *elem,
-		       GString *parentName, GString *parentFullName,
-		       GBool inPageSet, XFATableInfo *tableInfo,
-		       GHash *nameCount, GHash *nameIdx,
-		       GHash *fullNameCount, GHash *fullNameIdx,
-		       GString *exclGroupName, Catalog *catalog) {
-  ZxAttr *attr;
-  GString *name, *fullName, *namePart, *fullNamePart;
-  GHash *childNameCount, *childNameIdx, *childFullNameCount, *childFullNameIdx;
-  int colSpan, i;
-
-  if (elem->isElement("template")) {
-    name = new GString("form");
-    fullName = new GString("form");
-    childNameCount = new GHash();
-    scanNames(elem, childNameCount);
-    childNameIdx = new GHash();
-    childFullNameCount = new GHash();
-    scanFullNames(elem, childFullNameCount);
-    childFullNameIdx = new GHash();
-  } else {
-    if ((namePart = getNodeName(elem))) {
-      name = GString::format("{0:t}.{1:t}", parentName, namePart);
-      if (nameCount->lookupInt(namePart) > 1) {
-	i = nameIdx->lookupInt(namePart);
-	name->appendf("[{0:d}]", i);
-	nameIdx->replace(namePart, i + 1);
-      }
-      childNameCount = new GHash();
-      scanNames(elem, childNameCount);
-      childNameIdx = new GHash();
-    } else {
-      name = parentName->copy();
-      childNameCount = nameCount;
-      childNameIdx = nameIdx;
-    }
-    if ((fullNamePart = getNodeFullName(elem))) {
-      fullName = GString::format("{0:t}.{1:t}", parentFullName, fullNamePart);
-      if (fullNameCount->lookupInt(fullNamePart) > 1) {
-	i = fullNameIdx->lookupInt(fullNamePart);
-	fullName->appendf("[{0:d}]", i);
-	fullNameIdx->replace(fullNamePart, i + 1);
-      }
-      childFullNameCount = new GHash();
-      scanFullNames(elem, childFullNameCount);
-      childFullNameIdx = new GHash();
-    } else {
-      fullName = parentFullName->copy();
-      childFullNameCount = fullNameCount;
-      childFullNameIdx = fullNameIdx;
-    }
-  }
-
-  if (tableInfo && (elem->isElement("field") || elem->isElement("draw"))) {
-    if ((attr = elem->findAttr("colSpan"))) {
-      colSpan = atoi(attr->getValue()->getCString());
-    } else {
-      colSpan = 1;
-    }
-  } else {
-    colSpan = 0;
-  }
-
-  if (elem->isElement("field")) {
-    scanField(elem, name, fullName, exclGroupName,
-	      inPageSet, tableInfo, colSpan, catalog);
-  } else {
-    scanNonField(elem, name, fullName, inPageSet, tableInfo, colSpan,
-		 childNameCount, childNameIdx,
-		 childFullNameCount, childFullNameIdx,
-		 catalog);
-  }
-
-  if (tableInfo) {
-    tableInfo->columnIdx += colSpan;
-  }
-
-  delete name;
-  delete fullName;
-  if (childNameCount != nameCount) {
-    delete childNameCount;
-  }
-  if (childNameIdx != nameIdx) {
-    delete childNameIdx;
-  }
-  if (childFullNameCount != fullNameCount) {
-    delete childFullNameCount;
-  }
-  if (childFullNameIdx != fullNameIdx) {
-    delete childFullNameIdx;
-  }
-}
-
-// Traverse all children of <elem>, incrementing nameCount[name] for
-// each named child.  Traversal stops at each named child.
-void XFAForm::scanNames(ZxElement *elem, GHash *nameCount) {
-  ZxNode *node;
-  ZxElement *child;
-  GString *namePart;
-
-  for (node = elem->getFirstChild(); node; node = node->getNextChild()) {
-    if (node->isElement()) {
-      child = (ZxElement *)node;
-      if ((namePart = getNodeName(child))) {
-	if (nodeIsBindGlobal(child)) {
-	  nameCount->replace(namePart, 1);
-	} else {
-	  nameCount->replace(namePart, nameCount->lookupInt(namePart) + 1);
-	}
-      } else {
-	scanNames(child, nameCount);
-      }
-    }
-  }
-}
-
-// Traverse all children of <elem>, incrementing fullNameCount[name]
-// for each full-named child.  Traversal stops at each full-named
-// child.
-void XFAForm::scanFullNames(ZxElement *elem, GHash *fullNameCount) {
-  ZxNode *node;
-  ZxElement *child;
-  GString *fullNamePart;
-
-  for (node = elem->getFirstChild(); node; node = node->getNextChild()) {
-    if (node->isElement()) {
-      child = (ZxElement *)node;
-      if ((fullNamePart = getNodeFullName(child))) {
-	if (nodeIsBindGlobal(child)) {
-	  fullNameCount->replace(fullNamePart, 1);
-	} else {
-	  fullNameCount->replace(fullNamePart,
-				 fullNameCount->lookupInt(fullNamePart) + 1);
-	}
-      } else {
-	scanFullNames(child, fullNameCount);
-      }
-    }
-  }
-}
-
-void XFAForm::scanField(ZxElement *elem, GString *name, GString *fullName,
-			GString *exclGroupName, GBool inPageSet,
-			XFATableInfo *tableInfo, int colSpan,
-			Catalog *catalog) {
-  double xSubOffset, ySubOffset, columnWidth, rowHeight;
-
-  if (curPageNum == 0) {
-    curPageNum = 1;
-  }
-
-  xSubOffset = ySubOffset = 0;
-  columnWidth = rowHeight = 0;
-  if (tableInfo) {
-    if (tableInfo->columnIdx > 0 &&
-	tableInfo->columnIdx <= tableInfo->nColumns) {
-      xSubOffset = tableInfo->columnRight[tableInfo->columnIdx - 1];
-    }
-    if (tableInfo->columnIdx + colSpan <= tableInfo->nColumns) {
-      columnWidth = tableInfo->columnRight[tableInfo->columnIdx + colSpan - 1]
-	            - xSubOffset;
-    }
-    ySubOffset = tableInfo->rowTop;
-    rowHeight = tableInfo->rowHeight;
-    curXOffset += xSubOffset;
-    curYOffset += ySubOffset;
-  }
-
-  fields->append(new XFAFormField(this, elem, name->copy(), fullName->copy(),
-				  exclGroupName ? exclGroupName->copy()
-				                : (GString *)NULL,
-				  curPageNum, curXOffset, curYOffset,
-				  columnWidth, rowHeight));
-
-  if (tableInfo) {
-    curXOffset -= xSubOffset;
-    curYOffset -= ySubOffset;
-  }
-}
-
-void XFAForm::scanNonField(ZxElement *elem, GString *name, GString *fullName,
-			   GBool inPageSet,
-			   XFATableInfo *tableInfo, int colSpan,
-			   GHash *nameCount, GHash *nameIdx,
-			   GHash *fullNameCount, GHash *fullNameIdx,
-			   Catalog *catalog) {
-  XFATableInfo *newTableInfo;
-  ZxElement *brk, *contentArea;
-  ZxNode *child;
-  ZxAttr *attr;
-  PDFRectangle *box;
-  GString *exclGroupName;
-  double xSubOffset, ySubOffset;
-  int savedPageNum;
-
-  newTableInfo = tableInfo;
-
-  if (elem->isElement("subform")) {
-
-    // update page number
-    if (((brk = elem->findFirstChildElement("breakBefore")) &&
-	 (attr = brk->findAttr("targetType")) &&
-	 !attr->getValue()->cmp("pageArea")) ||
-	((brk = elem->findFirstChildElement("break")) &&
-	 (attr = brk->findAttr("before")) &&
-	 !attr->getValue()->cmp("pageArea")) ||
-	(curPageNum < nPages &&
-	 (attr = elem->findAttr("w")) &&
-	 (box = catalog->getPage(curPageNum + 1)->getMediaBox()) &&
-	 XFAFormField::getMeasurement(attr, 0) == box->x2 - box->x1 &&
-	 (attr = elem->findAttr("h")) &&
-	 XFAFormField::getMeasurement(attr, 0) == box->y2 - box->y1)) {
-      if (curPageNum < nPages) {
-	++curPageNum;
-      }
-    }
-
-    // update tableInfo
-    if ((attr = elem->findAttr("layout"))) {
-      if (!attr->getValue()->cmp("table")) {
-	newTableInfo = new XFATableInfo(elem->findAttr("columnWidths"));
-	newTableInfo->rowIdx = -1;
-	newTableInfo->columnIdx = 0;
-      } else if (tableInfo && !attr->getValue()->cmp("row")) {
-	++tableInfo->rowIdx;
-	tableInfo->columnIdx = 0;
-	tableInfo->rowTop += tableInfo->rowHeight;
-	tableInfo->computeRowHeight(elem);
-      }
-    }
-
-    // update position
-    xSubOffset = XFAFormField::getMeasurement(elem->findAttr("x"), 0);
-    ySubOffset = XFAFormField::getMeasurement(elem->findAttr("y"), 0);
-    curXOffset += xSubOffset;
-    curYOffset += ySubOffset;
-
-  } else if (elem->isElement("area") ||
-	     elem->isElement("exclGroup")) {
-    xSubOffset = XFAFormField::getMeasurement(elem->findAttr("x"), 0);
-    ySubOffset = XFAFormField::getMeasurement(elem->findAttr("y"), 0);
-    curXOffset += xSubOffset;
-    curYOffset += ySubOffset;
-
-  } else {
-    xSubOffset = ySubOffset = 0;
-  }
-
-  savedPageNum = curPageNum;
-  if (elem->isElement("pageSet")) {
-    inPageSet = gTrue;
-    curPageNum = 0;
-
-  } else if (elem->isElement("pageArea")) {
-    if (inPageSet) {
-      if (curPageNum < nPages) {
-	++curPageNum;
-      }
-      if ((contentArea = elem->findFirstChildElement("contentArea"))) {
-	pageOffsetX[curPageNum - 1] =
-	    XFAFormField::getMeasurement(contentArea->findAttr("x"), 0);
-	pageOffsetY[curPageNum - 1] =
-	    XFAFormField::getMeasurement(contentArea->findAttr("y"), 0);
-	// looks like the contentArea offset (pageOffsetX/Y) should
-	// not be added to fields defined inside the pageArea
-	// element (?)
-	xSubOffset -= pageOffsetX[curPageNum - 1];
-	ySubOffset -= pageOffsetY[curPageNum - 1];
-	curXOffset -= pageOffsetX[curPageNum - 1];
-	curYOffset -= pageOffsetY[curPageNum - 1];
-      }
-    }
-  }
-
-  if (elem->isElement("exclGroup")) {
-    exclGroupName = name;
-  } else {
-    exclGroupName = NULL;
-  }
-
-  for (child = elem->getFirstChild(); child; child = child->getNextChild()) {
-    if (child->isElement()) {
-      scanNode((ZxElement *)child, name, fullName, inPageSet,
-	       newTableInfo, nameCount, nameIdx, fullNameCount, fullNameIdx,
-	       exclGroupName, catalog);
-    }
-  }
-
-  curXOffset -= xSubOffset;
-  curYOffset -= ySubOffset;
-
-  if (newTableInfo != tableInfo) {
-    delete newTableInfo;
-  }
-
-  if (elem->isElement("pageSet")) {
-    pageSetNPages = curPageNum;
-    curPageNum = savedPageNum;
-    inPageSet = gFalse;
-  }
-}
-
-GString *XFAForm::getNodeName(ZxElement *elem) {
-  ZxElement *bindElem;
-  ZxAttr *attr;
-
-  if (!(elem->getType()->cmp("field") &&
-	(bindElem = elem->findFirstChildElement("bind")) &&
-	(attr = bindElem->findAttr("match")) &&
-	!attr->getValue()->cmp("none")) &&
-      !elem->isElement("area") &&
-      (attr = elem->findAttr("name"))) {
-    return attr->getValue();
-  }
-  return NULL;
-}
-
-GString *XFAForm::getNodeFullName(ZxElement *elem) {
-  ZxAttr *attr;
-
-  if (!elem->isElement("area") &&
-      (attr = elem->findAttr("name"))) {
-    return attr->getValue();
-  }
-  return NULL;
-}
-
-GBool XFAForm::nodeIsBindGlobal(ZxElement *elem) {
-  ZxElement *bindElem;
-  ZxAttr *attr;
-
-  return (bindElem = elem->findFirstChildElement("bind")) &&
-         (attr = bindElem->findAttr("match")) &&
-         !attr->getValue()->cmp("global");
-}
-
-void XFAForm::draw(int pageNum, Gfx *gfx, GBool printing) {
-  GfxFontDict *fontDict;
-  Object obj1;
-  int i;
-
-  // build the font dictionary
-  fontDict = NULL;
-  if (resourceDict.isDict()) {
-    if (resourceDict.dictLookup("Font", &obj1)->isDict()) {
-      fontDict = new GfxFontDict(doc->getXRef(), NULL, obj1.getDict());
-    }
-    obj1.free();
-  }
-
-  for (i = 0; i < fields->getLength(); ++i) {
-    ((XFAFormField *)fields->get(i))->draw(pageNum, gfx, printing, fontDict);
-  }
-
-  delete fontDict;
-}
-
-int XFAForm::getNumFields() {
-  return fields->getLength();
-}
-
-FormField *XFAForm::getField(int idx) {
-  return (XFAFormField *)fields->get(idx);
-}
-
-//------------------------------------------------------------------------
-// XFAFormField
-//------------------------------------------------------------------------
-
-XFAFormField::XFAFormField(XFAForm *xfaFormA, ZxElement *xmlA,
-			   GString *nameA, GString *fullNameA,
-			   GString *exclGroupNameA,
-			   int pageNumA, double xOffsetA, double yOffsetA,
-			   double columnWidthA, double rowHeightA) {
-  xfaForm = xfaFormA;
-  xml = xmlA;
-  name = nameA;
-  fullName = fullNameA;
-  exclGroupName = exclGroupNameA;
-  pageNum = pageNumA;
-  xOffset = xOffsetA;
-  yOffset = yOffsetA;
-  columnWidth = columnWidthA;
-  rowHeight = rowHeightA;
-}
-
-XFAFormField::~XFAFormField() {
-  delete name;
-  delete fullName;
-  if (exclGroupName) {
-    delete exclGroupName;
-  }
-}
-
-int XFAFormField::getPageNum() {
-  return pageNum;
-}
-
-const char *XFAFormField::getType() {
-  ZxElement *uiElem;
-  ZxNode *node;
-
-  if ((uiElem = xml->findFirstChildElement("ui"))) {
-    for (node = uiElem->getFirstChild(); node; node = node->getNextChild()) {
-      if (node->isElement("textEdit")) {
-	return "Text";
-      } else if (node->isElement("numericEdit")) {
-	return "Numeric";
-      } else if (node->isElement("dateTimeEdit")) {
-	return "DateTime";
-      } else if (node->isElement("choiceList")) {
-	return "ChoiceList";
-      } else if (node->isElement("checkButton")) {
-	return "CheckButton";
-      } else if (node->isElement("barcode")) {
-	return "BarCode";
-      }
-      //~ other field types go here
-    }
-  }
-  return NULL;
-}
-
-Unicode *XFAFormField::getName(int *length) {
-  //~ assumes name is UTF-8
-  return utf8ToUnicode(name, length);
-}
-
-Unicode *XFAFormField::getValue(int *length) {
-  ZxElement *uiElem;
-  ZxNode *node;
-  GString *s;
-
-  //~ assumes value is UTF-8
-  s = NULL;
-  if ((uiElem = xml->findFirstChildElement("ui"))) {
-    for (node = uiElem->getFirstChild(); node; node = node->getNextChild()) {
-      if (node->isElement("textEdit")) {
-	s = getFieldValue("text");
-	break;
-      } else if (node->isElement("numericEdit")) {
-	//~ not sure if this is correct
-	s = getFieldValue("text");
-	break;
-      } else if (node->isElement("dateTimeEdit")) {
-	s = getFieldValue("text");
-	break;
-      } else if (node->isElement("checkButton")) {
-	if (!(s = getFieldValue("integer"))) {
-	  s = getFieldValue("text");
-	}
-	break;
-      } else if (node->isElement("barcode")) {
-	s = getFieldValue("text");
-	break;
-      }
-      //~ other field types go here
-    }
-  }
-  if (!s) {
-    return NULL;
-  }
-  return utf8ToUnicode(s, length);
-}
-
-Unicode *XFAFormField::utf8ToUnicode(GString *s, int *length) {
-  Unicode *u;
-  int n, size, c0, c1, c2, c3, c4, c5, i;
-
-  n = size = 0;
-  u = NULL;
-  i = 0;
-  while (i < s->getLength()) {
-    if (n == size) {
-      size = size ? size * 2 : 16;
-      u = (Unicode *)greallocn(u, size, sizeof(Unicode));
-    }
-    c0 = s->getChar(i++) & 0xff;
-    if (c0 <= 0x7f) {
-      u[n++] = c0;
-    } else if (c0 <= 0xdf && i < n) {
-      c1 = s->getChar(i++) & 0xff;
-      u[n++] = ((c0 & 0x1f) << 6) | (c1 & 0x3f);
-    } else if (c0 <= 0xef && i+1 < n) {
-      c1 = s->getChar(i++) & 0xff;
-      c2 = s->getChar(i++) & 0xff;
-      u[n++] = ((c0 & 0x0f) << 12) | ((c1 & 0x3f) << 6) | (c2 & 0x3f);
-    } else if (c0 <= 0xf7 && i+2 < n) {
-      c1 = s->getChar(i++) & 0xff;
-      c2 = s->getChar(i++) & 0xff;
-      c3 = s->getChar(i++) & 0xff;
-      u[n++] = ((c0 & 0x07) << 18) | ((c1 & 0x3f) << 12) | ((c2 & 0x3f) << 6)
-	       | (c3 & 0x3f);
-    } else if (c0 <= 0xfb && i+3 < n) {
-      c1 = s->getChar(i++) & 0xff;
-      c2 = s->getChar(i++) & 0xff;
-      c3 = s->getChar(i++) & 0xff;
-      c4 = s->getChar(i++) & 0xff;
-      u[n++] = ((c0 & 0x03) << 24) | ((c1 & 0x3f) << 18) | ((c2 & 0x3f) << 12)
-	       | ((c3 & 0x3f) << 6) | (c4 & 0x3f);
-    } else if (c0 <= 0xfd && i+4 < n) {
-      c1 = s->getChar(i++) & 0xff;
-      c2 = s->getChar(i++) & 0xff;
-      c3 = s->getChar(i++) & 0xff;
-      c4 = s->getChar(i++) & 0xff;
-      c5 = s->getChar(i++) & 0xff;
-      u[n++] = ((c0 & 0x01) << 30) | ((c1 & 0x3f) << 24) | ((c2 & 0x3f) << 18)
-	       | ((c3 & 0x3f) << 12) | ((c4 & 0x3f) << 6) | (c5 & 0x3f);
-    } else {
-      u[n++] = '?';
-    }
-  }
-  *length = n;
-  return u;
-}
-
-void XFAFormField::getBBox(double *llx, double *lly,
-			   double *urx, double *ury) {
-  double xfaX, xfaY, xfaW, xfaH, pdfX, pdfY, pdfW, pdfH;
-  int pdfRot;
-
-  getRectangle(&xfaX, &xfaY, &xfaW, &xfaH,
-	       &pdfX, &pdfY, &pdfW, &pdfH, &pdfRot);
-  *llx = pdfX;
-  *lly = pdfY;
-  *urx = pdfX + pdfW;
-  *ury = pdfY + pdfH;
-}
-
-void XFAFormField::getFont(Ref *fontID, double *fontSize) {
-  ZxElement *fontElem;
-  ZxAttr *attr;
-  GBool bold, italic;
-
-  fontID->num = fontID->gen = -1;
-  *fontSize = 0;
-  if ((fontElem = xml->findFirstChildElement("font"))) {
-    bold = italic = gFalse;
-    if ((attr = fontElem->findAttr("weight"))) {
-      if (!attr->getValue()->cmp("bold")) {
-	bold = gTrue;
-      }
-    }
-    if ((attr = fontElem->findAttr("posture"))) {
-      if (!attr->getValue()->cmp("italic")) {
-	italic = gTrue;
-      }
-    }
-    if ((attr = fontElem->findAttr("typeface"))) {
-      *fontID = findFontName(attr->getValue(), bold, italic);
-    }
-    if ((attr = fontElem->findAttr("size"))) {
-      *fontSize = getMeasurement(attr, 0);
-    }
-  }
-}
-
-void XFAFormField::getColor(double *red, double *green, double *blue) {
-  ZxElement *fontElem, *fillElem, *colorElem;
-  ZxAttr *attr;
-  int r, g, b;
-
-  *red = *green = *blue = 0;
-  if ((fontElem = xml->findFirstChildElement("font"))) {
-    if ((fillElem = fontElem->findFirstChildElement("fill"))) {
-      if ((colorElem = fillElem->findFirstChildElement("color"))) {
-	if ((attr = colorElem->findAttr("value"))) {
-	  if (sscanf(attr->getValue()->getCString(), "%d,%d,%d",
-		     &r, &g, &b) == 3) {
-	    *red = r / 255.0;
-	    *green = g / 255.0;
-	    *blue = b / 255.0;
-	  }
-	}
-      }
-    }
-  }
-}
-
-void XFAFormField::draw(int pageNumA, Gfx *gfx, GBool printing,
-			GfxFontDict *fontDict) {
-  ZxElement *uiElem;
-  ZxNode *node;
-  ZxAttr *attr;
-  GString *appearBuf;
-  MemStream *appearStream;
-  Object appearDict, appearance, resourceDict, resourceSubdict;
-  Object fontResources, fontResource, defaultFont;
-  Object obj1, obj2;
-  char *resType, *fontName;
-  double mat[6];
-  double xfaX, xfaY, xfaW, xfaH, pdfX, pdfY, pdfW, pdfH;
-  int rot3, i;
-
-  if (pageNumA != pageNum) {
-    return;
-  }
-
-  // check the 'presence' attribute
-  if ((attr = xml->findAttr("presence"))) {
-    if (!attr->getValue()->cmp("hidden") ||
-	!attr->getValue()->cmp("invisible")) {
-      return;
-    }
-  }
-
-  getRectangle(&xfaX, &xfaY, &xfaW, &xfaH, &pdfX, &pdfY, &pdfW, &pdfH, &rot3);
-
-  // generate transform matrix
-  switch (rot3) {
-  case 0:
-  default:
-    mat[0] = 1;  mat[1] = 0;
-    mat[2] = 0;  mat[3] = 1;
-    mat[4] = 0;  mat[5] = 0;
-    break;
-  case 90:
-    mat[0] =  0;  mat[1] = 1;
-    mat[2] = -1;  mat[3] = 0;
-    mat[4] =  xfaH;  mat[5] = 0;
-    break;
-  case 180:
-    mat[0] = -1;  mat[1] =  0;
-    mat[2] =  0;  mat[3] = -1;
-    mat[4] =  xfaW;  mat[5] =  xfaH;
-    break;
-  case 270:
-    mat[0] = 0;  mat[1] = -1;
-    mat[2] = 1;  mat[3] =  0;
-    mat[4] = 0;  mat[5] =  xfaW;
-    break;
-  }
-
-  // get the appearance stream data
-  appearBuf = new GString();
-#if 0 //~ for debugging
-  double debugPad = 0;
-  appearBuf->appendf("q 1 1 0 rg {0:.4f} {1:.4f} {2:.4f} {3:.4f} re f Q\n",
-		     debugPad, debugPad, xfaW - 2*debugPad, xfaH - 2*debugPad);
-#endif
-  if ((uiElem = xml->findFirstChildElement("ui"))) {
-    for (node = uiElem->getFirstChild(); node; node = node->getNextChild()) {
-      if (node->isElement("textEdit") ||
-	  node->isElement("numericEdit")) {
-	drawTextEdit(fontDict, xfaW, xfaH, rot3, appearBuf);
-	break;
-      } else if (node->isElement("dateTimeEdit")) {
-	drawTextEdit(fontDict, xfaW, xfaH, rot3, appearBuf);
-	break;
-      } else if (node->isElement("choiceList")) {
-	drawTextEdit(fontDict, xfaW, xfaH, rot3, appearBuf);
-	break;
-      } else if (node->isElement("checkButton")) {
-	drawCheckButton(fontDict, xfaW, xfaH, rot3, appearBuf);
-	break;
-      } else if (node->isElement("barcode")) {
-	drawBarCode(fontDict, xfaW, xfaH, rot3, appearBuf);
-	break;
-      }
-      //~ other field types go here
-    }
-  } else {
-    drawTextEdit(fontDict, xfaW, xfaH, rot3, appearBuf);
-  }
-
-  // create the appearance stream
-  appearDict.initDict(xfaForm->doc->getXRef());
-  appearDict.dictAdd(copyString("Length"),
-		     obj1.initInt(appearBuf->getLength()));
-  appearDict.dictAdd(copyString("Subtype"), obj1.initName("Form"));
-  obj1.initArray(xfaForm->doc->getXRef());
-  obj1.arrayAdd(obj2.initReal(0));
-  obj1.arrayAdd(obj2.initReal(0));
-  obj1.arrayAdd(obj2.initReal(xfaW));
-  obj1.arrayAdd(obj2.initReal(xfaH));
-  appearDict.dictAdd(copyString("BBox"), &obj1);
-  obj1.initArray(xfaForm->doc->getXRef());
-  obj1.arrayAdd(obj2.initReal(mat[0]));
-  obj1.arrayAdd(obj2.initReal(mat[1]));
-  obj1.arrayAdd(obj2.initReal(mat[2]));
-  obj1.arrayAdd(obj2.initReal(mat[3]));
-  obj1.arrayAdd(obj2.initReal(mat[4]));
-  obj1.arrayAdd(obj2.initReal(mat[5]));
-  appearDict.dictAdd(copyString("Matrix"), &obj1);
-  // NB: we need to deep-copy the resource dict and font resource
-  // subdict, because the font subdict is modified, and multiple
-  // threads can be sharing these objects.
-  resourceDict.initDict(xfaForm->doc->getXRef());
-  if (xfaForm->resourceDict.isDict()) {
-    for (i = 0; i < xfaForm->resourceDict.dictGetLength(); ++i) {
-      resType = xfaForm->resourceDict.dictGetKey(i);
-      if (strcmp(resType, "Font")) {
-	xfaForm->resourceDict.dictGetVal(i, &resourceSubdict);
-	resourceDict.dictAdd(copyString(resType), &resourceSubdict);
-      }
-    }
-  }
-  fontResources.initDict(xfaForm->doc->getXRef());
-  if (xfaForm->resourceDict.isDict() &&
-      xfaForm->resourceDict.dictLookup("Font", &resourceSubdict)->isDict()) {
-    for (i = 0; i < resourceSubdict.dictGetLength(); ++i) {
-      fontName = resourceSubdict.dictGetKey(i);
-      resourceSubdict.dictGetVal(i, &fontResource);
-      fontResources.dictAdd(copyString(fontName), &fontResource);
-    }
-    resourceSubdict.free();
-  }
-  defaultFont.initDict(xfaForm->doc->getXRef());
-  defaultFont.dictAdd(copyString("Type"), obj1.initName("Font"));
-  defaultFont.dictAdd(copyString("Subtype"), obj1.initName("Type1"));
-  defaultFont.dictAdd(copyString("BaseFont"), obj1.initName("Helvetica"));
-  defaultFont.dictAdd(copyString("Encoding"), obj1.initName("WinAnsiEncoding"));
-  fontResources.dictAdd(copyString("xpdf_default_font"), &defaultFont);
-  resourceDict.dictAdd(copyString("Font"), &fontResources);
-  appearDict.dictAdd(copyString("Resources"), &resourceDict);
-  appearStream = new MemStream(appearBuf->getCString(), 0,
-			       appearBuf->getLength(), &appearDict);
-  appearance.initStream(appearStream);
-  gfx->drawAnnot(&appearance, NULL, pdfX, pdfY, pdfX + pdfW, pdfY + pdfH);
-  appearance.free();
-  delete appearBuf;
-}
-
-void XFAFormField::getRectangle(double *xfaX, double *xfaY,
-				double *xfaW, double *xfaH,
-				double *pdfX, double *pdfY,
-				double *pdfW, double *pdfH,
-				int *pdfRot) {
-  Page *page;
-  PDFRectangle *pageRect;
-  ZxElement *captionElem, *paraElem, *marginElem;
-  ZxAttr *attr;
-  double x2, y2, w2, h2, t;
-  double anchorX, anchorY;
-  int pageRot, rot;
-
-  page = xfaForm->doc->getCatalog()->getPage(pageNum);
-  pageRect = page->getMediaBox();
-  pageRot = page->getRotate();
-
-  anchorX = 0;
-  anchorY = 0;
-  if ((attr = xml->findAttr("anchorType"))) {
-    if (!attr->getValue()->cmp("topLeft")) {
-      anchorX = 0;
-      anchorY = 0;
-    } else if (!attr->getValue()->cmp("topCenter")) {
-      anchorX = 0.5;
-      anchorY = 0;
-    } else if (!attr->getValue()->cmp("topRight")) {
-      anchorX = 1;
-      anchorY = 0;
-    } else if (!attr->getValue()->cmp("middleLeft")) {
-      anchorX = 0;
-      anchorY = 0.5;
-    } else if (!attr->getValue()->cmp("middleCenter")) {
-      anchorX = 0.5;
-      anchorY = 0.5;
-    } else if (!attr->getValue()->cmp("middleRight")) {
-      anchorX = 1;
-      anchorY = 0.5;
-    } else if (!attr->getValue()->cmp("bottomLeft")) {
-      anchorX = 0;
-      anchorY = 1;
-    } else if (!attr->getValue()->cmp("bottomCenter")) {
-      anchorX = 0.5;
-      anchorY = 1;
-    } else if (!attr->getValue()->cmp("bottomRight")) {
-      anchorX = 1;
-      anchorY = 1;
-    }
-  }
-  *xfaX = getMeasurement(xml->findAttr("x"), 0) + xOffset;
-  *xfaY = getMeasurement(xml->findAttr("y"), 0) + yOffset;
-  if (!(attr = xml->findAttr("w"))) {
-    attr = xml->findAttr("minW");
-  }
-  *xfaW = getMeasurement(attr, 0);
-  if (*xfaW < columnWidth) {
-    *xfaW = columnWidth;
-  }
-  if (!(attr = xml->findAttr("h"))) {
-    attr = xml->findAttr("minH");
-  }
-  *xfaH = getMeasurement(attr, 0);
-  if (*xfaH < rowHeight) {
-    *xfaH = rowHeight;
-  }
-  if ((attr = xml->findAttr("rotate"))) {
-    rot = atoi(attr->getValue()->getCString());
-    if ((rot %= 360) < 0) {
-      rot += 360;
-    }
-  } else {
-    rot = 0;
-  }
-
-  // look for <caption reserve="...."> -- add the caption width/height
-  // (plus a margin allowance)
-  if ((captionElem = xml->findFirstChildElement("caption"))) {
-    if ((attr = captionElem->findAttr("reserve"))) {
-      t = getMeasurement(attr, 0);
-      if ((attr = captionElem->findAttr("placement"))) {
-	if (!attr->getValue()->cmp("left")) {
-	  *xfaX += t + 1.5;
-	  *xfaW -= t + 1.5;
-	} else if (!attr->getValue()->cmp("right")) {
-	  *xfaW -= t + 1.5;
-	} else if (!attr->getValue()->cmp("top")) {
-	  *xfaY += t;
-	  *xfaH -= t;
-	} else if (!attr->getValue()->cmp("bottom")) {
-	  *xfaH -= t;
-	}
-      } else {
-	// default is placement="left"
-	*xfaX += t + 1.5;
-	*xfaW -= t + 1.5;
-      }
-    }
-  }
-
-  // look for <margin>
-  if ((marginElem = xml->findFirstChildElement("margin"))) {
-    if ((attr = marginElem->findAttr("leftInset"))) {
-      t = getMeasurement(attr, 0);
-      *xfaX += t;
-      *xfaW -= t;
-    }
-    if ((attr = marginElem->findAttr("rightInset"))) {
-      t = getMeasurement(attr, 0);
-      *xfaW -= t;
-    }
-    if ((attr = marginElem->findAttr("topInset"))) {
-      t = getMeasurement(attr, 0);
-      *xfaY += t;
-      *xfaH -= t;
-    }
-    if ((attr = marginElem->findAttr("bottomInset"))) {
-      t = getMeasurement(attr, 0);
-      *xfaH -= t;
-    }
-  }
-
-  // look for <para> -- add the margins
-  if ((paraElem = xml->findFirstChildElement("para"))) {
-    if ((attr = paraElem->findAttr("marginLeft"))) {
-      t = getMeasurement(attr, 0);
-      *xfaX += t;
-      *xfaW -= t;
-    }
-    if ((attr = paraElem->findAttr("marginRight"))) {
-      t = getMeasurement(attr, 0);
-      *xfaW -= t;
-    }
-    if ((attr = paraElem->findAttr("spaceAbove"))) {
-      t = getMeasurement(attr, 0);
-      *xfaY += t;
-      *xfaH -= t;
-    }
-    if ((attr = paraElem->findAttr("spaceBelow"))) {
-      t = getMeasurement(attr, 0);
-      *xfaH -= t;
-    }
-  }
-
-  // get annot rect (UL corner, width, height) in XFA coords
-  // notes:
-  // - XFA coordinates are top-left origin, after page rotation
-  // - XFA coordinates are dependent on choice of anchor point
-  //   and field rotation
-  switch (rot) {
-  case 0:
-  default:
-    x2 = *xfaX - anchorX * *xfaW;
-    y2 = *xfaY - anchorY * *xfaH;
-    w2 = *xfaW;
-    h2 = *xfaH;
-    break;
-  case 90:
-    x2 = *xfaX - anchorY * *xfaH;
-    y2 = *xfaY - (1 - anchorX) * *xfaW;
-    w2 = *xfaH;
-    h2 = *xfaW;
-    break;
-  case 180:
-    x2 = *xfaX - (1 - anchorX) * *xfaW;
-    y2 = *xfaY - (1 - anchorY) * *xfaH;
-    w2 = *xfaW;
-    h2 = *xfaH;
-    break;
-  case 270:
-    x2 = *xfaX - (1 - anchorY) * *xfaH;
-    y2 = *xfaY - anchorX * *xfaW;
-    w2 = *xfaH;
-    h2 = *xfaW;
-    break;
-  }
-
-  // convert annot rect to PDF coords (LL corner, width, height),
-  // taking page rotation into account
-  switch (pageRot) {
-  case 0:
-  default:
-    *pdfX = pageRect->x1 + x2;
-    *pdfY = pageRect->y2 - (y2 + h2);
-    *pdfW = w2;
-    *pdfH = h2;
-    break;
-  case 90:
-    *pdfX = pageRect->x1 + y2;
-    *pdfY = pageRect->y1 + x2;
-    *pdfW = h2;
-    *pdfH = w2;
-    break;
-  case 180:
-    *pdfX = pageRect->x2 - (x2 + w2);
-    *pdfY = pageRect->y1 + y2;
-    *pdfW = w2;
-    *pdfH = h2;
-    break;
-  case 270:
-    *pdfX = pageRect->x2 - (y2 + h2);
-    *pdfY = pageRect->y1 + (x2 + w2);
-    *pdfW = h2;
-    *pdfH = w2;
-    break;
-  }
-  *pdfRot = (rot + pageRot) % 360;
-}
-
-void XFAFormField::drawTextEdit(GfxFontDict *fontDict,
-				double w, double h, int rot,
-				GString *appearBuf) {
-  ZxElement *formatElem, *pictureElem;
-  ZxNode *pictureChildElem;
-  ZxElement *valueElem, *textElem, *uiElem, *textEditElem, *combElem;
-  ZxElement *fontElem, *paraElem;
-  ZxAttr *attr;
-  GString *picture, *value, *formattedValue, *fontName;
-  double fontSize;
-  int maxChars, combCells;
-  GBool multiLine, bold, italic;
-  XFAHorizAlign hAlign;
-  XFAVertAlign vAlign;
-
-  if (!(value = getFieldValue("text"))) {
-    return;
-  }
-
-  uiElem = xml->findFirstChildElement("ui");
-
-  //--- picture formatting
-  if (uiElem &&
-      (formatElem = xml->findFirstChildElement("format")) &&
-      (pictureElem = formatElem->findFirstChildElement("picture")) &&
-      (pictureChildElem = pictureElem->getFirstChild()) &&
-      pictureChildElem->isCharData()) {
-    picture = ((ZxCharData *)pictureChildElem)->getData();
-    if (uiElem->findFirstChildElement("dateTimeEdit")) {
-      formattedValue = pictureFormatDateTime(value, picture);
-    } else if (uiElem->findFirstChildElement("numericEdit")) {
-      formattedValue = pictureFormatNumber(value, picture);
-    } else if (uiElem->findFirstChildElement("textEdit")) {
-      formattedValue = pictureFormatText(value, picture);
-    } else {
-      formattedValue = value->copy();
-    }
-  } else {
-    formattedValue = value->copy();
-  }
-
-  maxChars = 0;
-  if ((valueElem = xml->findFirstChildElement("value")) &&
-      (textElem = valueElem->findFirstChildElement("text")) &&
-      (attr = textElem->findAttr("maxChars"))) {
-    maxChars = atoi(attr->getValue()->getCString());
-  }
-
-  multiLine = gFalse;
-  combCells = 0;
-  if (uiElem &&
-      (textEditElem = uiElem->findFirstChildElement("textEdit"))) {
-    if ((attr = textEditElem->findAttr("multiLine")) &&
-	!attr->getValue()->cmp("1")) {
-      multiLine = gTrue;
-    }
-    if ((combElem = textEditElem->findFirstChildElement("comb"))) {
-      if ((attr = combElem->findAttr("numberOfCells"))) {
-	combCells = atoi(attr->getValue()->getCString());
-      } else {
-	combCells = maxChars;
-      }
-    }
-  }
-	
-  fontName = NULL;
-  fontSize = 10;
-  bold = gFalse;
-  italic = gFalse;
-  if ((fontElem = xml->findFirstChildElement("font"))) {
-    if ((attr = fontElem->findAttr("typeface"))) {
-      fontName = attr->getValue()->copy();
-    }
-    if ((attr = fontElem->findAttr("weight"))) {
-      if (!attr->getValue()->cmp("bold")) {
-	bold = gTrue;
-      }
-    }
-    if ((attr = fontElem->findAttr("posture"))) {
-      if (!attr->getValue()->cmp("italic")) {
-	italic = gTrue;
-      }
-    }
-    if ((attr = fontElem->findAttr("size"))) {
-      fontSize = getMeasurement(attr, fontSize);
-    }
-  }
-  if (!fontName) {
-    fontName = new GString("Courier");
-  }
-
-  hAlign = xfaHAlignLeft;
-  vAlign = xfaVAlignTop;
-  if ((paraElem = xml->findFirstChildElement("para"))) {
-    if ((attr = paraElem->findAttr("hAlign"))) {
-      if (!attr->getValue()->cmp("left")) {
-	hAlign = xfaHAlignLeft;
-      } else if (!attr->getValue()->cmp("center")) {
-	hAlign = xfaHAlignCenter;
-      } else if (!attr->getValue()->cmp("right")) {
-	hAlign = xfaHAlignRight;
-      }
-      //~ other hAlign values (justify, justifyAll, radix) are
-      //~   currently unsupported
-    }
-    if ((attr = paraElem->findAttr("vAlign"))) {
-      if (!attr->getValue()->cmp("top")) {
-	vAlign = xfaVAlignTop;
-      } else if (!attr->getValue()->cmp("bottom")) {
-	vAlign = xfaVAlignBottom;
-      } else if (!attr->getValue()->cmp("middle")) {
-	vAlign = xfaVAlignMiddle;
-      }
-    }
-  }
-
-  drawText(formattedValue, multiLine, combCells,
-	   fontName, bold, italic, fontSize,
-	   hAlign, vAlign, 0, 0, w, h, gFalse, fontDict, appearBuf);
-  delete fontName;
-  delete formattedValue;
-}
-
-void XFAFormField::drawCheckButton(GfxFontDict *fontDict,
-				   double w, double h, int rot,
-				   GString *appearBuf) {
-  ZxElement *items;
-  ZxNode *firstItem, *firstItemVal;
-  const char *itemType;
-  const char *onValue;
-  GString *value;
-  double x, y;
-
-  // get the "on" value for this check button
-  itemType = "integer";
-  onValue = "1";
-  if ((items = xml->findFirstChildElement("items"))) {
-    if ((firstItem = items->getFirstChild())) {
-      if (firstItem->isElement("text") && firstItem->getFirstChild()) {
-	itemType = "text";
-	if ((firstItemVal = firstItem->getFirstChild())->isCharData()) {
-	  onValue = ((ZxCharData *)firstItemVal)->getData()->getCString();
-	}
-      } else if (firstItem->isElement("integer") &&
-		 firstItem->getFirstChild()) {
-	itemType = "integer";
-	if ((firstItemVal = firstItem->getFirstChild())->isCharData()) {
-	  onValue = ((ZxCharData *)firstItemVal)->getData()->getCString();
-	}
-      }
-    }
-  }
-
-  // compare its value to the "on" value
-  if (!(value = getFieldValue(itemType))) {
-    return;
-  }
-  if (value->cmp(onValue)) {
-    return;
-  }
-
-  // adjust shape to be square
-  x = y = 0;
-  if (w > h) {
-    x += 0.5 * (w - h);
-    w = h;
-  } else {
-    y += 0.5 * (h - w);
-    h = w;
-  }
-
-  // margins
-  x += 1.5;
-  w -= 3;
-  y += 1.5;
-  h -= 3;
-
-  //~ this should look at the "shape" and "mark" attributes
-
-  appearBuf->appendf("0.5 w {0:.4f} {1:.4f} m {2:.4f} {3:.4f} l {0:.4f} {3:.4f} m {2:.4f} {1:.4f} l S\n",
-		     x, y, x + w, y + h);
-}
-
-void XFAFormField::drawBarCode(GfxFontDict *fontDict,
-			       double w, double h, int rot,
-			       GString *appearBuf) {
-  ZxElement *uiElem, *barcodeElem, *fontElem;
-  ZxAttr *attr;
-  GString *value, *value2, *barcodeType, *textLocation, *fontName, *s1, *s2;
-  XFAVertAlign textAlign;
-  double wideNarrowRatio, moduleWidth, moduleHeight, fontSize;
-  double yText, wText, yBarcode, hBarcode, wNarrow, xx;
-  GBool doText;
-  int dataLength, errorCorrectionLevel, checksum;
-  GBool bold, italic;
-  char *p;
-  int i, j, c;
-
-  //--- get field value
-  if (!(value = getFieldValue("text"))) {
-    return;
-  }
-
-  //--- get font
-  fontName = NULL;
-  fontSize = 0.2 * h;
-  bold = gFalse;
-  italic = gFalse;
-  if ((fontElem = xml->findFirstChildElement("font"))) {
-    if ((attr = fontElem->findAttr("typeface"))) {
-      fontName = attr->getValue()->copy();
-    }
-    if ((attr = fontElem->findAttr("weight"))) {
-      if (!attr->getValue()->cmp("bold")) {
-	bold = gTrue;
-      }
-    }
-    if ((attr = fontElem->findAttr("posture"))) {
-      if (!attr->getValue()->cmp("italic")) {
-	italic = gTrue;
-      }
-    }
-    if ((attr = fontElem->findAttr("size"))) {
-      fontSize = getMeasurement(attr, fontSize);
-    }
-  }
-  if (!fontName) {
-    fontName = new GString("Courier");
-  }
-
-  //--- get field attributes
-  barcodeType = NULL;
-  wideNarrowRatio = 3;
-  moduleWidth = 0;
-  moduleHeight = 0;
-  dataLength = 0;
-  errorCorrectionLevel = 0;
-  textLocation = NULL;
-  if ((uiElem = xml->findFirstChildElement("ui")) &&
-      (barcodeElem = uiElem->findFirstChildElement("barcode"))) {
-    if ((attr = barcodeElem->findAttr("type"))) {
-      barcodeType = attr->getValue();
-    }
-    if ((attr = barcodeElem->findAttr("wideNarrowRatio"))) {
-      s1 = attr->getValue();
-      if ((p = strchr(s1->getCString(), ':'))) {
-	s2 = new GString(s1, 0, (int)(p - s1->getCString()));
-	wideNarrowRatio = atof(p + 1);
-	if (wideNarrowRatio == 0) {
-	  wideNarrowRatio = 1;
-	}
-	wideNarrowRatio = atof(s2->getCString()) / wideNarrowRatio;
-	delete s2;
-      } else {
-	wideNarrowRatio = atof(s1->getCString());
-      }
-    }
-    if ((attr = barcodeElem->findAttr("moduleWidth"))) {
-      moduleWidth = getMeasurement(attr, (0.25 / 25.4) * 72.0); // 0.25mm
-    }
-    if ((attr = barcodeElem->findAttr("moduleHeight"))) {
-      moduleHeight = getMeasurement(attr, (0.5 / 25.4) * 72.0); // 0.5mm
-    }
-    if ((attr = barcodeElem->findAttr("dataLength"))) {
-      dataLength = atoi(attr->getValue()->getCString());
-    }
-    if ((attr = barcodeElem->findAttr("errorCorrectionLevel"))) {
-      errorCorrectionLevel = atoi(attr->getValue()->getCString());
-    }
-    if ((attr = barcodeElem->findAttr("textLocation"))) {
-      textLocation = attr->getValue();
-    }
-  }
-  if (!barcodeType) {
-    error(errSyntaxError, -1, "Missing 'type' attribute in XFA barcode field");
-    delete fontName;
-    return;
-  }
-
-  //--- compute the embedded text type position
-  doText = gTrue;
-  yText = yBarcode = hBarcode = 0;
-  if (textLocation && !textLocation->cmp("above")) {
-    textAlign = xfaVAlignTop;
-    yText = h;
-    yBarcode = 0;
-    hBarcode = h - fontSize;
-  } else if (textLocation && !textLocation->cmp("belowEmbedded")) {
-    textAlign = xfaVAlignBottom;
-    yText = 0;
-    yBarcode = 0;
-    hBarcode = h;
-  } else if (textLocation && !textLocation->cmp("aboveEmbedded")) {
-    textAlign = xfaVAlignTop;
-    yText = h;
-    yBarcode = 0;
-    hBarcode = h;
-  } else if (textLocation && !textLocation->cmp("none")) {
-    textAlign = xfaVAlignBottom; // make gcc happy
-    doText = gFalse;
-  } else { // default is "below"
-    textAlign = xfaVAlignBottom;
-    yText = 0;
-    yBarcode = fontSize;
-    hBarcode = h - fontSize;
-  }
-  wText = w;
-
-  //--- remove extraneous start/stop chars
-  value2 = value->copy();
-  if (!barcodeType->cmp("code3Of9")) {
-    if (value2->getLength() >= 1 && value2->getChar(0) == '*') {
-      value2->del(0);
-    }
-    if (value2->getLength() >= 1 &&
-	value2->getChar(value2->getLength() - 1) == '*') {
-      value2->del(value2->getLength() - 1);
-    }
-  }
-
-  //--- draw the bar code
-  if (!barcodeType->cmp("code3Of9")) {
-    if (!dataLength) {
-      error(errSyntaxError, -1,
-	    "Missing 'dataLength' attribute in XFA barcode field");
-      goto err;
-    }
-    appearBuf->append("0 g\n");
-    wNarrow = w / ((7 + 3 * wideNarrowRatio) * (dataLength + 2));
-    xx = 0;
-    for (i = -1; i <= value2->getLength(); ++i) {
-      if (i < 0 || i >= value2->getLength()) {
-	c = '*';
-      } else {
-	c = value2->getChar(i) & 0x7f;
-      }
-      for (j = 0; j < 10; j += 2) {
-	appearBuf->appendf("{0:.4f} {1:.4f} {2:.4f} {3:.4f} re f\n",
-			   xx, yBarcode,
-			   (code3Of9Data[c][j] ? wideNarrowRatio : 1) * wNarrow,
-			   hBarcode);
-	xx += ((code3Of9Data[c][j] ? wideNarrowRatio : 1) +
-	       (code3Of9Data[c][j+1] ? wideNarrowRatio : 1)) * wNarrow;
-      }
-    }
-    // center the text on the drawn barcode (not the max length barcode)
-    wText = (value2->getLength() + 2) * (7 + 3 * wideNarrowRatio) * wNarrow;
-  } else if (!barcodeType->cmp("code128B")) {
-    if (!dataLength) {
-      error(errSyntaxError, -1,
-	    "Missing 'dataLength' attribute in XFA barcode field");
-      goto err;
-    }
-    appearBuf->append("0 g\n");
-    wNarrow = w / (11 * (dataLength + 3) + 2);
-    xx = 0;
-    checksum = 0;
-    for (i = -1; i <= value2->getLength() + 1; ++i) {
-      if (i == -1) {
-	// start code B
-	c = 104;
-	checksum += c;
-      } else if (i == value2->getLength()) {
-	// checksum
-	c = checksum % 103;
-      } else if (i == value2->getLength() + 1) {
-	// stop code
-	c = 106;
-      } else {
-	c = value2->getChar(i) & 0xff;
-	if (c >= 32 && c <= 127) {
-	  c -= 32;
-	} else {
-	  c = 0;
-	}	  
-	checksum += (i + 1) * c;
-      }
-      for (j = 0; j < 6; j += 2) {
-	appearBuf->appendf("{0:.4f} {1:.4f} {2:.4f} {3:.4f} re f\n",
-			   xx, yBarcode,
-			   code128Data[c][j] * wNarrow, hBarcode);
-	xx += (code128Data[c][j] + code128Data[c][j+1]) * wNarrow;
-      }
-    }
-    // final bar of the stop code
-    appearBuf->appendf("{0:.4f} {1:.4f} {2:.4f} {3:.4f} re f\n",
-		       xx, yBarcode, 2 * wNarrow, hBarcode);
-    // center the text on the drawn barcode (not the max length barcode)
-    wText = (11 * (value2->getLength() + 3) + 2) * wNarrow;
-  } else if (!barcodeType->cmp("pdf417")) {
-    drawPDF417Barcode(w, h, moduleWidth, moduleHeight, errorCorrectionLevel,
-		      value2, appearBuf);
-    doText = gFalse;
-  } else {
-    error(errSyntaxError, -1,
-	  "Unimplemented barcode type '{0:t}' in XFA barcode field",
-	  barcodeType);
-  }
-  //~ add other barcode types here
-
-  //--- draw the embedded text
-  if (doText) {
-    appearBuf->append("0 g\n");
-    drawText(value2, gFalse, 0,
-	     fontName, bold, italic, fontSize,
-	     xfaHAlignCenter, textAlign, 0, yText, wText, h, gTrue,
-	     fontDict, appearBuf);
-  }
-
- err:
-  delete fontName;
-  delete value2;
-}
-
-Object *XFAFormField::getResources(Object *res) {
-  return xfaForm->resourceDict.copy(res);
-}
-
-double XFAFormField::getMeasurement(ZxAttr *attr, double defaultVal) {
-  GString *s;
-
-  if (!attr) {
-    return defaultVal;
-  }
-  s = attr->getValue();
-  return getMeasurement(s, 0);
-}
-
-double XFAFormField::getMeasurement(GString *s, int begin) {
-  double val, mul;
-  GBool neg;
-  int i;
-
-  i = begin;
-  neg = gFalse;
-  if (i < s->getLength() && s->getChar(i) == '+') {
-    ++i;
-  } else if (i < s->getLength() && s->getChar(i) == '-') {
-    neg = gTrue;
-    ++i;
-  }
-  val = 0;
-  while (i < s->getLength() && s->getChar(i) >= '0' && s->getChar(i) <= '9') {
-    val = val * 10 + s->getChar(i) - '0';
-    ++i;
-  }
-  if (i < s->getLength() && s->getChar(i) == '.') {
-    ++i;
-    mul = 0.1;
-    while (i < s->getLength() && s->getChar(i) >= '0' && s->getChar(i) <= '9') {
-      val += mul * (s->getChar(i) - '0');
-      mul *= 0.1;
-      ++i;
-    }
-  }
-  if (neg) {
-    val = -val;
-  }
-  if (i+1 < s->getLength()) {
-    if (s->getChar(i) == 'i' && s->getChar(i+1) == 'n') {
-      val *= 72;
-    } else if (s->getChar(i) == 'p' && s->getChar(i+1) == 't') {
-      // no change
-    } else if (s->getChar(i) == 'c' && s->getChar(i+1) == 'm') {
-      val *= 72 / 2.54;
-    } else if (s->getChar(i) == 'm' && s->getChar(i+1) == 'm') {
-      val *= 72 / 25.4;
-    } else {
-      // default to inches
-      val *= 72;
-    }
-  } else {
-    // default to inches
-    val *= 72;
-  }
-  return val;
-}
-
-GString *XFAFormField::getFieldValue(const char *valueChildType) {
-  ZxElement *valueElem, *datasets, *data, *formElem, *elem;
-  char *p;
-
-  // check the <datasets> packet
-  p = name->getCString();
-  if (xfaForm->xml->getRoot() && !strncmp(p, "form.",  5)) {
-    if ((datasets =
-	 xfaForm->xml->getRoot()->findFirstChildElement("xfa:datasets")) &&
-	(data = datasets->findFirstChildElement("xfa:data"))) {
-      elem = findFieldInDatasets(data, p + 5);
-      if (elem &&
-	  elem->getFirstChild() &&
-	  elem->getFirstChild()->isCharData() &&
-	  ((ZxCharData *)elem->getFirstChild())->getData()->getLength() > 0) {
-	return ((ZxCharData *)elem->getFirstChild())->getData();
-      }
-    }
-  }
-  if (exclGroupName) {
-    p = exclGroupName->getCString();
-    if (xfaForm->xml->getRoot() && !strncmp(p, "form.",  5)) {
-      if ((datasets =
-	   xfaForm->xml->getRoot()->findFirstChildElement("xfa:datasets")) &&
-	  (data = datasets->findFirstChildElement("xfa:data"))) {
-	elem = findFieldInDatasets(data, p + 5);
-	if (elem &&
-	    elem->getFirstChild() &&
-	    elem->getFirstChild()->isCharData() &&
-	    ((ZxCharData *)elem->getFirstChild())->getData()->getLength() > 0) {
-	  return ((ZxCharData *)elem->getFirstChild())->getData();
-	}
-      }
-    }
-  }
-
-  // check the <form> element
-  p = fullName->getCString();
-  if (xfaForm->xml->getRoot() && !strncmp(p, "form.",  5)) {
-    if ((formElem = xfaForm->xml->getRoot()->findFirstChildElement("form"))) {
-      elem = findFieldInFormElem(formElem, p + 5);
-      if (elem &&
-	  (valueElem = elem->findFirstChildElement("value")) &&
-	  (elem = valueElem->findFirstChildElement(valueChildType))) {
-	if (elem->getFirstChild() &&
-	    elem->getFirstChild()->isCharData() &&
-	    ((ZxCharData *)elem->getFirstChild())
-	    ->getData()->getLength() > 0) {
-	  return ((ZxCharData *)elem->getFirstChild())->getData();
-	}
-      }
-    }
-  }
-
-  // check the <value> element within the field
-  if ((valueElem = xml->findFirstChildElement("value")) &&
-      (elem = valueElem->findFirstChildElement(valueChildType))) {
-    if (elem->getFirstChild() &&
-	elem->getFirstChild()->isCharData() &&
-	((ZxCharData *)elem->getFirstChild())->getData()->getLength() > 0) {
-      return ((ZxCharData *)elem->getFirstChild())->getData();
-    }
-  }
-
-  return NULL;
-}
-
-ZxElement *XFAFormField::findFieldInDatasets(ZxElement *elem, char *partName) {
-  ZxNode *node;
-  ZxElement *result;
-  GString *nodeName;
-  char *next;
-  int curIdx, idx, n;
-
-  curIdx = 0;
-  for (node = elem->getFirstChild(); node; node = node->getNextChild()) {
-    if (node->isElement()) {
-      nodeName = ((ZxElement *)node)->getType();
-      n = nodeName->getLength();
-      if (!strncmp(partName, nodeName->getCString(), n)) { 
-	if (partName[n] == '[') {
-	  idx = atoi(partName + n + 1);
-	  if (idx == curIdx) {
-	    for (++n; partName[n] && partName[n-1] != ']'; ++n) ;
-	  } else {
-	    ++curIdx;
-	    continue;
-	  }
-	}
-	if (!partName[n]) {
-	  return (ZxElement *)node;
-	} else if (partName[n] == '.') {
-	  if ((result = findFieldInDatasets((ZxElement *)node,
-					    partName + n + 1))) {
-	    return result;
-	  }
-	  break;
-	}
-      }
-    }
-  }
-
-  // search for an "ancestor match"
-  if ((next = strchr(partName, '.'))) {
-    return findFieldInDatasets(elem, next + 1);
-  }
-
-  return NULL;
-}
-
-ZxElement *XFAFormField::findFieldInFormElem(ZxElement *elem, char *partName) {
-  ZxElement *elem2;
-  ZxNode *node;
-  ZxAttr *attr;
-  GString *nodeName;
-  int curIdx, idx, n;
-
-  curIdx = 0;
-  for (node = elem->getFirstChild(); node; node = node->getNextChild()) {
-    if ((node->isElement("subform") || node->isElement("field")) &&
-	((attr = ((ZxElement *)node)->findAttr("name")))) {
-      nodeName = attr->getValue();
-      n = nodeName->getLength();
-      if (!strncmp(partName, nodeName->getCString(), n)) { 
-	if (partName[n] == '[') {
-	  idx = atoi(partName + n + 1);
-	  if (idx == curIdx) {
-	    for (++n; partName[n] && partName[n-1] != ']'; ++n) ;
-	  } else {
-	    ++curIdx;
-	    continue;
-	  }
-	}
-	if (!partName[n]) {
-	  return (ZxElement *)node;
-	} else if (partName[n] == '.') {
-	  return findFieldInFormElem((ZxElement *)node, partName + n + 1);
-	}
-      }
-    } else if (node->isElement("subform")) {
-      if ((elem2 = findFieldInFormElem((ZxElement *)node, partName))) {
-	return elem2;
-      }
-    }
-  }
-  return NULL;
-}
-
-void XFAFormField::transform(int rot, double w, double h,
-			     double *wNew, double *hNew, GString *appearBuf) {
-  switch (rot) {
-  case 0:
-  default:
-    appearBuf->appendf("1 0 0 1 0 {0:.4f} cm\n", -h);
-    break;
-  case 90:
-    appearBuf->appendf("0 1 -1 0 {0:.4f} 0 cm\n", w);
-    *wNew = h;
-    *hNew = w;
-    break;
-  case 180:
-    appearBuf->appendf("-1 0 0 -1 {0:.4f} {1:.4f} cm\n", w, h);
-    *wNew = w;
-    *hNew = h;
-    break;
-  case 270:
-    appearBuf->appendf("0 -1 1 0 0 {0:.4f} cm\n", h);
-    *wNew = h;
-    *hNew = w;
-    break;
-  }
-}
-
-void XFAFormField::drawText(GString *text, GBool multiLine, int combCells,
-			    GString *fontName, GBool bold,
-			    GBool italic, double fontSize,
-			    XFAHorizAlign hAlign, XFAVertAlign vAlign,
-			    double x, double y, double w, double h,
-			    GBool whiteBackground,
-			    GfxFontDict *fontDict, GString *appearBuf) {
-  GString *text2;
-  GfxFont *font;
-  const char *fontTag;
-  GString *s;
-  Unicode u;
-  double yTop, xx, yy, tw, charWidth, lineHeight;
-  double ascent, descent, rectX, rectY, rectW, rectH, blkH;
-  int nLines, line, i, j, k, c, rectI;
-
-  // convert UTF-8 to Latin1
-  //~ this currently drops all non-Latin1 characters
-  text2 = new GString();
-  i = 0;
-  while (getUTF8(text, &i, &u)) {
-    if (u <= 0xff) {
-      text2->append((char)u);
-    } else {
-      text2->append('?');
-    }
-  }
-
-  // find the font
-  if ((font = findFont(fontDict, fontName, bold, italic))) {
-    fontTag = font->getTag()->getCString();
-    ascent = font->getAscent() * fontSize;
-    descent = font->getDescent() * fontSize;
-  } else {
-    error(errSyntaxError, -1, "Couldn't find a font for '{0:t}', {1:s}, {2:s} used in XFA field",
-	  fontName, bold ? "bold" : "non-bold",
-	  italic ? "italic" : "non-italic");
-    fontTag = "xpdf_default_font";
-    ascent = 0.718 * fontSize;
-    descent = -0.207 * fontSize;
-  }
-
-  // setup
-  rectW = rectH = 0;
-  rectI = appearBuf->getLength();
-  appearBuf->append("BT\n");
-  appearBuf->appendf("/{0:s} {1:.2f} Tf\n", fontTag, fontSize);
-
-  // multi-line text
-  if (multiLine) {
-
-    // compute line height
-    lineHeight = 1.2 * fontSize;
-
-    // handle bottom/middle alignment
-    if (vAlign == xfaVAlignBottom || vAlign == xfaVAlignMiddle) {
-      nLines = 0;
-      i = 0;
-      while (i < text2->getLength()) {
-	getNextLine(text2, i, font, fontSize, w, &j, &tw, &k);
-	++nLines;
-	i = k;
-      }
-      blkH = nLines * lineHeight - (lineHeight - fontSize);
-      if (vAlign == xfaVAlignBottom) {
-	yTop = y + blkH;
-      } else {
-	yTop = y + 0.5 * (h + blkH);
-      }
-      if (yTop > y + h) {
-	yTop = y + h;
-      }
-    } else {
-      yTop = y + h;
-    }
-
-    // write a series of lines of text
-    line = 0;
-    i = 0;
-    while (i < text2->getLength()) {
-
-      getNextLine(text2, i, font, fontSize, w, &j, &tw, &k);
-      if (tw > rectW) {
-	rectW = tw;
-      }
-
-      // compute text start position
-      switch (hAlign) {
-      case xfaHAlignLeft:
-      default:
-	xx = x;
-	break;
-      case xfaHAlignCenter:
-	xx = x + 0.5 * (w - tw);
-	break;
-      case xfaHAlignRight:
-	xx = x + w - tw;
-	break;
-      }
-      yy = yTop - line * lineHeight - ascent;
-
-      // draw the line
-      appearBuf->appendf("1 0 0 1 {0:.4f} {1:.4f} Tm\n", xx, yy);
-      appearBuf->append('(');
-      for (; i < j; ++i) {
-	c = text2->getChar(i) & 0xff;
-	if (c == '(' || c == ')' || c == '\\') {
-	  appearBuf->append('\\');
-	  appearBuf->append((char)c);
-	} else if (c < 0x20 || c >= 0x80) {
-	  appearBuf->appendf("\\{0:03o}", c);
-	} else {
-	  appearBuf->append((char)c);
-	}
-      }
-      appearBuf->append(") Tj\n");
-
-      // next line
-      i = k;
-      ++line;
-    }
-    rectH = line * lineHeight;
-    rectY = y + h - rectH;
- 
-  // comb formatting
-  } else if (combCells > 0) {
-
-    // compute comb spacing
-    tw = w / combCells;
-
-    // compute text start position
-    switch (hAlign) {
-    case xfaHAlignLeft:
-    default:
-      xx = x;
-      break;
-    case xfaHAlignCenter:
-      xx = x + (int)(0.5 * (combCells - text2->getLength())) * tw;
-      break;
-    case xfaHAlignRight:
-      xx = x + w - text2->getLength() * tw;
-      break;
-    }
-    rectW = text2->getLength() * tw;
-    switch (vAlign) {
-    case xfaVAlignTop:
-    default:
-      yy = y + h - ascent;
-      break;
-    case xfaVAlignMiddle:
-      yy = y + 0.5 * (h - (ascent + descent));
-      break;
-    case xfaVAlignBottom:
-      yy = y - descent;
-      break;
-    }
-    rectY = yy + descent;
-    rectH = ascent - descent;
-
-    // write the text string
-    for (i = 0; i < text2->getLength(); ++i) {
-      c = text2->getChar(i) & 0xff;
-      if (font && !font->isCIDFont()) {
-	charWidth = fontSize * ((Gfx8BitFont *)font)->getWidth((Guchar)c);
-	appearBuf->appendf("1 0 0 1 {0:.4f} {1:.4f} Tm\n",
-			   xx + i * tw + 0.5 * (tw - charWidth), yy);
-      } else {
-	appearBuf->appendf("1 0 0 1 {0:.4f} {1:.4f} Tm\n",
-			   xx + i * tw, yy);
-      }
-      appearBuf->append('(');
-      if (c == '(' || c == ')' || c == '\\') {
-	appearBuf->append('\\');
-	appearBuf->append((char)c);
-      } else if (c < 0x20 || c >= 0x80) {
-	appearBuf->appendf("{0:.4f} 0 Td\n", w);
-      } else {
-	appearBuf->append((char)c);
-      }
-      appearBuf->append(") Tj\n");
-    }
-
-  // regular (non-comb) formatting
-  } else {
-
-    // compute string width
-    if (font && !font->isCIDFont()) {
-      tw = 0;
-      for (i = 0; i < text2->getLength(); ++i) {
-	tw += ((Gfx8BitFont *)font)->getWidth(text2->getChar(i));
-      }
-    } else {
-      // otherwise, make a crude estimate
-      tw = text2->getLength() * 0.5;
-    }
-    tw *= fontSize;
-    rectW = tw;
-
-    // compute text start position
-    switch (hAlign) {
-    case xfaHAlignLeft:
-    default:
-      xx = x;
-      break;
-    case xfaHAlignCenter:
-      xx = x + 0.5 * (w - tw);
-      break;
-    case xfaHAlignRight:
-      xx = x + w - tw;
-      break;
-    }
-    switch (vAlign) {
-    case xfaVAlignTop:
-    default:
-      yy = y + h - ascent;
-      break;
-    case xfaVAlignMiddle:
-      yy = y + 0.5 * (h - (ascent + descent));
-      break;
-    case xfaVAlignBottom:
-      yy = y - descent;
-      break;
-    }
-    rectY = yy + descent;
-    rectH = ascent - descent;
-    appearBuf->appendf("{0:.4f} {1:.4f} Td\n", xx, yy);
-
-    // write the text string
-    appearBuf->append('(');
-    for (i = 0; i < text2->getLength(); ++i) {
-      c = text2->getChar(i) & 0xff;
-      if (c == '(' || c == ')' || c == '\\') {
-	appearBuf->append('\\');
-	appearBuf->append((char)c);
-      } else if (c < 0x20 || c >= 0x80) {
-	appearBuf->appendf("\\{0:03o}", c);
-      } else {
-	appearBuf->append((char)c);
-      }
-    }
-    appearBuf->append(") Tj\n");
-  }
-
-  // cleanup
-  appearBuf->append("ET\n");
-
-  // draw a white rectangle behind the text
-  if (whiteBackground) {
-    switch (hAlign) {
-    case xfaHAlignLeft:
-    default:
-      rectX = x;
-      break;
-    case xfaHAlignCenter:
-      rectX = x + 0.5 * (w - rectW);
-      break;
-    case xfaHAlignRight:
-      rectX = x + w - rectW;
-      break;
-    }
-    rectX -= 0.25 * fontSize;
-    rectW += 0.5 * fontSize;
-    rectY -= 0.1 * fontSize;
-    rectH += 0.2 * fontSize;
-    s = GString::format("q 1 g {0:.4f} {1:.4f} {2:.4f} {3:.4f} re f Q\n",
-			rectX, rectY, rectW, rectH);
-    appearBuf->insert(rectI, s);
-    delete s;
-  }
-
-  delete text2;
-}
-
-// Searches <fontDict> for a font matching(<fontName>, <bold>,
-// <italic>).
-GfxFont *XFAFormField::findFont(GfxFontDict *fontDict, GString *fontName,
-				GBool bold, GBool italic) {
-  GString *reqName, *testName;
-  GfxFont *font;
-  GBool foundName, foundBold, foundItalic;
-  char *p;
-  char c;
-  int i, j;
-
-  if (!fontDict) {
-    return NULL;
-  }
-
-  reqName = new GString();
-  for (i = 0; i < fontName->getLength(); ++i) {
-    c = fontName->getChar(i);
-    if (c != ' ') {
-      reqName->append(c);
-    }
-  }
-
-  for (i = 0; i < fontDict->getNumFonts(); ++i) {
-    font = fontDict->getFont(i);
-    if (!font || !font->getName()) {
-      continue;
-    }
-    testName = new GString();
-    for (j = 0; j < font->getName()->getLength(); ++j) {
-      c = font->getName()->getChar(j);
-      if (c != ' ') {
-	testName->append(c);
-      }
-    }
-    foundName = foundBold = foundItalic = gFalse;
-    for (p = testName->getCString(); *p; ++p) {
-      if (!strncasecmp(p, reqName->getCString(), reqName->getLength())) {
-	foundName = gTrue;
-      }
-      if (!strncasecmp(p, "bold", 4)) {
-	foundBold = gTrue;
-      }
-      if (!strncasecmp(p, "italic", 6) || !strncasecmp(p, "oblique", 7)) {
-	foundItalic = gTrue;
-      }
-    }
-    delete testName;
-    if (foundName && foundBold == bold && foundItalic == italic) {
-      delete reqName;
-      return font;
-    }
-  }
-
-  delete reqName;
-  return NULL;
-}
-
-// Searches the font resource dict for a font matching(<name>, <bold>,
-// <italic>), and returns the font object ID.  This does not require a
-// GfxFontDict, and it does not do any parsing of font objects beyond
-// looking at BaseFont.
-Ref XFAFormField::findFontName(GString *name, GBool bold, GBool italic) {
-  Object fontDictObj, fontObj, baseFontObj, fontRef;
-  Ref fontID;
-  GString *reqName, *testName;
-  GBool foundName, foundBold, foundItalic;
-  char *p;
-  char c;
-  int i;
-
-  fontID.num = fontID.gen = -1;
-
-  // remove space chars from the requested name
-  reqName = new GString();
-  for (i = 0; i < name->getLength(); ++i) {
-    c = name->getChar(i);
-    if (c != ' ') {
-      reqName->append(c);
-    }
-  }
-
-  if (xfaForm->resourceDict.isDict()) {
-    if (xfaForm->resourceDict.dictLookup("Font", &fontDictObj)->isDict()) {
-      for (i = 0; i < fontDictObj.dictGetLength() && fontID.num < 0; ++i) {
-	fontDictObj.dictGetVal(i, &fontObj);
-	if (fontObj.dictLookup("BaseFont", &baseFontObj)->isName()) {
-
-	  // remove space chars from the font name
-	  testName = new GString();
-	  for (p = baseFontObj.getName(); *p; ++p) {
-	    if (*p != ' ') {
-	      testName->append(p);
-	    }
-	  }
-
-	  // compare the names
-	  foundName = foundBold = foundItalic = gFalse;
-	  for (p = testName->getCString(); *p; ++p) {
-	    if (!strncasecmp(p, reqName->getCString(), reqName->getLength())) {
-	      foundName = gTrue;
-	    }
-	    if (!strncasecmp(p, "bold", 4)) {
-	      foundBold = gTrue;
-	    }
-	    if (!strncasecmp(p, "italic", 6) || !strncasecmp(p, "oblique", 7)) {
-	      foundItalic = gTrue;
-	    }
-	  }
-	  delete testName;
-	  if (foundName && foundBold == bold && foundItalic == italic) {
-	    if (fontObj.dictGetValNF(i, &fontRef)) {
-	      fontID = fontRef.getRef();
-	    }
-	    fontRef.free();
-	  }
-	}
-
-	baseFontObj.free();
-	fontObj.free();
-      }
-    }
-    fontDictObj.free();
-  }
-  delete reqName;
-
-  return fontID;
-}
-
-// Figure out how much text will fit on the next line.  Returns:
-// *end = one past the last character to be included
-// *width = width of the characters start .. end-1
-// *next = index of first character on the following line
-void XFAFormField::getNextLine(GString *text, int start,
-			       GfxFont *font, double fontSize, double wMax,
-			       int *end, double *width, int *next) {
-  double w, dw;
-  int j, k, c;
-
-  // figure out how much text will fit on the line
-  //~ what does Adobe do with tabs?
-  w = 0;
-  for (j = start; j < text->getLength() && w <= wMax; ++j) {
-    c = text->getChar(j) & 0xff;
-    if (c == 0x0a || c == 0x0d) {
-      break;
-    }
-    if (font && !font->isCIDFont()) {
-      dw = ((Gfx8BitFont *)font)->getWidth((Guchar)c) * fontSize;
-    } else {
-      // otherwise, make a crude estimate
-      dw = 0.5 * fontSize;
-    }
-    w += dw;
-  }
-  if (w > wMax) {
-    for (k = j; k > start && text->getChar(k-1) != ' '; --k) ;
-    for (; k > start && text->getChar(k-1) == ' '; --k) ;
-    if (k > start) {
-      j = k;
-    }
-    if (j == start) {
-      // handle the pathological case where the first character is
-      // too wide to fit on the line all by itself
-      j = start + 1;
-    }
-  }
-  *end = j;
-
-  // compute the width
-  w = 0;
-  for (k = start; k < j; ++k) {
-    if (font && !font->isCIDFont()) {
-      dw = ((Gfx8BitFont *)font)->getWidth(text->getChar(k)) * fontSize;
-    } else {
-      // otherwise, make a crude estimate
-      dw = 0.5 * fontSize;
-    }
-    w += dw;
-  }
-  *width = w;
-
-  // next line
-  while (j < text->getLength() && text->getChar(j) == ' ') {
-    ++j;
-  }
-  if (j < text->getLength() && text->getChar(j) == 0x0d) {
-    ++j;
-  }
-  if (j < text->getLength() && text->getChar(j) == 0x0a) {
-    ++j;
-  }
-  *next = j;
-}
-
-//------------------------------------------------------------------------
-// 'picture' formatting
-//------------------------------------------------------------------------
-
-class XFAPictureNode {
-public:
-  virtual ~XFAPictureNode() {}
-  virtual GBool isLiteral() { return gFalse; }
-  virtual GBool isSign() { return gFalse; }
-  virtual GBool isDigit() { return gFalse; }
-  virtual GBool isDecPt() { return gFalse; }
-  virtual GBool isSeparator() { return gFalse; }
-  virtual GBool isYear() { return gFalse; }
-  virtual GBool isMonth() { return gFalse; }
-  virtual GBool isDay() { return gFalse; }
-  virtual GBool isHour() { return gFalse; }
-  virtual GBool isMinute() { return gFalse; }
-  virtual GBool isSecond() { return gFalse; }
-  virtual GBool isChar() { return gFalse; }
-};
-
-class XFAPictureLiteral: public XFAPictureNode {
-public:
-  XFAPictureLiteral(GString *sA) { s = sA; }
-  virtual ~XFAPictureLiteral() { delete s; }
-  virtual GBool isLiteral() { return gTrue; }
-  GString *s;
-};
-
-class XFAPictureSign: public XFAPictureNode {
-public:
-  XFAPictureSign(char cA) { c = cA; }
-  virtual GBool isSign() { return gTrue; }
-  char c;
-};
-
-class XFAPictureDigit: public XFAPictureNode {
-public:
-  XFAPictureDigit(char cA) { c = cA; pos = 0; }
-  virtual GBool isDigit() { return gTrue; }
-  char c;
-  int pos;
-};
-
-class XFAPictureDecPt: public XFAPictureNode {
-public:
-  XFAPictureDecPt() { }
-  virtual GBool isDecPt() { return gTrue; }
-};
-
-class XFAPictureSeparator: public XFAPictureNode {
-public:
-  XFAPictureSeparator() { }
-  virtual GBool isSeparator() { return gTrue; }
-};
-
-class XFAPictureYear: public XFAPictureNode {
-public:
-  XFAPictureYear(int nDigitsA) { nDigits = nDigitsA; }
-  virtual GBool isYear() { return gTrue; }
-  int nDigits;
-};
-
-class XFAPictureMonth: public XFAPictureNode {
-public:
-  XFAPictureMonth(int nDigitsA) { nDigits = nDigitsA; }
-  virtual GBool isMonth() { return gTrue; }
-  int nDigits;
-};
-
-class XFAPictureDay: public XFAPictureNode {
-public:
-  XFAPictureDay(int nDigitsA) { nDigits = nDigitsA; }
-  virtual GBool isDay() { return gTrue; }
-  int nDigits;
-};
-
-class XFAPictureHour: public XFAPictureNode {
-public:
-  XFAPictureHour(GBool is24HourA, int nDigitsA)
-    { is24Hour = is24HourA; nDigits = nDigitsA; }
-  virtual GBool isHour() { return gTrue; }
-  GBool is24Hour;
-  int nDigits;
-};
-
-class XFAPictureMinute: public XFAPictureNode {
-public:
-  XFAPictureMinute(int nDigitsA) { nDigits = nDigitsA; }
-  virtual GBool isMinute() { return gTrue; }
-  int nDigits;
-};
-
-class XFAPictureSecond: public XFAPictureNode {
-public:
-  XFAPictureSecond(int nDigitsA) { nDigits = nDigitsA; }
-  virtual GBool isSecond() { return gTrue; }
-  int nDigits;
-};
-
-class XFAPictureChar: public XFAPictureNode {
-public:
-  XFAPictureChar() {}
-  virtual GBool isChar() { return gTrue; }
-};
-
-GString *XFAFormField::pictureFormatDateTime(GString *value, GString *picture) {
-  GList *pic;
-  XFAPictureNode *node;
-  GString *ret, *s;
-  char c;
-  int year, month, day, hour, min, sec;
-  int len, picStart, picEnd, u, n, i, j;
-
-  len = value->getLength();
-  if (len == 0) {
-    return value->copy();
-  }
-
-  //--- parse the value
-
-  // expected format is yyyy(-mm(-dd)?)?Thh(:mm(:ss)?)?
-  // where:
-  // - the '-'s and ':'s are optional
-  // - the 'T' is literal
-  // - we're ignoring optional time zone info at the end
-  // (if the value is not in this canonical format, we just punt and
-  // return the value string)
-  //~ another option would be to parse the value following the
-  //~   <ui><picture> element
-  year = month = day = hour = min = sec = 0;
-  i = 0;
-  if (!(i + 4 <= len && isValidInt(value, i, 4))) {
-    return value->copy();
-  }
-  year = convertInt(value, i, 4);
-  i += 4;
-  if (i < len && value->getChar(i) == '-') {
-    ++i;
-  }
-  if (i + 2 <= len && isValidInt(value, i, 2)) {
-    month = convertInt(value, i, 2);
-    i += 2;
-    if (i < len && value->getChar(i) == '-') {
-      ++i;
-    }
-    if (i + 2 <= len && isValidInt(value, i, 2)) {
-      day = convertInt(value, i, 2);
-      i += 2;
-    }
-  }
-  if (i < len) {
-    if (value->getChar(i) != 'T') {
-      return value->copy();
-    }
-    ++i;
-    if (!(i + 2 <= len && isValidInt(value, i, 2))) {
-      return value->copy();
-    }
-    hour = convertInt(value, i, 2);
-    i += 2;
-    if (i < len && value->getChar(i) == ':') {
-      ++i;
-    }
-    if (i + 2 <= len && isValidInt(value, i, 2)) {
-      min = convertInt(value, i, 2);
-      i += 2;
-      if (i < len && value->getChar(i) == ':') {
-	++i;
-      }
-      if (i + 2 <= len && isValidInt(value, i, 2)) {
-	sec = convertInt(value, i, 2);
-	i += 2;
-      }
-    }
-  }
-  if (i < len) {
-    return value->copy();
-  }
-
-  //--- skip the category and locale in the picture
-
-  picStart = 0;
-  picEnd = picture->getLength();
-  for (i = 0; i < picture->getLength(); ++i) {
-    c = picture->getChar(i);
-    if (c == '{') {
-      picStart = i + 1;
-      for (picEnd = picStart;
-	   picEnd < picture->getLength() && picture->getChar(picEnd) != '}';
-	   ++picEnd) ;
-      break;
-    } else if (!((c >= 'a' && c <= 'z') ||
-		 (c >= 'A' && c <= 'Z') ||
-		 c == '(' ||
-		 c == ')')) {
-      break;
-    }
-  }
-
-  //--- parse the picture
-
-  pic = new GList();
-  i = picStart;
-  while (i < picEnd) {
-    c = picture->getChar(i);
-    ++i;
-    if (c == '\'') {
-      s = new GString();
-      while (i < picEnd) {
-	c = picture->getChar(i);
-	if (c == '\'') {
-	  ++i;
-	  if (i < picEnd && picture->getChar(i) == '\'') {
-	    s->append('\'');
-	    ++i;
-	  } else {
-	    break;
-	  }
-	} else if (c == '\\') {
-	  ++i;
-	  if (i == picEnd) {
-	    break;
-	  }
-	  c = picture->getChar(i);
-	  ++i;
-	  if (c == 'u' && i+4 <= picEnd) {
-	    u = 0;
-	    for (j = 0; j < 4; ++j, ++i) {
-	      c = picture->getChar(i);
-	      u <<= 4;
-	      if (c >= '0' && c <= '9') {
-		u += c - '0';
-	      } else if (c >= 'a' && c <= 'f') {
-		u += c - 'a' + 10;
-	      } else if (c >= 'A' && c <= 'F') {
-		u += c - 'A' + 10;
-	      }
-	    }
-	    //~ this should convert to UTF-8 (?)
-	    if (u <= 0xff) {
-	      s->append((char)u);
-	    }
-	  } else {
-	    s->append(c);
-	  }
-	} else {
-	  s->append(c);
-	}
-      }
-      pic->append(new XFAPictureLiteral(s));
-    } else if (c == ',' || c == '-' || c == ':' ||
-	       c == '/' || c == '.' || c == ' ') {
-      s = new GString();
-      s->append(c);
-      pic->append(new XFAPictureLiteral(s));
-    } else if (c == 'Y') {
-      for (n = 1; n < 4 && i < picEnd && picture->getChar(i) == 'Y'; ++n, ++i) ;
-      pic->append(new XFAPictureYear(n));
-    } else if (c == 'M') {
-      for (n = 1; n < 2 && i < picEnd && picture->getChar(i) == 'M'; ++n, ++i) ;
-      pic->append(new XFAPictureMonth(n));
-    } else if (c == 'D') {
-      for (n = 1; n < 2 && i < picEnd && picture->getChar(i) == 'D'; ++n, ++i) ;
-      pic->append(new XFAPictureDay(n));
-    } else if (c == 'h') {
-      for (n = 1; n < 2 && i < picEnd && picture->getChar(i) == 'h'; ++n, ++i) ;
-      pic->append(new XFAPictureHour(gFalse, n));
-    } else if (c == 'H') {
-      for (n = 1; n < 2 && i < picEnd && picture->getChar(i) == 'H'; ++n, ++i) ;
-      pic->append(new XFAPictureHour(gTrue, n));
-    } else if (c == 'M') {
-      for (n = 1; n < 2 && i < picEnd && picture->getChar(i) == 'M'; ++n, ++i) ;
-      pic->append(new XFAPictureMinute(n));
-    } else if (c == 'S') {
-      for (n = 1; n < 2 && i < picEnd && picture->getChar(i) == 'S'; ++n, ++i) ;
-      pic->append(new XFAPictureSecond(n));
-    }
-  }
-
-  //--- generate formatted text
-
-  ret = new GString();
-  for (i = 0; i < pic->getLength(); ++i) {
-    node = (XFAPictureNode *)pic->get(i);
-    if (node->isLiteral()) {
-      ret->append(((XFAPictureLiteral *)node)->s);
-    } else if (node->isYear()) {
-      if (((XFAPictureYear *)node)->nDigits == 2) {
-	if (year >= 1930 && year < 2030) {
-	  ret->appendf("{0:02d}", year % 100);
-	} else {
-	  ret->append("??");
-	}
-      } else {
-	ret->appendf("{0:04d}", year);
-      }
-    } else if (node->isMonth()) {
-      if (((XFAPictureMonth *)node)->nDigits == 1) {
-	ret->appendf("{0:d}", month);
-      } else {
-	ret->appendf("{0:02d}", month);
-      }
-    } else if (node->isDay()) {
-      if (((XFAPictureDay *)node)->nDigits == 1) {
-	ret->appendf("{0:d}", day);
-      } else {
-	ret->appendf("{0:02d}", day);
-      }
-    } else if (node->isHour()) {
-      if (((XFAPictureHour *)node)->is24Hour) {
-	n = hour;
-      } else {
-	n = hour % 12;
-	if (n == 0) {
-	  n = 12;
-	}
-      }
-      if (((XFAPictureHour *)node)->nDigits == 1) {
-	ret->appendf("{0:d}", n);
-      } else {
-	ret->appendf("{0:02d}", n);
-      }
-    } else if (node->isMinute()) {
-      if (((XFAPictureMinute *)node)->nDigits == 1) {
-	ret->appendf("{0:d}", min);
-      } else {
-	ret->appendf("{0:02d}", min);
-      }
-    } else if (node->isSecond()) {
-      if (((XFAPictureSecond *)node)->nDigits == 1) {
-	ret->appendf("{0:d}", sec);
-      } else {
-	ret->appendf("{0:02d}", sec);
-      }
-    }
-  }
-  deleteGList(pic, XFAPictureNode);
-
-  return ret;
-}
-
-GString *XFAFormField::pictureFormatNumber(GString *value, GString *picture) {
-  GList *pic;
-  XFAPictureNode *node;
-  GString *ret, *s;
-  GBool neg, haveDigits;
-  char c;
-  int start, decPt, trailingZero, len;
-  int picStart, picEnd, u, pos, i, j;
-
-  len = value->getLength();
-  if (len == 0) {
-    return value->copy();
-  }
-
-  //--- parse the value
-
-  // -nnnn.nnnn0000
-  //  ^   ^    ^   ^
-  //  |   |    |   +-- len
-  //  |   |    +------ trailingZero
-  //  |   +----------- decPt
-  //  +--------------- start
-  start = 0;
-  neg = gFalse;
-  if (value->getChar(start) == '-') {
-    neg = gTrue;
-    ++start;
-  } else if (value->getChar(start) == '+') {
-    ++start;
-  }
-  for (decPt = start; decPt < len && value->getChar(decPt) != '.'; ++decPt) ;
-  for (trailingZero = len;
-       trailingZero > decPt && value->getChar(trailingZero - 1) == '0';
-       --trailingZero) ;
-
-  //--- skip the category and locale in the picture
-
-  picStart = 0;
-  picEnd = picture->getLength();
-  for (i = 0; i < picture->getLength(); ++i) {
-    c = picture->getChar(i);
-    if (c == '{') {
-      picStart = i + 1;
-      for (picEnd = picStart;
-	   picEnd < picture->getLength() && picture->getChar(picEnd) != '}';
-	   ++picEnd) ;
-      break;
-    } else if (!((c >= 'a' && c <= 'z') ||
-		 (c >= 'A' && c <= 'Z') ||
-		 c == '(' ||
-		 c == ')')) {
-      break;
-    }
-  }
-
-  //--- parse the picture
-
-  pic = new GList();
-  i = picStart;
-  while (i < picEnd) {
-    c = picture->getChar(i);
-    ++i;
-    if (c == '\'') {
-      s = new GString();
-      while (i < picEnd) {
-	c = picture->getChar(i);
-	if (c == '\'') {
-	  ++i;
-	  if (i < picEnd && picture->getChar(i) == '\'') {
-	    s->append('\'');
-	    ++i;
-	  } else {
-	    break;
-	  }
-	} else if (c == '\\') {
-	  ++i;
-	  if (i == picEnd) {
-	    break;
-	  }
-	  c = picture->getChar(i);
-	  ++i;
-	  if (c == 'u' && i+4 <= picEnd) {
-	    u = 0;
-	    for (j = 0; j < 4; ++j, ++i) {
-	      c = picture->getChar(i);
-	      u <<= 4;
-	      if (c >= '0' && c <= '9') {
-		u += c - '0';
-	      } else if (c >= 'a' && c <= 'F') {
-		u += c - 'a' + 10;
-	      } else if (c >= 'A' && c <= 'F') {
-		u += c - 'A' + 10;
-	      }
-	    }
-	    //~ this should convert to UTF-8 (?)
-	    if (u <= 0xff) {
-	      s->append((char)u);
-	    }
-	  } else {
-	    s->append(c);
-	  }
-	} else {
-	  s->append(c);
-	  ++i;
-	}
-      }
-      pic->append(new XFAPictureLiteral(s));
-    } else if (c == '-' || c == ':' || c == '/' || c == ' ') {
-      s = new GString();
-      s->append(c);
-      pic->append(new XFAPictureLiteral(s));
-    } else if (c == 's' || c == 'S') {
-      pic->append(new XFAPictureSign(c));
-    } else if (c == 'Z' || c == 'z' || c == '8' || c == '9') {
-      pic->append(new XFAPictureDigit(c));
-    } else if (c == '.') {
-      pic->append(new XFAPictureDecPt());
-    } else if (c == ',') {
-      pic->append(new XFAPictureSeparator());
-    }
-  }
-  for (i = 0; i < pic->getLength(); ++i) {
-    node = (XFAPictureNode *)pic->get(i);
-    if (node->isDecPt()) {
-      break;
-    }
-  }
-  pos = 0;
-  for (j = i - 1; j >= 0; --j) {
-    node = (XFAPictureNode *)pic->get(j);
-    if (node->isDigit()) {
-      ((XFAPictureDigit *)node)->pos = pos;
-      ++pos;
-    }
-  }
-  pos = -1;
-  for (j = i + 1; j < pic->getLength(); ++j) {
-    node = (XFAPictureNode *)pic->get(j);
-    if (node->isDigit()) {
-      ((XFAPictureDigit *)node)->pos = pos;
-      --pos;
-    }
-  }
-
-  //--- generate formatted text
-
-  ret = new GString();
-  haveDigits = gFalse;
-  for (i = 0; i < pic->getLength(); ++i) {
-    node = (XFAPictureNode *)pic->get(i);
-    if (node->isLiteral()) {
-      ret->append(((XFAPictureLiteral *)node)->s);
-    } else if (node->isSign()) {
-      if (((XFAPictureSign *)node)->c == 'S') {
-	ret->append(neg ? '-' : ' ');
-      } else {
-	if (neg) {
-	  ret->append('-');
-	}
-      }
-    } else if (node->isDigit()) {
-      pos = ((XFAPictureDigit *)node)->pos;
-      c = ((XFAPictureDigit *)node)->c;
-      if (pos >= 0 && pos < decPt - start) {
-	ret->append(value->getChar(decPt - 1 - pos));
-	haveDigits = gTrue;
-      } else if (pos < 0 && -pos <= trailingZero - decPt - 1) {
-	ret->append(value->getChar(decPt - pos));
-	haveDigits = gTrue;
-      } else if (c == '8' &&
-		 pos < 0 &&
-		 -pos <= len - decPt - 1) {
-	ret->append('0');
-	haveDigits = gTrue;
-      } else if (c == '9') {
-	ret->append('0');
-	haveDigits = gTrue;
-      } else if (c == 'Z' && pos >= 0) {
-	ret->append(' ');
-      }
-    } else if (node->isDecPt()) {
-      if (!(i+1 < pic->getLength() &&
-	    ((XFAPictureNode *)pic->get(i+1))->isDigit() &&
-	    ((XFAPictureDigit *)pic->get(i+1))->c == 'z') ||
-	  trailingZero > decPt + 1) {
-	ret->append('.');
-      }
-    } else if (node->isSeparator()) {
-      if (haveDigits) {
-	ret->append(',');
-      }
-    }
-  }
-  deleteGList(pic, XFAPictureNode);
-
-  return ret;
-}
-
-GString *XFAFormField::pictureFormatText(GString *value, GString *picture) {
-  GList *pic;
-  XFAPictureNode *node;
-  GString *ret, *s;
-  char c;
-  int len, picStart, picEnd, u, i, j;
-
-  len = value->getLength();
-  if (len == 0) {
-    return value->copy();
-  }
-
-  //--- skip the category and locale in the picture
-
-  picStart = 0;
-  picEnd = picture->getLength();
-  for (i = 0; i < picture->getLength(); ++i) {
-    c = picture->getChar(i);
-    if (c == '{') {
-      picStart = i + 1;
-      for (picEnd = picStart;
-	   picEnd < picture->getLength() && picture->getChar(picEnd) != '}';
-	   ++picEnd) ;
-      break;
-    } else if (!((c >= 'a' && c <= 'z') ||
-		 (c >= 'A' && c <= 'Z') ||
-		 c == '(' ||
-		 c == ')')) {
-      break;
-    }
-  }
-
-  //--- parse the picture
-
-  pic = new GList();
-  i = picStart;
-  while (i < picEnd) {
-    c = picture->getChar(i);
-    ++i;
-    if (c == '\'') {
-      s = new GString();
-      while (i < picEnd) {
-	c = picture->getChar(i);
-	if (c == '\'') {
-	  ++i;
-	  if (i < picEnd && picture->getChar(i) == '\'') {
-	    s->append('\'');
-	    ++i;
-	  } else {
-	    break;
-	  }
-	} else if (c == '\\') {
-	  ++i;
-	  if (i == picEnd) {
-	    break;
-	  }
-	  c = picture->getChar(i);
-	  ++i;
-	  if (c == 'u' && i+4 <= picEnd) {
-	    u = 0;
-	    for (j = 0; j < 4; ++j, ++i) {
-	      c = picture->getChar(i);
-	      u <<= 4;
-	      if (c >= '0' && c <= '9') {
-		u += c - '0';
-	      } else if (c >= 'a' && c <= 'F') {
-		u += c - 'a' + 10;
-	      } else if (c >= 'A' && c <= 'F') {
-		u += c - 'A' + 10;
-	      }
-	    }
-	    //~ this should convert to UTF-8 (?)
-	    if (u <= 0xff) {
-	      s->append((char)u);
-	    }
-	  } else {
-	    s->append(c);
-	  }
-	} else {
-	  s->append(c);
-	  ++i;
-	}
-      }
-      pic->append(new XFAPictureLiteral(s));
-    } else if (c == ',' || c == '-' || c == ':' ||
-	       c == '/' || c == '.' || c == ' ') {
-      s = new GString();
-      s->append(c);
-      pic->append(new XFAPictureLiteral(s));
-    } else if (c == 'A' || c == 'X' || c == 'O' || c == '0' || c == '9') {
-      pic->append(new XFAPictureChar());
-    }
-  }
-
-  //--- generate formatted text
-
-  ret = new GString();
-  j = 0;
-  for (i = 0; i < pic->getLength(); ++i) {
-    node = (XFAPictureNode *)pic->get(i);
-    if (node->isLiteral()) {
-      ret->append(((XFAPictureLiteral *)node)->s);
-    } else if (node->isChar()) {
-      // if there are more chars in the picture than in the value,
-      // Adobe renders the value as-is, without picture formatting
-      if (j >= value->getLength()) {
-	delete ret;
-	ret = value->copy();
-	break;
-      }
-      ret->append(value->getChar(j));
-      ++j;
-    }
-  }
-  deleteGList(pic, XFAPictureNode);
-
-  return ret;
-}
-
-GBool XFAFormField::isValidInt(GString *s, int start, int len) {
-  int i;
-
-  for (i = 0; i < len; ++i) {
-    if (!(start + i < s->getLength() &&
-	  s->getChar(start + i) >= '0' &&
-	  s->getChar(start + i) <= '9')) {
-      return gFalse;
-    }
-  }
-  return gTrue;
-}
-
-int XFAFormField::convertInt(GString *s, int start, int len) {
-  char c;
-  int x, i;
-
-  x = 0;
-  for (i = 0; i < len && start + i < s->getLength(); ++i) {
-    c = s->getChar(start + i);
-    if (c < '0' || c > '9') {
-      break;
-    }
-    x = x * 10 + (c - '0');
-  }
-  return x;
-}

Deleted: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/XFAForm.h
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/XFAForm.h	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/XFAForm.h	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,181 +0,0 @@
-//========================================================================
-//
-// XFAForm.h
-//
-// Copyright 2012 Glyph & Cog, LLC
-//
-//========================================================================
-
-#ifndef XFAFORM_H
-#define XFAFORM_H
-
-#include <aconf.h>
-
-#ifdef USE_GCC_PRAGMAS
-#pragma interface
-#endif
-
-#include "Form.h"
-
-class GHash;
-class XFATableInfo;
-class ZxDoc;
-class ZxElement;
-class ZxAttr;
-
-//------------------------------------------------------------------------
-
-enum XFAHorizAlign {
-  xfaHAlignLeft,
-  xfaHAlignCenter,
-  xfaHAlignRight
-};
-
-enum XFAVertAlign {
-  xfaVAlignTop,
-  xfaVAlignBottom,
-  xfaVAlignMiddle
-};
-
-//------------------------------------------------------------------------
-
-class XFAForm: public Form {
-public:
-
-  static XFAForm *load(PDFDoc *docA, Catalog *catalog,
-		       Object *acroFormObj, Object *xfaObj);
-
-  virtual ~XFAForm();
-
-  virtual const char *getType() { return "XFA"; }
-
-  virtual void draw(int pageNum, Gfx *gfx, GBool printing);
-
-  virtual int getNumFields();
-  virtual FormField *getField(int idx);
-
-private:
-
-  XFAForm(PDFDoc *docA, int nPagesA, ZxDoc *xmlA,
-	  Object *resourceDictA, GBool fullXFAA);
-  void scanNode(ZxElement *elem,
-		GString *parentName, GString *parentFullName,
-		GBool inPageSet, XFATableInfo *tableInfo,
-		GHash *nameCount, GHash *nameIdx,
-		GHash *fullNameCount, GHash *fullNameIdx,
-		GString *exclGroupName, Catalog *catalog);
-  void scanNames(ZxElement *elem, GHash *nameCount);
-  void scanFullNames(ZxElement *elem, GHash *fullNameCount);
-  void scanField(ZxElement *elem, GString *name, GString *fullName,
-		 GString *exclGroupName, GBool inPageSet,
-		 XFATableInfo *tableInfo, int colSpan,
-		 Catalog *catalog);
-  void scanNonField(ZxElement *elem, GString *name, GString *fullName,
-		    GBool inPageSet,
-		    XFATableInfo *tableInfo, int colSpan,
-		    GHash *nameCount, GHash *nameIdx,
-		    GHash *fullNameCount, GHash *fullNameIdx,
-		    Catalog *catalog);
-  GString *getNodeName(ZxElement *elem);
-  GString *getNodeFullName(ZxElement *elem);
-  GBool nodeIsBindGlobal(ZxElement *elem);
-
-  ZxDoc *xml;
-  GList *fields;		// [XFAFormField]
-  Object resourceDict;
-  GBool fullXFA;		// true for "Full XFA", false for
-				//   "XFA Foreground"
-  int nPages;			// number of pages in PDF file
-  double *pageOffsetX,		// x,y offset for each page
-         *pageOffsetY;
-  int pageSetNPages;		// number of pages in pageSet element
-  int curPageNum;		// current page number - used by scanFields()
-  double curXOffset,		// current x,y offset - used by scanFields()
-         curYOffset;
-
-  friend class XFAFormField;
-};
-
-//------------------------------------------------------------------------
-
-class XFAFormField: public FormField {
-public:
-
-  XFAFormField(XFAForm *xfaFormA, ZxElement *xmlA,
-	       GString *nameA, GString *fullNameA, GString *exclGroupNameA,
-	       int pageNumA, double xOffsetA, double yOffsetA,
-	       double columnWidthA, double rowHeightA);
-
-  virtual ~XFAFormField();
-
-  virtual int getPageNum();
-  virtual const char *getType();
-  virtual Unicode *getName(int *length);
-  virtual Unicode *getValue(int *length);
-  virtual void getBBox(double *llx, double *lly, double *urx, double *ury);
-  virtual void getFont(Ref *fontID, double *fontSize);
-  virtual void getColor(double *red, double *green, double *blue);
-
-  virtual Object *getResources(Object *res);
-
-private:
-
-  Unicode *utf8ToUnicode(GString *s, int *length);
-  void draw(int pageNumA, Gfx *gfx, GBool printing, GfxFontDict *fontDict);
-  void getRectangle(double *xfaX, double *xfaY,
-		    double *xfaW, double *xfaH,
-		    double *pdfX, double *pdfY,
-		    double *pdfW, double *pdfH,
-		    int *pdfRot);
-  void drawTextEdit(GfxFontDict *fontDict,
-		    double w, double h, int rot,
-		    GString *appearBuf);
-  void drawCheckButton(GfxFontDict *fontDict,
-		       double w, double h, int rot,
-		       GString *appearBuf);
-  void drawBarCode(GfxFontDict *fontDict,
-		   double w, double h, int rot,
-		   GString *appearBuf);
-  static double getMeasurement(ZxAttr *attr, double defaultVal);
-  static double getMeasurement(GString *s, int begin);
-  GString *getFieldValue(const char *valueChildType);
-  ZxElement *findFieldInDatasets(ZxElement *elem, char *partName);
-  ZxElement *findFieldInFormElem(ZxElement *elem, char *partName);
-  void transform(int rot, double w, double h,
-		 double *wNew, double *hNew, GString *appearBuf);
-  void drawText(GString *text, GBool multiLine, int combCells,
-		GString *fontName, GBool bold,
-		GBool italic, double fontSize,
-		XFAHorizAlign hAlign, XFAVertAlign vAlign,
-		double x, double y, double w, double h,
-		GBool whiteBackground,
-		GfxFontDict *fontDict, GString *appearBuf);
-  GfxFont *findFont(GfxFontDict *fontDict, GString *fontName,
-		    GBool bold, GBool italic);
-  Ref findFontName(GString *name, GBool bold, GBool italic);
-  void getNextLine(GString *text, int start,
-		   GfxFont *font, double fontSize, double wMax,
-		   int *end, double *width, int *next);
-  GString *pictureFormatDateTime(GString *value, GString *picture);
-  GString *pictureFormatNumber(GString *value, GString *picture);
-  GString *pictureFormatText(GString *value, GString *picture);
-  GBool isValidInt(GString *s, int start, int len);
-  int convertInt(GString *s, int start, int len);
-
-  XFAForm *xfaForm;
-  ZxElement *xml;
-  GString *name;
-  GString *fullName;
-  GString *exclGroupName;
-  int pageNum;
-  double xOffset, yOffset;
-  double columnWidth;		// column width, if this field is in a
-				//   table; otherwise zero
-  double rowHeight;		// row height, if this field is in a
-				//   table; otherwise zero
-
-  friend class XFAForm;
-  friend class XFATableInfo;
-};
-
-#endif

Added: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/XFAScanner.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/XFAScanner.cc	                        (rev 0)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/XFAScanner.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -0,0 +1,675 @@
+//========================================================================
+//
+// XFAScanner.cc
+//
+// Copyright 2020 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include "GString.h"
+#include "GHash.h"
+#include "Object.h"
+#include "Error.h"
+#include "Zoox.h"
+#include "XFAScanner.h"
+
+//------------------------------------------------------------------------
+
+// fields have two names:
+//
+// name:
+//   - nodes with bind=global set the index to 0 ("foo[0]") regardless
+//     of the number of nodes with the same name
+//   - nodes with bind=none are dropped from the name
+//   - <area> nodes are dropped from the name
+//   - used for field value lookup in <xfa:datasets>
+//
+// fullName:
+//   - all named nodes are treated the same, regardless of bind=global
+//     or bind=none
+//   - <area> nodes are included in the name, but don't reset the
+//     numbering (i.e., <area> nodes are "transparent" with respect to
+//     node numbering)
+//   - used for field value lookup in <form>
+//   - used for matching with AcroForm names
+//
+// Both names use indexes on all nodes, even if there's only one node
+// with the name -- this isn't correct for XFA naming, but it matches
+// the AcroForm behavior.
+
+//------------------------------------------------------------------------
+
+XFAFieldLayoutInfo::XFAFieldLayoutInfo(XFAFieldLayoutHAlign hAlignA,
+				       XFAFieldLayoutVAlign vAlignA) {
+  hAlign = hAlignA;
+  vAlign = vAlignA;
+}
+
+//------------------------------------------------------------------------
+
+XFAFieldPictureInfo::XFAFieldPictureInfo(XFAFieldPictureSubtype subtypeA,
+					 GString *formatA) {
+  subtype = subtypeA;
+  format = formatA;
+}
+
+XFAFieldPictureInfo::~XFAFieldPictureInfo() {
+  delete format;
+}
+
+//------------------------------------------------------------------------
+
+XFAFieldBarcodeInfo::XFAFieldBarcodeInfo(GString *barcodeTypeA,
+					 double wideNarrowRatioA,
+					 double moduleWidthA,
+					 double moduleHeightA,
+					 int dataLengthA,
+					 int errorCorrectionLevelA,
+					 GString *textLocationA) {
+  barcodeType = barcodeTypeA;
+  wideNarrowRatio = wideNarrowRatioA;
+  moduleWidth = moduleWidthA;
+  moduleHeight = moduleHeightA;
+  dataLength = dataLengthA;
+  errorCorrectionLevel = errorCorrectionLevelA;
+  textLocation = textLocationA;
+}
+
+XFAFieldBarcodeInfo::~XFAFieldBarcodeInfo() {
+  delete barcodeType;
+  delete textLocation;
+}
+
+//------------------------------------------------------------------------
+
+XFAField::XFAField(GString *nameA, GString *fullNameA, GString *valueA,
+		   XFAFieldLayoutInfo *layoutInfoA,
+		   XFAFieldPictureInfo *pictureInfoA,
+		   XFAFieldBarcodeInfo *barcodeInfoA)
+  : name(nameA)
+  , fullName(fullNameA)
+  , value(valueA)
+  , layoutInfo(layoutInfoA)
+  , pictureInfo(pictureInfoA)
+  , barcodeInfo(barcodeInfoA)
+{
+}
+
+XFAField::~XFAField() {
+  delete name;
+  delete fullName;
+  delete value;
+  delete layoutInfo;
+  delete pictureInfo;
+  delete barcodeInfo;
+}
+
+//------------------------------------------------------------------------
+
+XFAScanner *XFAScanner::load(Object *xfaObj) {
+  GString *xfaData = readXFAStreams(xfaObj);
+  if (!xfaData) {
+    return NULL;
+  }
+  ZxDoc *xml = ZxDoc::loadMem(xfaData->getCString(), xfaData->getLength());
+  delete xfaData;
+  if (!xml) {
+    error(errSyntaxError, -1, "Invalid XML in XFA form");
+    return NULL;
+  }
+
+  XFAScanner *scanner = new XFAScanner();
+
+  if (xml->getRoot()) {
+    GHash *formValues = scanner->scanFormValues(xml->getRoot());
+    ZxElement *dataElem = NULL;
+    ZxElement *datasets =
+        xml->getRoot()->findFirstChildElement("xfa:datasets");
+    if (datasets) {
+      dataElem = datasets->findFirstChildElement("xfa:data");
+    }
+    ZxElement *tmpl = xml->getRoot()->findFirstChildElement("template");
+    if (tmpl) {
+      scanner->scanNode(tmpl, NULL, NULL, NULL, NULL, NULL,
+			dataElem, formValues);
+    }
+    deleteGHash(formValues, GString);
+  }
+
+  delete xml;
+
+  return scanner;
+}
+
+XFAScanner::XFAScanner() {
+  fields = new GHash();
+}
+
+XFAScanner::~XFAScanner() {
+  deleteGHash(fields, XFAField);
+}
+
+XFAField *XFAScanner::findField(GString *acroFormFieldName) {
+  return (XFAField *)fields->lookup(acroFormFieldName);
+}
+
+GString *XFAScanner::readXFAStreams(Object *xfaObj) {
+  GString *data = new GString();
+  char buf[4096];
+  int n;
+  if (xfaObj->isStream()) {
+    xfaObj->streamReset();
+    while ((n = xfaObj->getStream()->getBlock(buf, sizeof(buf))) > 0) {
+      data->append(buf, n);
+    }
+  } else if (xfaObj->isArray()) {
+    for (int i = 1; i < xfaObj->arrayGetLength(); i += 2) {
+      Object obj;
+      if (!xfaObj->arrayGet(i, &obj)->isStream()) {
+	error(errSyntaxError, -1, "XFA array element is wrong type");
+	obj.free();
+	delete data;
+	return NULL;
+      }
+      obj.streamReset();
+      while ((n = obj.getStream()->getBlock(buf, sizeof(buf))) > 0) {
+	data->append(buf, n);
+      }
+      obj.free();
+    }
+  } else {
+    error(errSyntaxError, -1, "XFA object is wrong type");
+    return NULL;
+  }
+  return data;
+}
+
+GHash *XFAScanner::scanFormValues(ZxElement *xmlRoot) {
+  GHash *formValues = new GHash(gTrue);
+  ZxElement *formElem = xmlRoot->findFirstChildElement("form");
+  if (formElem) {
+    scanFormNode(formElem, NULL, formValues);
+  }
+  return formValues;
+}
+
+void XFAScanner::scanFormNode(ZxElement *elem, GString *fullName,
+			      GHash *formValues) {
+  GHash *fullNameIdx = new GHash();
+  for (ZxNode *node = elem->getFirstChild();
+       node;
+       node = node->getNextChild()) {
+    if (node->isElement("value")) {
+      if (fullName) {
+	ZxNode *child1Node = ((ZxElement *)node)->getFirstChild();
+	if (child1Node && child1Node->isElement()) {
+	  ZxNode *child2Node = ((ZxElement *)child1Node)->getFirstChild();
+	  if (child2Node && child2Node->isCharData()) {
+	    formValues->add(fullName->copy(),
+			    ((ZxCharData *)child2Node)->getData()->copy());
+	  }
+	}
+      }
+    } else if (node->isElement()) {
+      ZxAttr *nameAttr = ((ZxElement *)node)->findAttr("name");
+      if (nameAttr && (node->isElement("subform") ||
+		       node->isElement("field"))) {
+	GString *nodeName = nameAttr->getValue();
+	GString *childFullName;
+	if (fullName) {
+	  childFullName = GString::format("{0:t}.{1:t}", fullName, nodeName);
+	} else {
+	  childFullName = nodeName->copy();
+	}
+	int idx = fullNameIdx->lookupInt(nodeName);
+	childFullName->appendf("[{0:d}]", idx);
+	fullNameIdx->replace(nodeName, idx + 1);
+	scanFormNode((ZxElement *)node, childFullName, formValues);
+	delete childFullName;
+      } else if (node->isElement("subform")) {
+	scanFormNode((ZxElement *)node, fullName, formValues);
+      }
+    }
+  }
+  delete fullNameIdx;
+}
+
+void XFAScanner::scanNode(ZxElement *elem,
+			  GString *parentName, GString *parentFullName,
+			  GHash *nameIdx, GHash *fullNameIdx,
+			  GString *exclGroupName, ZxElement *dataElem,
+			  GHash *formValues) {
+  GString *nodeName = getNodeName(elem);
+  GHash *childNameIdx;
+  if (!nameIdx || nodeName) {
+    childNameIdx = new GHash();
+  } else {
+    childNameIdx = nameIdx;
+  }
+  GString *nodeFullName = getNodeFullName(elem);
+  GHash *childFullNameIdx;
+  if (!fullNameIdx || (nodeFullName && !elem->isElement("area"))) {
+    childFullNameIdx = new GHash();
+  } else {
+    childFullNameIdx = fullNameIdx;
+  }
+
+  GString *childName;
+  if (nodeName) {
+    if (parentName) {
+      childName = GString::format("{0:t}.{1:t}", parentName, nodeName);
+    } else {
+      childName = nodeName->copy();
+    }
+    int idx = nameIdx->lookupInt(nodeName);
+    nameIdx->replace(nodeName, idx + 1);
+    if (nodeIsBindGlobal(elem)) {
+      childName->appendf("[0]");
+    } else {
+      childName->appendf("[{0:d}]", idx);
+    }
+  } else {
+    childName = parentName;
+  }
+  GString *childFullName;
+  if (nodeFullName) {
+    if (parentFullName) {
+      childFullName = GString::format("{0:t}.{1:t}",
+				      parentFullName, nodeFullName);
+    } else {
+      childFullName = nodeFullName->copy();
+    }
+    int idx = fullNameIdx->lookupInt(nodeFullName);
+    fullNameIdx->replace(nodeFullName, idx + 1);
+    childFullName->appendf("[{0:d}]", idx);
+  } else {
+    childFullName = parentFullName;
+  }
+
+  if (elem->isElement("field")) {
+    scanField(elem, childName, childFullName, exclGroupName,
+	      dataElem, formValues);
+  } else {
+    GString *childExclGroupName;
+    if (elem->isElement("exclGroup")) {
+      childExclGroupName = childName;
+    } else {
+      childExclGroupName = NULL;
+    }
+    for (ZxNode *child = elem->getFirstChild();
+	 child;
+	 child = child->getNextChild()) {
+      if (child->isElement()) {
+	scanNode((ZxElement *)child, childName, childFullName,
+		 childNameIdx, childFullNameIdx, childExclGroupName,
+		 dataElem, formValues);
+      }
+    }
+  }
+
+  if (childName != parentName) {
+    delete childName;
+  }
+  if (childFullName != parentFullName) {
+    delete childFullName;
+  }
+  if (childNameIdx != nameIdx) {
+    delete childNameIdx;
+  }
+  if (childFullNameIdx != fullNameIdx) {
+    delete childFullNameIdx;
+  }
+}
+
+void XFAScanner::scanField(ZxElement *elem, GString *name, GString *fullName,
+			   GString *exclGroupName, ZxElement *dataElem,
+			   GHash *formValues) {
+  GString *value = getFieldValue(elem, name, fullName, exclGroupName,
+				 dataElem, formValues);
+  XFAFieldLayoutInfo *layoutInfo = getFieldLayoutInfo(elem);
+  XFAFieldPictureInfo *pictureInfo = getFieldPictureInfo(elem);
+  XFAFieldBarcodeInfo *barcodeInfo = getFieldBarcodeInfo(elem);
+  XFAField *field = new XFAField(name->copy(), fullName->copy(), value,
+				 layoutInfo, pictureInfo, barcodeInfo);
+  fields->add(field->fullName, field);
+}
+
+GString *XFAScanner::getFieldValue(ZxElement *elem, GString *name,
+				   GString *fullName, GString *exclGroupName,
+				   ZxElement *dataElem, GHash *formValues) {
+  GString *val = NULL;
+
+  //--- check the <xfa:datasets> packet
+  val = getDatasetsValue(name->getCString(), dataElem);
+  if (!val && exclGroupName) {
+    val = (GString *)getDatasetsValue(exclGroupName->getCString(), dataElem);
+  }
+
+  //--- check the <form> element
+  if (!val) {
+    val = (GString *)formValues->lookup(fullName);
+  }
+
+  //--- check the <value> element within the field
+  if (!val) {
+    ZxElement *valueElem = elem->findFirstChildElement("value");
+    if (valueElem) {
+      ZxNode *child1Node = valueElem->getFirstChild();
+      if (child1Node && child1Node->isElement()) {
+	ZxNode *child2Node = ((ZxElement *)child1Node)->getFirstChild();
+	if (child2Node && child2Node->isCharData()) {
+	  val = ((ZxCharData *)child2Node)->getData();
+	}
+      }
+    }
+  }
+
+  //--- get the checkbutton item value
+  GString *checkbuttonItem = NULL;
+  ZxElement *uiElem = elem->findFirstChildElement("ui");
+  if (uiElem) {
+    ZxNode *uiChild = uiElem->getFirstChild();
+    if (uiChild && uiChild->isElement("checkButton")) {
+      ZxElement *itemsElem = elem->findFirstChildElement("items");
+      if (itemsElem) {
+	ZxNode *node1 = itemsElem->getFirstChild();
+	if (node1 && node1->isElement()) {
+	  ZxNode *node2 = ((ZxElement *)node1)->getFirstChild();
+	  if (node2 && node2->isCharData()) {
+	    checkbuttonItem = ((ZxCharData *)node2)->getData();
+	  }
+	}
+      }
+    }
+  }
+  // convert XFA checkbutton value to AcroForm-style On/Off value
+  if (checkbuttonItem && val) {
+    if (val->cmp(checkbuttonItem)) {
+      val = new GString("Off");
+    } else {
+      val = new GString("On");
+    }
+  } else if (val) {
+    val = val->copy();
+  }
+
+  return val;
+}
+
+GString *XFAScanner::getDatasetsValue(char *partName, ZxElement *elem) {
+  if (!elem) {
+    return NULL;
+  }
+
+  // partName = xxxx[nn].yyyy----
+  char *p = strchr(partName, '[');
+  if (!p) {
+    return NULL;
+  }
+  int partLen = (int)(p - partName);
+  int idx = atoi(p + 1);
+  p = strchr(p + 1, '.');
+  if (p) {
+    ++p;
+  }
+
+  int curIdx = 0;
+  for (ZxNode *node = elem->getFirstChild();
+       node;
+       node = node->getNextChild()) {
+    if (!node->isElement()) {
+      continue;
+    }
+    GString *nodeName = ((ZxElement *)node)->getType();
+    if (nodeName->getLength() != partLen ||
+	strncmp(nodeName->getCString(), partName, partLen)) {
+      continue;
+    }
+    if (curIdx != idx) {
+      ++curIdx;
+      continue;
+    }
+    if (p) {
+      GString *val = getDatasetsValue(p, (ZxElement *)node);
+      if (val) {
+	return val;
+      }
+      break;
+    } else {
+      ZxNode *child = ((ZxElement *)node)->getFirstChild();
+      if (!child || !child->isCharData()) {
+	return NULL;
+      }
+      return ((ZxCharData *)child)->getData();
+    }
+  }
+
+  // search for an 'ancestor match'
+  if (p) {
+    return getDatasetsValue(p, elem);
+  }
+
+  return NULL;
+}
+
+XFAFieldLayoutInfo *XFAScanner::getFieldLayoutInfo(ZxElement *elem) {
+  ZxElement *paraElem = elem->findFirstChildElement("para");
+  if (!paraElem) {
+    return NULL;
+  }
+  XFAFieldLayoutHAlign hAlign = xfaFieldLayoutHAlignLeft;
+  ZxAttr *hAlignAttr = paraElem->findAttr("hAlign");
+  if (hAlignAttr) {
+    if (!hAlignAttr->getValue()->cmp("left")) {
+      hAlign = xfaFieldLayoutHAlignLeft;
+    } else if (!hAlignAttr->getValue()->cmp("center")) {
+      hAlign = xfaFieldLayoutHAlignCenter;
+    } else if (!hAlignAttr->getValue()->cmp("right")) {
+      hAlign = xfaFieldLayoutHAlignRight;
+    }
+  }
+  XFAFieldLayoutVAlign vAlign = xfaFieldLayoutVAlignTop;
+  ZxAttr *vAlignAttr = paraElem->findAttr("vAlign");
+  if (vAlignAttr) {
+    if (!vAlignAttr->getValue()->cmp("top")) {
+      vAlign = xfaFieldLayoutVAlignTop;
+    } else if (!vAlignAttr->getValue()->cmp("middle")) {
+      vAlign = xfaFieldLayoutVAlignMiddle;
+    } else if (!vAlignAttr->getValue()->cmp("bottom")) {
+      vAlign = xfaFieldLayoutVAlignBottom;
+    }
+  }
+  return new XFAFieldLayoutInfo(hAlign, vAlign);
+}
+
+XFAFieldPictureInfo *XFAScanner::getFieldPictureInfo(ZxElement *elem) {
+  ZxElement *uiElem = elem->findFirstChildElement("ui");
+  if (!uiElem) {
+    return NULL;
+  }
+  XFAFieldPictureSubtype subtype;
+  if (uiElem->findFirstChildElement("dateTimeEdit")) {
+    subtype = xfaFieldPictureDateTime;
+  } else if (uiElem->findFirstChildElement("numericEdit")) {
+    subtype = xfaFieldPictureNumeric;
+  } else if (uiElem->findFirstChildElement("textEdit")) {
+    subtype = xfaFieldPictureText;
+  } else {
+    return NULL;
+  }
+
+  ZxElement *formatElem, *pictureElem;
+  ZxNode *pictureChildNode;
+  if (!(formatElem = elem->findFirstChildElement("format")) ||
+      !(pictureElem = formatElem->findFirstChildElement("picture")) ||
+      !(pictureChildNode = pictureElem->getFirstChild()) ||
+      !pictureChildNode->isCharData()) {
+    return NULL;
+  }
+  GString *format = ((ZxCharData *)pictureChildNode)->getData()->copy();
+
+  return new XFAFieldPictureInfo(subtype, format);
+}
+
+XFAFieldBarcodeInfo *XFAScanner::getFieldBarcodeInfo(ZxElement *elem) {
+  ZxElement *uiElem, *barcodeElem;
+  if (!(uiElem = elem->findFirstChildElement("ui")) ||
+      !(barcodeElem = uiElem->findFirstChildElement("barcode"))) {
+    return NULL;
+  }
+
+  ZxAttr *attr;
+  if (!(attr = barcodeElem->findAttr("type"))) {
+    return NULL;
+  }
+  GString *barcodeType = attr->getValue()->copy();
+
+  double wideNarrowRatio = 3;
+  if ((attr = barcodeElem->findAttr("wideNarrowRatio"))) {
+    char *s = attr->getValue()->getCString();
+    char *colon = strchr(s, ':');
+    if (colon) {
+      GString *numStr = new GString(s, (int)(colon - s));
+      double num = atof(numStr->getCString());
+      delete numStr;
+      double den = atof(colon + 1);
+      if (den == 0) {
+	wideNarrowRatio = num;
+      } else {
+	wideNarrowRatio = num / den;
+      }
+    } else {
+      wideNarrowRatio = atof(s);
+    }
+  }
+
+  double moduleWidth = (0.25 / 25.4) * 72.0; // 0.25mm
+  if ((attr = barcodeElem->findAttr("moduleWidth"))) {
+    moduleWidth = getMeasurement(attr->getValue());
+  }
+
+  double moduleHeight = (5.0 / 25.4) * 72.0; // 5mm
+  if ((attr = barcodeElem->findAttr("moduleHeight"))) {
+    moduleHeight = getMeasurement(attr->getValue());
+  }
+
+  int dataLength = 0;
+  if ((attr = barcodeElem->findAttr("dataLength"))) {
+    dataLength = atoi(attr->getValue()->getCString());
+  }
+
+  int errorCorrectionLevel = 0;
+  if ((attr = barcodeElem->findAttr("errorCorrectionLevel"))) {
+    errorCorrectionLevel = atoi(attr->getValue()->getCString());
+  }
+
+  GString *textLocation;
+  if ((attr = barcodeElem->findAttr("textLocation"))) {
+    textLocation = attr->getValue()->copy();
+  } else {
+    textLocation = new GString("below");
+  }
+
+  return new XFAFieldBarcodeInfo(barcodeType, wideNarrowRatio,
+				 moduleWidth, moduleHeight, dataLength,
+				 errorCorrectionLevel, textLocation);
+}
+
+double XFAScanner::getMeasurement(GString *s) {
+  int i = 0;
+  GBool neg = gFalse;
+  if (i < s->getLength() && s->getChar(i) == '+') {
+    ++i;
+  } else if (i < s->getLength() && s->getChar(i) == '-') {
+    neg = gTrue;
+    ++i;
+  }
+  double val = 0;
+  while (i < s->getLength() && s->getChar(i) >= '0' && s->getChar(i) <= '9') {
+    val = val * 10 + s->getChar(i) - '0';
+    ++i;
+  }
+  if (i < s->getLength() && s->getChar(i) == '.') {
+    ++i;
+    double mul = 0.1;
+    while (i < s->getLength() &&
+	   s->getChar(i) >= '0' && s->getChar(i) <= '9') {
+      val += mul * (s->getChar(i) - '0');
+      mul *= 0.1;
+      ++i;
+    }
+  }
+  if (neg) {
+    val = -val;
+  }
+  if (i+1 < s->getLength()) {
+    if (s->getChar(i) == 'i' && s->getChar(i+1) == 'n') {
+      val *= 72;
+    } else if (s->getChar(i) == 'p' && s->getChar(i+1) == 't') {
+      // no change
+    } else if (s->getChar(i) == 'c' && s->getChar(i+1) == 'm') {
+      val *= 72 / 2.54;
+    } else if (s->getChar(i) == 'm' && s->getChar(i+1) == 'm') {
+      val *= 72 / 25.4;
+    } else {
+      // default to inches
+      val *= 72;
+    }
+  } else {
+    // default to inches
+    val *= 72;
+  }
+  return val;
+}
+
+GString *XFAScanner::getNodeName(ZxElement *elem) {
+  if (elem->isElement("template") ||
+      elem->isElement("area") ||
+      elem->isElement("draw")) {
+    return NULL;
+  }
+  if (!elem->isElement("field") && nodeIsBindNone(elem)) {
+    return NULL;
+  }
+  ZxAttr *nameAttr = elem->findAttr("name");
+  if (!nameAttr) {
+    return NULL;
+  }
+  return nameAttr->getValue();
+}
+
+GString *XFAScanner::getNodeFullName(ZxElement *elem) {
+  if (elem->isElement("template") ||
+      elem->isElement("draw")) {
+    return NULL;
+  }
+  ZxAttr *nameAttr = elem->findAttr("name");
+  if (!nameAttr) {
+    return NULL;
+  }
+  return nameAttr->getValue();
+}
+
+GBool XFAScanner::nodeIsBindGlobal(ZxElement *elem) {
+  ZxElement *bindElem = elem->findFirstChildElement("bind");
+  if (!bindElem) {
+    return gFalse;
+  }
+  ZxAttr *attr = bindElem->findAttr("match");
+  return attr && !attr->getValue()->cmp("global");
+}
+
+GBool XFAScanner::nodeIsBindNone(ZxElement *elem) {
+  ZxElement *bindElem = elem->findFirstChildElement("bind");
+  if (!bindElem) {
+    return gFalse;
+  }
+  ZxAttr *attr = bindElem->findAttr("match");
+  return attr && !attr->getValue()->cmp("none");
+}


Property changes on: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/XFAScanner.cc
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/XFAScanner.h
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/XFAScanner.h	                        (rev 0)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/XFAScanner.h	2021-02-15 19:17:20 UTC (rev 845)
@@ -0,0 +1,166 @@
+//========================================================================
+//
+// XFAScanner.h
+//
+// Copyright 2020 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef XFASCANNER_H
+#define XFASCANNER_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+class GHash;
+class ZxElement;
+
+//------------------------------------------------------------------------
+
+enum XFAFieldLayoutHAlign {
+  xfaFieldLayoutHAlignLeft,
+  xfaFieldLayoutHAlignCenter,
+  xfaFieldLayoutHAlignRight
+};
+
+enum XFAFieldLayoutVAlign {
+  xfaFieldLayoutVAlignTop,
+  xfaFieldLayoutVAlignMiddle,
+  xfaFieldLayoutVAlignBottom
+};
+
+class XFAFieldLayoutInfo {
+public:
+
+  XFAFieldLayoutInfo(XFAFieldLayoutHAlign hAlignA,
+		     XFAFieldLayoutVAlign vAlignA);
+
+  XFAFieldLayoutHAlign hAlign;
+  XFAFieldLayoutVAlign vAlign;
+};
+
+//------------------------------------------------------------------------
+
+enum XFAFieldPictureSubtype {
+  xfaFieldPictureDateTime,
+  xfaFieldPictureNumeric,
+  xfaFieldPictureText
+};
+
+class XFAFieldPictureInfo {
+public:
+
+  XFAFieldPictureInfo(XFAFieldPictureSubtype subtypeA, GString *formatA);
+  ~XFAFieldPictureInfo();
+
+  XFAFieldPictureSubtype subtype;
+  GString *format;		// picture format string
+};
+
+//------------------------------------------------------------------------
+
+class XFAFieldBarcodeInfo {
+public:
+
+  XFAFieldBarcodeInfo(GString *barcodeTypeA, double wideNarrowRatioA,
+		      double moduleWidthA, double moduleHeightA,
+		      int dataLengthA, int errorCorrectionLevelA,
+		      GString *textLocationA);
+  ~XFAFieldBarcodeInfo();
+
+  GString *barcodeType;
+  double wideNarrowRatio;
+  double moduleWidth;
+  double moduleHeight;
+  int dataLength;
+  int errorCorrectionLevel;
+  GString *textLocation;
+};
+
+//------------------------------------------------------------------------
+
+class XFAField {
+public:
+
+  XFAField(GString *nameA, GString *fullNameA, GString *valueA,
+	   XFAFieldLayoutInfo *layoutInfoA,
+	   XFAFieldPictureInfo *pictureInfoA,
+	   XFAFieldBarcodeInfo *barcodeInfoA);
+  ~XFAField();
+
+  // Get the field's value, or NULL if it doesn't have a value.  Sets
+  // *[length] to the length of the Unicode string.
+  GString *getValue() { return value; }
+
+  // Return a pointer to the field's picture formatting info object,
+  // or NULL if the field doesn't have picture formatting.
+  XFAFieldPictureInfo *getPictureInfo() { return pictureInfo; }
+
+  // Return a pointer to the field's layout info object, or NULL if
+  // the field doesn't have layout info.
+  XFAFieldLayoutInfo *getLayoutInfo() { return layoutInfo; }
+
+  // Return a pointer to the field's barcode info object, or NULL if
+  // the field isn't a barcode.
+  XFAFieldBarcodeInfo *getBarcodeInfo() { return barcodeInfo; }
+
+private:
+
+  friend class XFAScanner;
+
+  GString *name;		// UTF-8
+  GString *fullName;		// UTF-8
+  GString *value;		// UTF-8
+  XFAFieldLayoutInfo *layoutInfo;
+  XFAFieldPictureInfo *pictureInfo;
+  XFAFieldBarcodeInfo *barcodeInfo;
+};
+
+//------------------------------------------------------------------------
+
+class XFAScanner {
+public:
+
+  static XFAScanner *load(Object *xfaObj);
+
+  virtual ~XFAScanner();
+
+  // Find an XFA field matchined the specified AcroForm field name.
+  // Returns NULL if there is no matching field.
+  XFAField *findField(GString *acroFormFieldName);
+
+private:
+
+  XFAScanner();
+  static GString *readXFAStreams(Object *xfaObj);
+  GHash *scanFormValues(ZxElement *xmlRoot);
+  void scanFormNode(ZxElement *elem, GString *fullName,
+		    GHash *formValues);
+  void scanNode(ZxElement *elem,
+		GString *parentName, GString *parentFullName,
+		GHash *nameIdx, GHash *fullNameIdx,
+		GString *exclGroupName, ZxElement *xmlRoot,
+		GHash *formValues);
+  void scanField(ZxElement *elem, GString *name, GString *fullName,
+		 GString *exclGroupName, ZxElement *xmlRoot,
+		 GHash *formValues);
+  GString *getFieldValue(ZxElement *elem, GString *name,
+			 GString *fullName, GString *exclGroupName,
+			 ZxElement *xmlRoot, GHash *formValues);
+  GString *getDatasetsValue(char *partName, ZxElement *elem);
+  XFAFieldLayoutInfo *getFieldLayoutInfo(ZxElement *elem);
+  XFAFieldPictureInfo *getFieldPictureInfo(ZxElement *elem);
+  XFAFieldBarcodeInfo *getFieldBarcodeInfo(ZxElement *elem);
+  double getMeasurement(GString *s);
+  GString *getNodeName(ZxElement *elem);
+  GString *getNodeFullName(ZxElement *elem);
+  GBool nodeIsBindGlobal(ZxElement *elem);
+  GBool nodeIsBindNone(ZxElement *elem);
+
+  GHash *fields;		// [XFAField]
+};
+
+#endif


Property changes on: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/XFAScanner.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/XRef.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/XRef.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/XRef.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -350,7 +350,7 @@
 
     // read the xref table
     posSet = new XRefPosSet();
-    while (readXRef(&pos, posSet)) ;
+    while (readXRef(&pos, posSet, gFalse)) ;
     xrefTablePosLen = posSet->getLength();
     xrefTablePos = (GFileOffset *)gmallocn(xrefTablePosLen,
 					   sizeof(GFileOffset));
@@ -438,8 +438,10 @@
 }
 
 // Read one xref table section.  Also reads the associated trailer
-// dictionary, and returns the prev pointer (if any).
-GBool XRef::readXRef(GFileOffset *pos, XRefPosSet *posSet) {
+// dictionary, and returns the prev pointer (if any).  The [hybrid]
+// flag is true when following the XRefStm link in a hybrid-reference
+// file.
+GBool XRef::readXRef(GFileOffset *pos, XRefPosSet *posSet, GBool hybrid) {
   Parser *parser;
   Object obj;
   GBool more;
@@ -461,13 +463,14 @@
   for (i = 0; i < n && Lexer::isSpace(buf[i]); ++i) ;
 
   // parse an old-style xref table
-  if (i + 4 < n &&
+  if (!hybrid &&
+      i + 4 < n &&
       buf[i] == 'x' && buf[i+1] == 'r' && buf[i+2] == 'e' && buf[i+3] == 'f' &&
       Lexer::isSpace(buf[i+4])) {
     more = readXRefTable(pos, i + 5, posSet);
 
   // parse an xref stream
-  } else if (i < n && buf[i] >= '0' && buf[i] <= '9') {
+  } else {
     obj.initNull();
     parser = new Parser(NULL,
 	       new Lexer(NULL,
@@ -474,34 +477,30 @@
 		 str->makeSubStream(start + *pos, gFalse, 0, &obj)),
 	       gTrue);
     if (!parser->getObj(&obj, gTrue)->isInt()) {
-      goto err2;
+      goto err;
     }
     obj.free();
     if (!parser->getObj(&obj, gTrue)->isInt()) {
-      goto err2;
+      goto err;
     }
     obj.free();
     if (!parser->getObj(&obj, gTrue)->isCmd("obj")) {
-      goto err2;
+      goto err;
     }
     obj.free();
     if (!parser->getObj(&obj)->isStream()) {
-      goto err2;
+      goto err;
     }
-    more = readXRefStream(obj.getStream(), pos);
+    more = readXRefStream(obj.getStream(), pos, hybrid);
     obj.free();
     delete parser;
-
-  } else {
-    goto err1;
   }
 
   return more;
 
- err2:
+ err:
   obj.free();
   delete parser;
- err1:
   ok = gFalse;
   return gFalse;
 }
@@ -662,7 +661,7 @@
   //~ this can be a 64-bit int (?)
   if (obj.getDict()->lookup("XRefStm", &obj2)->isInt()) {
     pos2 = (GFileOffset)(Guint)obj2.getInt();
-    readXRef(&pos2, posSet);
+    readXRef(&pos2, posSet, gTrue);
     if (!ok) {
       obj2.free();
       obj.free();
@@ -679,7 +678,7 @@
   return gFalse;
 }
 
-GBool XRef::readXRefStream(Stream *xrefStr, GFileOffset *pos) {
+GBool XRef::readXRefStream(Stream *xrefStr, GFileOffset *pos, GBool hybrid) {
   Dict *dict;
   int w[3];
   GBool more;
@@ -857,125 +856,250 @@
 
 // Attempt to construct an xref table for a damaged file.
 GBool XRef::constructXRef() {
-  Parser *parser;
-  Object newTrailerDict, obj;
-  char buf[256];
-  GFileOffset pos;
-  int num, gen;
-  int newSize;
-  int streamEndsSize;
-  char *p;
-  int i;
-  GBool gotRoot;
-
-  gfree(entries);
-  size = 0;
-  entries = NULL;
-
-  gotRoot = gFalse;
-  streamEndsLen = streamEndsSize = 0;
-
+  int *streamObjNums = NULL;
+  int streamObjNumsLen = 0;
+  int streamObjNumsSize = 0;
+  int lastObjNum = -1;
+  rootNum = -1;
+  int streamEndsSize = 0;
+  streamEndsLen = 0;
+  char buf[4096 + 1];
   str->reset();
+  GFileOffset bufPos = start;
+  char *p = buf;
+  char *end = buf;
+  GBool startOfLine = gTrue;
+  GBool eof = gFalse;
   while (1) {
-    pos = str->getPos();
-    if (!str->getLine(buf, 256)) {
+    if (end - p < 256 && !eof) {
+      memcpy(buf, p, end - p);
+      bufPos += p - buf;
+      p = buf + (end - p);
+      int n = (int)(buf + 4096 - p);
+      int m = str->getBlock(p, n);
+      end = p + m;
+      *end = '\0';
+      p = buf;
+      eof = m < n;
+    }
+    if (p == end && eof) {
       break;
     }
-    p = buf;
+    if (startOfLine && !strncmp(p, "trailer", 7)) {
+      constructTrailerDict((GFileOffset)(bufPos + (p + 7 - buf)));
+      p += 7;
+      startOfLine = gFalse;
+    } else if (startOfLine && !strncmp(p, "endstream", 9)) {
+      if (streamEndsLen == streamEndsSize) {
+	streamEndsSize += 64;
+	streamEnds = (GFileOffset *)greallocn(streamEnds, streamEndsSize,
+					      sizeof(GFileOffset));
+      }
+      streamEnds[streamEndsLen++] = (GFileOffset)(bufPos + (p - buf));
+      p += 9;
+      startOfLine = gFalse;
+    } else if (startOfLine && *p >= '0' && *p <= '9') {
+      p = constructObjectEntry(p, (GFileOffset)(bufPos + (p - buf)),
+			       &lastObjNum);
+      startOfLine = gFalse;
+    } else if (p[0] == '>' && p[1] == '>') {
+      p += 2;
+      startOfLine = gFalse;
+      // skip any PDF whitespace except for '\0'
+      while (*p == '\t' || *p == '\n' || *p == '\x0c' ||
+	     *p == '\r' || *p == ' ') {
+	startOfLine = *p == '\n' || *p == '\r';
+	++p;
+      }
+      if (!strncmp(p, "stream", 6)) {
+	if (lastObjNum >= 0) {
+	  if (streamObjNumsLen == streamObjNumsSize) {
+	    streamObjNumsSize += 64;
+	    streamObjNums = (int *)greallocn(streamObjNums, streamObjNumsSize,
+					     sizeof(int));
+	  }
+	  streamObjNums[streamObjNumsLen++] = lastObjNum;
+	}
+	p += 6;
+	startOfLine = gFalse;
+      }
+    } else {
+      startOfLine = *p == '\n' || *p == '\r';
+      ++p;
+    }
+  }
 
-    // skip whitespace
-    while (*p && Lexer::isSpace(*p & 0xff)) ++p;
+  // read each stream object, check for xref or object stream
+  for (int i = 0; i < streamObjNumsLen; ++i) {
+    Object obj;
+    fetch(streamObjNums[i], entries[streamObjNums[i]].gen, &obj);
+    if (obj.isStream()) {
+      Dict *dict = obj.streamGetDict();
+      Object type;
+      dict->lookup("Type", &type);
+      if (type.isName("XRef")) {
+	saveTrailerDict(dict, gTrue);
+      } else if (type.isName("ObjStm")) {
+	constructObjectStreamEntries(&obj, streamObjNums[i]);
+      }
+      type.free();
+    }
+    obj.free();
+  }
 
-    // got trailer dictionary
-    if (!strncmp(p, "trailer", 7)) {
-      obj.initNull();
-      parser = new Parser(NULL,
+  gfree(streamObjNums);
+
+  if (rootNum < 0) {
+    error(errSyntaxError, -1, "Couldn't find trailer dictionary");
+    return gFalse;
+  }
+  return gTrue;
+}
+
+// Attempt to construct a trailer dict at [pos] in the stream.
+void XRef::constructTrailerDict(GFileOffset pos) {
+  Object newTrailerDict, obj;
+  obj.initNull();
+  Parser *parser =
+      new Parser(NULL,
 		 new Lexer(NULL,
-		   str->makeSubStream(pos + 7, gFalse, 0, &obj)),
+			   str->makeSubStream(pos, gFalse, 0, &obj)),
 		 gFalse);
-      parser->getObj(&newTrailerDict);
-      if (newTrailerDict.isDict()) {
-	newTrailerDict.dictLookupNF("Root", &obj);
-	if (obj.isRef()) {
-	  rootNum = obj.getRefNum();
-	  rootGen = obj.getRefGen();
-	  if (!trailerDict.isNone()) {
-	    trailerDict.free();
-	  }
-	  newTrailerDict.copy(&trailerDict);
-	  gotRoot = gTrue;
-	}
-	obj.free();
-      }
-      newTrailerDict.free();
-      delete parser;
+  parser->getObj(&newTrailerDict);
+  if (newTrailerDict.isDict()) {
+    saveTrailerDict(newTrailerDict.getDict(), gFalse);
+  }
+  newTrailerDict.free();
+  delete parser;
+}
 
-    // look for object
-    } else if (isdigit(*p & 0xff)) {
-      num = atoi(p);
-      if (num > 0) {
-	do {
-	  ++p;
-	} while (*p && isdigit(*p & 0xff));
-	if (isspace(*p & 0xff)) {
-	  do {
-	    ++p;
-	  } while (*p && isspace(*p & 0xff));
-	  if (isdigit(*p & 0xff)) {
-	    gen = atoi(p);
-	    do {
-	      ++p;
-	    } while (*p && isdigit(*p & 0xff));
-	    if (isspace(*p & 0xff)) {
-	      do {
-		++p;
-	      } while (*p && isspace(*p & 0xff));
-	      if (!strncmp(p, "obj", 3)) {
-		if (num >= size) {
-		  newSize = (num + 1 + 255) & ~255;
-		  if (newSize < 0) {
-		    error(errSyntaxError, -1, "Bad object number");
-		    return gFalse;
-		  }
-		  entries = (XRefEntry *)
-		      greallocn(entries, newSize, sizeof(XRefEntry));
-		  for (i = size; i < newSize; ++i) {
-		    entries[i].offset = (GFileOffset)-1;
-		    entries[i].type = xrefEntryFree;
-		  }
-		  size = newSize;
-		}
-		if (entries[num].type == xrefEntryFree ||
-		    gen >= entries[num].gen) {
-		  entries[num].offset = pos - start;
-		  entries[num].gen = gen;
-		  entries[num].type = xrefEntryUncompressed;
-		  if (num > last) {
-		    last = num;
-		  }
-		}
-	      }
-	    }
-	  }
-	}
+// If [dict] "looks like" a trailer dict (i.e., has a Root entry),
+// save it as the trailer dict.
+void XRef::saveTrailerDict(Dict *dict, GBool isXRefStream) {
+  Object obj;
+  dict->lookupNF("Root", &obj);
+  if (obj.isRef()) {
+    int newRootNum = obj.getRefNum();
+    // the xref stream scanning code runs after all objects are found,
+    // so we can check for a valid root object number at that point
+    if (!isXRefStream || newRootNum <= last) {
+      rootNum = newRootNum;
+      rootGen = obj.getRefGen();
+      if (!trailerDict.isNone()) {
+	trailerDict.free();
       }
+      trailerDict.initDict(dict);
+    }
+  }
+  obj.free();
+}
 
-    } else if (!strncmp(p, "endstream", 9)) {
-      if (streamEndsLen == streamEndsSize) {
-	streamEndsSize += 64;
-	streamEnds = (GFileOffset *)greallocn(streamEnds, streamEndsSize,
-					      sizeof(GFileOffset));
+// Look for an object header ("nnn ggg obj") at [p].  The first
+// character at *[p] is a digit.  [pos] is the position of *[p].
+char *XRef::constructObjectEntry(char *p, GFileOffset pos, int *objNum) {
+  // we look for non-end-of-line space characters here, to deal with
+  // situations like:
+  //    nnn          <-- garbage digits on a line
+  //    nnn nnn obj  <-- actual object
+  // and we also ignore '\0' (because it's used to terminate the
+  // buffer in this damage-scanning code)
+  int num = 0;
+  do {
+    num = (num * 10) + (*p - '0');
+    ++p;
+  } while (*p >= '0' && *p <= '9' && num < 100000000);
+  if (*p != '\t' && *p != '\x0c' && *p != ' ') {
+    return p;
+  }
+  do {
+    ++p;
+  } while (*p == '\t' || *p == '\x0c' || *p == ' ');
+  if (!(*p >= '0' && *p <= '9')) {
+    return p;
+  }
+  int gen = 0;
+  do {
+    gen = (gen * 10) + (*p - '0');
+    ++p;
+  } while (*p >= '0' && *p <= '9' && gen < 100000000);
+  if (*p != '\t' && *p != '\x0c' && *p != ' ') {
+    return p;
+  }
+  do {
+    ++p;
+  } while (*p == '\t' || *p == '\x0c' || *p == ' ');
+  if (strncmp(p, "obj", 3)) {
+    return p;
+  }
+
+  if (constructXRefEntry(num, gen, pos - start, xrefEntryUncompressed)) {
+    *objNum = num;
+  }
+
+  return p;
+}
+
+// Read the header from an object stream, and add xref entries for all
+// of its objects.
+void XRef::constructObjectStreamEntries(Object *objStr, int objStrObjNum) {
+  Object obj1, obj2;
+
+  // get the object count
+  if (!objStr->streamGetDict()->lookup("N", &obj1)->isInt()) {
+    obj1.free();
+    return;
+  }
+  int nObjects = obj1.getInt();
+  obj1.free();
+  if (nObjects <= 0 || nObjects > 1000000) {
+    return;
+  }
+
+  // parse the header: object numbers and offsets
+  Parser *parser = new Parser(NULL,
+			      new Lexer(NULL, objStr->getStream()->copy()),
+			      gFalse);
+  for (int i = 0; i < nObjects; ++i) {
+    parser->getObj(&obj1, gTrue);
+    parser->getObj(&obj2, gTrue);
+    if (obj1.isInt() && obj2.isInt()) {
+      int num = obj1.getInt();
+      if (num >= 0 && num < 1000000) {
+	constructXRefEntry(num, i, objStrObjNum, xrefEntryCompressed);
       }
-      streamEnds[streamEndsLen++] = pos;
     }
+    obj2.free();
+    obj1.free();
   }
+  delete parser;
+}
 
-  if (gotRoot) {
-    return gTrue;
+GBool XRef::constructXRefEntry(int num, int gen, GFileOffset pos,
+			       XRefEntryType type) {
+  if (num >= size) {
+    int newSize = (num + 1 + 255) & ~255;
+    if (newSize < 0) {
+      return gFalse;
+    }
+    entries = (XRefEntry *)greallocn(entries, newSize, sizeof(XRefEntry));
+    for (int i = size; i < newSize; ++i) {
+      entries[i].offset = (GFileOffset)-1;
+      entries[i].type = xrefEntryFree;
+    }
+    size = newSize;
   }
 
-  error(errSyntaxError, -1, "Couldn't find trailer dictionary");
-  return gFalse;
+  if (entries[num].type == xrefEntryFree ||
+      gen >= entries[num].gen) {
+    entries[num].offset = pos;
+    entries[num].gen = gen;
+    entries[num].type = type;
+    if (num > last) {
+      last = num;
+    }
+  }
+
+  return gTrue;
 }
 
 void XRef::setEncryption(int permFlagsA, GBool ownerPasswordOkA,
@@ -1153,6 +1277,9 @@
   gLockMutex(&objStrsMutex);
 #endif
   if (!(objStr = getObjectStream(objStrNum))) {
+#if MULTITHREADED
+    gUnlockMutex(&objStrsMutex);
+#endif
     return gFalse;
   }
   cleanObjectStreamCache();

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/XRef.h
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/XRef.h	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/XRef.h	2021-02-15 19:17:20 UTC (rev 845)
@@ -166,11 +166,17 @@
 #endif
 
   GFileOffset getStartXref();
-  GBool readXRef(GFileOffset *pos, XRefPosSet *posSet);
+  GBool readXRef(GFileOffset *pos, XRefPosSet *posSet, GBool hybrid);
   GBool readXRefTable(GFileOffset *pos, int offset, XRefPosSet *posSet);
+  GBool readXRefStream(Stream *xrefStr, GFileOffset *pos, GBool hybrid);
   GBool readXRefStreamSection(Stream *xrefStr, int *w, int first, int n);
-  GBool readXRefStream(Stream *xrefStr, GFileOffset *pos);
   GBool constructXRef();
+  void constructTrailerDict(GFileOffset pos);
+  void saveTrailerDict(Dict *dict, GBool isXRefStream);
+  char *constructObjectEntry(char *p, GFileOffset pos, int *objNum);
+  void constructObjectStreamEntries(Object *objStr, int objStrObjNum);
+  GBool constructXRefEntry(int num, int gen, GFileOffset pos,
+			   XRefEntryType type);
   GBool getObjectStreamObject(int objStrNum, int objIdx,
 			      int objNum, Object *obj);
   ObjectStream *getObjectStream(int objStrNum);

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Zoox.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Zoox.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Zoox.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -430,7 +430,8 @@
   GString *name, *value;
   const char *start;
   char quote, c;
-  int x, n;
+  unsigned int x;
+  int n;
 
   name = parseName();
   parseSpace();
@@ -559,7 +560,8 @@
   GString *data;
   const char *start;
   char c;
-  int x, n;
+  unsigned int x;
+  int n;
 
   data = new GString();
   while (parsePtr < parseEnd && *parsePtr != '<') {
@@ -638,7 +640,7 @@
   par->addChild(new ZxCharData(data, true));
 }
 
-void ZxDoc::appendUTF8(GString *s, int c) {
+void ZxDoc::appendUTF8(GString *s, unsigned int c) {
   if (c <= 0x7f) {
     s->append((char)c);
   } else if (c <= 0x7ff) {

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Zoox.h
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Zoox.h	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/Zoox.h	2021-02-15 19:17:20 UTC (rev 845)
@@ -103,7 +103,7 @@
   ZxAttr *parseAttr();
   void parseContent(ZxElement *par);
   void parseCharData(ZxElement *par);
-  void appendUTF8(GString *s, int c);
+  void appendUTF8(GString *s, unsigned int c);
   void parseCDSect(ZxNode *par);
   void parseMisc(ZxNode *par);
   void parseComment(ZxNode *par);

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/config.h
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/config.h	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/config.h	2021-02-15 19:17:20 UTC (rev 845)
@@ -2,7 +2,7 @@
 //
 // config.h
 //
-// Copyright 1996-2019 Glyph & Cog, LLC
+// Copyright 1996-2021 Glyph & Cog, LLC
 //
 //========================================================================
 
@@ -14,13 +14,13 @@
 //------------------------------------------------------------------------
 
 // xpdf version
-#define xpdfVersion          "4.02"
-#define xpdfVersionNum       4.02
+#define xpdfVersion          "4.03"
+#define xpdfVersionNum       4.03
 #define xpdfMajorVersion     4
-#define xpdfMinorVersion     2
+#define xpdfMinorVersion     3
 #define xpdfUpdateVersion    0
 #define xpdfMajorVersionStr  "4"
-#define xpdfMinorVersionStr  "2"
+#define xpdfMinorVersionStr  "3"
 #define xpdfUpdateVersionStr "0"
 
 // supported PDF version
@@ -28,11 +28,11 @@
 #define supportedPDFVersionNum 2.0
 
 // copyright notice
-#define xpdfCopyright "Copyright 1996-2019 Glyph & Cog, LLC"
+#define xpdfCopyright "Copyright 1996-2021 Glyph & Cog, LLC"
 
 // Windows resource file stuff
-#define winxpdfVersion "WinXpdf 4.02"
-#define xpdfCopyrightAmp "Copyright 1996-2019 Glyph && Cog, LLC"
+#define winxpdfVersion "WinXpdf 4.03"
+#define xpdfCopyrightAmp "Copyright 1996-2021 Glyph && Cog, LLC"
 
 //------------------------------------------------------------------------
 // paper size
@@ -59,12 +59,14 @@
 #endif
 
 // system config file name (set via the configure script)
-#ifdef SYSTEM_XPDFRC
-#define xpdfSysConfigFile SYSTEM_XPDFRC
-#else
+#if defined(_WIN32)
 // under Windows, we get the directory with the executable and then
 // append this file name
 #define xpdfSysConfigFile "xpdfrc"
+#elif defined(SYSTEM_XPDFRC)
+#define xpdfSysConfigFile SYSTEM_XPDFRC
+#else
+#define xpdfSysConfigFile "/etc/xpdfrc"
 #endif
 
 //------------------------------------------------------------------------

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/pdfdetach.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/pdfdetach.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/pdfdetach.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -16,6 +16,7 @@
 #include "PDFDoc.h"
 #include "CharTypes.h"
 #include "UnicodeMap.h"
+#include "UTF8.h"
 #include "Error.h"
 #include "config.h"
 
@@ -67,8 +68,7 @@
   PDFDoc *doc;
   Unicode *name;
   char uBuf[8];
-  char path[1024];
-  char *p;
+  GString *path;
   GBool ok;
   int exitCode;
   int nFiles, nameLen, n, i, j;
@@ -84,7 +84,7 @@
     ok = gFalse;
   }
   if (!ok || argc != 2 || printVersion || printHelp) {
-    fprintf(stderr, "pdfdetach version %s\n", xpdfVersion);
+    fprintf(stderr, "pdfdetach version %s [www.xpdfreader.com]\n", xpdfVersion);
     fprintf(stderr, "%s\n", xpdfCopyright);
     if (!printVersion) {
       printUsage("pdfdetach", "<PDF-file>", argDesc);
@@ -148,32 +148,24 @@
   } else if (saveAll) {
     for (i = 0; i < nFiles; ++i) {
       if (savePath[0]) {
-	n = (int)strlen(savePath);
-	if (n > (int)sizeof(path) - 2) {
-	  n = sizeof(path) - 2;
-	}
-	memcpy(path, savePath, n);
-	path[n] = '/';
-	p = path + n + 1;
+	path = new GString(savePath);
+	path->append('/');
       } else {
-	p = path;
+	path = new GString();
       }
       name = doc->getEmbeddedFileName(i);
       nameLen = doc->getEmbeddedFileNameLength(i);
       for (j = 0; j < nameLen; ++j) {
-	n = uMap->mapUnicode(name[j], uBuf, sizeof(uBuf));
-	if (p + n >= path + sizeof(path)) {
-	  break;
-	}
-	memcpy(p, uBuf, n);
-	p += n;
+	n = mapUTF8(name[j], uBuf, sizeof(uBuf));
+	path->append(uBuf, n);
       }
-      *p = '\0';
-      if (!doc->saveEmbeddedFile(i, path)) {
-	error(errIO, -1, "Error saving embedded file as '{0:s}'", p);
+      if (!doc->saveEmbeddedFileU(i, path->getCString())) {
+	error(errIO, -1, "Error saving embedded file as '{0:t}'", path);
+	delete path;
 	exitCode = 2;
 	goto err2;
       }
+      delete path;
     }
 
   // save an embedded file
@@ -183,27 +175,23 @@
       goto err2;
     }
     if (savePath[0]) {
-      p = savePath;
+      path = new GString(savePath);
     } else {
       name = doc->getEmbeddedFileName(saveNum - 1);
       nameLen = doc->getEmbeddedFileNameLength(saveNum - 1);
-      p = path;
+      path = new GString();
       for (j = 0; j < nameLen; ++j) {
-	n = uMap->mapUnicode(name[j], uBuf, sizeof(uBuf));
-	if (p + n >= path + sizeof(path)) {
-	  break;
-	}
-	memcpy(p, uBuf, n);
-	p += n;
+	n = mapUTF8(name[j], uBuf, sizeof(uBuf));
+	path->append(uBuf, n);
       }
-      *p = '\0';
-      p = path;
     }
-    if (!doc->saveEmbeddedFile(saveNum - 1, p)) {
-      error(errIO, -1, "Error saving embedded file as '{0:s}'", p);
+    if (!doc->saveEmbeddedFileU(saveNum - 1, path->getCString())) {
+      error(errIO, -1, "Error saving embedded file as '{0:t}'", path);
+      delete path;
       exitCode = 2;
       goto err2;
     }
+    delete path;
   }
 
   exitCode = 0;

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/pdffonts.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/pdffonts.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/pdffonts.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -23,7 +23,7 @@
 #include "Dict.h"
 #include "GfxFont.h"
 #include "Annot.h"
-#include "Form.h"
+#include "AcroForm.h"
 #include "PDFDoc.h"
 #include "config.h"
 
@@ -102,7 +102,7 @@
   Page *page;
   Dict *resDict;
   Annots *annots;
-  Form *form;
+  AcroForm *form;
   Object obj1, obj2;
   int pg, i, j;
   int exitCode;
@@ -113,7 +113,7 @@
   fixCommandLine(&argc, &argv);
   ok = parseArgs(argDesc, &argc, argv);
   if (!ok || argc != 2 || printVersion || printHelp) {
-    fprintf(stderr, "pdffonts version %s\n", xpdfVersion);
+    fprintf(stderr, "pdffonts version %s [www.xpdfreader.com]\n", xpdfVersion);
     fprintf(stderr, "%s\n", xpdfCopyright);
     if (!printVersion) {
       printUsage("pdffonts", "<PDF-file>", argDesc);

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/pdfimages.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/pdfimages.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/pdfimages.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -87,7 +87,7 @@
   fixCommandLine(&argc, &argv);
   ok = parseArgs(argDesc, &argc, argv);
   if (!ok || argc != 3 || printVersion || printHelp) {
-    fprintf(stderr, "pdfimages version %s\n", xpdfVersion);
+    fprintf(stderr, "pdfimages version %s [www.xpdfreader.com]\n", xpdfVersion);
     fprintf(stderr, "%s\n", xpdfCopyright);
     if (!printVersion) {
       printUsage("pdfimages", "<PDF-file> <image-root>", argDesc);

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/pdfinfo.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/pdfinfo.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/pdfinfo.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -102,6 +102,9 @@
   FILE *f;
   GString *metadata;
   ZxDoc *xmp;
+  int permFlags, keyLength, encVersion;
+  GBool ownerPasswordOk;
+  CryptAlgorithm encAlgorithm;
   GBool ok;
   int exitCode;
   int pg, i;
@@ -113,7 +116,7 @@
   fixCommandLine(&argc, &argv);
   ok = parseArgs(argDesc, &argc, argv);
   if (!ok || argc != 2 || printVersion || printHelp) {
-    fprintf(stderr, "pdfinfo version %s\n", xpdfVersion);
+    fprintf(stderr, "pdfinfo version %s [www.xpdfreader.com]\n", xpdfVersion);
     fprintf(stderr, "%s\n", xpdfCopyright);
     if (!printVersion) {
       printUsage("pdfinfo", "<PDF-file>", argDesc);
@@ -216,15 +219,19 @@
   printf("Pages:          %d\n", doc->getNumPages());
 
   // print encryption info
-  printf("Encrypted:      ");
   if (doc->isEncrypted()) {
-    printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
+    doc->getXRef()->getEncryption(&permFlags, &ownerPasswordOk, &keyLength,
+				  &encVersion, &encAlgorithm);
+    printf("Encrypted:      %s %d-bit\n",
+	   encAlgorithm == cryptRC4 ? "RC4" : "AES",
+	   keyLength * 8);
+    printf("Permissions:    print:%s copy:%s change:%s addNotes:%s\n",
 	   doc->okToPrint(gTrue) ? "yes" : "no",
 	   doc->okToCopy(gTrue) ? "yes" : "no",
 	   doc->okToChange(gTrue) ? "yes" : "no",
 	   doc->okToAddNotes(gTrue) ? "yes" : "no");
   } else {
-    printf("no\n");
+    printf("Encrypted:      no\n");
   }
 
   // print page size
@@ -261,18 +268,18 @@
     if (multiPage) {
       for (pg = firstPage; pg <= lastPage; ++pg) {
 	page = doc->getCatalog()->getPage(pg);
-	sprintf(buf, "Page %4d MediaBox: ", pg);
+	snprintf(buf, sizeof(buf), "Page %4d MediaBox: ", pg);
 	printBox(buf, page->getMediaBox());
-	sprintf(buf, "Page %4d CropBox:  ", pg);
+	snprintf(buf, sizeof(buf), "Page %4d CropBox:  ", pg);
 	printBox(buf, page->getCropBox());
-	sprintf(buf, "Page %4d BleedBox: ", pg);
+	snprintf(buf, sizeof(buf), "Page %4d BleedBox: ", pg);
 	printBox(buf, page->getBleedBox());
-	sprintf(buf, "Page %4d TrimBox:  ", pg);
+	snprintf(buf, sizeof(buf), "Page %4d TrimBox:  ", pg);
 	printBox(buf, page->getTrimBox());
-	sprintf(buf, "Page %4d ArtBox:   ", pg);
+	snprintf(buf, sizeof(buf), "Page %4d ArtBox:   ", pg);
 	printBox(buf, page->getArtBox());
       }
-    } else {
+    } else if (doc->getNumPages() > 0) {
       page = doc->getCatalog()->getPage(firstPage);
       printBox("MediaBox:       ", page->getMediaBox());
       printBox("CropBox:        ", page->getCropBox());

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/pdftohtml.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/pdftohtml.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/pdftohtml.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -31,6 +31,7 @@
 static int lastPage = 0;
 static double zoom = 1;
 static int resolution = 150;
+static GBool noFonts = gFalse;
 static GBool skipInvisible = gFalse;
 static GBool allInvisible = gFalse;
 static char ownerPassword[33] = "\001";
@@ -45,10 +46,12 @@
    "first page to convert"},
   {"-l",       argInt,      &lastPage,      0,
    "last page to convert"},
-  {"-z",      argFP,       &zoom,     0,
+  {"-z",       argFP,       &zoom,          0,
    "initial zoom level (1.0 means 72dpi)"},
-  {"-r",      argInt,      &resolution,     0,
+  {"-r",       argInt,      &resolution,    0,
    "resolution, in DPI (default is 150)"},
+  {"-nofonts", argFlag, &noFonts,           0,
+   "do not extract embedded fonts"},
   {"-skipinvisible", argFlag, &skipInvisible, 0,
    "do not draw invisible text"},
   {"-allinvisible",  argFlag, &allInvisible,  0,
@@ -97,7 +100,7 @@
   fixCommandLine(&argc, &argv);
   ok = parseArgs(argDesc, &argc, argv);
   if (!ok || argc != 3 || printVersion || printHelp) {
-    fprintf(stderr, "pdftohtml version %s\n", xpdfVersion);
+    fprintf(stderr, "pdftohtml version %s [www.xpdfreader.com]\n", xpdfVersion);
     fprintf(stderr, "%s\n", xpdfCopyright);
     if (!printVersion) {
       printUsage("pdftohtml", "<PDF-file> <html-dir>", argDesc);
@@ -155,7 +158,7 @@
   }
 
   // create HTML directory
-  if (!createDir(htmlDir, 0755)) {
+  if (makeDir(htmlDir, 0755)) {
     error(errIO, -1, "Couldn't create HTML output directory '{0:s}'",
 	  htmlDir);
     exitCode = 2;
@@ -171,7 +174,7 @@
   htmlGen->setZoom(zoom);
   htmlGen->setDrawInvisibleText(!skipInvisible);
   htmlGen->setAllTextInvisible(allInvisible);
-  htmlGen->setExtractFontFiles(gTrue);
+  htmlGen->setExtractFontFiles(!noFonts);
   htmlGen->startDoc(doc);
 
   // convert the pages
@@ -178,13 +181,13 @@
   for (pg = firstPage; pg <= lastPage; ++pg) {
     htmlFileName = GString::format("{0:s}/page{1:d}.html", htmlDir, pg);
     pngFileName = GString::format("{0:s}/page{1:d}.png", htmlDir, pg);
-    if (!(htmlFile = fopen(htmlFileName->getCString(), "wb"))) {
+    if (!(htmlFile = openFile(htmlFileName->getCString(), "wb"))) {
       error(errIO, -1, "Couldn't open HTML file '{0:t}'", htmlFileName);
       delete htmlFileName;
       delete pngFileName;
       goto err2;
     }
-    if (!(pngFile = fopen(pngFileName->getCString(), "wb"))) {
+    if (!(pngFile = openFile(pngFileName->getCString(), "wb"))) {
       error(errIO, -1, "Couldn't open PNG file '{0:t}'", pngFileName);
       fclose(htmlFile);
       delete htmlFileName;
@@ -236,7 +239,7 @@
   int pg;
 
   htmlFileName = GString::format("{0:s}/index.html", htmlDir);
-  html = fopen(htmlFileName->getCString(), "w");
+  html = openFile(htmlFileName->getCString(), "w");
   delete htmlFileName;
   if (!html) {
     error(errIO, -1, "Couldn't open HTML file '{0:t}'", htmlFileName);

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/pdftopng.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/pdftopng.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/pdftopng.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -18,6 +18,7 @@
 #include "gmempp.h"
 #include "parseargs.h"
 #include "GString.h"
+#include "gfile.h"
 #include "GlobalParams.h"
 #include "Object.h"
 #include "PDFDoc.h"
@@ -32,6 +33,7 @@
 static GBool mono = gFalse;
 static GBool gray = gFalse;
 static GBool pngAlpha = gFalse;
+static int rotate = 0;
 static char enableFreeTypeStr[16] = "";
 static char antialiasStr[16] = "";
 static char vectorAntialiasStr[16] = "";
@@ -55,6 +57,8 @@
    "generate a grayscale PNG file"},
   {"-alpha",  argFlag,     &pngAlpha,      0,
    "include an alpha channel in the PNG file"},
+  {"-rot",    argInt,      &rotate,        0,
+   "set page rotation: 0, 90, 180, or 270"},
 #if HAVE_FREETYPE_H
   {"-freetype",   argString,      enableFreeTypeStr, sizeof(enableFreeTypeStr),
    "enable FreeType font rasterizer: yes, no"},
@@ -119,7 +123,7 @@
     goto err0;
   }
   if (!ok || argc != 3 || printVersion || printHelp) {
-    fprintf(stderr, "pdftopng version %s\n", xpdfVersion);
+    fprintf(stderr, "pdftopng version %s [www.xpdfreader.com]\n", xpdfVersion);
     fprintf(stderr, "%s\n", xpdfCopyright);
     if (!printVersion) {
       printUsage("pdftopng", "<PDF-file> <PNG-root>", argDesc);
@@ -197,7 +201,7 @@
   }
   splashOut->startDoc(doc->getXRef());
   for (pg = firstPage; pg <= lastPage; ++pg) {
-    doc->displayPage(splashOut, pg, resolution, resolution, 0,
+    doc->displayPage(splashOut, pg, resolution, resolution, rotate,
 		     gFalse, gTrue, gFalse);
     if (mono) {
       if (!strcmp(pngRoot, "-")) {
@@ -207,7 +211,7 @@
 #endif
       } else {
 	pngFile = GString::format("{0:s}-{1:06d}.png", pngRoot, pg);
-	if (!(f = fopen(pngFile->getCString(), "wb"))) {
+	if (!(f = openFile(pngFile->getCString(), "wb"))) {
 	  exit(2);
 	}
 	delete pngFile;
@@ -225,7 +229,7 @@
 #endif
       } else {
 	pngFile = GString::format("{0:s}-{1:06d}.png", pngRoot, pg);
-	if (!(f = fopen(pngFile->getCString(), "wb"))) {
+	if (!(f = openFile(pngFile->getCString(), "wb"))) {
 	  exit(2);
 	}
 	delete pngFile;
@@ -244,7 +248,7 @@
 #endif
       } else {
 	pngFile = GString::format("{0:s}-{1:06d}.png", pngRoot, pg);
-	if (!(f = fopen(pngFile->getCString(), "wb"))) {
+	if (!(f = openFile(pngFile->getCString(), "wb"))) {
 	  exit(2);
 	}
 	delete pngFile;

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/pdftoppm.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/pdftoppm.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/pdftoppm.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -36,6 +36,7 @@
 #if SPLASH_CMYK
 static GBool cmyk = gFalse;
 #endif
+static int rotate = 0;
 static char enableFreeTypeStr[16] = "";
 static char antialiasStr[16] = "";
 static char vectorAntialiasStr[16] = "";
@@ -61,6 +62,8 @@
   {"-cmyk",   argFlag,     &cmyk,          0,
    "generate a CMYK PAM file"},
 #endif
+  {"-rot",    argInt,      &rotate,        0,
+   "set page rotation: 0, 90, 180, or 270"},
 #if HAVE_FREETYPE_H
   {"-freetype",   argString,      enableFreeTypeStr, sizeof(enableFreeTypeStr),
    "enable FreeType font rasterizer: yes, no"},
@@ -133,7 +136,7 @@
     ok = gFalse;
   }
   if (!ok || argc != 3 || printVersion || printHelp) {
-    fprintf(stderr, "pdftoppm version %s\n", xpdfVersion);
+    fprintf(stderr, "pdftoppm version %s [www.xpdfreader.com]\n", xpdfVersion);
     fprintf(stderr, "%s\n", xpdfCopyright);
     if (!printVersion) {
       printUsage("pdftoppm", "<PDF-file> <PPM-root>", argDesc);
@@ -226,7 +229,7 @@
   }
   splashOut->startDoc(doc->getXRef());
   for (pg = firstPage; pg <= lastPage; ++pg) {
-    doc->displayPage(splashOut, pg, resolution, resolution, 0,
+    doc->displayPage(splashOut, pg, resolution, resolution, rotate,
 		     gFalse, gTrue, gFalse);
     if (!strcmp(ppmRoot, "-")) {
 #ifdef _WIN32

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/pdftops.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/pdftops.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/pdftops.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -182,7 +182,7 @@
   fixCommandLine(&argc, &argv);
   ok = parseArgs(argDesc, &argc, argv);
   if (!ok || argc < 2 || argc > 3 || printVersion || printHelp) {
-    fprintf(stderr, "pdftops version %s\n", xpdfVersion);
+    fprintf(stderr, "pdftops version %s [www.xpdfreader.com]\n", xpdfVersion);
     fprintf(stderr, "%s\n", xpdfCopyright);
     if (!printVersion) {
       printUsage("pdftops", "<PDF-file> [<PS-file>]", argDesc);
@@ -355,7 +355,7 @@
   // write PostScript file
   psOut = new PSOutputDev(psFileName->getCString(), doc,
 			  firstPage, lastPage, mode,
-			  0, 0, 0, 0, gFalse, NULL, NULL, userUnit);
+			  0, 0, 0, 0, gFalse, NULL, NULL, userUnit, gTrue);
   if (!psOut->isOk()) {
     delete psOut;
     exitCode = 2;

Modified: branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/pdftotext.cc
===================================================================
--- branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/pdftotext.cc	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/libs/xpdf/xpdf-src/xpdf/pdftotext.cc	2021-02-15 19:17:20 UTC (rev 845)
@@ -19,6 +19,7 @@
 #include "gmempp.h"
 #include "parseargs.h"
 #include "GString.h"
+#include "GList.h"
 #include "GlobalParams.h"
 #include "Object.h"
 #include "Stream.h"
@@ -39,6 +40,7 @@
 static int lastPage = 0;
 static GBool physLayout = gFalse;
 static GBool simpleLayout = gFalse;
+static GBool simple2Layout = gFalse;
 static GBool tableLayout = gFalse;
 static GBool linePrinter = gFalse;
 static GBool rawOrder = gFalse;
@@ -58,6 +60,7 @@
 static char userPassword[33] = "\001";
 static GBool quiet = gFalse;
 static char cfgFileName[256] = "";
+static GBool listEncodings = gFalse;
 static GBool printVersion = gFalse;
 static GBool printHelp = gFalse;
 
@@ -70,6 +73,8 @@
    "maintain original physical layout"},
   {"-simple",  argFlag,     &simpleLayout,  0,
    "simple one-column page layout"},
+  {"-simple2", argFlag,     &simple2Layout, 0,
+   "simple one-column page layout, version 2"},
   {"-table",   argFlag,     &tableLayout,   0,
    "similar to -layout, but optimized for tables"},
   {"-lineprinter", argFlag, &linePrinter,   0,
@@ -108,6 +113,8 @@
    "don't print any messages or errors"},
   {"-cfg",     argString,   cfgFileName,    sizeof(cfgFileName),
    "configuration file to use in place of .xpdfrc"},
+  {"-listencodings", argFlag, &listEncodings, 0,
+   "list all available output text encodings"},
   {"-v",       argFlag,     &printVersion,  0,
    "print copyright and version info"},
   {"-h",       argFlag,     &printHelp,     0,
@@ -153,8 +160,19 @@
   // parse args
   fixCommandLine(&argc, &argv);
   ok = parseArgs(argDesc, &argc, argv);
+  if (ok && listEncodings) {
+    // list available encodings
+    globalParams = new GlobalParams(cfgFileName);
+    GList *encs = globalParams->getAvailableTextEncodings();
+    for (int i = 0; i < encs->getLength(); ++i) {
+      printf("%s\n", ((GString *)encs->get(i))->getCString());
+    }
+    deleteGList(encs, GString);
+    delete globalParams;
+    goto err0;
+  }
   if (!ok || argc < 2 || argc > 3 || printVersion || printHelp) {
-    fprintf(stderr, "pdftotext version %s\n", xpdfVersion);
+    fprintf(stderr, "pdftotext version %s [www.xpdfreader.com]\n", xpdfVersion);
     fprintf(stderr, "%s\n", xpdfCopyright);
     if (!printVersion) {
       printUsage("pdftotext", "<PDF-file> [<text-file>]", argDesc);
@@ -247,6 +265,8 @@
     textOutControl.fixedPitch = fixedPitch;
   } else if (simpleLayout) {
     textOutControl.mode = textOutSimpleLayout;
+  } else if (simple2Layout) {
+    textOutControl.mode = textOutSimple2Layout;
   } else if (linePrinter) {
     textOutControl.mode = textOutLinePrinter;
     textOutControl.fixedPitch = fixedPitch;
@@ -264,7 +284,7 @@
   textOutControl.marginTop = marginTop;
   textOutControl.marginBottom = marginBottom;
   textOut = new TextOutputDev(textFileName->getCString(), &textOutControl,
-			      gFalse);
+			      gFalse, gTrue);
   if (textOut->isOk()) {
     doc->displayPages(textOut, firstPage, lastPage, 72, 72, 0,
 		      gFalse, gTrue, gFalse);

Modified: branches/stable/source/src/m4/ChangeLog
===================================================================
--- branches/stable/source/src/m4/ChangeLog	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/m4/ChangeLog	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,3 +1,11 @@
+2021-02-09  Karl Berry  <karl at freefriends.org>
+
+	* kpse-setup.m4 (_KPSE_RECURSE): add debug if configure not found.
+
+2021-02-07  Karl Berry  <karl at freefriends.org>
+
+	* kpse-pkgs.m4 (KPSE_UTILS_PKGS): new utils program xml2pmx.
+
 2020-05-14  Karl Berry  <karl at freefriends.org>
 
 	* kpse-pkgs.m4 (KPSE_LIBS_PKGS),

Modified: branches/stable/source/src/m4/kpse-pkgs.m4
===================================================================
--- branches/stable/source/src/m4/kpse-pkgs.m4	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/m4/kpse-pkgs.m4	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,4 +1,4 @@
-# $Id: kpse-pkgs.m4 55138 2020-05-14 17:47:47Z karl $
+# $Id: kpse-pkgs.m4 57680 2021-02-08 15:49:16Z karl $
 # Private Autoconf macros for the TeX Live (TL) tree.
 # Copyright 2016-2020 Karl Berry <tex-live at tug.org>
 # Copyright 2009-2015 Peter Breitenlohner <tex-live at tug.org>
@@ -92,6 +92,7 @@
 tpic2pdftex
 vlna
 xindy
+xml2pmx
 xpdfopen
 ])]) # KPSE_UTILS_PKGS
 

Modified: branches/stable/source/src/m4/kpse-setup.m4
===================================================================
--- branches/stable/source/src/m4/kpse-setup.m4	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/m4/kpse-setup.m4	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,6 +1,6 @@
-# $Id: kpse-setup.m4 54307 2020-03-14 22:22:16Z karl $
+# $Id: kpse-setup.m4 57699 2021-02-10 02:06:16Z karl $
 # Private macros for the TeX Live (TL) tree.
-# Copyright 2017-2020 Karl Berry <tex-live at tug.org>
+# Copyright 2017-2021 Karl Berry <tex-live at tug.org>
 # Copyright 2009-2015 Peter Breitenlohner <tex-live at tug.org>
 #
 # This file is free software; the copyright holder
@@ -283,6 +283,8 @@
 if test -x $srcdir/$4Kpse_Pkg/configure; then
   $3 && Kpse_add([MAKE_SUBDIRS])
   Kpse_add([CONF_SUBDIRS])
+else
+  echo 'tldbg:[$0] skipping subdir, no (executable) configure: '"$srcdir"'/$4Kpse_Pkg/configure' >&AS_MESSAGE_LOG_FD
 fi
 ])[]dnl m4_ifdef
 ])

Modified: branches/stable/source/src/texk/Makefile.in
===================================================================
--- branches/stable/source/src/texk/Makefile.in	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/texk/Makefile.in	2021-02-15 19:17:20 UTC (rev 845)
@@ -131,6 +131,7 @@
 	$(top_srcdir)/../utils/xindy/ac/withenable.ac \
 	$(top_srcdir)/../utils/xindy/ac/xindy.ac \
 	$(top_srcdir)/../utils/xindy/ac/clisp.ac \
+	$(top_srcdir)/../utils/xml2pmx/ac/withenable.ac \
 	$(top_srcdir)/../utils/xpdfopen/ac/withenable.ac \
 	$(top_srcdir)/../texk/web2c/ac/withenable.ac \
 	$(top_srcdir)/../texk/web2c/ac/web2c.ac \

Modified: branches/stable/source/src/texk/README
===================================================================
--- branches/stable/source/src/texk/README	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/texk/README	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,5 +1,5 @@
-$Id: README 57051 2020-12-03 10:39:54Z hironobu $
-Copyright 2006-2020 TeX Users Group.
+$Id: README 57560 2021-01-30 06:39:57Z takuji $
+Copyright 2006-2021 TeX Users Group.
 You may freely use, modify and/or distribute this file.
 
 This TeX Live directory contains the programs that use the kpathsea
@@ -63,8 +63,9 @@
 
 dvipsk - maintained here, by us
 
-dvisvgm 2.9.1 - checked 21mar20
+dvisvgm 2.11.1 - checked 23jan21
   https://dvisvgm.de/Downloads/
+  https://github.com/mgieseki/dvisvgm
 
 gregorio 5.2.1 - checked 19dec19
   CTAN/support/gregoriotex/gregorio-5.2.1.zip

Modified: branches/stable/source/src/texk/configure
===================================================================
--- branches/stable/source/src/texk/configure	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/texk/configure	2021-02-15 19:17:20 UTC (rev 845)
@@ -709,6 +709,7 @@
 enable_xindy_rules
 enable_xindy_docs
 with_clisp_runtime
+enable_xml2pmx
 enable_xpdfopen
 enable_web2c
 with_banner_add
@@ -1494,6 +1495,7 @@
   --enable-xindy          build the xindy package
   --enable-xindy-rules      build and install make-rules package
   --enable-xindy-docs       build and install documentation
+  --disable-xml2pmx       do not build the xml2pmx package
   --disable-xpdfopen      do not build the xpdfopen package
   --disable-web2c         do not build the web2c (TeX & Co.) package
   --enable-auto-core        cause TeX&MF to dump core, given a certain
@@ -3635,6 +3637,24 @@
 fi ;;
 esac
 
+## utils/xml2pmx/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory utils/xml2pmx/
+## configure options and TL libraries required for xml2pmx
+# Check whether --enable-xml2pmx was given.
+if test "${enable_xml2pmx+set}" = set; then :
+  enableval=$enable_xml2pmx;
+fi
+case $enable_xml2pmx in #(
+  yes|no) :
+     ;; #(
+  *) :
+
+   enable_xml2pmx=$enable_all_pkgs
+     { $as_echo "$as_me:${as_lineno-$LINENO}: Assuming \`--enable-xml2pmx=$enable_xml2pmx'" >&5
+$as_echo "$as_me: Assuming \`--enable-xml2pmx=$enable_xml2pmx'" >&6;}
+     ac_configure_args="$ac_configure_args '--enable-xml2pmx=$enable_xml2pmx'"
+    ;;
+esac
+
 ## utils/xpdfopen/ac/withenable.ac: configure.ac fragment for the TeX Live subdirectory utils/xpdfopen/
 ## configure options and TL libraries required for xpdfopen
 # Check whether --enable-xpdfopen was given.
@@ -6425,130 +6445,194 @@
 if test -x $srcdir/web2c/configure; then
   test "x$enable_web2c" = xyes && MAKE_SUBDIRS="$MAKE_SUBDIRS web2c"
   CONF_SUBDIRS="$CONF_SUBDIRS web2c"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/web2c/configure' >&5
 fi
 if test -x $srcdir/afm2pl/configure; then
   test "x$enable_afm2pl" = xyes && MAKE_SUBDIRS="$MAKE_SUBDIRS afm2pl"
   CONF_SUBDIRS="$CONF_SUBDIRS afm2pl"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/afm2pl/configure' >&5
 fi
 if test -x $srcdir/bibtex-x/configure; then
   test "x$enable_bibtex_x" = xyes && MAKE_SUBDIRS="$MAKE_SUBDIRS bibtex-x"
   CONF_SUBDIRS="$CONF_SUBDIRS bibtex-x"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/bibtex-x/configure' >&5
 fi
 if test -x $srcdir/chktex/configure; then
   test "x$enable_chktex" = xyes && MAKE_SUBDIRS="$MAKE_SUBDIRS chktex"
   CONF_SUBDIRS="$CONF_SUBDIRS chktex"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/chktex/configure' >&5
 fi
 if test -x $srcdir/cjkutils/configure; then
   test "x$enable_cjkutils" = xyes && MAKE_SUBDIRS="$MAKE_SUBDIRS cjkutils"
   CONF_SUBDIRS="$CONF_SUBDIRS cjkutils"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/cjkutils/configure' >&5
 fi
 if test -x $srcdir/detex/configure; then
   test "x$enable_detex" = xyes && MAKE_SUBDIRS="$MAKE_SUBDIRS detex"
   CONF_SUBDIRS="$CONF_SUBDIRS detex"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/detex/configure' >&5
 fi
 if test -x $srcdir/dtl/configure; then
   test "x$enable_dtl" = xyes && MAKE_SUBDIRS="$MAKE_SUBDIRS dtl"
   CONF_SUBDIRS="$CONF_SUBDIRS dtl"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/dtl/configure' >&5
 fi
 if test -x $srcdir/dvi2tty/configure; then
   test "x$enable_dvi2tty" = xyes && MAKE_SUBDIRS="$MAKE_SUBDIRS dvi2tty"
   CONF_SUBDIRS="$CONF_SUBDIRS dvi2tty"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/dvi2tty/configure' >&5
 fi
 if test -x $srcdir/dvidvi/configure; then
   test "x$enable_dvidvi" = xyes && MAKE_SUBDIRS="$MAKE_SUBDIRS dvidvi"
   CONF_SUBDIRS="$CONF_SUBDIRS dvidvi"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/dvidvi/configure' >&5
 fi
 if test -x $srcdir/dviljk/configure; then
   test "x$enable_dviljk" = xyes && MAKE_SUBDIRS="$MAKE_SUBDIRS dviljk"
   CONF_SUBDIRS="$CONF_SUBDIRS dviljk"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/dviljk/configure' >&5
 fi
 if test -x $srcdir/dviout-util/configure; then
   test "x$enable_dviout_util" = xyes && MAKE_SUBDIRS="$MAKE_SUBDIRS dviout-util"
   CONF_SUBDIRS="$CONF_SUBDIRS dviout-util"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/dviout-util/configure' >&5
 fi
 if test -x $srcdir/dvipdfm-x/configure; then
   test "x$enable_dvipdfm_x" = xyes && MAKE_SUBDIRS="$MAKE_SUBDIRS dvipdfm-x"
   CONF_SUBDIRS="$CONF_SUBDIRS dvipdfm-x"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/dvipdfm-x/configure' >&5
 fi
 if test -x $srcdir/dvipng/configure; then
   test "x$enable_dvipng" = xyes && MAKE_SUBDIRS="$MAKE_SUBDIRS dvipng"
   CONF_SUBDIRS="$CONF_SUBDIRS dvipng"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/dvipng/configure' >&5
 fi
 if test -x $srcdir/dvipos/configure; then
   test "x$enable_dvipos" = xyes && MAKE_SUBDIRS="$MAKE_SUBDIRS dvipos"
   CONF_SUBDIRS="$CONF_SUBDIRS dvipos"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/dvipos/configure' >&5
 fi
 if test -x $srcdir/dvipsk/configure; then
   test "x$enable_dvipsk" = xyes && MAKE_SUBDIRS="$MAKE_SUBDIRS dvipsk"
   CONF_SUBDIRS="$CONF_SUBDIRS dvipsk"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/dvipsk/configure' >&5
 fi
 if test -x $srcdir/dvisvgm/configure; then
   test "x$enable_dvisvgm" = xyes && MAKE_SUBDIRS="$MAKE_SUBDIRS dvisvgm"
   CONF_SUBDIRS="$CONF_SUBDIRS dvisvgm"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/dvisvgm/configure' >&5
 fi
 if test -x $srcdir/gregorio/configure; then
   test "x$enable_gregorio" = xyes && MAKE_SUBDIRS="$MAKE_SUBDIRS gregorio"
   CONF_SUBDIRS="$CONF_SUBDIRS gregorio"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/gregorio/configure' >&5
 fi
 if test -x $srcdir/gsftopk/configure; then
   test "x$enable_gsftopk" = xyes && MAKE_SUBDIRS="$MAKE_SUBDIRS gsftopk"
   CONF_SUBDIRS="$CONF_SUBDIRS gsftopk"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/gsftopk/configure' >&5
 fi
 if test -x $srcdir/lcdf-typetools/configure; then
   test "x$enable_lcdf_typetools" = xyes && MAKE_SUBDIRS="$MAKE_SUBDIRS lcdf-typetools"
   CONF_SUBDIRS="$CONF_SUBDIRS lcdf-typetools"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/lcdf-typetools/configure' >&5
 fi
 if test -x $srcdir/makeindexk/configure; then
   test "x$enable_makeindexk" = xyes && MAKE_SUBDIRS="$MAKE_SUBDIRS makeindexk"
   CONF_SUBDIRS="$CONF_SUBDIRS makeindexk"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/makeindexk/configure' >&5
 fi
 if test -x $srcdir/makejvf/configure; then
   test "x$enable_makejvf" = xyes && MAKE_SUBDIRS="$MAKE_SUBDIRS makejvf"
   CONF_SUBDIRS="$CONF_SUBDIRS makejvf"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/makejvf/configure' >&5
 fi
 if test -x $srcdir/mendexk/configure; then
   test "x$enable_mendexk" = xyes && MAKE_SUBDIRS="$MAKE_SUBDIRS mendexk"
   CONF_SUBDIRS="$CONF_SUBDIRS mendexk"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/mendexk/configure' >&5
 fi
 if test -x $srcdir/musixtnt/configure; then
   test "x$enable_musixtnt" = xyes && MAKE_SUBDIRS="$MAKE_SUBDIRS musixtnt"
   CONF_SUBDIRS="$CONF_SUBDIRS musixtnt"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/musixtnt/configure' >&5
 fi
 if test -x $srcdir/ps2pk/configure; then
   test "x$enable_ps2pk" = xyes && MAKE_SUBDIRS="$MAKE_SUBDIRS ps2pk"
   CONF_SUBDIRS="$CONF_SUBDIRS ps2pk"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/ps2pk/configure' >&5
 fi
 if test -x $srcdir/psutils/configure; then
   test "x$enable_psutils" = xyes && MAKE_SUBDIRS="$MAKE_SUBDIRS psutils"
   CONF_SUBDIRS="$CONF_SUBDIRS psutils"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/psutils/configure' >&5
 fi
 if test -x $srcdir/seetexk/configure; then
   test "x$enable_seetexk" = xyes && MAKE_SUBDIRS="$MAKE_SUBDIRS seetexk"
   CONF_SUBDIRS="$CONF_SUBDIRS seetexk"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/seetexk/configure' >&5
 fi
 if test -x $srcdir/tex4htk/configure; then
   test "x$enable_tex4htk" = xyes && MAKE_SUBDIRS="$MAKE_SUBDIRS tex4htk"
   CONF_SUBDIRS="$CONF_SUBDIRS tex4htk"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/tex4htk/configure' >&5
 fi
 if test -x $srcdir/ttf2pk2/configure; then
   test "x$enable_ttf2pk2" = xyes && MAKE_SUBDIRS="$MAKE_SUBDIRS ttf2pk2"
   CONF_SUBDIRS="$CONF_SUBDIRS ttf2pk2"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/ttf2pk2/configure' >&5
 fi
 if test -x $srcdir/ttfdump/configure; then
   test "x$enable_ttfdump" = xyes && MAKE_SUBDIRS="$MAKE_SUBDIRS ttfdump"
   CONF_SUBDIRS="$CONF_SUBDIRS ttfdump"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/ttfdump/configure' >&5
 fi
 if test -x $srcdir/upmendex/configure; then
   test "x$enable_upmendex" = xyes && MAKE_SUBDIRS="$MAKE_SUBDIRS upmendex"
   CONF_SUBDIRS="$CONF_SUBDIRS upmendex"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/upmendex/configure' >&5
 fi
 if test -x $srcdir/xdvik/configure; then
   test "x$enable_xdvik" = xyes && MAKE_SUBDIRS="$MAKE_SUBDIRS xdvik"
   CONF_SUBDIRS="$CONF_SUBDIRS xdvik"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/xdvik/configure' >&5
 fi
 if test -x $srcdir/texlive/configure; then
   test "x$enable_texlive" = xyes && MAKE_SUBDIRS="$MAKE_SUBDIRS texlive"
   CONF_SUBDIRS="$CONF_SUBDIRS texlive"
+else
+  echo 'tldbg:_KPSE_RECURSE skipping subdir, no (executable) configure: '"$srcdir"'/texlive/configure' >&5
 fi
 
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAKE_SUBDIRS" >&5

Modified: branches/stable/source/src/texk/kpathsea/texmf.cnf
===================================================================
--- branches/stable/source/src/texk/kpathsea/texmf.cnf	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/texk/kpathsea/texmf.cnf	2021-02-15 19:17:20 UTC (rev 845)
@@ -764,9 +764,7 @@
 % 
 Part 3: Array and other sizes for TeX, Metafont, etc.
 %
 % If you want to change some of these sizes only for a certain TeX
-% variant, the usual dot notation works, e.g.,
-% main_memory.hugetex = 20000000
-%
+% variant, the usual dot notation works, as shown below for ConTeXt.
 % If a change here appears to be ignored, try redumping the format file.
 
 % Memory. Must be less than 8,000,000 total.
@@ -827,8 +825,9 @@
 %
 trie_size = 1000000
 
-hyph_size = 8191        % prime number of hyphenation exceptions, >610, <32767.
+hyph_size = 8191        % prime number of hyphenation exceptions, >610, <65535
                         % http://primes.utm.edu/curios/page.php/8191.html
+                        % dynamically increased as necessary, so not important.
 nest_size = 500         % simultaneous semantic levels (e.g., groups)
 max_in_open = 15        % simultaneous input files and error insertions, 
                         % also applies to MetaPost

Modified: branches/stable/source/src/texk/web2c/ChangeLog
===================================================================
--- branches/stable/source/src/texk/web2c/ChangeLog	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/texk/web2c/ChangeLog	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,3 +1,181 @@
+2021-02-14  Petr Olsak  <petr at olsak.net>
+
+	* tracingstacklevels.ch: slow_print(cur_ext) also.
+
+2021-02-13  Karl Berry  <karl at freefriends.org>
+
+	* enctexdir/enctex1.ch,
+	* enctexdir/enctex2.ch,
+	* enctexdir/enctex-tex.ch,
+	* enctexdir/enctex-pdftex.ch: new files, from enctex.ch.
+	* am/texmf.am (tex_ch_srcs): split enctex changes into
+	common (enctex1.ch, enctex2.ch) and differing (enctex-tex.ch,
+	enctex-pdftex.ch) pieces to avoid duplicating the whole thing.
+	* enctex.ch,
+	* enctex2.ch: remove.
+
+2021-02-13  Hironori Kitagawa  <h_kitagawa2001 at yahoo.co.jp>
+
+	* eptexdir/am/eptex.am, eptexdir/etex.ch1,
+	euptexdir/am/euptex.am, ptexdir/am/ptex.am,
+	ptexdir/ptex-base.ch, synctexdir/synctex-ep-mem.ch1,
+	synctexdir/synctex-p-mem.ch1, and uptexdir/am/uptex.am:
+	Support \tracingstacklevels in [e][u]pTeX.
+
+2021-02-13  Akira Kakuto  <kakuto at w32tex.org>
+
+	* enctex.ch: Recover the original enctex.ch in order to be
+	compatible with the TeX.
+	* enctex2.ch: Rename the new enctex.ch for pdfTeX.
+	* pdftexdir/am/pdftex.am: Rename enctex.ch to enctex2.ch.
+
+2021-02-12  Karl Berry  <karl at freefriends.org>
+
+	* tracingstacklevels.ch: new change file for \tracingstacklevels
+	parameter, proposed and implemented by Petr Olsak.
+	* pdftexdir/am/pdftex.am (pdftex_ch_srcs),
+	* xetexdir/am/xetex.am (xetex_ch_srcs): add it.
+	* tests/tracingstacklevels.tex,
+	* tests/tracingstacklevel2.tex: test files (for manual use; not
+	included in make check).
+	* xetexdir/xetex.ch (v): new declaration needed in start_input.
+	* enctex.ch: adjust web2c_int_pars so that this is applied after
+	tracingstacklevels.ch.
+
+2021-02-08  Andreas Scherer  <https://ascherer.github.io>
+
+	* ctangleboot.cin,
+	* cwebboot.cin: Don't repeat yourself.
+
+2021-02-07  Andreas Scherer  <https://ascherer.github.io>
+
+	* cwebboot.cin: CWEB development has moved to another level.
+
+2021-02-07  Andreas Scherer  <https://ascherer.github.io>
+
+	* ctangleboot.cin,
+	* cwebboot.cin,
+	* cwebdir/*,
+	* man/ctwill.man,
+	* man/cweb.man: New CWEB 4.0 amd CWEBbin 2021.
+
+2021-02-05  Karl Berry  <karl at freefriends.org>
+
+	* mf.ch: adjust for latest fixes.
+
+2021-02-05  Donald Knuth  <tex-k at tug.org>
+
+	* mf.web,
+	* tex.web: further fixes. Reports from Udo Wermuth
+	and Phelype Oleinik.
+	* triptrap/trip.log: update for newly added blank line.
+
+2021-01-31  Karl Berry  <karl at freefriends.org>
+
+	* weave.ch (banner): 4.5.
+
+2021-01-31  Donald Knuth  <tex-k at tug.org>
+
+	* weave.web (banner, title): should have been 4.5.
+	Report from Wolfgang Helbig.
+
+2021-01-29  Karl Berry  <karl at freefriends.org>
+
+	* NEWS: mention tuneup.
+
+	* alephdir/alephextra.h,
+	* alephdir/com16bit.ch,
+	* alephdir/eobase.ch,
+	* alephdir/eocprt.ch,
+	* alephdir/eoext.ch,
+	* alephdir/eover.ch,
+	* alephdir/om16bit.ch,
+	* alephdir/omfont.ch,
+	* alephdir/omstr.ch,
+	* eptexdir/eptex.ech,
+	* eptexdir/eptexextra.h,
+	* etexdir/etex.ch,
+	* etexdir/etexextra.h,
+	* etexdir/tex.ch0,
+	* etexdir/tex.ech,
+	* euptexdir/euptex.ch0,
+	* euptexdir/euptexextra.h,
+	* lib/texmfmp.c,
+	* mf-binpool.ch,
+	* mf.ch,
+	* mfluadir/mf-lua.ch,
+	* mfluadir/mflua_version.h,
+	* mfluadir/mfluaextra.h,
+	* mfluajitdir/mf-luajit.ch,
+	* mfluajitdir/mfluajitextra.h,
+	* mft.ch,
+	* pdftexdir/pdftexextra.h,
+	* pdftexdir/tex.ch0,
+	* ptexdir/ptex-base.ch,
+	* ptexdir/ptexextra.h,
+	* tangle.ch,
+	* tangleboot.pin,
+	* tex.ch,
+	* uptexdir/uptex-m.ch,
+	* uptexdir/uptexextra.h,
+	* weave.ch,
+	* xetexdir/xetexextra.h: updates for 2021 tuneup.
+
+	* mftraptest.test,
+	* triptest.test,
+	* triptrap-sh,
+	* mfluadir/mfluatrap/mfluatrap.diffs,
+	* etexdir/etrip/etrip.diffs,
+	* triptrap/trip.diffs,
+	* triptrap/mftrap.diffs,
+	* triptrap/mptrap.diffs,
+	* eptexdir/eptrip/eptrip.diffs,
+	* uptexdir/uptrip/uptrip.diffs,
+	* euptexdir/euptrip/euptrip.diffs,
+	* mfluajitdir/mfluajittrap/mfluajittrap.diffs,
+	* ptexdir/ptrip/ptrip.diffs: trip/trap updates for 2021 tuneup.
+
+	* tangleboot.pin: update bootstrap file.
+
+	* triptrap/README,
+	* Makefile.am: doc for running triptrap.
+
+2021-01-29  Donald Knuth  <tex-k at tug.org>
+
+	2021 tuneup update. Overview:
+	  https://tug.org/TUGboat/tb42-1/tb130knuth-tuneup21.pdf
+	Bug reporting info:
+	  https://tug.org/texmfbug/
+	New TeX version is 3.141592653, MF 2.71828182.
+
+	* dvitype.web,
+	* gftodvi.web,
+	* gftopk.web,
+	* gftype.web,
+	* mf.web,
+	* mft.web,
+	* pltotf.web,
+	* pooltype.web,
+	* tangle.web,
+	* tex.web,
+	* tftopl.web,
+	* vftovp.web,
+	* vptovf.web,
+	* weave.web: new versions. BTW, these are all of the web
+	files which DEK maintains. The rest are maintained by other people:
+	bibtex.web (Oren), patgen.web and dvicopy.web (here),
+	pktype.web and pktogf.web (Tom Rokicki).
+	
+	* triptrap/mftrap.fot,
+	* triptrap/mftrap.log,
+	* triptrap/mftrapin.log,
+	* triptrap/trap.typ,
+	* triptrap/trip.fot,
+	* triptrap/trip.log,
+	* triptrap/trip.tex,
+	* triptrap/trip.typ,
+	* triptrap/tripin.log: trip and trap test updates.
+
 2020-10-27  Karl Berry  <karl at freefriends.org>
 
 	* pktogf.web: TFM widths are 2^20 times the ratio, not 2^24.

Modified: branches/stable/source/src/texk/web2c/Makefile.am
===================================================================
--- branches/stable/source/src/texk/web2c/Makefile.am	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/texk/web2c/Makefile.am	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,7 +1,7 @@
-## $Id: Makefile.am 57374 2021-01-10 20:13:26Z lscarso $
+## $Id: Makefile.am 57558 2021-01-30 01:42:07Z karl $
 ## Makefile.am for the TeX Live subdirectory texk/web2c/.
 ##
-## Copyright 2017-2020 Karl Berry <tex-live at tug.org>
+## Copyright 2017-2021 Karl Berry <tex-live at tug.org>
 ## Copyright 2009-2015 Peter Breitenlohner <tex-live at tug.org>
 ## You may freely use, modify and/or distribute this file.
 ##
@@ -157,6 +157,31 @@
 AM_TESTS_ENVIRONMENT += LN_S='$(LN_S)'; export LN_S;
 AM_TESTS_ENVIRONMENT += KPSEWHICH='$(KPSEWHICH)'; export KPSEWHICH;
 
+# To run, e.g., just the original trip test, in the build directory:
+#   make -C $ww TRIPTRAP=trip.diffs triptrap
+# where $ww is the web2c build directory.   
+# 
+# This will run the triptrap-sh script
+#   which then runs make TEST=triptest.test check-am,
+#   which then runs the (srcdir file) triptest.test script;
+#   its output will be in (builddir file) trip.diffs,
+#   and triptest.out if the test failed,   
+#   plus various created files in the tripdir/ subdirectory.
+# The triptest.diffs file will have the actual abs_srcdir value replaced
+#  with the constant string "SRCDIR" to minimize differences, and "../"
+#  replaced with "./" to match the canonical output. Confusing. For the
+#  real output, see triptest.log.
+# 
+# To build only tex, make -C $ww tex (i.e., in builddir) should do it.
+# Unfortunately the check-am target depends on all-am, so all engines
+# are built before any tests are run. If this is a problem, just have to
+# edit the generated Makefile in builddir to remove the dependency.
+# 
+# Other per-engine invocations (see triptrap-sh for complete list):
+#   make -C $ww mf && make -C $ww TRIPTRAP=mftrap.diffs triptrap
+#   make -C $ww etex && make -C $ww TRIPTRAP=etrip.diffs triptrap   
+#   make -C $ww ptex && make -C $ww TRIPTRAP=ptrip.diffs triptrap   
+#   
 triptrap_diffs = $(AM_V_GEN)srcdir=$(srcdir) abs_srcdir=$(abs_srcdir) MAKE=$(MAKE) $(SHELL) $(srcdir)/triptrap-sh
 
 .PHONY: triptrap

Modified: branches/stable/source/src/texk/web2c/Makefile.in
===================================================================
--- branches/stable/source/src/texk/web2c/Makefile.in	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/texk/web2c/Makefile.in	2021-02-15 19:17:20 UTC (rev 845)
@@ -3680,6 +3680,32 @@
 	DIFF='$(DIFF)'; export DIFF; DIFFFLAGS='$(DIFFFLAGS)'; export \
 	DIFFFLAGS; LN_S='$(LN_S)'; export LN_S; \
 	KPSEWHICH='$(KPSEWHICH)'; export KPSEWHICH;
+
+# To run, e.g., just the original trip test, in the build directory:
+#   make -C $ww TRIPTRAP=trip.diffs triptrap
+# where $ww is the web2c build directory.   
+# 
+# This will run the triptrap-sh script
+#   which then runs make TEST=triptest.test check-am,
+#   which then runs the (srcdir file) triptest.test script;
+#   its output will be in (builddir file) trip.diffs,
+#   and triptest.out if the test failed,   
+#   plus various created files in the tripdir/ subdirectory.
+# The triptest.diffs file will have the actual abs_srcdir value replaced
+#  with the constant string "SRCDIR" to minimize differences, and "../"
+#  replaced with "./" to match the canonical output. Confusing. For the
+#  real output, see triptest.log.
+# 
+# To build only tex, make -C $ww tex (i.e., in builddir) should do it.
+# Unfortunately the check-am target depends on all-am, so all engines
+# are built before any tests are run. If this is a problem, just have to
+# edit the generated Makefile in builddir to remove the dependency.
+# 
+# Other per-engine invocations (see triptrap-sh for complete list):
+#   make -C $ww mf && make -C $ww TRIPTRAP=mftrap.diffs triptrap
+#   make -C $ww etex && make -C $ww TRIPTRAP=etrip.diffs triptrap   
+#   make -C $ww ptex && make -C $ww TRIPTRAP=ptrip.diffs triptrap   
+#   
 triptrap_diffs = $(AM_V_GEN)srcdir=$(srcdir) abs_srcdir=$(abs_srcdir) MAKE=$(MAKE) $(SHELL) $(srcdir)/triptrap-sh
 
 # The environment for making dumps.
@@ -3748,7 +3774,9 @@
 tex_ch_srcs = \
 	tex.web \
 	tex.ch \
-	enctex.ch \
+	enctexdir/enctex1.ch \
+	enctexdir/enctex-tex.ch \
+	enctexdir/enctex2.ch \
 	$(tex_ch_synctex) \
 	tex-binpool.ch
 
@@ -4241,7 +4269,9 @@
 	etexdir/tex.ch0 \
 	tex.ch \
 	zlib-fmt.ch \
-	enctex.ch \
+	enctexdir/enctex1.ch \
+	enctexdir/enctex-tex.ch \
+	enctexdir/enctex2.ch \
 	$(etex_ch_synctex) \
 	etexdir/tex.ch1 \
 	etexdir/tex.ech \
@@ -4276,6 +4306,7 @@
 ptex_web_srcs = \
 	tex.web \
 	tex.ch \
+	tracingstacklevels.ch \
 	zlib-fmt.ch
 
 ptex_ch_srcs = \
@@ -4335,6 +4366,7 @@
 	etexdir/etex.ch \
 	etexdir/tex.ch0 \
 	tex.ch \
+	tracingstacklevels.ch \
 	zlib-fmt.ch \
 	etexdir/tex.ech
 
@@ -4379,6 +4411,7 @@
 uptex_web_srcs = \
 	tex.web \
 	tex.ch \
+	tracingstacklevels.ch \
 	zlib-fmt.ch
 
 uptex_ch_srcs = \
@@ -4443,6 +4476,7 @@
 	etexdir/etex.ch \
 	etexdir/tex.ch0 \
 	tex.ch \
+	tracingstacklevels.ch \
 	zlib-fmt.ch \
 	etexdir/tex.ech
 
@@ -4513,8 +4547,11 @@
 	pdftexdir/pdftex.web \
 	pdftexdir/tex.ch0 \
 	tex.ch \
+	tracingstacklevels.ch \
 	zlib-fmt.ch \
-	enctex.ch \
+	enctexdir/enctex1.ch \
+	enctexdir/enctex-pdftex.ch \
+	enctexdir/enctex2.ch \
 	$(pdftex_ch_synctex) \
 	pdftexdir/pdftex.ch \
 	pdftexdir/char-warning-pdftex.ch \
@@ -5202,6 +5239,7 @@
 	xetexdir/xetex.web \
 	xetexdir/tex.ch0 \
 	tex.ch \
+	tracingstacklevels.ch \
 	$(xetex_ch_synctex) \
 	xetexdir/xetex.ch \
 	$(xetex_post_ch_synctex) \

Modified: branches/stable/source/src/texk/web2c/NEWS
===================================================================
--- branches/stable/source/src/texk/web2c/NEWS	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/texk/web2c/NEWS	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,11 +1,18 @@
 This file records noteworthy changes.  (Public domain.)
 
-* pdftex, xetex, e(u)ptex: if \tracinglostchars >= 3,
-make missing characters an error (not just a log message),
-and always report the character code in hex.
+* Knuth 2021 tune-up, with fixes to all of his *.web files. Overview:
+https://tug.org/TUGboat/42-1/tb130knuth-tuneup21.pdf
+New TeX version is 3.141592653, MF 2.71828182.
 
-* obscure interaction sequences try to avoid crashing.
+* for all engines except original TeX:
+- if \tracinglostchars >= 3, make missing characters an error (not just
+  a log message), and always report the character code in hex.
+- if new primitive parameter \tracingstacklevels > 0, logging of macro
+  expansion at higher levels is truncated; also, the macro expansion
+  depth is indicated on \tracingmacros log lines.
 
+* obscure interaction sequences no longer crash.
+
 

 2020 (for TeX Live 2020, 27 March 2020)
 * \input now also accepts a group-delimited filename, e.g.,

Modified: branches/stable/source/src/texk/web2c/am/texmf.am
===================================================================
--- branches/stable/source/src/texk/web2c/am/texmf.am	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/texk/web2c/am/texmf.am	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,4 +1,4 @@
-## $Id: texmf.am 53155 2019-12-17 19:24:59Z karl $
+## $Id: texmf.am 57736 2021-02-13 23:02:37Z karl $
 ## texk/web2c/am/texmf.am: Makefile fragment for TeX and MF.
 ##
 ## Copyright 2015-2019 Karl Berry <tex-live at tug.org>
@@ -64,7 +64,9 @@
 tex_ch_srcs = \
 	tex.web \
 	tex.ch \
-	enctex.ch \
+	enctexdir/enctex1.ch \
+	enctexdir/enctex-tex.ch \
+	enctexdir/enctex2.ch \
 	$(tex_ch_synctex) \
 	tex-binpool.ch
 ##

Modified: branches/stable/source/src/texk/web2c/ctangleboot.cin
===================================================================
--- branches/stable/source/src/texk/web2c/ctangleboot.cin	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/texk/web2c/ctangleboot.cin	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,15 +1,9 @@
 /*1:*/
-#line 64 "cwebdir/ctangle.w"
+#line 66 "cwebdir/ctangle.w"
 
-/*2:*/
-#line 73 "cwebdir/ctang-w2c.ch"
+/*4:*/
+#line 53 "cwebdir/comm-w2c.h"
 
-#include <string.h> 
-#line 83 "cwebdir/ctangle.w"
-
-/*:2*//*6:*/
-#line 52 "cwebdir/comm-w2c.h"
-
 #ifndef HAVE_GETTEXT
 #define HAVE_GETTEXT 0
 #endif
@@ -20,33 +14,20 @@
 #define gettext(A) A
 #endif
 
+#include <ctype.h>  
 #include <stdbool.h>  
+#include <stddef.h>  
 #include <stdint.h>  
-#include <stdio.h> 
-
-/*:6*//*62:*/
-#line 888 "cwebdir/ctangle.w"
-
-#include <ctype.h>  
 #include <stdlib.h>  
+#include <stdio.h>  
+#include <string.h>  
 
-/*:62*/
-#line 65 "cwebdir/ctangle.w"
+/*:4*/
+#line 67 "cwebdir/ctangle.w"
 
-#define banner "This is CTANGLE, Version 3.64" \
+#define banner "This is CTANGLE, Version 4.0" \
  \
 
-#define max_bytes 1000000 \
-
-#define max_toks 1000000
-#define max_names 10239 \
-
-#define max_texts 10239
-#define hash_size 8501
-#define longest_name 10000
-#define stack_size 50
-#define buf_size 1000 \
-
 #define _(S) gettext(S)  \
 
 #define and_and 04
@@ -87,15 +68,20 @@
 #define mark_harmless {if(history==spotless) history= harmless_message;}
 #define mark_error history= error_message
 #define confusion(s) fatal(_("! This can't happen: ") ,s)  \
+ \
 
+#define max_include_depth 10 \
+
 #define max_file_name_length 1024
 #define cur_file file[include_depth]
 #define cur_file_name file_name[include_depth]
-#define web_file_name file_name[0]
-#define cur_line line[include_depth] \
+#define cur_line line[include_depth]
+#define web_file file[0]
+#define web_file_name file_name[0] \
 
 #define show_banner flags['b']
 #define show_progress flags['p']
+#define show_stats flags['s']
 #define show_happiness flags['h']
 #define temporary_output flags['t']
 #define make_xrefs flags['x'] \
@@ -107,6 +93,18 @@
 #define C_printf(c,a) fprintf(C_file,c,a) 
 #define C_putc(c) putc(c,C_file)  \
 
+#define max_bytes 1000000 \
+
+#define max_toks 1000000
+#define max_names 10239 \
+
+#define max_sections 4000
+#define max_texts 10239
+#define longest_name 10000
+#define stack_size 500
+#define buf_size 1000
+#define long_buf_size (buf_size+longest_name)  \
+
 #define equiv equiv_or_xref \
 
 #define section_flag max_texts \
@@ -148,7 +146,7 @@
 
 #define isxalpha(c) ((c) =='_'||(c) =='$')  \
 
-#define ishigh(c) ((unsigned char) (c) > 0177)  \
+#define ishigh(c) ((eight_bits) (c) > 0177)  \
  \
 
 #define compress(c) if(loc++<=limit) return(c)  \
@@ -159,10 +157,10 @@
 #define max_banner 50 \
 
 
-#line 66 "cwebdir/ctangle.w"
+#line 68 "cwebdir/ctangle.w"
 
-/*5:*/
-#line 34 "cwebdir/comm-w2c.h"
+/*3:*/
+#line 35 "cwebdir/comm-w2c.h"
 
 typedef bool boolean;
 typedef uint8_t eight_bits;
@@ -173,8 +171,8 @@
 extern cweb program;
 extern int phase;
 
-/*:5*//*7:*/
-#line 86 "cwebdir/comm-w2c.h"
+/*:3*//*5:*/
+#line 91 "cwebdir/comm-w2c.h"
 
 extern char section_text[];
 extern char*section_text_end;
@@ -181,8 +179,8 @@
 extern char*id_first;
 extern char*id_loc;
 
-/*:7*//*8:*/
-#line 101 "cwebdir/comm-w2c.h"
+/*:5*//*6:*/
+#line 105 "cwebdir/comm-w2c.h"
 
 extern char buffer[];
 extern char*buffer_end;
@@ -189,8 +187,8 @@
 extern char*loc;
 extern char*limit;
 
-/*:8*//*9:*/
-#line 116 "cwebdir/comm-w2c.h"
+/*:6*//*7:*/
+#line 120 "cwebdir/comm-w2c.h"
 
 typedef struct name_info{
 char*byte_start;
@@ -213,27 +211,14 @@
 extern name_pointer hash[];
 extern hash_pointer hash_end;
 extern hash_pointer h;
-extern boolean names_match(name_pointer,const char*,size_t,eight_bits);
-extern name_pointer id_lookup(const char*,const char*,char);
 
-extern name_pointer section_lookup(char*,char*,int);
-extern void init_node(name_pointer);
-extern void init_p(name_pointer,eight_bits);
-extern void print_prefix_name(name_pointer);
-extern void print_section_name(name_pointer);
-extern void sprint_section_name(char*,name_pointer);
+/*:7*//*9:*/
+#line 164 "cwebdir/comm-w2c.h"
 
-/*:9*//*10:*/
-#line 157 "cwebdir/comm-w2c.h"
-
 extern int history;
-extern int wrap_up(void);
-extern void err_print(const char*);
-extern void fatal(const char*,const char*);
-extern void overflow(const char*);
 
-/*:10*//*11:*/
-#line 172 "cwebdir/comm-w2c.h"
+/*:9*//*11:*/
+#line 184 "cwebdir/comm-w2c.h"
 
 extern int include_depth;
 extern FILE*file[];
@@ -242,10 +227,10 @@
 extern char tex_file_name[];
 extern char idx_file_name[];
 extern char scn_file_name[];
-extern char check_file_name[];
 extern char file_name[][max_file_name_length];
 
 extern char change_file_name[];
+extern char check_file_name[];
 extern int line[];
 extern int change_line;
 extern int change_depth;
@@ -252,12 +237,9 @@
 extern boolean input_has_ended;
 extern boolean changing;
 extern boolean web_file_open;
-extern boolean get_line(void);
-extern void check_complete(void);
-extern void reset_input(void);
 
-/*:11*//*12:*/
-#line 195 "cwebdir/comm-w2c.h"
+/*:11*//*13:*/
+#line 209 "cwebdir/comm-w2c.h"
 
 extern sixteen_bits section_count;
 extern boolean changed_section[];
@@ -264,41 +246,34 @@
 extern boolean change_pending;
 extern boolean print_where;
 
-/*:12*//*13:*/
-#line 208 "cwebdir/comm-w2c.h"
+/*:13*//*14:*/
+#line 223 "cwebdir/comm-w2c.h"
 
 extern int argc;
 extern char**argv;
 extern boolean flags[];
+extern const char*use_language;
 
-/*:13*//*14:*/
-#line 220 "cwebdir/comm-w2c.h"
+/*:14*//*15:*/
+#line 236 "cwebdir/comm-w2c.h"
 
 extern FILE*C_file;
 extern FILE*tex_file;
 extern FILE*idx_file;
 extern FILE*scn_file;
+extern FILE*active_file;
 extern FILE*check_file;
-extern FILE*active_file;
 
-/*:14*//*15:*/
-#line 230 "cwebdir/comm-w2c.h"
+/*:15*//*116:*/
+#line 473 "cwebdir/ctang-w2c.ch"
 
-extern void common_init(void);
-extern void print_stats(void);
-extern void cb_show_banner(void);
-#line 128 "cwebdir/ctangle.w"
-
-/*:15*//*108:*/
-#line 903 "cwebdir/ctang-w2c.ch"
-
 extern char cb_banner[];
 
-/*:108*/
-#line 67 "cwebdir/ctangle.w"
+/*:116*/
+#line 69 "cwebdir/ctangle.w"
 
-/*16:*/
-#line 152 "cwebdir/ctangle.w"
+/*19:*/
+#line 122 "cwebdir/ctangle.w"
 
 typedef struct{
 eight_bits*tok_start;
@@ -306,8 +281,8 @@
 }text;
 typedef text*text_pointer;
 
-/*:16*//*27:*/
-#line 296 "cwebdir/ctangle.w"
+/*:19*//*31:*/
+#line 270 "cwebdir/ctangle.w"
 
 typedef struct{
 eight_bits*end_field;
@@ -318,11 +293,11 @@
 }output_state;
 typedef output_state*stack_pointer;
 
-/*:27*/
-#line 68 "cwebdir/ctangle.w"
+/*:31*/
+#line 70 "cwebdir/ctangle.w"
 
-/*17:*/
-#line 159 "cwebdir/ctangle.w"
+/*20:*/
+#line 129 "cwebdir/ctangle.w"
 
 text text_info[max_texts];
 text_pointer text_info_end= text_info+max_texts-1;
@@ -331,13 +306,13 @@
 eight_bits*tok_mem_end= tok_mem+max_toks-1;
 eight_bits*tok_ptr;
 
-/*:17*//*23:*/
-#line 227 "cwebdir/ctangle.w"
+/*:20*//*26:*/
+#line 198 "cwebdir/ctangle.w"
 
 text_pointer last_unnamed;
 
-/*:23*//*28:*/
-#line 312 "cwebdir/ctangle.w"
+/*:26*//*32:*/
+#line 286 "cwebdir/ctangle.w"
 
 output_state cur_state;
 
@@ -345,163 +320,207 @@
 stack_pointer stack_ptr;
 stack_pointer stack_end= stack+stack_size;
 
-/*:28*//*32:*/
-#line 384 "cwebdir/ctangle.w"
+/*:32*//*37:*/
+#line 362 "cwebdir/ctangle.w"
 
 int cur_val;
 
-/*:32*//*36:*/
-#line 473 "cwebdir/ctangle.w"
+/*:37*//*42:*/
+#line 454 "cwebdir/ctangle.w"
 
 eight_bits out_state;
 boolean protect;
 
-/*:36*//*38:*/
-#line 502 "cwebdir/ctangle.w"
+/*:42*//*45:*/
+#line 486 "cwebdir/ctangle.w"
 
 name_pointer output_files[max_files];
 name_pointer*cur_out_file,*end_output_files,*an_output_file;
 char cur_section_name_char;
-char output_file_name[longest_name];
+char output_file_name[longest_name+1];
 
-/*:38*//*45:*/
-#line 599 "cwebdir/ctangle.w"
+/*:45*//*52:*/
+#line 586 "cwebdir/ctangle.w"
 
 boolean output_defs_seen= 0;
 
-/*:45*//*51:*/
-#line 710 "cwebdir/ctangle.w"
+/*:52*//*57:*/
+#line 695 "cwebdir/ctangle.w"
 
 char translit[128][translit_length];
 
-/*:51*//*56:*/
-#line 789 "cwebdir/ctangle.w"
+/*:57*//*62:*/
+#line 774 "cwebdir/ctangle.w"
 
 eight_bits ccode[256];
 
-/*:56*//*59:*/
-#line 845 "cwebdir/ctangle.w"
+/*:62*//*66:*/
+#line 834 "cwebdir/ctangle.w"
 
 boolean comment_continues= 0;
 
-/*:59*//*61:*/
-#line 884 "cwebdir/ctangle.w"
+/*:66*//*68:*/
+#line 873 "cwebdir/ctangle.w"
 
 name_pointer cur_section_name;
 int no_where;
 
-/*:61*//*75:*/
-#line 1195 "cwebdir/ctangle.w"
+/*:68*//*82:*/
+#line 1187 "cwebdir/ctangle.w"
 
 text_pointer cur_text;
 eight_bits next_control;
 
-/*:75*//*82:*/
-#line 1353 "cwebdir/ctangle.w"
+/*:82*//*90:*/
+#line 1348 "cwebdir/ctangle.w"
 
 extern sixteen_bits section_count;
 
-/*:82*/
-#line 69 "cwebdir/ctangle.w"
+/*:90*/
+#line 71 "cwebdir/ctangle.w"
 
-/*41:*/
-#line 533 "cwebdir/ctangle.w"
+/*8:*/
+#line 143 "cwebdir/comm-w2c.h"
 
-#line 264 "cwebdir/ctang-w2c.ch"
-static void phase_two(void);
-#line 535 "cwebdir/ctangle.w"
+extern boolean names_match(name_pointer,const char*,size_t,eight_bits);
+extern name_pointer id_lookup(const char*,const char*,char);
 
-/*:41*//*46:*/
-#line 602 "cwebdir/ctangle.w"
+extern name_pointer section_lookup(char*,char*,int);
+extern void init_node(name_pointer);
+extern void init_p(name_pointer,eight_bits);
+extern void print_prefix_name(name_pointer);
+extern void print_section_name(name_pointer);
+extern void sprint_section_name(char*,name_pointer);
 
-#line 351 "cwebdir/ctang-w2c.ch"
-static void output_defs(void);
-#line 604 "cwebdir/ctangle.w"
+/*:8*//*10:*/
+#line 167 "cwebdir/comm-w2c.h"
 
-/*:46*//*48:*/
-#line 648 "cwebdir/ctangle.w"
+extern int wrap_up(void);
+extern void err_print(const char*);
+extern void fatal(const char*,const char*);
+extern void overflow(const char*);
 
-#line 371 "cwebdir/ctang-w2c.ch"
-static void out_char(eight_bits);
-#line 650 "cwebdir/ctangle.w"
+/*:10*//*12:*/
+#line 203 "cwebdir/comm-w2c.h"
 
-/*:48*//*90:*/
-#line 1460 "cwebdir/ctangle.w"
+extern boolean get_line(void);
+extern void check_complete(void);
+extern void reset_input(void);
 
-#line 667 "cwebdir/ctang-w2c.ch"
-static void phase_one(void);
-#line 1462 "cwebdir/ctangle.w"
+/*:12*//*16:*/
+#line 245 "cwebdir/comm-w2c.h"
 
-/*:90*//*92:*/
-#line 1478 "cwebdir/ctangle.w"
+extern void common_init(void);
+extern void print_stats(void);
+extern void cb_show_banner(void);
 
-#line 681 "cwebdir/ctang-w2c.ch"
-static void skip_limbo(void);
-#line 1480 "cwebdir/ctangle.w"
+/*:16*//*29:*/
+#line 231 "cwebdir/ctangle.w"
 
-/*:92*//*97:*/
-#line 766 "cwebdir/ctang-w2c.ch"
+static void store_two_bytes(sixteen_bits);
 
-static eight_bits get_next(void);
+/*:29*//*34:*/
+#line 310 "cwebdir/ctangle.w"
+
+static void push_level(name_pointer);
+static void pop_level(int);
+
+/*:34*//*38:*/
+#line 369 "cwebdir/ctangle.w"
+
+static void get_output(void);
+
+/*:38*//*43:*/
+#line 462 "cwebdir/ctangle.w"
+
+static void flush_buffer(void);
+
+/*:43*//*48:*/
+#line 517 "cwebdir/ctangle.w"
+
+static void phase_two(void);
+
+/*:48*//*53:*/
+#line 589 "cwebdir/ctangle.w"
+
+static void output_defs(void);
+static void out_char(eight_bits);
+
+/*:53*//*64:*/
+#line 798 "cwebdir/ctangle.w"
+
 static eight_bits skip_ahead(void);
 static boolean skip_comment(boolean);
-static void flush_buffer(void);
-static void get_output(void);
-static void pop_level(int);
-static void push_level(name_pointer);
+
+/*:64*//*69:*/
+#line 885 "cwebdir/ctangle.w"
+
+static eight_bits get_next(void);
+
+/*:69*//*83:*/
+#line 1191 "cwebdir/ctangle.w"
+
 static void scan_repl(eight_bits);
+
+/*:83*//*91:*/
+#line 1355 "cwebdir/ctangle.w"
+
 static void scan_section(void);
-static void store_two_bytes(sixteen_bits);
 
-/*:97*/
-#line 70 "cwebdir/ctangle.w"
+/*:91*//*99:*/
+#line 1458 "cwebdir/ctangle.w"
 
+static void phase_one(void);
 
-#line 68 "cwebdir/ctang-w2c.ch"
-/*:1*//*3:*/
-#line 91 "cwebdir/ctangle.w"
+/*:99*//*101:*/
+#line 1476 "cwebdir/ctangle.w"
 
-#line 82 "cwebdir/ctang-w2c.ch"
+static void skip_limbo(void);
+
+/*:101*/
+#line 72 "cwebdir/ctangle.w"
+
+
+/*:1*//*2:*/
+#line 81 "cwebdir/ctangle.w"
+
 int main(
 int ac,
 char**av)
-#line 95 "cwebdir/ctangle.w"
 {
 argc= ac;argv= av;
 program= ctangle;
-/*18:*/
-#line 167 "cwebdir/ctangle.w"
+/*21:*/
+#line 137 "cwebdir/ctangle.w"
 
 text_info->tok_start= tok_ptr= tok_mem;
 text_ptr= text_info+1;text_ptr->tok_start= tok_mem;
 
 
-/*:18*//*20:*/
-#line 177 "cwebdir/ctangle.w"
+/*:21*//*23:*/
+#line 147 "cwebdir/ctangle.w"
 
-#line 143 "cwebdir/ctang-w2c.ch"
 init_node(name_dir);
-#line 179 "cwebdir/ctangle.w"
 
-/*:20*//*24:*/
-#line 230 "cwebdir/ctangle.w"
+/*:23*//*27:*/
+#line 201 "cwebdir/ctangle.w"
 last_unnamed= text_info;text_info->text_link= 0;
 
-/*:24*//*39:*/
-#line 512 "cwebdir/ctangle.w"
+/*:27*//*46:*/
+#line 496 "cwebdir/ctangle.w"
 
 cur_out_file= end_output_files= output_files+max_files;
 
-/*:39*//*52:*/
-#line 713 "cwebdir/ctangle.w"
+/*:46*//*58:*/
+#line 698 "cwebdir/ctangle.w"
 
 {
 int i;
-for(i= 0;i<128;i++)sprintf(translit[i],"X%02X",(unsigned)(128+i));
+for(i= 0;i<128;i++)sprintf(translit[i],"X%02X",(unsigned int)(128+i));
 }
 
-/*:52*//*57:*/
-#line 792 "cwebdir/ctangle.w"
+/*:58*//*63:*/
+#line 777 "cwebdir/ctangle.w"
 {
 int c;
 for(c= 0;c<256;c++)ccode[c]= ignore;
@@ -520,31 +539,30 @@
 ccode['\'']= ord;
 }
 
-/*:57*//*71:*/
-#line 1116 "cwebdir/ctangle.w"
+/*:63*//*78:*/
+#line 1108 "cwebdir/ctangle.w"
 section_text[0]= ' ';
 
-/*:71*//*109:*/
-#line 906 "cwebdir/ctang-w2c.ch"
+/*:78*//*117:*/
+#line 476 "cwebdir/ctang-w2c.ch"
 
 strncpy(cb_banner,banner,max_banner-1);
 
-/*:109*/
-#line 98 "cwebdir/ctangle.w"
-;
+/*:117*/
+#line 88 "cwebdir/ctangle.w"
+
 common_init();
-#line 90 "cwebdir/ctang-w2c.ch"
+#line 53 "cwebdir/ctang-w2c.ch"
 if(show_banner)cb_show_banner();
-#line 101 "cwebdir/ctangle.w"
+#line 91 "cwebdir/ctangle.w"
 phase_one();
 phase_two();
 return wrap_up();
 }
 
-/*:3*//*21:*/
-#line 183 "cwebdir/ctangle.w"
+/*:2*//*24:*/
+#line 153 "cwebdir/ctangle.w"
 
-#line 153 "cwebdir/ctang-w2c.ch"
 boolean names_match(
 name_pointer p,
 const char*first,
@@ -551,57 +569,46 @@
 size_t l,
 eight_bits t)
 {(void)t;
-#line 189 "cwebdir/ctangle.w"
 if(length(p)!=l)return 0;
 return!strncmp(first,p->byte_start,l);
 }
 
-/*:21*//*22:*/
-#line 198 "cwebdir/ctangle.w"
+/*:24*//*25:*/
+#line 169 "cwebdir/ctangle.w"
 
-#line 166 "cwebdir/ctang-w2c.ch"
 void
 init_node(
 name_pointer node)
-#line 202 "cwebdir/ctangle.w"
 {
-#line 174 "cwebdir/ctang-w2c.ch"
 node->equiv= (void*)text_info;
-#line 204 "cwebdir/ctangle.w"
 }
-#line 181 "cwebdir/ctang-w2c.ch"
 void
 init_p(name_pointer p,eight_bits t){(void)p;(void)t;}
-#line 207 "cwebdir/ctangle.w"
 
-/*:22*//*26:*/
-#line 260 "cwebdir/ctangle.w"
+/*:25*//*30:*/
+#line 234 "cwebdir/ctangle.w"
 
-#line 190 "cwebdir/ctang-w2c.ch"
-static void
+void
 store_two_bytes(
 sixteen_bits x)
-#line 264 "cwebdir/ctangle.w"
 {
-#line 198 "cwebdir/ctang-w2c.ch"
+#line 65 "cwebdir/ctang-w2c.ch"
 if(tok_ptr+2> tok_mem_end)overflow(_("token"));
-#line 266 "cwebdir/ctangle.w"
+#line 240 "cwebdir/ctangle.w"
 *tok_ptr++= x>>8;
 *tok_ptr++= x&0377;
 }
 
-/*:26*//*30:*/
-#line 336 "cwebdir/ctangle.w"
+/*:30*//*35:*/
+#line 314 "cwebdir/ctangle.w"
 
-#line 206 "cwebdir/ctang-w2c.ch"
 static void
 push_level(
 name_pointer p)
-#line 340 "cwebdir/ctangle.w"
 {
-#line 214 "cwebdir/ctang-w2c.ch"
+#line 71 "cwebdir/ctang-w2c.ch"
 if(stack_ptr==stack_end)overflow(_("stack"));
-#line 342 "cwebdir/ctangle.w"
+#line 320 "cwebdir/ctangle.w"
 *stack_ptr= cur_state;
 stack_ptr++;
 if(p!=NULL){
@@ -611,14 +618,12 @@
 }
 }
 
-/*:30*//*31:*/
-#line 355 "cwebdir/ctangle.w"
+/*:35*//*36:*/
+#line 333 "cwebdir/ctangle.w"
 
-#line 222 "cwebdir/ctang-w2c.ch"
 static void
 pop_level(
 int flag)
-#line 359 "cwebdir/ctangle.w"
 {
 if(flag&&cur_repl->text_link<section_flag){
 cur_repl= cur_repl->text_link+text_info;
@@ -629,13 +634,11 @@
 if(stack_ptr> stack)cur_state= *stack_ptr;
 }
 
-/*:31*//*33:*/
-#line 391 "cwebdir/ctangle.w"
+/*:36*//*39:*/
+#line 372 "cwebdir/ctangle.w"
 
-#line 231 "cwebdir/ctang-w2c.ch"
 static void
 get_output(void)
-#line 394 "cwebdir/ctangle.w"
 {
 sixteen_bits a;
 restart:if(stack_ptr==stack)return;
@@ -654,18 +657,16 @@
 switch(a/024000){
 case 0:cur_val= a;out_char(identifier);break;
 case 1:if(a==output_defs_flag)output_defs();
-else/*34:*/
-#line 423 "cwebdir/ctangle.w"
+else/*40:*/
+#line 404 "cwebdir/ctangle.w"
 
 {
 a-= 024000;
-#line 238 "cwebdir/ctang-w2c.ch"
 if((a+name_dir)->equiv!=(void*)text_info)push_level(a+name_dir);
-#line 427 "cwebdir/ctangle.w"
 else if(a!=0){
-#line 244 "cwebdir/ctang-w2c.ch"
+#line 77 "cwebdir/ctang-w2c.ch"
 fputs(_("\n! Not present: <"),stdout);
-#line 429 "cwebdir/ctangle.w"
+#line 410 "cwebdir/ctangle.w"
 print_section_name(a+name_dir);err_print(">");
 
 }
@@ -672,9 +673,9 @@
 goto restart;
 }
 
-/*:34*/
-#line 412 "cwebdir/ctangle.w"
-;
+/*:40*/
+#line 393 "cwebdir/ctangle.w"
+
 break;
 default:cur_val= a-050000;if(cur_val> 0)cur_section= cur_val;
 out_char(section_number);
@@ -682,13 +683,11 @@
 }
 }
 
-/*:33*//*37:*/
-#line 481 "cwebdir/ctangle.w"
+/*:39*//*44:*/
+#line 465 "cwebdir/ctangle.w"
 
-#line 251 "cwebdir/ctang-w2c.ch"
 static void
 flush_buffer(void)
-#line 484 "cwebdir/ctangle.w"
 {
 C_putc('\n');
 if(cur_line%100==0&&show_progress){
@@ -699,51 +698,49 @@
 cur_line++;
 }
 
-/*:37*//*42:*/
-#line 536 "cwebdir/ctangle.w"
+/*:44*//*49:*/
+#line 520 "cwebdir/ctangle.w"
 
-#line 271 "cwebdir/ctang-w2c.ch"
 static void
 phase_two(void){
-#line 539 "cwebdir/ctangle.w"
 web_file_open= 0;
 cur_line= 1;
-/*29:*/
-#line 325 "cwebdir/ctangle.w"
+/*33:*/
+#line 299 "cwebdir/ctangle.w"
 
 stack_ptr= stack+1;cur_name= name_dir;cur_repl= text_info->text_link+text_info;
 cur_byte= cur_repl->tok_start;cur_end= (cur_repl+1)->tok_start;cur_section= 0;
 
-/*:29*/
-#line 541 "cwebdir/ctangle.w"
-;
-/*44:*/
-#line 595 "cwebdir/ctangle.w"
+/*:33*/
+#line 525 "cwebdir/ctangle.w"
 
+/*51:*/
+#line 582 "cwebdir/ctangle.w"
+
 if(!output_defs_seen)
 output_defs();
 
-/*:44*/
-#line 542 "cwebdir/ctangle.w"
-;
+/*:51*/
+#line 526 "cwebdir/ctangle.w"
+
 if(text_info->text_link==0&&cur_out_file==end_output_files){
-#line 278 "cwebdir/ctang-w2c.ch"
+#line 89 "cwebdir/ctang-w2c.ch"
 fputs(_("\n! No program text was specified."),stdout);mark_harmless;
-#line 545 "cwebdir/ctangle.w"
+#line 529 "cwebdir/ctangle.w"
 
 }
 else{
 if(cur_out_file==end_output_files){
 if(show_progress)
-#line 284 "cwebdir/ctang-w2c.ch"
+#line 95 "cwebdir/ctang-w2c.ch"
 printf(_("\nWriting the output file (%s):"),C_file_name);
-#line 551 "cwebdir/ctangle.w"
+#line 535 "cwebdir/ctangle.w"
 }
 else{
 if(show_progress){
-#line 290 "cwebdir/ctang-w2c.ch"
+#line 101 "cwebdir/ctang-w2c.ch"
 fputs(_("\nWriting the output files:"),stdout);
-#line 555 "cwebdir/ctangle.w"
+#line 539 "cwebdir/ctangle.w"
 
 printf(" (%s)",C_file_name);
 update_terminal;
@@ -752,16 +749,16 @@
 }
 while(stack_ptr> stack)get_output();
 flush_buffer();
-writeloop:/*43:*/
-#line 322 "cwebdir/ctang-w2c.ch"
+writeloop:/*50:*/
+#line 130 "cwebdir/ctang-w2c.ch"
 
 fclose(C_file);C_file= NULL;
-/*98:*/
-#line 786 "cwebdir/ctang-w2c.ch"
+/*106:*/
+#line 356 "cwebdir/ctang-w2c.ch"
 
 if((C_file= fopen(C_file_name,"r"))!=NULL){
-/*99:*/
-#line 793 "cwebdir/ctang-w2c.ch"
+/*107:*/
+#line 363 "cwebdir/ctang-w2c.ch"
 
 char x[BUFSIZ],y[BUFSIZ];
 int x_size,y_size,comparison= false;
@@ -770,8 +767,8 @@
 fatal(_("! Cannot open output file "),check_file_name);
 
 
-if(temporary_output)/*100:*/
-#line 808 "cwebdir/ctang-w2c.ch"
+if(temporary_output)/*108:*/
+#line 378 "cwebdir/ctang-w2c.ch"
 
 do{
 x_size= fread(x,1,BUFSIZ,C_file);
@@ -780,18 +777,18 @@
 if(comparison)comparison= !memcmp(x,y,x_size);
 }while(comparison&&!feof(C_file)&&!feof(check_file));
 
-/*:100*/
-#line 801 "cwebdir/ctang-w2c.ch"
+/*:108*/
+#line 371 "cwebdir/ctang-w2c.ch"
 
 
 fclose(C_file);C_file= NULL;
 fclose(check_file);check_file= NULL;
 
-/*:99*/
-#line 788 "cwebdir/ctang-w2c.ch"
+/*:107*/
+#line 358 "cwebdir/ctang-w2c.ch"
 
-/*101:*/
-#line 819 "cwebdir/ctang-w2c.ch"
+/*109:*/
+#line 389 "cwebdir/ctang-w2c.ch"
 
 if(comparison)
 remove(check_file_name);
@@ -800,14 +797,14 @@
 rename(check_file_name,C_file_name);
 }
 
-/*:101*/
-#line 789 "cwebdir/ctang-w2c.ch"
+/*:109*/
+#line 359 "cwebdir/ctang-w2c.ch"
 
 }else
 rename(check_file_name,C_file_name);
 
-/*:98*/
-#line 324 "cwebdir/ctang-w2c.ch"
+/*:106*/
+#line 132 "cwebdir/ctang-w2c.ch"
 
 for(an_output_file= end_output_files;an_output_file> cur_out_file;){
 an_output_file--;
@@ -827,15 +824,15 @@
 cur_end= (cur_repl+1)->tok_start;
 while(stack_ptr> stack)get_output();
 flush_buffer();fclose(C_file);C_file= NULL;
-/*102:*/
-#line 832 "cwebdir/ctang-w2c.ch"
+/*110:*/
+#line 402 "cwebdir/ctang-w2c.ch"
 
 if(0==strcmp("/dev/stdout",output_file_name))
-/*104:*/
-#line 859 "cwebdir/ctang-w2c.ch"
+/*112:*/
+#line 429 "cwebdir/ctang-w2c.ch"
 {
-/*107:*/
-#line 890 "cwebdir/ctang-w2c.ch"
+/*115:*/
+#line 460 "cwebdir/ctang-w2c.ch"
 
 char in_buf[BUFSIZ+1];
 int in_size,comparison= true;
@@ -843,8 +840,8 @@
 fatal(_("! Cannot open output file "),check_file_name);
 
 
-/*:107*/
-#line 860 "cwebdir/ctang-w2c.ch"
+/*:115*/
+#line 430 "cwebdir/ctang-w2c.ch"
 
 do{
 in_size= fread(in_buf,1,BUFSIZ,check_file);
@@ -852,8 +849,8 @@
 fprintf(stdout,"%s",in_buf);
 }while(!feof(check_file));
 fclose(check_file);check_file= NULL;
-/*103:*/
-#line 849 "cwebdir/ctang-w2c.ch"
+/*111:*/
+#line 419 "cwebdir/ctang-w2c.ch"
 
 if(comparison)
 remove(check_file_name);
@@ -862,20 +859,20 @@
 rename(check_file_name,output_file_name);
 }
 
-/*:103*/
-#line 867 "cwebdir/ctang-w2c.ch"
+/*:111*/
+#line 437 "cwebdir/ctang-w2c.ch"
 
 }
 
-/*:104*/
-#line 834 "cwebdir/ctang-w2c.ch"
+/*:112*/
+#line 404 "cwebdir/ctang-w2c.ch"
 
 else if(0==strcmp("/dev/stderr",output_file_name))
-/*105:*/
-#line 872 "cwebdir/ctang-w2c.ch"
+/*113:*/
+#line 442 "cwebdir/ctang-w2c.ch"
 {
-/*107:*/
-#line 890 "cwebdir/ctang-w2c.ch"
+/*115:*/
+#line 460 "cwebdir/ctang-w2c.ch"
 
 char in_buf[BUFSIZ+1];
 int in_size,comparison= true;
@@ -883,8 +880,8 @@
 fatal(_("! Cannot open output file "),check_file_name);
 
 
-/*:107*/
-#line 873 "cwebdir/ctang-w2c.ch"
+/*:115*/
+#line 443 "cwebdir/ctang-w2c.ch"
 
 do{
 in_size= fread(in_buf,1,BUFSIZ,check_file);
@@ -892,8 +889,8 @@
 fprintf(stderr,"%s",in_buf);
 }while(!feof(check_file));
 fclose(check_file);check_file= NULL;
-/*103:*/
-#line 849 "cwebdir/ctang-w2c.ch"
+/*111:*/
+#line 419 "cwebdir/ctang-w2c.ch"
 
 if(comparison)
 remove(check_file_name);
@@ -902,21 +899,21 @@
 rename(check_file_name,output_file_name);
 }
 
-/*:103*/
-#line 880 "cwebdir/ctang-w2c.ch"
+/*:111*/
+#line 450 "cwebdir/ctang-w2c.ch"
 
 }
 
-/*:105*/
-#line 836 "cwebdir/ctang-w2c.ch"
+/*:113*/
+#line 406 "cwebdir/ctang-w2c.ch"
 
 else if(0==strcmp("/dev/null",output_file_name))
-/*106:*/
-#line 885 "cwebdir/ctang-w2c.ch"
+/*114:*/
+#line 455 "cwebdir/ctang-w2c.ch"
 {
 int comparison= true;
-/*103:*/
-#line 849 "cwebdir/ctang-w2c.ch"
+/*111:*/
+#line 419 "cwebdir/ctang-w2c.ch"
 
 if(comparison)
 remove(check_file_name);
@@ -925,18 +922,18 @@
 rename(check_file_name,output_file_name);
 }
 
-/*:103*/
-#line 887 "cwebdir/ctang-w2c.ch"
+/*:111*/
+#line 457 "cwebdir/ctang-w2c.ch"
 
 }
 
-/*:106*/
-#line 838 "cwebdir/ctang-w2c.ch"
+/*:114*/
+#line 408 "cwebdir/ctang-w2c.ch"
 
 else{
 if((C_file= fopen(output_file_name,"r"))!=NULL){
-/*99:*/
-#line 793 "cwebdir/ctang-w2c.ch"
+/*107:*/
+#line 363 "cwebdir/ctang-w2c.ch"
 
 char x[BUFSIZ],y[BUFSIZ];
 int x_size,y_size,comparison= false;
@@ -945,8 +942,8 @@
 fatal(_("! Cannot open output file "),check_file_name);
 
 
-if(temporary_output)/*100:*/
-#line 808 "cwebdir/ctang-w2c.ch"
+if(temporary_output)/*108:*/
+#line 378 "cwebdir/ctang-w2c.ch"
 
 do{
 x_size= fread(x,1,BUFSIZ,C_file);
@@ -955,18 +952,18 @@
 if(comparison)comparison= !memcmp(x,y,x_size);
 }while(comparison&&!feof(C_file)&&!feof(check_file));
 
-/*:100*/
-#line 801 "cwebdir/ctang-w2c.ch"
+/*:108*/
+#line 371 "cwebdir/ctang-w2c.ch"
 
 
 fclose(C_file);C_file= NULL;
 fclose(check_file);check_file= NULL;
 
-/*:99*/
-#line 841 "cwebdir/ctang-w2c.ch"
+/*:107*/
+#line 411 "cwebdir/ctang-w2c.ch"
 
-/*103:*/
-#line 849 "cwebdir/ctang-w2c.ch"
+/*111:*/
+#line 419 "cwebdir/ctang-w2c.ch"
 
 if(comparison)
 remove(check_file_name);
@@ -975,39 +972,37 @@
 rename(check_file_name,output_file_name);
 }
 
-/*:103*/
-#line 842 "cwebdir/ctang-w2c.ch"
+/*:111*/
+#line 412 "cwebdir/ctang-w2c.ch"
 
 }else
 rename(check_file_name,output_file_name);
 }
 
-/*:102*/
-#line 343 "cwebdir/ctang-w2c.ch"
+/*:110*/
+#line 151 "cwebdir/ctang-w2c.ch"
 
 }
 strcpy(check_file_name,"");
-#line 590 "cwebdir/ctangle.w"
+#line 577 "cwebdir/ctangle.w"
 
-/*:43*/
-#line 563 "cwebdir/ctangle.w"
-;
-#line 296 "cwebdir/ctang-w2c.ch"
+/*:50*/
+#line 547 "cwebdir/ctangle.w"
+
 if(show_happiness){
 if(show_progress)new_line;
+#line 107 "cwebdir/ctang-w2c.ch"
 fputs(_("Done."),stdout);
+#line 551 "cwebdir/ctangle.w"
 }
-#line 565 "cwebdir/ctangle.w"
 }
 }
 
-/*:42*//*47:*/
-#line 605 "cwebdir/ctangle.w"
+/*:49*//*54:*/
+#line 593 "cwebdir/ctangle.w"
 
-#line 358 "cwebdir/ctang-w2c.ch"
 static void
 output_defs(void)
-#line 608 "cwebdir/ctangle.w"
 {
 sixteen_bits a;
 push_level(NULL);
@@ -1030,9 +1025,9 @@
 if(a<024000){
 cur_val= a;out_char(identifier);
 }
-#line 365 "cwebdir/ctang-w2c.ch"
+#line 159 "cwebdir/ctang-w2c.ch"
 else if(a<050000){confusion(_("macro defs have strange char"));}
-#line 631 "cwebdir/ctangle.w"
+#line 619 "cwebdir/ctangle.w"
 else{
 cur_val= a-050000;cur_section= cur_val;out_char(section_number);
 }
@@ -1045,14 +1040,12 @@
 pop_level(0);
 }
 
-/*:47*//*49:*/
-#line 651 "cwebdir/ctangle.w"
+/*:54*//*55:*/
+#line 636 "cwebdir/ctangle.w"
 
-#line 379 "cwebdir/ctang-w2c.ch"
 static void
 out_char(
 eight_bits cur_char)
-#line 655 "cwebdir/ctangle.w"
 {
 char*j,*k;
 restart:
@@ -1060,8 +1053,8 @@
 case'\n':if(protect&&out_state!=verbatim)C_putc(' ');
 if(protect||out_state==verbatim)C_putc('\\');
 flush_buffer();if(out_state!=verbatim)out_state= normal;break;
-/*53:*/
-#line 719 "cwebdir/ctangle.w"
+/*59:*/
+#line 704 "cwebdir/ctangle.w"
 
 case identifier:
 if(out_state==num_or_id)C_putc(' ');
@@ -1068,19 +1061,19 @@
 j= (cur_val+name_dir)->byte_start;
 k= (cur_val+name_dir+1)->byte_start;
 while(j<k){
-if((unsigned char)(*j)<0200)C_putc(*j);
+if((eight_bits)(*j)<0200)C_putc(*j);
 
-else C_printf("%s",translit[(unsigned char)(*j)-0200]);
+else C_printf("%s",translit[(eight_bits)(*j)-0200]);
 j++;
 }
 out_state= num_or_id;break;
 
-/*:53*/
-#line 662 "cwebdir/ctangle.w"
-;
-/*54:*/
-#line 732 "cwebdir/ctangle.w"
+/*:59*/
+#line 647 "cwebdir/ctangle.w"
 
+/*60:*/
+#line 717 "cwebdir/ctangle.w"
+
 case section_number:
 if(cur_val> 0)C_printf("/*%d:*/",cur_val);
 else if(cur_val<0)C_printf("/*:%d*/",-cur_val);
@@ -1105,12 +1098,12 @@
 }
 break;
 
-/*:54*/
-#line 663 "cwebdir/ctangle.w"
-;
-/*50:*/
-#line 404 "cwebdir/ctang-w2c.ch"
+/*:60*/
+#line 648 "cwebdir/ctangle.w"
 
+/*56:*/
+#line 666 "cwebdir/ctangle.w"
+
 case plus_plus:C_putc('+');C_putc('+');out_state= normal;break;
 case minus_minus:C_putc('-');C_putc('-');out_state= normal;break;
 case minus_gt:C_putc('-');C_putc('>');out_state= normal;break;
@@ -1128,11 +1121,10 @@
 case period_ast:C_putc('.');C_putc('*');out_state= normal;break;
 case minus_gt_ast:C_putc('-');C_putc('>');C_putc('*');out_state= normal;
 break;
-#line 699 "cwebdir/ctangle.w"
 
-/*:50*/
-#line 664 "cwebdir/ctangle.w"
-;
+/*:56*/
+#line 649 "cwebdir/ctangle.w"
+
 case'=':case'>':C_putc(cur_char);C_putc(' ');
 out_state= normal;break;
 case join:out_state= unbreakable;break;
@@ -1149,14 +1141,11 @@
 }
 }
 
-#line 404 "cwebdir/ctang-w2c.ch"
-/*:49*//*58:*/
-#line 813 "cwebdir/ctangle.w"
+/*:55*//*65:*/
+#line 802 "cwebdir/ctangle.w"
 
-#line 428 "cwebdir/ctang-w2c.ch"
 static eight_bits
 skip_ahead(void)
-#line 816 "cwebdir/ctangle.w"
 {
 eight_bits c;
 while(1){
@@ -1170,13 +1159,11 @@
 }
 }
 
-/*:58*//*60:*/
-#line 848 "cwebdir/ctangle.w"
+/*:65*//*67:*/
+#line 837 "cwebdir/ctangle.w"
 
-#line 436 "cwebdir/ctang-w2c.ch"
 static boolean skip_comment(
 boolean is_long_comment)
-#line 851 "cwebdir/ctangle.w"
 {
 char c;
 while(1){
@@ -1184,9 +1171,9 @@
 if(is_long_comment){
 if(get_line())return(comment_continues= 1);
 else{
-#line 443 "cwebdir/ctang-w2c.ch"
+#line 165 "cwebdir/ctang-w2c.ch"
 err_print(_("! Input ended in mid-comment"));
-#line 859 "cwebdir/ctangle.w"
+#line 848 "cwebdir/ctangle.w"
 
 return(comment_continues= 0);
 }
@@ -1199,9 +1186,9 @@
 }
 if(c=='@'){
 if(ccode[(eight_bits)*loc]==new_section){
-#line 449 "cwebdir/ctang-w2c.ch"
+#line 171 "cwebdir/ctang-w2c.ch"
 err_print(_("! Section name ended in mid-comment"));loc--;
-#line 872 "cwebdir/ctangle.w"
+#line 861 "cwebdir/ctangle.w"
 
 return(comment_continues= 0);
 }
@@ -1210,13 +1197,11 @@
 }
 }
 
-/*:60*//*63:*/
-#line 900 "cwebdir/ctangle.w"
+/*:67*//*70:*/
+#line 888 "cwebdir/ctangle.w"
 
-#line 456 "cwebdir/ctang-w2c.ch"
 static eight_bits
 get_next(void)
-#line 903 "cwebdir/ctangle.w"
 {
 static int preprocessing= 0;
 eight_bits c;
@@ -1226,8 +1211,8 @@
 if(get_line()==0)return(new_section);
 else if(print_where&&!no_where){
 print_where= 0;
-/*77:*/
-#line 1225 "cwebdir/ctangle.w"
+/*85:*/
+#line 1220 "cwebdir/ctangle.w"
 
 store_two_bytes(0150000);
 if(changing&&include_depth==change_depth){
@@ -1238,14 +1223,12 @@
 store_two_bytes((sixteen_bits)cur_line);
 }
 id_loc= id_first+strlen(id_first);
-#line 598 "cwebdir/ctang-w2c.ch"
 {int a_l= id_lookup(id_first,id_loc,0)-name_dir;app_repl((a_l/0400)+0200);
 app_repl(a_l%0400);}
-#line 1237 "cwebdir/ctangle.w"
 
-/*:77*/
-#line 912 "cwebdir/ctangle.w"
-;
+/*:85*/
+#line 900 "cwebdir/ctangle.w"
+
 }
 else return('\n');
 }
@@ -1257,8 +1240,8 @@
 else continue;
 }
 loc++;
-if(xisdigit(c)||c=='.')/*66:*/
-#line 978 "cwebdir/ctangle.w"
+if(xisdigit(c)||c=='.')/*73:*/
+#line 969 "cwebdir/ctangle.w"
 {
 id_first= loc-1;
 if(*id_first=='.'&&!xisdigit(*loc))goto mistake;
@@ -1282,38 +1265,34 @@
 return(constant);
 }
 
-/*:66*/
-#line 924 "cwebdir/ctangle.w"
+/*:73*/
+#line 912 "cwebdir/ctangle.w"
 
-#line 463 "cwebdir/ctang-w2c.ch"
 else if(c=='\''||c=='"'
 ||((c=='L'||c=='u'||c=='U')&&(*loc=='\''||*loc=='"'))
 ||((c=='u'&&*loc=='8')&&(*(loc+1)=='\''||*(loc+1)=='"')))
-#line 926 "cwebdir/ctangle.w"
-/*67:*/
-#line 1006 "cwebdir/ctangle.w"
+/*74:*/
+#line 997 "cwebdir/ctangle.w"
 {
 char delim= c;
 id_first= section_text+1;
 id_loc= section_text;*++id_loc= delim;
-#line 494 "cwebdir/ctang-w2c.ch"
 if(delim=='L'||delim=='u'||delim=='U'){
 if(delim=='u'&&*loc=='8'){*++id_loc= *loc++;}
 delim= *loc++;*++id_loc= delim;
 }
-#line 1013 "cwebdir/ctangle.w"
 while(1){
 if(loc>=limit){
 if(*(limit-1)!='\\'){
-#line 503 "cwebdir/ctang-w2c.ch"
+#line 177 "cwebdir/ctang-w2c.ch"
 err_print(_("! String didn't end"));loc= limit;break;
-#line 1017 "cwebdir/ctangle.w"
+#line 1009 "cwebdir/ctangle.w"
 
 }
 if(get_line()==0){
-#line 509 "cwebdir/ctang-w2c.ch"
+#line 183 "cwebdir/ctang-w2c.ch"
 err_print(_("! Input ended in middle of string"));loc= buffer;break;
-#line 1021 "cwebdir/ctangle.w"
+#line 1013 "cwebdir/ctangle.w"
 
 }
 else if(++id_loc<=section_text_end)*id_loc= '\n';
@@ -1331,9 +1310,9 @@
 if(++id_loc<=section_text_end)*id_loc= c;
 }
 if(id_loc>=section_text_end){
-#line 515 "cwebdir/ctang-w2c.ch"
+#line 189 "cwebdir/ctang-w2c.ch"
 fputs(_("\n! String too long: "),stdout);
-#line 1039 "cwebdir/ctangle.w"
+#line 1031 "cwebdir/ctangle.w"
 
 term_write(section_text+1,25);
 err_print("...");
@@ -1342,63 +1321,61 @@
 return(string);
 }
 
-/*:67*/
-#line 926 "cwebdir/ctangle.w"
+/*:74*/
+#line 916 "cwebdir/ctangle.w"
 
 else if(isalpha(c)||isxalpha(c)||ishigh(c))
-/*65:*/
-#line 972 "cwebdir/ctangle.w"
+/*72:*/
+#line 962 "cwebdir/ctangle.w"
 {
 id_first= --loc;
-#line 485 "cwebdir/ctang-w2c.ch"
 while(isalpha((eight_bits)*++loc)||isdigit((eight_bits)*loc)
 ||isxalpha((eight_bits)*loc)||ishigh((eight_bits)*loc));
-#line 975 "cwebdir/ctangle.w"
 id_loc= loc;return(identifier);
 }
 
-/*:65*/
-#line 928 "cwebdir/ctangle.w"
+/*:72*/
+#line 918 "cwebdir/ctangle.w"
 
-else if(c=='@')/*68:*/
-#line 1050 "cwebdir/ctangle.w"
+else if(c=='@')/*75:*/
+#line 1042 "cwebdir/ctangle.w"
 {
 c= ccode[(eight_bits)*loc++];
 switch(c){
 case ignore:continue;
-#line 521 "cwebdir/ctang-w2c.ch"
+#line 195 "cwebdir/ctang-w2c.ch"
 case translit_code:err_print(_("! Use @l in limbo only"));continue;
-#line 1055 "cwebdir/ctangle.w"
+#line 1047 "cwebdir/ctangle.w"
 
 case control_text:while((c= skip_ahead())=='@');
 
 if(*(loc-1)!='>')
-#line 527 "cwebdir/ctang-w2c.ch"
+#line 201 "cwebdir/ctang-w2c.ch"
 err_print(_("! Double @ should be used in control text"));
-#line 1060 "cwebdir/ctangle.w"
+#line 1052 "cwebdir/ctangle.w"
 
 continue;
 case section_name:
 cur_section_name_char= *(loc-1);
-/*70:*/
-#line 1098 "cwebdir/ctangle.w"
+/*77:*/
+#line 1090 "cwebdir/ctangle.w"
 {
 char*k;
-/*72:*/
-#line 1118 "cwebdir/ctangle.w"
+/*79:*/
+#line 1110 "cwebdir/ctangle.w"
 
 k= section_text;
 while(1){
 if(loc> limit&&get_line()==0){
-#line 545 "cwebdir/ctang-w2c.ch"
+#line 219 "cwebdir/ctang-w2c.ch"
 err_print(_("! Input ended in section name"));
-#line 1123 "cwebdir/ctangle.w"
+#line 1115 "cwebdir/ctangle.w"
 
 loc= buffer+1;break;
 }
 c= *loc;
-/*73:*/
-#line 1142 "cwebdir/ctangle.w"
+/*80:*/
+#line 1134 "cwebdir/ctangle.w"
 
 if(c=='@'){
 c= *(loc+1);
@@ -1406,23 +1383,23 @@
 loc+= 2;break;
 }
 if(ccode[(eight_bits)c]==new_section){
-#line 557 "cwebdir/ctang-w2c.ch"
+#line 231 "cwebdir/ctang-w2c.ch"
 err_print(_("! Section name didn't end"));break;
-#line 1150 "cwebdir/ctangle.w"
+#line 1142 "cwebdir/ctangle.w"
 
 }
 if(ccode[(eight_bits)c]==section_name){
-#line 563 "cwebdir/ctang-w2c.ch"
+#line 237 "cwebdir/ctang-w2c.ch"
 err_print(_("! Nesting of section names not allowed"));break;
-#line 1154 "cwebdir/ctangle.w"
+#line 1146 "cwebdir/ctangle.w"
 
 }
 *(++k)= '@';loc++;
 }
 
-/*:73*/
-#line 1127 "cwebdir/ctangle.w"
-;
+/*:80*/
+#line 1119 "cwebdir/ctangle.w"
+
 loc++;if(k<section_text_end)k++;
 if(xisspace(c)){
 c= ' ';if(*(k-1)==' ')k--;
@@ -1430,9 +1407,9 @@
 *k= c;
 }
 if(k>=section_text_end){
-#line 551 "cwebdir/ctang-w2c.ch"
+#line 225 "cwebdir/ctang-w2c.ch"
 fputs(_("\n! Section name too long: "),stdout);
-#line 1136 "cwebdir/ctangle.w"
+#line 1128 "cwebdir/ctangle.w"
 
 term_write(section_text+1,25);
 printf("...");mark_harmless;
@@ -1439,15 +1416,15 @@
 }
 if(*k==' '&&k> section_text)k--;
 
-/*:72*/
-#line 1100 "cwebdir/ctangle.w"
-;
+/*:79*/
+#line 1092 "cwebdir/ctangle.w"
+
 if(k-section_text> 3&&strncmp(k-2,"...",3)==0)
 cur_section_name= section_lookup(section_text+1,k-3,1);
 else cur_section_name= section_lookup(section_text+1,k,0);
 if(cur_section_name_char=='(')
-/*40:*/
-#line 516 "cwebdir/ctangle.w"
+/*47:*/
+#line 500 "cwebdir/ctangle.w"
 
 {
 for(an_output_file= cur_out_file;
@@ -1457,41 +1434,41 @@
 if(cur_out_file> output_files)
 *--cur_out_file= cur_section_name;
 else{
-#line 258 "cwebdir/ctang-w2c.ch"
+#line 83 "cwebdir/ctang-w2c.ch"
 overflow(_("output files"));
-#line 526 "cwebdir/ctangle.w"
+#line 510 "cwebdir/ctangle.w"
 }
 }
 }
 
-/*:40*/
-#line 1106 "cwebdir/ctangle.w"
-;
+/*:47*/
+#line 1098 "cwebdir/ctangle.w"
+
 return(section_name);
 }
 
-/*:70*/
-#line 1064 "cwebdir/ctangle.w"
-;
-case string:/*74:*/
-#line 1164 "cwebdir/ctangle.w"
+/*:77*/
+#line 1056 "cwebdir/ctangle.w"
+
+case string:/*81:*/
+#line 1156 "cwebdir/ctangle.w"
 {
 id_first= loc++;*(limit+1)= '@';*(limit+2)= '>';
 while(*loc!='@'||*(loc+1)!='>')loc++;
-#line 569 "cwebdir/ctang-w2c.ch"
+#line 243 "cwebdir/ctang-w2c.ch"
 if(loc>=limit)err_print(_("! Verbatim string didn't end"));
-#line 1168 "cwebdir/ctangle.w"
+#line 1160 "cwebdir/ctangle.w"
 
 id_loc= loc;loc+= 2;
 return(string);
 }
 
-/*:74*/
-#line 1065 "cwebdir/ctangle.w"
-;
-case ord:/*69:*/
-#line 1077 "cwebdir/ctangle.w"
+/*:81*/
+#line 1057 "cwebdir/ctangle.w"
 
+case ord:/*76:*/
+#line 1069 "cwebdir/ctangle.w"
+
 id_first= loc;
 if(*loc=='\\'){
 if(*++loc=='\'')loc++;
@@ -1499,17 +1476,17 @@
 while(*loc!='\''){
 if(*loc=='@'){
 if(*(loc+1)!='@')
-#line 533 "cwebdir/ctang-w2c.ch"
+#line 207 "cwebdir/ctang-w2c.ch"
 err_print(_("! Double @ should be used in ASCII constant"));
-#line 1086 "cwebdir/ctangle.w"
+#line 1078 "cwebdir/ctangle.w"
 
 else loc++;
 }
 loc++;
 if(loc> limit){
-#line 539 "cwebdir/ctang-w2c.ch"
+#line 213 "cwebdir/ctang-w2c.ch"
 err_print(_("! String didn't end"));loc= limit-1;break;
-#line 1092 "cwebdir/ctangle.w"
+#line 1084 "cwebdir/ctangle.w"
 
 }
 }
@@ -1516,15 +1493,15 @@
 loc++;
 return(ord);
 
-/*:69*/
-#line 1066 "cwebdir/ctangle.w"
-;
+/*:76*/
+#line 1058 "cwebdir/ctangle.w"
+
 default:return(c);
 }
 }
 
-/*:68*/
-#line 929 "cwebdir/ctangle.w"
+/*:75*/
+#line 919 "cwebdir/ctangle.w"
 
 else if(xisspace(c)){
 if(!preprocessing||loc> limit)continue;
@@ -1532,16 +1509,14 @@
 else return(' ');
 }
 else if(c=='#'&&loc==buffer+1)preprocessing= 1;
-mistake:/*64:*/
-#line 950 "cwebdir/ctangle.w"
+mistake:/*71:*/
+#line 940 "cwebdir/ctangle.w"
 
 switch(c){
 case'+':if(*loc=='+')compress(plus_plus);break;
 case'-':if(*loc=='-'){compress(minus_minus);}
-#line 472 "cwebdir/ctang-w2c.ch"
 else{if(*loc=='>'){if(*(loc+1)=='*'){loc++;compress(minus_gt_ast);}
 else compress(minus_gt);}}break;
-#line 956 "cwebdir/ctangle.w"
 case'.':if(*loc=='*'){compress(period_ast);}
 else if(*loc=='.'&&*(loc+1)=='.'){
 loc++;compress(dot_dot_dot);
@@ -1555,30 +1530,26 @@
 else if(*loc=='<')compress(lt_lt);break;
 case'&':if(*loc=='&')compress(and_and);break;
 case'|':if(*loc=='|')compress(or_or);break;
-#line 479 "cwebdir/ctang-w2c.ch"
 case'!':if(*loc=='=')compress(non_eq);break;
-#line 970 "cwebdir/ctangle.w"
 }
 
-/*:64*/
-#line 936 "cwebdir/ctangle.w"
+/*:71*/
+#line 926 "cwebdir/ctangle.w"
 
 return(c);
 }
 }
 
-/*:63*//*76:*/
-#line 1199 "cwebdir/ctangle.w"
+/*:70*//*84:*/
+#line 1194 "cwebdir/ctangle.w"
 
-#line 583 "cwebdir/ctang-w2c.ch"
 static void
 scan_repl(
 eight_bits t)
-#line 1203 "cwebdir/ctangle.w"
 {
 sixteen_bits a;
-if(t==section_name){/*77:*/
-#line 1225 "cwebdir/ctangle.w"
+if(t==section_name){/*85:*/
+#line 1220 "cwebdir/ctangle.w"
 
 store_two_bytes(0150000);
 if(changing&&include_depth==change_depth){
@@ -1589,17 +1560,15 @@
 store_two_bytes((sixteen_bits)cur_line);
 }
 id_loc= id_first+strlen(id_first);
-#line 598 "cwebdir/ctang-w2c.ch"
 {int a_l= id_lookup(id_first,id_loc,0)-name_dir;app_repl((a_l/0400)+0200);
 app_repl(a_l%0400);}
-#line 1237 "cwebdir/ctangle.w"
 
-/*:77*/
-#line 1205 "cwebdir/ctangle.w"
-;}
+/*:85*/
+#line 1200 "cwebdir/ctangle.w"
+}
 while(1)switch(a= get_next()){
-/*78:*/
-#line 1238 "cwebdir/ctangle.w"
+/*86:*/
+#line 1233 "cwebdir/ctangle.w"
 
 case identifier:a= id_lookup(id_first,id_loc,0)-name_dir;
 app_repl((a/0400)+0200);
@@ -1606,29 +1575,29 @@
 app_repl(a%0400);break;
 case section_name:if(t!=section_name)goto done;
 else{
-/*79:*/
-#line 1271 "cwebdir/ctangle.w"
+/*87:*/
+#line 1266 "cwebdir/ctangle.w"
 {
 char*try_loc= loc;
 while(*try_loc==' '&&try_loc<limit)try_loc++;
 if(*try_loc=='+'&&try_loc<limit)try_loc++;
 while(*try_loc==' '&&try_loc<limit)try_loc++;
-#line 617 "cwebdir/ctang-w2c.ch"
+#line 273 "cwebdir/ctang-w2c.ch"
 if(*try_loc=='=')err_print(_("! Missing `@ ' before a named section"));
-#line 1277 "cwebdir/ctangle.w"
+#line 1272 "cwebdir/ctangle.w"
 
 
 
 }
 
-/*:79*/
-#line 1244 "cwebdir/ctangle.w"
-;
+/*:87*/
+#line 1239 "cwebdir/ctangle.w"
+
 a= cur_section_name-name_dir;
 app_repl((a/0400)+0250);
 app_repl(a%0400);
-/*77:*/
-#line 1225 "cwebdir/ctangle.w"
+/*85:*/
+#line 1220 "cwebdir/ctangle.w"
 
 store_two_bytes(0150000);
 if(changing&&include_depth==change_depth){
@@ -1639,18 +1608,16 @@
 store_two_bytes((sixteen_bits)cur_line);
 }
 id_loc= id_first+strlen(id_first);
-#line 598 "cwebdir/ctang-w2c.ch"
 {int a_l= id_lookup(id_first,id_loc,0)-name_dir;app_repl((a_l/0400)+0200);
 app_repl(a_l%0400);}
-#line 1237 "cwebdir/ctangle.w"
 
-/*:77*/
-#line 1248 "cwebdir/ctangle.w"
-;break;
+/*:85*/
+#line 1243 "cwebdir/ctangle.w"
+break;
 }
-#line 605 "cwebdir/ctang-w2c.ch"
+#line 261 "cwebdir/ctang-w2c.ch"
 case output_defs_code:if(t!=section_name)err_print(_("! Misplaced @h"));
-#line 1251 "cwebdir/ctangle.w"
+#line 1246 "cwebdir/ctangle.w"
 
 else{
 output_defs_seen= 1;
@@ -1657,8 +1624,8 @@
 a= output_defs_flag;
 app_repl((a/0400)+0200);
 app_repl(a%0400);
-/*77:*/
-#line 1225 "cwebdir/ctangle.w"
+/*85:*/
+#line 1220 "cwebdir/ctangle.w"
 
 store_two_bytes(0150000);
 if(changing&&include_depth==change_depth){
@@ -1669,27 +1636,25 @@
 store_two_bytes((sixteen_bits)cur_line);
 }
 id_loc= id_first+strlen(id_first);
-#line 598 "cwebdir/ctang-w2c.ch"
 {int a_l= id_lookup(id_first,id_loc,0)-name_dir;app_repl((a_l/0400)+0200);
 app_repl(a_l%0400);}
-#line 1237 "cwebdir/ctangle.w"
 
-/*:77*/
-#line 1257 "cwebdir/ctangle.w"
-;
+/*:85*/
+#line 1252 "cwebdir/ctangle.w"
+
 }
 break;
 case constant:case string:
-/*80:*/
-#line 1282 "cwebdir/ctangle.w"
+/*88:*/
+#line 1277 "cwebdir/ctangle.w"
 
 app_repl(a);
 while(id_first<id_loc){
 if(*id_first=='@'){
 if(*(id_first+1)=='@')id_first++;
-#line 623 "cwebdir/ctang-w2c.ch"
+#line 279 "cwebdir/ctang-w2c.ch"
 else err_print(_("! Double @ should be used in string"));
-#line 1288 "cwebdir/ctangle.w"
+#line 1283 "cwebdir/ctangle.w"
 
 }
 app_repl(*id_first++);
@@ -1696,12 +1661,12 @@
 }
 app_repl(a);break;
 
-/*:80*/
-#line 1261 "cwebdir/ctangle.w"
-;
+/*:88*/
+#line 1256 "cwebdir/ctangle.w"
+
 case ord:
-/*81:*/
-#line 1298 "cwebdir/ctangle.w"
+/*89:*/
+#line 1293 "cwebdir/ctangle.w"
 {
 int c= (eight_bits)*id_first;
 if(c=='\\'){
@@ -1727,24 +1692,20 @@
 if(xisdigit(*(id_first+1)))c= *(++id_first)-'0';
 else if(xisxdigit(*(id_first+1))){
 ++id_first;
-#line 629 "cwebdir/ctang-w2c.ch"
 c= toupper((eight_bits)*id_first)-'A'+10;
-#line 1324 "cwebdir/ctangle.w"
 }
 if(xisdigit(*(id_first+1)))c= 16*c+*(++id_first)-'0';
 else if(xisxdigit(*(id_first+1))){
 ++id_first;
-#line 635 "cwebdir/ctang-w2c.ch"
 c= 16*c+toupper((eight_bits)*id_first)-'A'+10;
-#line 1329 "cwebdir/ctangle.w"
 }
 break;
 case'\\':c= '\\';break;
 case'\'':c= '\'';break;
 case'\"':c= '\"';break;
-#line 641 "cwebdir/ctang-w2c.ch"
+#line 285 "cwebdir/ctang-w2c.ch"
 default:err_print(_("! Unrecognized escape sequence"));
-#line 1335 "cwebdir/ctangle.w"
+#line 1330 "cwebdir/ctangle.w"
 
 }
 }
@@ -1757,20 +1718,20 @@
 }
 break;
 
-/*:81*/
-#line 1263 "cwebdir/ctangle.w"
-;
+/*:89*/
+#line 1258 "cwebdir/ctangle.w"
+
 case definition:case format_code:case begin_C:if(t!=section_name)goto done;
 else{
-#line 611 "cwebdir/ctang-w2c.ch"
+#line 267 "cwebdir/ctang-w2c.ch"
 err_print(_("! @d, @f and @c are ignored in C text"));continue;
-#line 1267 "cwebdir/ctangle.w"
+#line 1262 "cwebdir/ctangle.w"
 
 }
 case new_section:goto done;
 
-/*:78*/
-#line 1210 "cwebdir/ctangle.w"
+/*:86*/
+#line 1205 "cwebdir/ctangle.w"
 
 case')':app_repl(a);
 if(t==macro)app_repl(' ');
@@ -1778,19 +1739,17 @@
 default:app_repl(a);
 }
 done:next_control= (eight_bits)a;
-#line 591 "cwebdir/ctang-w2c.ch"
+#line 255 "cwebdir/ctang-w2c.ch"
 if(text_ptr> text_info_end)overflow(_("text"));
-#line 1218 "cwebdir/ctangle.w"
+#line 1213 "cwebdir/ctangle.w"
 cur_text= text_ptr;(++text_ptr)->tok_start= tok_ptr;
 }
 
-/*:76*//*83:*/
-#line 1360 "cwebdir/ctangle.w"
+/*:84*//*92:*/
+#line 1358 "cwebdir/ctangle.w"
 
-#line 648 "cwebdir/ctang-w2c.ch"
 static void
 scan_section(void)
-#line 1363 "cwebdir/ctangle.w"
 {
 name_pointer p;
 text_pointer q;
@@ -1801,8 +1760,8 @@
 }
 next_control= 0;
 while(1){
-/*84:*/
-#line 1399 "cwebdir/ctangle.w"
+/*93:*/
+#line 1397 "cwebdir/ctangle.w"
 
 while(next_control<definition)
 
@@ -1810,18 +1769,18 @@
 loc-= 2;next_control= get_next();
 }
 
-/*:84*/
-#line 1374 "cwebdir/ctangle.w"
-;
+/*:93*/
+#line 1372 "cwebdir/ctangle.w"
+
 if(next_control==definition){
-/*85:*/
-#line 1406 "cwebdir/ctangle.w"
+/*94:*/
+#line 1404 "cwebdir/ctangle.w"
 {
 while((next_control= get_next())=='\n');
 if(next_control!=identifier){
-#line 655 "cwebdir/ctang-w2c.ch"
+#line 291 "cwebdir/ctang-w2c.ch"
 err_print(_("! Definition flushed, must start with identifier"));
-#line 1410 "cwebdir/ctangle.w"
+#line 1408 "cwebdir/ctangle.w"
 
 continue;
 }
@@ -1835,8 +1794,8 @@
 cur_text->text_link= 0;
 }
 
-/*:85*/
-#line 1376 "cwebdir/ctangle.w"
+/*:94*/
+#line 1374 "cwebdir/ctangle.w"
 
 continue;
 }
@@ -1845,43 +1804,41 @@
 }
 if(next_control==section_name){
 p= cur_section_name;
-/*86:*/
-#line 1431 "cwebdir/ctangle.w"
+/*95:*/
+#line 1429 "cwebdir/ctangle.w"
 
 while((next_control= get_next())=='+');
 if(next_control!='='&&next_control!=eq_eq)
 continue;
 
-/*:86*/
-#line 1384 "cwebdir/ctangle.w"
-;
+/*:95*/
+#line 1382 "cwebdir/ctangle.w"
+
 break;
 }
 return;
 }
 no_where= print_where= 0;
-/*87:*/
-#line 1436 "cwebdir/ctangle.w"
+/*96:*/
+#line 1434 "cwebdir/ctangle.w"
 
-/*88:*/
-#line 1441 "cwebdir/ctangle.w"
+/*97:*/
+#line 1439 "cwebdir/ctangle.w"
 
 store_two_bytes((sixteen_bits)(0150000+section_count));
 
 
-/*:88*/
-#line 1437 "cwebdir/ctangle.w"
-;
+/*:97*/
+#line 1435 "cwebdir/ctangle.w"
+
 scan_repl(section_name);
-/*89:*/
-#line 1445 "cwebdir/ctangle.w"
+/*98:*/
+#line 1443 "cwebdir/ctangle.w"
 
 if(p==name_dir||p==0){
 (last_unnamed)->text_link= cur_text-text_info;last_unnamed= cur_text;
 }
-#line 661 "cwebdir/ctang-w2c.ch"
 else if(p->equiv==(void*)text_info)p->equiv= (void*)cur_text;
-#line 1450 "cwebdir/ctangle.w"
 
 else{
 q= (text_pointer)p->equiv;
@@ -1892,22 +1849,20 @@
 cur_text->text_link= section_flag;
 
 
-/*:89*/
-#line 1439 "cwebdir/ctangle.w"
-;
+/*:98*/
+#line 1437 "cwebdir/ctangle.w"
 
-/*:87*/
-#line 1390 "cwebdir/ctangle.w"
-;
+
+/*:96*/
+#line 1388 "cwebdir/ctangle.w"
+
 }
 
-/*:83*//*91:*/
-#line 1463 "cwebdir/ctangle.w"
+/*:92*//*100:*/
+#line 1461 "cwebdir/ctangle.w"
 
-#line 674 "cwebdir/ctang-w2c.ch"
 static void
 phase_one(void){
-#line 1466 "cwebdir/ctangle.w"
 phase= 1;
 section_count= 0;
 reset_input();
@@ -1917,13 +1872,11 @@
 phase= 2;
 }
 
-/*:91*//*93:*/
-#line 1481 "cwebdir/ctangle.w"
+/*:100*//*102:*/
+#line 1479 "cwebdir/ctangle.w"
 
-#line 688 "cwebdir/ctang-w2c.ch"
 static void
 skip_limbo(void)
-#line 1484 "cwebdir/ctangle.w"
 {
 char c;
 while(1){
@@ -1934,19 +1887,19 @@
 c= *loc++;
 if(ccode[(eight_bits)c]==new_section)break;
 switch(ccode[(eight_bits)c]){
-case translit_code:/*94:*/
-#line 1510 "cwebdir/ctangle.w"
+case translit_code:/*103:*/
+#line 1508 "cwebdir/ctangle.w"
 
 while(xisspace(*loc)&&loc<limit)loc++;
 loc+= 3;
 if(loc> limit||!xisxdigit(*(loc-3))||!xisxdigit(*(loc-2))
 ||(*(loc-3)>='0'&&*(loc-3)<='7')||!xisspace(*(loc-1)))
-#line 707 "cwebdir/ctang-w2c.ch"
+#line 309 "cwebdir/ctang-w2c.ch"
 err_print(_("! Improper hex number following @l"));
-#line 1516 "cwebdir/ctangle.w"
+#line 1514 "cwebdir/ctangle.w"
 
 else{
-unsigned i;
+unsigned int i;
 char*beg;
 sscanf(loc-3,"%x",&i);
 while(xisspace(*loc)&&loc<limit)loc++;
@@ -1953,34 +1906,32 @@
 beg= loc;
 while(loc<limit&&(xisalpha(*loc)||xisdigit(*loc)||*loc=='_'))loc++;
 if(loc-beg>=translit_length)
-#line 713 "cwebdir/ctang-w2c.ch"
+#line 315 "cwebdir/ctang-w2c.ch"
 err_print(_("! Replacement string in @l too long"));
-#line 1526 "cwebdir/ctangle.w"
+#line 1524 "cwebdir/ctangle.w"
 
 else{
-#line 719 "cwebdir/ctang-w2c.ch"
 strncpy(translit[i-0200],beg,(size_t)(loc-beg));
-#line 1529 "cwebdir/ctangle.w"
 translit[i-0200][loc-beg]= '\0';
 }
 }
 
-/*:94*/
-#line 1494 "cwebdir/ctangle.w"
-;break;
+/*:103*/
+#line 1492 "cwebdir/ctangle.w"
+break;
 case format_code:case'@':break;
 case control_text:if(c=='q'||c=='Q'){
 while((c= skip_ahead())=='@');
 if(*(loc-1)!='>')
-#line 695 "cwebdir/ctang-w2c.ch"
+#line 297 "cwebdir/ctang-w2c.ch"
 err_print(_("! Double @ should be used in control text"));
-#line 1500 "cwebdir/ctangle.w"
+#line 1498 "cwebdir/ctangle.w"
 
 break;
 }
-#line 701 "cwebdir/ctang-w2c.ch"
+#line 303 "cwebdir/ctang-w2c.ch"
 default:err_print(_("! Double @ should be used in limbo"));
-#line 1504 "cwebdir/ctangle.w"
+#line 1502 "cwebdir/ctangle.w"
 
 }
 }
@@ -1987,24 +1938,23 @@
 }
 }
 
-/*:93*//*95:*/
-#line 1536 "cwebdir/ctangle.w"
+/*:102*//*104:*/
+#line 1534 "cwebdir/ctangle.w"
 
-#line 726 "cwebdir/ctang-w2c.ch"
 void
 print_stats(void){
-#line 740 "cwebdir/ctang-w2c.ch"
+#line 328 "cwebdir/ctang-w2c.ch"
 puts(_("\nMemory usage statistics:"));
 printf(_("%ld names (out of %ld)\n"),
-(long)(name_ptr-name_dir),(long)max_names);
+(ptrdiff_t)(name_ptr-name_dir),(long)max_names);
 printf(_("%ld replacement texts (out of %ld)\n"),
-(long)(text_ptr-text_info),(long)max_texts);
+(ptrdiff_t)(text_ptr-text_info),(long)max_texts);
 printf(_("%ld bytes (out of %ld)\n"),
-(long)(byte_ptr-byte_mem),(long)max_bytes);
+(ptrdiff_t)(byte_ptr-byte_mem),(long)max_bytes);
 printf(_("%ld tokens (out of %ld)\n"),
-#line 1547 "cwebdir/ctangle.w"
-(long)(tok_ptr-tok_mem),(long)max_toks);
+#line 1545 "cwebdir/ctangle.w"
+(ptrdiff_t)(tok_ptr-tok_mem),(long)max_toks);
 }
 
-#line 753 "cwebdir/ctang-w2c.ch"
-/*:95*/
+#line 341 "cwebdir/ctang-w2c.ch"
+/*:104*/

Modified: branches/stable/source/src/texk/web2c/cwebboot.cin
===================================================================
--- branches/stable/source/src/texk/web2c/cwebboot.cin	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/texk/web2c/cwebboot.cin	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,31 +1,40 @@
 /*1:*/
-#line 58 "cwebdir/common.w"
+#line 66 "cwebdir/common.w"
 
-/*85:*/
-#line 1247 "cwebdir/comm-w2c.ch"
+/*3:*/
+#line 53 "cwebdir/comm-w2c.h"
 
-#include <stdbool.h>  
-#include <stddef.h>  
-
-/*:85*//*88:*/
-#line 1286 "cwebdir/comm-w2c.ch"
-
 #ifndef HAVE_GETTEXT
 #define HAVE_GETTEXT 0
 #endif
 
 #if HAVE_GETTEXT
-#include <locale.h>  
 #include <libintl.h> 
 #else
+#define gettext(A) A
+#endif
+
+#include <ctype.h>  
+#include <stdbool.h>  
+#include <stddef.h>  
+#include <stdint.h>  
+#include <stdlib.h>  
+#include <stdio.h>  
+#include <string.h>  
+
+/*:3*//*89:*/
+#line 710 "cwebdir/comm-w2c.ch"
+
+#if HAVE_GETTEXT
+#include <locale.h>  
+#else
 #define setlocale(A,B) ""
 #define bindtextdomain(A,B) ""
 #define textdomain(A) ""
-#define gettext(A) A
 #endif
 
-/*:88*//*90:*/
-#line 1380 "cwebdir/comm-w2c.ch"
+/*:89*//*91:*/
+#line 757 "cwebdir/comm-w2c.ch"
 
 typedef bool boolean;
 #define HAVE_BOOLEAN
@@ -34,15 +43,17 @@
 #include <w2c/config.h>  
 #include <lib/lib.h>  
 
-/*:90*//*93:*/
-#line 1419 "cwebdir/comm-w2c.ch"
+/*:91*//*94:*/
+#line 796 "cwebdir/comm-w2c.ch"
 
 #define CWEB
 #include "help.h" 
 
-/*:93*/
-#line 59 "cwebdir/common.w"
+/*:94*/
+#line 67 "cwebdir/common.w"
 
+#define _(S) gettext(S)  \
+
 #define and_and 04
 #define lt_lt 020
 #define gt_gt 021
@@ -59,12 +70,30 @@
 #define period_ast 026
 #define minus_gt_ast 027 \
 
-#define buf_size 1000
-#define longest_name 10000
-#define long_buf_size (buf_size+longest_name) 
+#define xisalpha(c) (isalpha((eight_bits) c) &&((eight_bits) c<0200) ) 
+#define xisdigit(c) (isdigit((eight_bits) c) &&((eight_bits) c<0200) ) 
 #define xisspace(c) (isspace((eight_bits) c) &&((eight_bits) c<0200) ) 
-#define xisupper(c) (isupper((eight_bits) c) &&((eight_bits) c<0200) )  \
+#define xislower(c) (islower((eight_bits) c) &&((eight_bits) c<0200) ) 
+#define xisupper(c) (isupper((eight_bits) c) &&((eight_bits) c<0200) ) 
+#define xisxdigit(c) (isxdigit((eight_bits) c) &&((eight_bits) c<0200) )  \
 
+#define length(c) (size_t) ((c+1) ->byte_start-(c) ->byte_start) 
+#define print_id(c) term_write((c) ->byte_start,length((c) ) ) 
+#define llink link
+#define rlink dummy.Rlink
+#define root name_dir->rlink \
+
+#define chunk_marker 0 \
+
+#define spotless 0
+#define harmless_message 1
+#define error_message 2
+#define fatal_message 3
+#define mark_harmless {if(history==spotless) history= harmless_message;}
+#define mark_error history= error_message
+#define confusion(s) fatal(_("! This can't happen: ") ,s)  \
+ \
+
 #define max_include_depth 10 \
 
 #define max_file_name_length 1024
@@ -74,6 +103,32 @@
 #define web_file file[0]
 #define web_file_name file_name[0] \
 
+#define show_banner flags['b']
+#define show_progress flags['p']
+#define show_stats flags['s']
+#define show_happiness flags['h']
+#define temporary_output flags['t']
+#define make_xrefs flags['x'] \
+
+#define update_terminal fflush(stdout) 
+#define new_line putchar('\n') 
+#define putxchar putchar
+#define term_write(a,b) fflush(stdout) ,fwrite(a,sizeof(char) ,b,stdout) 
+#define C_printf(c,a) fprintf(C_file,c,a) 
+#define C_putc(c) putc(c,C_file)  \
+
+#define max_bytes 1000000 \
+
+#define max_toks 1000000
+#define max_names 10239 \
+
+#define max_sections 4000
+#define max_texts 10239
+#define longest_name 10000
+#define stack_size 500
+#define buf_size 1000
+#define long_buf_size (buf_size+longest_name)  \
+
 #define lines_dont_match (change_limit-change_buffer!=limit-buffer|| \
 strncmp(buffer,change_buffer,(size_t) (limit-buffer) ) )  \
 
@@ -83,31 +138,14 @@
 if(*loc=='@'&&(xisspace(*(loc+1) ) ||*(loc+1) =='*') ) change_pending= b; \
 } \
 
-#define max_sections 10239 \
- \
-
 #define too_long() {include_depth--; \
 err_print(_("! Include file name too long") ) ;goto restart;} \
- \
 
-#define max_bytes 1000000 \
-
-#define max_names 10239 \
- \
-
-#define length(c) (size_t) ((c+1) ->byte_start-(c) ->byte_start) 
-#define print_id(c) term_write((c) ->byte_start,length((c) ) )  \
-
 #define hash_size 8501 \
 
-#define llink link
-#define rlink dummy.Rlink
-#define root name_dir->rlink \
- \
-
 #define first_chunk(p) ((p) ->byte_start+2) 
-#define prefix_length(p) (int) ((unsigned char) *((p) ->byte_start) *256+ \
-(unsigned char) *((p) ->byte_start+1) ) 
+#define prefix_length(p) (int) ((eight_bits) *((p) ->byte_start) *256+ \
+(eight_bits) *((p) ->byte_start+1) ) 
 #define set_prefix_length(p,m) (*((p) ->byte_start) = (m) /256, \
 *((p) ->byte_start+1) = (m) %256)  \
 
@@ -119,37 +157,12 @@
 
 #define bad_extension 5 \
 
-#define spotless 0
-#define harmless_message 1
-#define error_message 2
-#define fatal_message 3
-#define mark_harmless {if(history==spotless) history= harmless_message;}
-#define mark_error history= error_message \
-
 #define RETURN_OK 0
 #define RETURN_WARN 5
 #define RETURN_ERROR 10
 #define RETURN_FAIL 20 \
 
-#define confusion(s) fatal(_("! This can't happen: ") ,s)  \
- \
-
-#define show_banner flags['b']
-#define show_progress flags['p']
-#define show_stats flags['s']
-#define show_happiness flags['h']
-#define temporary_output flags['t']
-#define make_xrefs flags['x'] \
-
 #define flag_change (**argv!='-') 
-#define update_terminal fflush(stdout)  \
-
-#define new_line putchar('\n') 
-#define putxchar putchar
-#define term_write(a,b) fflush(stdout) ,fwrite(a,sizeof(char) ,b,stdout) 
-#define C_printf(c,a) fprintf(C_file,c,a) 
-#define C_putc(c) putc(c,C_file)  \
-
 #define max_banner 50 \
 
 #define PATH_SEPARATOR separators[0]
@@ -156,37 +169,140 @@
 #define DIR_SEPARATOR separators[1]
 #define DEVICE_SEPARATOR separators[2] \
 
-#define _(S) gettext(S)  \
-
 #define kpse_find_cweb(name) kpse_find_file(name,kpse_cweb_format,true)  \
 
 
-#line 60 "cwebdir/common.w"
+#line 68 "cwebdir/common.w"
 
 /*2:*/
-#line 73 "cwebdir/common.w"
+#line 35 "cwebdir/comm-w2c.h"
 
-#line 77 "cwebdir/comm-w2c.ch"
+typedef bool boolean;
 typedef uint8_t eight_bits;
 typedef uint16_t sixteen_bits;
-#line 84 "cwebdir/comm-w2c.ch"
 typedef enum{
 ctangle,cweave,ctwill
 }cweb;
+extern cweb program;
+extern int phase;
+
+/*:2*//*4:*/
+#line 91 "cwebdir/comm-w2c.h"
+
+extern char section_text[];
+extern char*section_text_end;
+extern char*id_first;
+extern char*id_loc;
+
+/*:4*//*5:*/
+#line 105 "cwebdir/comm-w2c.h"
+
+extern char buffer[];
+extern char*buffer_end;
+extern char*loc;
+extern char*limit;
+
+/*:5*//*6:*/
+#line 120 "cwebdir/comm-w2c.h"
+
+typedef struct name_info{
+char*byte_start;
+struct name_info*link;
+union{
+struct name_info*Rlink;
+
+char Ilk;
+}dummy;
+void*equiv_or_xref;
+}name_info;
+typedef name_info*name_pointer;
+typedef name_pointer*hash_pointer;
+extern char byte_mem[];
+extern char*byte_mem_end;
+extern name_info name_dir[];
+extern name_pointer name_dir_end;
+extern name_pointer name_ptr;
+extern char*byte_ptr;
+extern name_pointer hash[];
+extern hash_pointer hash_end;
+extern hash_pointer h;
+
+/*:6*//*8:*/
+#line 164 "cwebdir/comm-w2c.h"
+
+extern int history;
+
+/*:8*//*10:*/
+#line 184 "cwebdir/comm-w2c.h"
+
+extern int include_depth;
+extern FILE*file[];
+extern FILE*change_file;
+extern char C_file_name[];
+extern char tex_file_name[];
+extern char idx_file_name[];
+extern char scn_file_name[];
+extern char file_name[][max_file_name_length];
+
+extern char change_file_name[];
+extern char check_file_name[];
+extern int line[];
+extern int change_line;
+extern int change_depth;
+extern boolean input_has_ended;
+extern boolean changing;
+extern boolean web_file_open;
+
+/*:10*//*12:*/
+#line 209 "cwebdir/comm-w2c.h"
+
+extern sixteen_bits section_count;
+extern boolean changed_section[];
+extern boolean change_pending;
+extern boolean print_where;
+
+/*:12*//*13:*/
+#line 223 "cwebdir/comm-w2c.h"
+
+extern int argc;
+extern char**argv;
+extern boolean flags[];
+extern const char*use_language;
+
+/*:13*//*14:*/
+#line 236 "cwebdir/comm-w2c.h"
+
+extern FILE*C_file;
+extern FILE*tex_file;
+extern FILE*idx_file;
+extern FILE*scn_file;
+extern FILE*active_file;
+extern FILE*check_file;
+
+/*:14*/
+#line 69 "cwebdir/common.w"
+
+/*18:*/
+#line 83 "cwebdir/common.w"
+
+#line 72 "cwebdir/comm-w2c.ch"
 cweb program;
-#line 76 "cwebdir/common.w"
+#line 85 "cwebdir/common.w"
 
-/*:2*//*6:*/
-#line 130 "cwebdir/comm-w2c.ch"
+/*:18*//*19:*/
+#line 92 "cwebdir/common.w"
+int phase;
 
+/*:19*//*21:*/
+#line 129 "cwebdir/common.w"
+
 char section_text[longest_name+1];
 char*section_text_end= section_text+longest_name;
 char*id_first;
 char*id_loc;
-#line 138 "cwebdir/common.w"
 
-/*:6*//*7:*/
-#line 159 "cwebdir/common.w"
+/*:21*//*22:*/
+#line 149 "cwebdir/common.w"
 
 char buffer[long_buf_size];
 char*buffer_end= buffer+buf_size-2;
@@ -193,9 +309,8 @@
 char*limit= buffer;
 char*loc= buffer;
 
-#line 155 "cwebdir/comm-w2c.ch"
-/*:7*//*10:*/
-#line 214 "cwebdir/common.w"
+/*:22*//*25:*/
+#line 194 "cwebdir/common.w"
 
 int include_depth;
 FILE*file[max_include_depth];
@@ -203,7 +318,7 @@
 char file_name[max_include_depth][max_file_name_length];
 
 char change_file_name[max_file_name_length];
-#line 222 "cwebdir/common.w"
+#line 202 "cwebdir/common.w"
 int line[max_include_depth];
 int change_line;
 int change_depth;
@@ -211,10 +326,15 @@
 boolean changing;
 boolean web_file_open= 0;
 
-/*:10*//*20:*/
-#line 418 "cwebdir/common.w"
+/*:25*//*26:*/
+#line 220 "cwebdir/common.w"
 
-#line 420 "cwebdir/common.w"
+char change_buffer[buf_size];
+char*change_limit;
+
+/*:26*//*37:*/
+#line 401 "cwebdir/common.w"
+
 sixteen_bits section_count;
 boolean changed_section[max_sections];
 boolean change_pending;
@@ -221,62 +341,34 @@
 
 boolean print_where= 0;
 
-/*:20*//*27:*/
-#line 594 "cwebdir/common.w"
+/*:37*//*43:*/
+#line 598 "cwebdir/common.w"
 
-typedef struct name_info{
-char*byte_start;
-/*31:*/
-#line 631 "cwebdir/common.w"
-
-struct name_info*link;
-
-/*:31*//*40:*/
-#line 730 "cwebdir/common.w"
-
-union{
-struct name_info*Rlink;
-
-char Ilk;
-}dummy;
-
-/*:40*//*55:*/
-#line 773 "cwebdir/comm-w2c.ch"
-
-void*equiv_or_xref;
-#line 1064 "cwebdir/common.w"
-
-/*:55*/
-#line 597 "cwebdir/common.w"
-
-}name_info;
-typedef name_info*name_pointer;
 char byte_mem[max_bytes];
 char*byte_mem_end= byte_mem+max_bytes-1;
 name_info name_dir[max_names];
 name_pointer name_dir_end= name_dir+max_names-1;
 
-/*:27*//*29:*/
-#line 617 "cwebdir/common.w"
+/*:43*//*44:*/
+#line 609 "cwebdir/common.w"
 
 name_pointer name_ptr;
 char*byte_ptr;
 
-/*:29*//*32:*/
-#line 644 "cwebdir/common.w"
+/*:44*//*46:*/
+#line 629 "cwebdir/common.w"
 
-typedef name_pointer*hash_pointer;
 name_pointer hash[hash_size];
 hash_pointer hash_end= hash+hash_size-1;
 hash_pointer h;
 
-/*:32*//*56:*/
-#line 1082 "cwebdir/common.w"
+/*:46*//*65:*/
+#line 1017 "cwebdir/common.w"
 
 int history= spotless;
 
-/*:56*//*67:*/
-#line 1220 "cwebdir/common.w"
+/*:65*//*73:*/
+#line 1138 "cwebdir/common.w"
 
 int argc;
 char**argv;
@@ -283,45 +375,36 @@
 char C_file_name[max_file_name_length];
 char tex_file_name[max_file_name_length];
 char idx_file_name[max_file_name_length];
-#line 934 "cwebdir/comm-w2c.ch"
+#line 431 "cwebdir/comm-w2c.ch"
 char scn_file_name[max_file_name_length];
 char check_file_name[max_file_name_length];
-#line 941 "cwebdir/comm-w2c.ch"
+#line 1145 "cwebdir/common.w"
 boolean flags[128];
-const char*use_language= "";
-#line 1228 "cwebdir/common.w"
 
-/*:67*//*77:*/
-#line 1370 "cwebdir/common.w"
+/*:73*//*83:*/
+#line 1286 "cwebdir/common.w"
 
 FILE*C_file;
 FILE*tex_file;
 FILE*idx_file;
-#line 1131 "cwebdir/comm-w2c.ch"
+#line 569 "cwebdir/comm-w2c.ch"
 FILE*scn_file;
 FILE*check_file;
-#line 1138 "cwebdir/comm-w2c.ch"
+#line 576 "cwebdir/comm-w2c.ch"
 FILE*active_file;
 char*found_filename;
-#line 1376 "cwebdir/common.w"
+#line 1292 "cwebdir/common.w"
 
-#line 1155 "cwebdir/comm-w2c.ch"
-/*:77*/
-#line 61 "cwebdir/common.w"
+#line 593 "cwebdir/comm-w2c.ch"
+/*:83*//*86:*/
+#line 638 "cwebdir/comm-w2c.ch"
 
-/*3:*/
-#line 83 "cwebdir/common.w"
-int phase;
+const char*use_language= "";
 
-/*:3*//*11:*/
-#line 240 "cwebdir/common.w"
 
-char change_buffer[buf_size];
-char*change_limit;
+/*:86*//*87:*/
+#line 651 "cwebdir/comm-w2c.ch"
 
-/*:11*//*86:*/
-#line 1260 "cwebdir/comm-w2c.ch"
-
 char cb_banner[max_banner];
 string texmf_locale;
 #ifndef SEPARATORS
@@ -329,141 +412,120 @@
 #endif
 char separators[]= SEPARATORS;
 
-/*:86*/
-#line 62 "cwebdir/common.w"
+/*:87*/
+#line 70 "cwebdir/common.w"
 
-/*33:*/
-#line 650 "cwebdir/common.w"
+/*7:*/
+#line 143 "cwebdir/comm-w2c.h"
 
-#line 502 "cwebdir/comm-w2c.ch"
 extern boolean names_match(name_pointer,const char*,size_t,eight_bits);
-#line 652 "cwebdir/common.w"
+extern name_pointer id_lookup(const char*,const char*,char);
 
-/*:33*//*38:*/
-#line 703 "cwebdir/common.w"
-
-#line 532 "cwebdir/comm-w2c.ch"
+extern name_pointer section_lookup(char*,char*,int);
+extern void init_node(name_pointer);
 extern void init_p(name_pointer,eight_bits);
-#line 705 "cwebdir/common.w"
+extern void print_prefix_name(name_pointer);
+extern void print_section_name(name_pointer);
+extern void sprint_section_name(char*,name_pointer);
 
-/*:38*//*46:*/
-#line 852 "cwebdir/common.w"
+/*:7*//*9:*/
+#line 167 "cwebdir/comm-w2c.h"
 
-#line 612 "cwebdir/comm-w2c.ch"
-extern void init_node(name_pointer);
-#line 854 "cwebdir/common.w"
+extern int wrap_up(void);
+extern void err_print(const char*);
+extern void fatal(const char*,const char*);
+extern void overflow(const char*);
 
-/*:46*//*53:*/
-#line 1017 "cwebdir/common.w"
+/*:9*//*11:*/
+#line 203 "cwebdir/comm-w2c.h"
 
-#line 738 "cwebdir/comm-w2c.ch"
-static int section_name_cmp(char**,int,name_pointer);
-#line 1019 "cwebdir/common.w"
+extern boolean get_line(void);
+extern void check_complete(void);
+extern void reset_input(void);
 
-/*:53*//*57:*/
-#line 1092 "cwebdir/common.w"
+/*:11*//*15:*/
+#line 245 "cwebdir/comm-w2c.h"
 
-#line 780 "cwebdir/comm-w2c.ch"
-extern void err_print(const char*);
-#line 1094 "cwebdir/common.w"
-
-/*:57*//*60:*/
-#line 1140 "cwebdir/common.w"
-
-#line 807 "cwebdir/comm-w2c.ch"
-extern int wrap_up(void);
+extern void common_init(void);
 extern void print_stats(void);
-#line 1143 "cwebdir/common.w"
+extern void cb_show_banner(void);
 
-#line 818 "cwebdir/comm-w2c.ch"
-/*:60*//*63:*/
-#line 1173 "cwebdir/common.w"
+/*:15*//*23:*/
+#line 159 "cwebdir/common.w"
 
-#line 881 "cwebdir/comm-w2c.ch"
-extern void fatal(const char*,const char*);
-extern void overflow(const char*);
-#line 1175 "cwebdir/common.w"
+static boolean input_ln(FILE*);
 
-/*:63*//*69:*/
-#line 1251 "cwebdir/common.w"
+/*:23*//*27:*/
+#line 231 "cwebdir/common.w"
 
-#line 971 "cwebdir/comm-w2c.ch"
-static void scan_args(void);
-#line 1253 "cwebdir/common.w"
+static void prime_the_change_buffer(void);
 
-/*:69*//*83:*/
-#line 1222 "cwebdir/comm-w2c.ch"
+/*:27*//*32:*/
+#line 303 "cwebdir/common.w"
 
-boolean get_line(void);
-name_pointer id_lookup(const char*,const char*,char);
-name_pointer section_lookup(char*,char*,int);
-void check_complete(void);
-void common_init(void);
-void print_prefix_name(name_pointer);
-void print_section_name(name_pointer);
-void reset_input(void);
-void sprint_section_name(char*,name_pointer);
+static void check_change(void);
 
-/*:83*//*84:*/
-#line 1235 "cwebdir/comm-w2c.ch"
+/*:32*//*55:*/
+#line 776 "cwebdir/common.w"
 
-static boolean input_ln(FILE*);
 static int web_strcmp(char*,int,char*,int);
 static name_pointer add_section_name(name_pointer,int,char*,char*,int);
 static void extend_section_name(name_pointer,char*,char*,int);
-static void check_change(void);
-static void prime_the_change_buffer(void);
 
-/*:84*//*98:*/
-#line 1485 "cwebdir/comm-w2c.ch"
+/*:55*//*63:*/
+#line 972 "cwebdir/common.w"
 
+static int section_name_cmp(char**,int,name_pointer);
+
+/*:63*//*75:*/
+#line 1170 "cwebdir/common.w"
+
+static void scan_args(void);
+
+/*:75*//*96:*/
+#line 809 "cwebdir/comm-w2c.ch"
+
 static void cb_usage(const_string str);
 static void cb_usagehelp(const_string*message,const_string bug_email);
-void cb_show_banner(void);
 
-/*:98*/
-#line 63 "cwebdir/common.w"
+/*:96*/
+#line 71 "cwebdir/common.w"
 
 
-/*:1*//*4:*/
-#line 89 "cwebdir/common.w"
+/*:1*//*20:*/
+#line 98 "cwebdir/common.w"
 
-#line 94 "cwebdir/comm-w2c.ch"
 void
 common_init(void)
-#line 92 "cwebdir/common.w"
 {
-#line 103 "cwebdir/comm-w2c.ch"
-/*30:*/
-#line 621 "cwebdir/common.w"
+#line 78 "cwebdir/comm-w2c.ch"
+/*45:*/
+#line 613 "cwebdir/common.w"
 
 name_dir->byte_start= byte_ptr= byte_mem;
 name_ptr= name_dir+1;
 name_ptr->byte_start= byte_mem;
+root= NULL;
 
-/*:30*//*34:*/
-#line 655 "cwebdir/common.w"
+/*:45*//*47:*/
+#line 636 "cwebdir/common.w"
 
 for(h= hash;h<=hash_end;*h++= NULL);
 
-/*:34*//*41:*/
-#line 737 "cwebdir/common.w"
+/*:47*/
+#line 78 "cwebdir/comm-w2c.ch"
 
-root= NULL;
+/*92:*/
+#line 771 "cwebdir/comm-w2c.ch"
 
-/*:41*/
-#line 103 "cwebdir/comm-w2c.ch"
-
-/*91:*/
-#line 1394 "cwebdir/comm-w2c.ch"
-
 kpse_set_program_name(argv[0],"cweb");
 
-/*:91*/
-#line 104 "cwebdir/comm-w2c.ch"
+/*:92*/
+#line 79 "cwebdir/comm-w2c.ch"
 
-/*89:*/
-#line 1342 "cwebdir/comm-w2c.ch"
+#line 85 "cwebdir/comm-w2c.ch"
+/*90:*/
+#line 719 "cwebdir/comm-w2c.ch"
 
 setlocale(LC_MESSAGES,setlocale(LC_CTYPE,""));
 texmf_locale= kpse_var_expand("${TEXMFLOCALEDIR}");
@@ -478,21 +540,24 @@
 textdomain("cweb");
 
 
-/*:89*/
-#line 105 "cwebdir/comm-w2c.ch"
+/*:90*/
+#line 85 "cwebdir/comm-w2c.ch"
 
-/*68:*/
-#line 1233 "cwebdir/common.w"
+/*74:*/
+#line 1151 "cwebdir/common.w"
 
-#line 948 "cwebdir/comm-w2c.ch"
-temporary_output= 1;
-#line 1235 "cwebdir/common.w"
+#line 438 "cwebdir/comm-w2c.ch"
+make_xrefs= true;
+temporary_output= true;
+#line 1153 "cwebdir/common.w"
+show_stats= false;
 
-/*:68*/
-#line 106 "cwebdir/comm-w2c.ch"
+/*:74*/
+#line 86 "cwebdir/comm-w2c.ch"
 
-/*78:*/
-#line 1155 "cwebdir/comm-w2c.ch"
+#line 104 "cwebdir/common.w"
+/*84:*/
+#line 593 "cwebdir/comm-w2c.ch"
 
 scan_args();
 if(program==ctangle){
@@ -523,21 +588,19 @@
 if((tex_file= fopen(check_file_name,"wb"))==NULL)
 fatal(_("! Cannot open output file "),check_file_name);
 }
-#line 1388 "cwebdir/common.w"
+#line 1304 "cwebdir/common.w"
 
-/*:78*/
-#line 107 "cwebdir/comm-w2c.ch"
+#line 628 "cwebdir/comm-w2c.ch"
+/*:84*/
+#line 104 "cwebdir/common.w"
 
-#line 96 "cwebdir/common.w"
 }
 
-/*:4*//*9:*/
-#line 172 "cwebdir/common.w"
+/*:20*//*24:*/
+#line 162 "cwebdir/common.w"
 
-#line 162 "cwebdir/comm-w2c.ch"
 static boolean input_ln(
 FILE*fp)
-#line 175 "cwebdir/common.w"
 {
 register int c= EOF;
 register char*k;
@@ -544,14 +607,14 @@
 if(feof(fp))return(0);
 limit= k= buffer;
 while(k<=buffer_end&&(c= getc(fp))!=EOF&&c!='\n')
-#line 169 "cwebdir/comm-w2c.ch"
+#line 92 "cwebdir/comm-w2c.ch"
 if((*(k++)= c)!=' '&&c!='\r')limit= k;
-#line 182 "cwebdir/common.w"
+#line 172 "cwebdir/common.w"
 if(k> buffer_end)
 if((c= getc(fp))!=EOF&&c!='\n'){
-#line 175 "cwebdir/comm-w2c.ch"
+#line 98 "cwebdir/comm-w2c.ch"
 ungetc(c,fp);loc= buffer;err_print(_("! Input line too long"));
-#line 185 "cwebdir/common.w"
+#line 175 "cwebdir/common.w"
 
 }
 if(c==EOF&&limit==buffer)return(0);
@@ -559,17 +622,15 @@
 return(1);
 }
 
-/*:9*//*12:*/
-#line 251 "cwebdir/common.w"
+/*:24*//*28:*/
+#line 234 "cwebdir/common.w"
 
-#line 201 "cwebdir/comm-w2c.ch"
 static void
 prime_the_change_buffer(void)
-#line 254 "cwebdir/common.w"
 {
 change_limit= change_buffer;
-/*13:*/
-#line 265 "cwebdir/common.w"
+/*29:*/
+#line 248 "cwebdir/common.w"
 
 while(1){
 change_line++;
@@ -576,61 +637,55 @@
 if(!input_ln(change_file))return;
 if(limit<buffer+2)continue;
 if(buffer[0]!='@')continue;
-#line 208 "cwebdir/comm-w2c.ch"
 if(xisupper(buffer[1]))buffer[1]= tolower((eight_bits)buffer[1]);
-#line 272 "cwebdir/common.w"
 if(buffer[1]=='x')break;
 if(buffer[1]=='y'||buffer[1]=='z'||buffer[1]=='i'){
 loc= buffer+2;
-#line 214 "cwebdir/comm-w2c.ch"
+#line 109 "cwebdir/comm-w2c.ch"
 err_print(_("! Missing @x in change file"));
-#line 276 "cwebdir/common.w"
+#line 259 "cwebdir/common.w"
 
 }
 }
 
-/*:13*/
-#line 256 "cwebdir/common.w"
-;
-/*14:*/
-#line 282 "cwebdir/common.w"
+/*:29*/
+#line 239 "cwebdir/common.w"
 
+/*30:*/
+#line 265 "cwebdir/common.w"
+
 do{
 change_line++;
 if(!input_ln(change_file)){
-#line 220 "cwebdir/comm-w2c.ch"
+#line 115 "cwebdir/comm-w2c.ch"
 err_print(_("! Change file ended after @x"));
-#line 287 "cwebdir/common.w"
+#line 270 "cwebdir/common.w"
 
 return;
 }
 }while(limit==buffer);
 
-/*:14*/
-#line 257 "cwebdir/common.w"
-;
-/*15:*/
-#line 292 "cwebdir/common.w"
+/*:30*/
+#line 240 "cwebdir/common.w"
 
+/*31:*/
+#line 275 "cwebdir/common.w"
+
 {
-#line 227 "cwebdir/comm-w2c.ch"
 change_limit= change_buffer+(ptrdiff_t)(limit-buffer);
 strncpy(change_buffer,buffer,(size_t)(limit-buffer+1));
-#line 296 "cwebdir/common.w"
 }
 
-/*:15*/
-#line 258 "cwebdir/common.w"
-;
+/*:31*/
+#line 241 "cwebdir/common.w"
+
 }
 
-/*:12*//*16:*/
-#line 320 "cwebdir/common.w"
+/*:28*//*33:*/
+#line 306 "cwebdir/common.w"
 
-#line 235 "cwebdir/comm-w2c.ch"
 static void
 check_change(void)
-#line 323 "cwebdir/common.w"
 {
 int n= 0;
 if(lines_dont_match)return;
@@ -642,24 +697,22 @@
 while(1){
 changing= 1;print_where= 1;change_line++;
 if(!input_ln(change_file)){
-#line 242 "cwebdir/comm-w2c.ch"
+#line 121 "cwebdir/comm-w2c.ch"
 err_print(_("! Change file ended before @y"));
-#line 335 "cwebdir/common.w"
+#line 321 "cwebdir/common.w"
 
 change_limit= change_buffer;changing= 0;
 return;
 }
 if(limit> buffer+1&&buffer[0]=='@'){
-#line 248 "cwebdir/comm-w2c.ch"
 char xyz_code= xisupper(buffer[1])?tolower((eight_bits)buffer[1]):buffer[1];
-#line 341 "cwebdir/common.w"
-/*17:*/
-#line 358 "cwebdir/common.w"
+/*34:*/
+#line 344 "cwebdir/common.w"
 
 if(xyz_code=='x'||xyz_code=='z'){
-#line 260 "cwebdir/comm-w2c.ch"
+#line 133 "cwebdir/comm-w2c.ch"
 loc= buffer+2;err_print(_("! Where is the matching @y?"));
-#line 361 "cwebdir/common.w"
+#line 347 "cwebdir/common.w"
 
 }
 else if(xyz_code=='y'){
@@ -666,9 +719,9 @@
 if(n> 0){
 loc= buffer+2;
 printf("\n! Hmm... %d ",n);
-#line 266 "cwebdir/comm-w2c.ch"
+#line 139 "cwebdir/comm-w2c.ch"
 err_print(_("of the preceding lines failed to match"));
-#line 368 "cwebdir/common.w"
+#line 354 "cwebdir/common.w"
 
 }
 change_depth= include_depth;
@@ -675,29 +728,27 @@
 return;
 }
 
-/*:17*/
-#line 342 "cwebdir/common.w"
-;
+/*:34*/
+#line 328 "cwebdir/common.w"
+
 }
-/*15:*/
-#line 292 "cwebdir/common.w"
+/*31:*/
+#line 275 "cwebdir/common.w"
 
 {
-#line 227 "cwebdir/comm-w2c.ch"
 change_limit= change_buffer+(ptrdiff_t)(limit-buffer);
 strncpy(change_buffer,buffer,(size_t)(limit-buffer+1));
-#line 296 "cwebdir/common.w"
 }
 
-/*:15*/
-#line 344 "cwebdir/common.w"
-;
+/*:31*/
+#line 330 "cwebdir/common.w"
+
 changing= 0;cur_line++;
 while(!input_ln(cur_file)){
 if(include_depth==0){
-#line 254 "cwebdir/comm-w2c.ch"
+#line 127 "cwebdir/comm-w2c.ch"
 err_print(_("! CWEB file ended during a change"));
-#line 349 "cwebdir/common.w"
+#line 335 "cwebdir/common.w"
 
 input_has_ended= 1;return;
 }
@@ -707,19 +758,17 @@
 }
 }
 
-/*:16*//*18:*/
-#line 378 "cwebdir/common.w"
+/*:33*//*35:*/
+#line 364 "cwebdir/common.w"
 
-#line 273 "cwebdir/comm-w2c.ch"
 void
 reset_input(void)
-#line 381 "cwebdir/common.w"
 {
 limit= buffer;loc= buffer+1;buffer[0]= ' ';
-/*19:*/
-#line 393 "cwebdir/common.w"
+/*36:*/
+#line 379 "cwebdir/common.w"
 
-#line 284 "cwebdir/comm-w2c.ch"
+#line 149 "cwebdir/comm-w2c.ch"
 if((found_filename= kpse_find_cweb(web_file_name))==NULL||
 (web_file= fopen(found_filename,"r"))==NULL){
 fatal(_("! Cannot open input file "),web_file_name);
@@ -730,11 +779,11 @@
 ((strncmp(found_filename,"./",2)==0)?2:0));
 free(found_filename);
 }else fatal(_("! Filename too long\n"),found_filename);
-#line 399 "cwebdir/common.w"
+#line 385 "cwebdir/common.w"
 
 
 web_file_open= 1;
-#line 300 "cwebdir/comm-w2c.ch"
+#line 165 "cwebdir/comm-w2c.ch"
 if((found_filename= kpse_find_cweb(change_file_name))==NULL||
 (change_file= fopen(found_filename,"r"))==NULL){
 fatal(_("! Cannot open change file "),change_file_name);
@@ -745,11 +794,11 @@
 ((strncmp(found_filename,"./",2)==0)?2:0));
 free(found_filename);
 }else fatal(_("! Filename too long\n"),found_filename);
-#line 404 "cwebdir/common.w"
+#line 390 "cwebdir/common.w"
 
-/*:19*/
-#line 383 "cwebdir/common.w"
-;
+/*:36*/
+#line 369 "cwebdir/common.w"
+
 include_depth= 0;cur_line= 0;change_line= 0;
 change_depth= include_depth;
 changing= 1;prime_the_change_buffer();changing= !changing;
@@ -756,23 +805,21 @@
 limit= buffer;loc= buffer+1;buffer[0]= ' ';input_has_ended= 0;
 }
 
-/*:18*//*21:*/
-#line 426 "cwebdir/common.w"
+/*:35*//*38:*/
+#line 408 "cwebdir/common.w"
 
-#line 328 "cwebdir/comm-w2c.ch"
 boolean get_line(void)
-#line 428 "cwebdir/common.w"
 {
 restart:
 if(changing&&include_depth==change_depth)
-/*25:*/
-#line 537 "cwebdir/common.w"
+/*41:*/
+#line 516 "cwebdir/common.w"
 {
 change_line++;
 if(!input_ln(change_file)){
-#line 440 "cwebdir/comm-w2c.ch"
+#line 274 "cwebdir/comm-w2c.ch"
 err_print(_("! Change file ended without @z"));
-#line 541 "cwebdir/common.w"
+#line 520 "cwebdir/common.w"
 
 buffer[0]= '@';buffer[1]= 'z';limit= buffer+2;
 }
@@ -785,14 +832,12 @@
 }
 *limit= ' ';
 if(buffer[0]=='@'){
-#line 446 "cwebdir/comm-w2c.ch"
 if(xisupper(buffer[1]))buffer[1]= tolower((eight_bits)buffer[1]);
-#line 554 "cwebdir/common.w"
 if(buffer[1]=='x'||buffer[1]=='y'){
 loc= buffer+2;
-#line 452 "cwebdir/comm-w2c.ch"
+#line 280 "cwebdir/comm-w2c.ch"
 err_print(_("! Where is the matching @z?"));
-#line 557 "cwebdir/common.w"
+#line 536 "cwebdir/common.w"
 
 }
 else if(buffer[1]=='z'){
@@ -802,12 +847,12 @@
 }
 }
 
-/*:25*/
-#line 431 "cwebdir/common.w"
-;
+/*:41*/
+#line 413 "cwebdir/common.w"
+
 if(!changing||include_depth> change_depth){
-/*24:*/
-#line 520 "cwebdir/common.w"
+/*40:*/
+#line 499 "cwebdir/common.w"
 {
 cur_line++;
 while(!input_ln(cur_file)){
@@ -825,9 +870,9 @@
 if(change_limit> change_buffer)check_change();
 }
 
-/*:24*/
-#line 433 "cwebdir/common.w"
-;
+/*:40*/
+#line 415 "cwebdir/common.w"
+
 if(changing&&include_depth==change_depth)goto restart;
 }
 if(input_has_ended)return 0;
@@ -836,27 +881,27 @@
 loc= buffer+2;*limit= '"';
 while(*loc==' '||*loc=='\t')loc++;
 if(loc>=limit){
-#line 334 "cwebdir/comm-w2c.ch"
+#line 180 "cwebdir/comm-w2c.ch"
 err_print(_("! Include file name not given"));
-#line 443 "cwebdir/common.w"
+#line 425 "cwebdir/common.w"
 
 goto restart;
 }
 if(include_depth>=max_include_depth-1){
-#line 340 "cwebdir/comm-w2c.ch"
+#line 186 "cwebdir/comm-w2c.ch"
 err_print(_("! Too many nested includes"));
-#line 448 "cwebdir/common.w"
+#line 430 "cwebdir/common.w"
 
 goto restart;
 }
 include_depth++;
-/*23:*/
-#line 380 "cwebdir/comm-w2c.ch"
+/*39:*/
+#line 453 "cwebdir/common.w"
 {
-#line 389 "cwebdir/comm-w2c.ch"
+#line 223 "cwebdir/comm-w2c.ch"
 char*cur_file_name_end= cur_file_name+max_file_name_length-1;
 char*k= cur_file_name;
-#line 479 "cwebdir/common.w"
+#line 458 "cwebdir/common.w"
 
 if(*loc=='"'){
 loc++;
@@ -867,7 +912,7 @@
 if(k> cur_file_name_end)too_long();
 
 *k= '\0';
-#line 396 "cwebdir/comm-w2c.ch"
+#line 230 "cwebdir/comm-w2c.ch"
 if((found_filename= kpse_find_cweb(cur_file_name))!=NULL&&
 (cur_file= fopen(found_filename,"r"))!=NULL){
 
@@ -877,45 +922,42 @@
 ((strncmp(found_filename,"./",2)==0)?2:0));
 free(found_filename);
 }else fatal(_("! Filename too long\n"),found_filename);
-#line 490 "cwebdir/common.w"
+#line 469 "cwebdir/common.w"
 cur_line= 0;print_where= 1;
 goto restart;
 }
-#line 434 "cwebdir/comm-w2c.ch"
+#line 268 "cwebdir/comm-w2c.ch"
 include_depth--;err_print(_("! Cannot open include file"));goto restart;
-#line 518 "cwebdir/common.w"
+#line 497 "cwebdir/common.w"
 }
 
-/*:23*/
-#line 452 "cwebdir/common.w"
-;
+/*:39*/
+#line 434 "cwebdir/common.w"
+
 }
 return 1;
 }
 
-#line 355 "cwebdir/comm-w2c.ch"
-/*:21*//*26:*/
-#line 569 "cwebdir/common.w"
+#line 201 "cwebdir/comm-w2c.ch"
+/*:38*//*42:*/
+#line 548 "cwebdir/common.w"
 
-#line 462 "cwebdir/comm-w2c.ch"
 void
 check_complete(void){
 if(change_limit!=change_buffer){
 strncpy(buffer,change_buffer,(size_t)(change_limit-change_buffer+1));
 limit= buffer+(ptrdiff_t)(change_limit-change_buffer);
-#line 575 "cwebdir/common.w"
 changing= 1;change_depth= include_depth;loc= buffer;
-#line 472 "cwebdir/comm-w2c.ch"
+#line 286 "cwebdir/comm-w2c.ch"
 err_print(_("! Change file entry did not match"));
-#line 577 "cwebdir/common.w"
+#line 556 "cwebdir/common.w"
 
 }
 }
 
-/*:26*//*35:*/
-#line 660 "cwebdir/common.w"
+/*:42*//*48:*/
+#line 641 "cwebdir/common.w"
 
-#line 514 "cwebdir/comm-w2c.ch"
 name_pointer
 id_lookup(
 const char*first,
@@ -923,27 +965,24 @@
 char t)
 {
 const char*i= first;
-#line 668 "cwebdir/common.w"
 int h;
 int l;
 name_pointer p;
 if(last==NULL)for(last= first;*last!='\0';last++);
-#line 526 "cwebdir/comm-w2c.ch"
 l= (int)(last-first);
-#line 673 "cwebdir/common.w"
-/*36:*/
-#line 683 "cwebdir/common.w"
+/*49:*/
+#line 664 "cwebdir/common.w"
 
-h= (unsigned char)*i;
-while(++i<last)h= (h+h+(int)((unsigned char)*i))%hash_size;
+h= (eight_bits)*i;
+while(++i<last)h= (h+h+(int)((eight_bits)*i))%hash_size;
 
 
-/*:36*/
-#line 673 "cwebdir/common.w"
-;
-/*37:*/
-#line 691 "cwebdir/common.w"
+/*:49*/
+#line 654 "cwebdir/common.w"
 
+/*50:*/
+#line 672 "cwebdir/common.w"
+
 p= hash[h];
 while(p&&!names_match(p,first,l,t))p= p->link;
 if(p==NULL){
@@ -951,37 +990,33 @@
 p->link= hash[h];hash[h]= p;
 }
 
-/*:37*/
-#line 674 "cwebdir/common.w"
-;
-if(p==name_ptr)/*39:*/
-#line 706 "cwebdir/common.w"
+/*:50*/
+#line 655 "cwebdir/common.w"
+
+if(p==name_ptr)/*51:*/
+#line 683 "cwebdir/common.w"
 {
-#line 539 "cwebdir/comm-w2c.ch"
+#line 293 "cwebdir/comm-w2c.ch"
 if(byte_ptr+l> byte_mem_end)overflow(_("byte memory"));
 if(name_ptr>=name_dir_end)overflow(_("name"));
-#line 709 "cwebdir/common.w"
+#line 686 "cwebdir/common.w"
 strncpy(byte_ptr,first,l);
 (++name_ptr)->byte_start= byte_ptr+= l;
-#line 546 "cwebdir/comm-w2c.ch"
 init_p(p,t);
-#line 712 "cwebdir/common.w"
 }
 
-/*:39*/
-#line 675 "cwebdir/common.w"
-;
+/*:51*/
+#line 656 "cwebdir/common.w"
+
 return(p);
 }
 
-/*:35*//*42:*/
-#line 764 "cwebdir/common.w"
+/*:48*//*52:*/
+#line 715 "cwebdir/common.w"
 
-#line 554 "cwebdir/comm-w2c.ch"
 void
 print_section_name(
 name_pointer p)
-#line 768 "cwebdir/common.w"
 {
 char*ss,*s= first_chunk(p);
 name_pointer q= p+1;
@@ -988,11 +1023,9 @@
 while(p!=name_dir){
 ss= (p+1)->byte_start-1;
 if(*ss==' '&&ss>=s){
-#line 564 "cwebdir/comm-w2c.ch"
 term_write(s,(size_t)(ss-s));p= q->link;q= p;
 }else{
 term_write(s,(size_t)(ss+1-s));p= name_dir;q= NULL;
-#line 777 "cwebdir/common.w"
 }
 s= p->byte_start;
 }
@@ -999,15 +1032,13 @@
 if(q)term_write("...",3);
 }
 
-/*:42*//*43:*/
-#line 783 "cwebdir/common.w"
+/*:52*//*53:*/
+#line 734 "cwebdir/common.w"
 
-#line 575 "cwebdir/comm-w2c.ch"
 void
 sprint_section_name(
 char*dest,
 name_pointer p)
-#line 788 "cwebdir/common.w"
 {
 char*ss,*s= first_chunk(p);
 name_pointer q= p+1;
@@ -1018,22 +1049,18 @@
 }else{
 ss++;p= name_dir;
 }
-#line 584 "cwebdir/comm-w2c.ch"
 strncpy(dest,s,(size_t)(ss-s)),dest+= ss-s;
-#line 799 "cwebdir/common.w"
 s= p->byte_start;
 }
 *dest= '\0';
 }
 
-/*:43*//*44:*/
-#line 804 "cwebdir/common.w"
+/*:53*//*54:*/
+#line 755 "cwebdir/common.w"
 
-#line 592 "cwebdir/comm-w2c.ch"
 void
 print_prefix_name(
 name_pointer p)
-#line 808 "cwebdir/common.w"
 {
 char*s= first_chunk(p);
 int l= prefix_length(p);
@@ -1041,16 +1068,14 @@
 if(s+l<(p+1)->byte_start)term_write("...",3);
 }
 
-/*:44*//*45:*/
-#line 825 "cwebdir/common.w"
+/*:54*//*56:*/
+#line 781 "cwebdir/common.w"
 
-#line 602 "cwebdir/comm-w2c.ch"
 static int web_strcmp(
 char*j,
 int j_len,
 char*k,
 int k_len)
-#line 829 "cwebdir/common.w"
 {
 char*j1= j+j_len,*k1= k+k_len;
 while(k<k1&&j<j1&&*j==*k)k++,j++;
@@ -1061,10 +1086,9 @@
 else return greater;
 }
 
-/*:45*//*47:*/
-#line 855 "cwebdir/common.w"
+/*:56*//*57:*/
+#line 810 "cwebdir/common.w"
 
-#line 624 "cwebdir/comm-w2c.ch"
 static name_pointer
 add_section_name(
 name_pointer par,
@@ -1072,16 +1096,14 @@
 char*first,
 char*last,
 int ispref)
-#line 863 "cwebdir/common.w"
 {
 name_pointer p= name_ptr;
 char*s= first_chunk(p);
-#line 636 "cwebdir/comm-w2c.ch"
 int name_len= (int)(last-first)+ispref;
-#line 643 "cwebdir/comm-w2c.ch"
+#line 301 "cwebdir/comm-w2c.ch"
 if(s+name_len> byte_mem_end)overflow(_("byte memory"));
 if(name_ptr+1>=name_dir_end)overflow(_("name"));
-#line 869 "cwebdir/common.w"
+#line 824 "cwebdir/common.w"
 (++name_ptr)->byte_start= byte_ptr= s+name_len;
 if(ispref){
 *(byte_ptr-1)= ' ';
@@ -1097,10 +1119,9 @@
 return par==NULL?(root= p):c==less?(par->llink= p):(par->rlink= p);
 }
 
-/*:47*//*48:*/
-#line 884 "cwebdir/common.w"
+/*:57*//*58:*/
+#line 839 "cwebdir/common.w"
 
-#line 655 "cwebdir/comm-w2c.ch"
 static void
 extend_section_name(
 name_pointer p,
@@ -1107,36 +1128,32 @@
 char*first,
 char*last,
 int ispref)
-#line 891 "cwebdir/common.w"
 {
 char*s;
 name_pointer q= p+1;
-#line 666 "cwebdir/comm-w2c.ch"
 int name_len= (int)(last-first)+ispref;
-#line 672 "cwebdir/comm-w2c.ch"
+#line 308 "cwebdir/comm-w2c.ch"
 if(name_ptr>=name_dir_end)overflow(_("name"));
-#line 896 "cwebdir/common.w"
+#line 851 "cwebdir/common.w"
 while(q->link!=name_dir)q= q->link;
 q->link= name_ptr;
 s= name_ptr->byte_start;
 name_ptr->link= name_dir;
-#line 678 "cwebdir/comm-w2c.ch"
+#line 314 "cwebdir/comm-w2c.ch"
 if(s+name_len> byte_mem_end)overflow(_("byte memory"));
-#line 901 "cwebdir/common.w"
+#line 856 "cwebdir/common.w"
 (++name_ptr)->byte_start= byte_ptr= s+name_len;
 strncpy(s,first,name_len);
 if(ispref)*(byte_ptr-1)= ' ';
 }
 
-/*:48*//*49:*/
-#line 912 "cwebdir/common.w"
+/*:58*//*59:*/
+#line 867 "cwebdir/common.w"
 
-#line 687 "cwebdir/comm-w2c.ch"
 name_pointer
 section_lookup(
 char*first,char*last,
 int ispref)
-#line 917 "cwebdir/common.w"
 {
 int c= 0;
 name_pointer p= root;
@@ -1144,11 +1161,9 @@
 name_pointer r= NULL;
 name_pointer par= NULL;
 
-#line 696 "cwebdir/comm-w2c.ch"
 int name_len= (int)(last-first)+1;
-#line 925 "cwebdir/common.w"
-/*50:*/
-#line 936 "cwebdir/common.w"
+/*60:*/
+#line 891 "cwebdir/common.w"
 
 while(p){
 c= web_strcmp(first,name_len,first_chunk(p),prefix_length(p));
@@ -1158,14 +1173,14 @@
 p= (c==less?p->llink:p->rlink);
 }else{
 if(r!=NULL){
-#line 702 "cwebdir/comm-w2c.ch"
+#line 320 "cwebdir/comm-w2c.ch"
 fputs(_("\n! Ambiguous prefix: matches <"),stdout);
-#line 946 "cwebdir/common.w"
+#line 901 "cwebdir/common.w"
 
 print_prefix_name(p);
-#line 708 "cwebdir/comm-w2c.ch"
+#line 326 "cwebdir/comm-w2c.ch"
 fputs(_(">\n and <"),stdout);
-#line 949 "cwebdir/common.w"
+#line 904 "cwebdir/common.w"
 print_prefix_name(r);
 err_print(">");
 return name_dir;
@@ -1178,28 +1193,28 @@
 p= q,q= NULL;
 }
 
-/*:50*/
-#line 926 "cwebdir/common.w"
-;
-/*51:*/
-#line 961 "cwebdir/common.w"
+/*:60*/
+#line 881 "cwebdir/common.w"
 
+/*61:*/
+#line 916 "cwebdir/common.w"
+
 if(r==NULL)
 return add_section_name(par,c,first,last+1,ispref);
 
-/*:51*/
-#line 927 "cwebdir/common.w"
-;
-/*52:*/
-#line 969 "cwebdir/common.w"
+/*:61*/
+#line 882 "cwebdir/common.w"
 
+/*62:*/
+#line 924 "cwebdir/common.w"
+
 switch(section_name_cmp(&first,name_len,r)){
 
 case prefix:
 if(!ispref){
-#line 714 "cwebdir/comm-w2c.ch"
+#line 332 "cwebdir/comm-w2c.ch"
 fputs(_("\n! New name is a prefix of <"),stdout);
-#line 975 "cwebdir/common.w"
+#line 930 "cwebdir/common.w"
 
 print_section_name(r);
 err_print(">");
@@ -1211,41 +1226,39 @@
 extend_section_name(r,first,last+1,ispref);
 return r;
 case bad_extension:
-#line 720 "cwebdir/comm-w2c.ch"
+#line 338 "cwebdir/comm-w2c.ch"
 fputs(_("\n! New name extends <"),stdout);
-#line 987 "cwebdir/common.w"
+#line 942 "cwebdir/common.w"
 
 print_section_name(r);
 err_print(">");
 return r;
 default:
-#line 726 "cwebdir/comm-w2c.ch"
+#line 344 "cwebdir/comm-w2c.ch"
 fputs(_("\n! Section name incompatible with <"),stdout);
-#line 993 "cwebdir/common.w"
+#line 948 "cwebdir/common.w"
 
 print_prefix_name(r);
-#line 732 "cwebdir/comm-w2c.ch"
+#line 350 "cwebdir/comm-w2c.ch"
 fputs(_(">,\n which abbreviates <"),stdout);
-#line 996 "cwebdir/common.w"
+#line 951 "cwebdir/common.w"
 print_section_name(r);
 err_print(">");
 return r;
 }
 
-/*:52*/
-#line 928 "cwebdir/common.w"
-;
+/*:62*/
+#line 883 "cwebdir/common.w"
+
 }
 
-/*:49*//*54:*/
-#line 1020 "cwebdir/common.w"
+/*:59*//*64:*/
+#line 975 "cwebdir/common.w"
 
-#line 747 "cwebdir/comm-w2c.ch"
 static int section_name_cmp(
 char**pfirst,
 int len,
 name_pointer r)
-#line 1025 "cwebdir/common.w"
 {
 char*first= *pfirst;
 name_pointer q= r+1;
@@ -1259,9 +1272,7 @@
 switch(c= web_strcmp(first,len,s,ss-s)){
 case equal:if(q==name_dir)
 if(ispref){
-#line 756 "cwebdir/comm-w2c.ch"
 *pfirst= first+(ptrdiff_t)(ss-s);
-#line 1039 "cwebdir/common.w"
 return extension;
 }else return equal;
 else return(q->byte_start==(q+1)->byte_start)?equal:prefix;
@@ -1268,9 +1279,7 @@
 case extension:
 if(!ispref)return bad_extension;
 first+= ss-s;
-#line 762 "cwebdir/comm-w2c.ch"
 if(q!=name_dir){len-= (int)(ss-s);s= q->byte_start;r= q;continue;}
-#line 1046 "cwebdir/common.w"
 *pfirst= first;return extension;
 default:return c;
 }
@@ -1277,26 +1286,24 @@
 }
 }
 
-/*:54*//*58:*/
-#line 1095 "cwebdir/common.w"
+/*:64*//*66:*/
+#line 1027 "cwebdir/common.w"
 
-#line 788 "cwebdir/comm-w2c.ch"
 void
 err_print(
 const char*s)
-#line 1099 "cwebdir/common.w"
 {
 char*k,*l;
 printf(*s=='!'?"\n%s":"%s",s);
-if(web_file_open)/*59:*/
-#line 1115 "cwebdir/common.w"
+if(web_file_open)/*67:*/
+#line 1047 "cwebdir/common.w"
 
 {if(changing&&include_depth==change_depth)
-#line 798 "cwebdir/comm-w2c.ch"
+#line 358 "cwebdir/comm-w2c.ch"
 printf(_(". (l. %d of change file)\n"),change_line);
 else if(include_depth==0)printf(_(". (l. %d)\n"),cur_line);
 else printf(_(". (l. %d of include file %s)\n"),cur_line,cur_file_name);
-#line 1120 "cwebdir/common.w"
+#line 1052 "cwebdir/common.w"
 l= (loc>=limit?limit:loc);
 if(l> buffer){
 for(k= buffer;k<l;k++)
@@ -1310,27 +1317,25 @@
 putchar(' ');
 }
 
-/*:59*/
-#line 1102 "cwebdir/common.w"
-;
+/*:67*/
+#line 1034 "cwebdir/common.w"
+
 update_terminal;mark_error;
 }
 
-/*:58*//*61:*/
-#line 1150 "cwebdir/common.w"
+/*:66*//*68:*/
+#line 1079 "cwebdir/common.w"
 
-#line 837 "cwebdir/comm-w2c.ch"
 int wrap_up(void){
-if(show_progress||show_happiness||(history> spotless))new_line;
-#line 1153 "cwebdir/common.w"
+if(show_progress)new_line;
 if(show_stats)
 print_stats();
-#line 844 "cwebdir/comm-w2c.ch"
-/*62:*/
-#line 1160 "cwebdir/common.w"
+#line 388 "cwebdir/comm-w2c.ch"
+/*69:*/
+#line 1089 "cwebdir/common.w"
 
 switch(history){
-#line 868 "cwebdir/comm-w2c.ch"
+#line 412 "cwebdir/comm-w2c.ch"
 case spotless:
 if(show_happiness)puts(_("(No errors were found.)"));break;
 case harmless_message:
@@ -1339,14 +1344,14 @@
 puts(_("(Pardon me, but I think I spotted something wrong.)"));break;
 case fatal_message:
 puts(_("(That was a fatal error, my friend.)"));
-#line 1168 "cwebdir/common.w"
+#line 1097 "cwebdir/common.w"
 }
 
-/*:62*/
-#line 844 "cwebdir/comm-w2c.ch"
+/*:69*/
+#line 388 "cwebdir/comm-w2c.ch"
 
-/*87:*/
-#line 1271 "cwebdir/comm-w2c.ch"
+/*88:*/
+#line 662 "cwebdir/comm-w2c.ch"
 
 if(C_file)fclose(C_file);
 if(tex_file)fclose(tex_file);
@@ -1354,10 +1359,10 @@
 if(strlen(check_file_name))
 remove(check_file_name);
 
-/*:87*/
-#line 845 "cwebdir/comm-w2c.ch"
+/*:88*/
+#line 389 "cwebdir/comm-w2c.ch"
 
-#line 852 "cwebdir/comm-w2c.ch"
+#line 396 "cwebdir/comm-w2c.ch"
 switch(history){
 case harmless_message:return RETURN_WARN;
 case error_message:return RETURN_ERROR;
@@ -1364,43 +1369,37 @@
 case fatal_message:return RETURN_FAIL;
 default:return RETURN_OK;
 }
-#line 1158 "cwebdir/common.w"
+#line 1087 "cwebdir/common.w"
 }
 
-/*:61*//*64:*/
-#line 890 "cwebdir/comm-w2c.ch"
+/*:68*//*70:*/
+#line 1105 "cwebdir/common.w"
 void
 fatal(
 const char*s,const char*t)
-#line 1182 "cwebdir/common.w"
 {
-#line 898 "cwebdir/comm-w2c.ch"
 if(*s)err_print(s);
-#line 1184 "cwebdir/common.w"
 err_print(t);
 history= fatal_message;exit(wrap_up());
 }
 
-/*:64*//*65:*/
-#line 906 "cwebdir/comm-w2c.ch"
+/*:70*//*71:*/
+#line 1116 "cwebdir/common.w"
 void
 overflow(
 const char*t)
-#line 1193 "cwebdir/common.w"
 {
-#line 914 "cwebdir/comm-w2c.ch"
+#line 425 "cwebdir/comm-w2c.ch"
 printf(_("\n! Sorry, %s capacity exceeded"),t);fatal("","");
-#line 1195 "cwebdir/common.w"
+#line 1121 "cwebdir/common.w"
 }
 
 
-/*:65*//*70:*/
-#line 1254 "cwebdir/common.w"
+/*:71*//*76:*/
+#line 1173 "cwebdir/common.w"
 
-#line 978 "cwebdir/comm-w2c.ch"
 static void
 scan_args(void)
-#line 1257 "cwebdir/common.w"
 {
 char*dot_pos;
 char*name_pos;
@@ -1407,9 +1406,8 @@
 register char*s;
 boolean found_web= 0,found_change= 0,found_out= 0;
 
-#line 1264 "cwebdir/common.w"
 
-#line 990 "cwebdir/comm-w2c.ch"
+#line 462 "cwebdir/comm-w2c.ch"
 
 #if defined DEV_NULL
 strncpy(change_file_name,DEV_NULL,max_file_name_length-2);
@@ -1421,36 +1419,36 @@
 strcpy(change_file_name,"/dev/null");
 #endif
 
+#line 1184 "cwebdir/common.w"
 while(--argc> 0){
-#line 1266 "cwebdir/common.w"
-if((**(++argv)=='-'||**argv=='+')&&*(*argv+1))/*74:*/
-#line 1068 "cwebdir/comm-w2c.ch"
+if((**(++argv)=='-'||**argv=='+')&&*(*argv+1))/*80:*/
+#line 510 "cwebdir/comm-w2c.ch"
 
 {
 if(strcmp("-help",*argv)==0||strcmp("--help",*argv)==0)
 
-/*94:*/
-#line 1423 "cwebdir/comm-w2c.ch"
+/*95:*/
+#line 800 "cwebdir/comm-w2c.ch"
 
 cb_usagehelp(program==ctangle?CTANGLEHELP:
 program==cweave?CWEAVEHELP:CTWILLHELP,NULL);
 
 
-/*:94*/
-#line 1072 "cwebdir/comm-w2c.ch"
+/*:95*/
+#line 514 "cwebdir/comm-w2c.ch"
 
 if(strcmp("-version",*argv)==0||strcmp("--version",*argv)==0)
 
-/*96:*/
-#line 1466 "cwebdir/comm-w2c.ch"
+/*98:*/
+#line 847 "cwebdir/comm-w2c.ch"
 
 printversionandexit(cb_banner,
 program==ctwill?"Donald E. Knuth":"Silvio Levy and Donald E. Knuth",
-NULL,"Contemporary development on https://github.com/ascherer/cwebbin.\n");
+NULL,"Contemporary development on https://github.com/ascherer/cweb.\n");
 
 
-/*:96*/
-#line 1075 "cwebdir/comm-w2c.ch"
+/*:98*/
+#line 517 "cwebdir/comm-w2c.ch"
 
 if(strcmp("-verbose",*argv)==0||strcmp("--verbose",*argv)==0)
 
@@ -1466,17 +1464,16 @@
 show_banner= show_progress= show_happiness= 0;
 }else
 if(*dot_pos=='d'){
-if(sscanf(++dot_pos,"%u",&kpathsea_debug)!=1)/*75:*/
-#line 1352 "cwebdir/common.w"
+if(sscanf(++dot_pos,"%u",&kpathsea_debug)!=1)/*81:*/
+#line 555 "cwebdir/comm-w2c.ch"
 
-#line 1118 "cwebdir/comm-w2c.ch"
 cb_usage(program==ctangle?"ctangle":program==cweave?"cweave":"ctwill");
 
-#line 1363 "cwebdir/common.w"
+#line 1279 "cwebdir/common.w"
 
-#line 1125 "cwebdir/comm-w2c.ch"
-/*:75*/
-#line 1090 "cwebdir/comm-w2c.ch"
+#line 563 "cwebdir/comm-w2c.ch"
+/*:81*/
+#line 532 "cwebdir/comm-w2c.ch"
 
 while(isdigit(*dot_pos))dot_pos++;
 dot_pos--;
@@ -1485,17 +1482,17 @@
 use_language= ++dot_pos;
 break;
 }else
-#line 1103 "cwebdir/comm-w2c.ch"
+#line 1265 "cwebdir/common.w"
  flags[(eight_bits)*dot_pos]= flag_change;
-#line 1350 "cwebdir/common.w"
 }
 
-/*:74*/
-#line 1266 "cwebdir/common.w"
+#line 555 "cwebdir/comm-w2c.ch"
+/*:80*/
+#line 1185 "cwebdir/common.w"
 
 else{
 s= name_pos= *argv;dot_pos= NULL;
-#line 1011 "cwebdir/comm-w2c.ch"
+#line 482 "cwebdir/comm-w2c.ch"
 while(*s){
 if(*s=='.')dot_pos= s++;
 else if(*s==DIR_SEPARATOR||*s==DEVICE_SEPARATOR||*s=='/')
@@ -1503,21 +1500,21 @@
 else s++;
 }
 
-#line 1274 "cwebdir/common.w"
-if(!found_web)/*71:*/
-#line 1292 "cwebdir/common.w"
+#line 1193 "cwebdir/common.w"
+if(!found_web)/*77:*/
+#line 1210 "cwebdir/common.w"
 
 {
 if(s-*argv> max_file_name_length-5)
-/*76:*/
-#line 1125 "cwebdir/comm-w2c.ch"
+/*82:*/
+#line 563 "cwebdir/comm-w2c.ch"
 fatal(_("! Filename too long\n"),*argv);
-#line 1365 "cwebdir/common.w"
+#line 1281 "cwebdir/common.w"
 
 
-/*:76*/
-#line 1295 "cwebdir/common.w"
-;
+/*:82*/
+#line 1213 "cwebdir/common.w"
+
 if(dot_pos==NULL)
 sprintf(web_file_name,"%s.w",*argv);
 else{
@@ -1524,7 +1521,7 @@
 strcpy(web_file_name,*argv);
 *dot_pos= 0;
 }
-#line 1303 "cwebdir/common.w"
+#line 1221 "cwebdir/common.w"
 sprintf(tex_file_name,"%s.tex",name_pos);
 sprintf(idx_file_name,"%s.idx",name_pos);
 sprintf(scn_file_name,"%s.scn",name_pos);
@@ -1532,52 +1529,48 @@
 found_web= 1;
 }
 
-/*:71*/
-#line 1275 "cwebdir/common.w"
+/*:77*/
+#line 1194 "cwebdir/common.w"
 
-else if(!found_change)/*72:*/
-#line 1310 "cwebdir/common.w"
+else if(!found_change)/*78:*/
+#line 1228 "cwebdir/common.w"
 
 {
-#line 1043 "cwebdir/comm-w2c.ch"
 if(strcmp(*argv,"-")!=0){
-#line 1314 "cwebdir/common.w"
 if(s-*argv> max_file_name_length-4)
-/*76:*/
-#line 1125 "cwebdir/comm-w2c.ch"
+/*82:*/
+#line 563 "cwebdir/comm-w2c.ch"
 fatal(_("! Filename too long\n"),*argv);
-#line 1365 "cwebdir/common.w"
+#line 1281 "cwebdir/common.w"
 
 
-/*:76*/
-#line 1315 "cwebdir/common.w"
-;
+/*:82*/
+#line 1232 "cwebdir/common.w"
+
 if(dot_pos==NULL)
 sprintf(change_file_name,"%s.ch",*argv);
 else strcpy(change_file_name,*argv);
-#line 1050 "cwebdir/comm-w2c.ch"
 }
 found_change= 1;
-#line 1321 "cwebdir/common.w"
 }
 
-/*:72*/
-#line 1276 "cwebdir/common.w"
+/*:78*/
+#line 1195 "cwebdir/common.w"
 
-else if(!found_out)/*73:*/
-#line 1323 "cwebdir/common.w"
+else if(!found_out)/*79:*/
+#line 1240 "cwebdir/common.w"
 
 {
 if(s-*argv> max_file_name_length-5)
-/*76:*/
-#line 1125 "cwebdir/comm-w2c.ch"
+/*82:*/
+#line 563 "cwebdir/comm-w2c.ch"
 fatal(_("! Filename too long\n"),*argv);
-#line 1365 "cwebdir/common.w"
+#line 1281 "cwebdir/common.w"
 
 
-/*:76*/
-#line 1326 "cwebdir/common.w"
-;
+/*:82*/
+#line 1243 "cwebdir/common.w"
+
 if(dot_pos==NULL){
 sprintf(tex_file_name,"%s.tex",*argv);
 sprintf(idx_file_name,"%s.idx",*argv);
@@ -1586,9 +1579,7 @@
 }else{
 strcpy(tex_file_name,*argv);
 strcpy(C_file_name,*argv);
-#line 1057 "cwebdir/comm-w2c.ch"
 if(make_xrefs){
-#line 1336 "cwebdir/common.w"
 *dot_pos= 0;
 sprintf(idx_file_name,"%s.idx",*argv);
 sprintf(scn_file_name,"%s.scn",*argv);
@@ -1597,42 +1588,38 @@
 found_out= 1;
 }
 
-#line 1067 "cwebdir/comm-w2c.ch"
-/*:73*/
-#line 1277 "cwebdir/common.w"
+/*:79*/
+#line 1196 "cwebdir/common.w"
 
-else/*75:*/
-#line 1352 "cwebdir/common.w"
+else/*81:*/
+#line 555 "cwebdir/comm-w2c.ch"
 
-#line 1118 "cwebdir/comm-w2c.ch"
- cb_usage(program==ctangle?"ctangle":program==cweave?"cweave":"ctwill");
+cb_usage(program==ctangle?"ctangle":program==cweave?"cweave":"ctwill");
 
-#line 1363 "cwebdir/common.w"
+#line 1279 "cwebdir/common.w"
 
-#line 1125 "cwebdir/comm-w2c.ch"
-/*:75*/
-#line 1278 "cwebdir/common.w"
-;
+#line 563 "cwebdir/comm-w2c.ch"
+/*:81*/
+#line 1197 "cwebdir/common.w"
+
 }
 }
-if(!found_web)/*75:*/
-#line 1352 "cwebdir/common.w"
+if(!found_web)/*81:*/
+#line 555 "cwebdir/comm-w2c.ch"
 
-#line 1118 "cwebdir/comm-w2c.ch"
 cb_usage(program==ctangle?"ctangle":program==cweave?"cweave":"ctwill");
 
-#line 1363 "cwebdir/common.w"
+#line 1279 "cwebdir/common.w"
 
-#line 1125 "cwebdir/comm-w2c.ch"
-/*:75*/
-#line 1281 "cwebdir/common.w"
-;
-#line 1283 "cwebdir/common.w"
+#line 563 "cwebdir/comm-w2c.ch"
+/*:81*/
+#line 1200 "cwebdir/common.w"
+
 }
 
-#line 1030 "cwebdir/comm-w2c.ch"
-/*:70*//*95:*/
-#line 1432 "cwebdir/comm-w2c.ch"
+#line 496 "cwebdir/comm-w2c.ch"
+/*:76*//*97:*/
+#line 813 "cwebdir/comm-w2c.ch"
 
 static void cb_usage(const_string str)
 {
@@ -1664,8 +1651,8 @@
 history= spotless;exit(wrap_up());
 }
 
-/*:95*//*97:*/
-#line 1474 "cwebdir/comm-w2c.ch"
+/*:97*//*99:*/
+#line 855 "cwebdir/comm-w2c.ch"
 
 void cb_show_banner(void)
 {
@@ -1677,4 +1664,4 @@
 
 }
 
-/*:97*/
+/*:99*/

Modified: branches/stable/source/src/texk/web2c/cwebdir/ChangeLog
===================================================================
--- branches/stable/source/src/texk/web2c/cwebdir/ChangeLog	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/texk/web2c/cwebdir/ChangeLog	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,3 +1,54 @@
+2021-02-11  Andreas Scherer  <https://ascherer.github.io>
+
+	* texinputs/pdfctwimac.tex: Fix bug in color setter.
+
+2021-02-08  Andreas Scherer  <https://ascherer.github.io>
+
+	* comm-w2c.ch,
+	* common.c,
+	* common.h,
+	* common.w,
+	* ctangle.c,
+	* ctangle.w,
+	* cweave.w: Don't repeat yourself.
+
+2021-02-07  Andreas Scherer  <https://ascherer.github.io>
+
+	* comm-w2c.ch: Fix 'reading error';
+	CWEB development has moved to another level.
+
+2021-02-07  Andreas Scherer  <https://ascherer.github.io>
+
+	* Makefile,
+	* README,
+	* comm-{amiga,bs,mac,os2,pc,ql,vms,w32}.ch,
+	* comm-w2c.ch,
+	* comm-w2c.h,
+	* common.c,
+	* common.h,
+	* common.w,
+	* ctang-{bs,pc,ql,vms,w32}.ch,
+	* ctang-man.ch,
+	* ctang-w2c.ch,
+	* ctangle.c,
+	* ctangle.w,
+	* ctwill-mini.ch,
+	* ctwill-w2c.ch,
+	* ctwill.bux,
+	* cweav-{bs,pc,ql,vms,w32}.ch,
+	* cweav-man.ch,
+	* cweav-w2c.ch,
+	* cweave.w,
+	* cweb.1,
+	* cwebmac.tex,
+	* cwebman-w2c.ch,
+	* cwebman.tex,
+	* examples/wmerge.w,
+	* po/{cweb,cweb-tl,web2c-help}.pot,
+	* po/de/{cweb,cweb-tl,web2c-help}.po,
+	* po/it/cweb.po,
+	* system.bux: New CWEB 4.0 and CWEBbin 2021.
+
 2020-07-30  Andreas Scherer  <https://ascherer.github.io>
 
 	* comm-w2c.ch,

Modified: branches/stable/source/src/texk/web2c/cwebdir/Makefile
===================================================================
--- branches/stable/source/src/texk/web2c/cwebdir/Makefile	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/texk/web2c/cwebdir/Makefile	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,6 +1,6 @@
 # This file is part of CWEB.
 # It is distributed WITHOUT ANY WARRANTY, express or implied.
-# Version 3.64 --- February 2002
+# Version 4.0 --- February 2021
 
 # Copyright (C) 1987,1990,1993,2000 Silvio Levy and Donald E. Knuth
 

Modified: branches/stable/source/src/texk/web2c/cwebdir/README
===================================================================
--- branches/stable/source/src/texk/web2c/cwebdir/README	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/texk/web2c/cwebdir/README	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,7 +1,7 @@
 % This file is part of CWEB.
 % The CWEB programs by Silvio Levy are based on programs by D. E. Knuth.
 % They are distributed WITHOUT ANY WARRANTY, express or implied.
-% This README file last updated January 2016 by Don Knuth
+% This README file last updated February 2021 by Andreas Scherer
 
 % Copyright (C) 1987,1990,1993,2000,2016 Silvio Levy and Donald E. Knuth
 
@@ -18,9 +18,13 @@
 % there will verify and forward bug reports.
 %
 % DEK takes no responsibility for the changefiles; they should be
-% maintained independently. His job is to correct errors in
-% ctangle.w, cweave.w, prod.w, common.w, cwebmac.tex, cwebman.tex,
-% and in the files of examples/*.w, nothing more.
+% maintained independently. He even transferred the job to correct errors
+% in ctangle.w, cweave.w, prod.w, common.w, cwebmac.tex, cwebman.tex,
+% and in the files of examples/*.w to Andreas Scherer in 2021.
+% Further significant developments, including versions that neither
+% Don Knuth nor Silvio Levy themselves do maintain, are ongoing.
+% All of the really current news about CWEB is, in fact, now to be found
+% on the CWEB development page https://github.com/ascherer/cweb.
 
 This directory contains the following files:
 
@@ -30,6 +34,7 @@
 comm-bs.ch
 comm-mac.ch
 comm-man.ch
+comm-os2.ch
 comm-pc.ch
 comm-ql.ch
 comm-vms.ch
@@ -68,7 +73,7 @@
 The file cweb.1 is a manual page.
 The file cweb.el is suggested for GNU-Emacs users.
 The file c++lib.w is for C++ users (say `@i c++lib.w' at beginning of program).
-The files *-man.ch are used if you want to make the full 239-page CWEB manual.
+The files *-man.ch are used if you want to make the full 240-page CWEB manual.
 The files *-bs.ch are used instead of *-pc.ch if you are doing BIG programs.
 You can use makefile.bs to make CWEB with *-bs.ch.
 The files *-ql.ch are for QDOS/SMSQ systems; see readme.ql for further info.
@@ -102,9 +107,3 @@
 are first bootstrapping to a new system, you may need to edit common.c and
 ctangle.c by hand, but the vast majority of the change-file changes are
 minor refinements that are not necessary for a rudimentary ctangle.
-
------------------------------------------
-These archival sources are maintained only to the extent of fixing
-significant bugs that were unintended at the time of writing.
-A multi-decade ongoing project to improve and extend CWEB can be found at
-  https://github.com/ascherer/cwebbin

Modified: branches/stable/source/src/texk/web2c/cwebdir/comm-amiga.ch
===================================================================
--- branches/stable/source/src/texk/web2c/cwebdir/comm-amiga.ch	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/texk/web2c/cwebdir/comm-amiga.ch	2021-02-15 19:17:20 UTC (rev 845)
@@ -4,14 +4,14 @@
 With Lattice C 5.1, use compilation switches -b0 -r0, and ignore the
 compiler warnings. With SAS 6.0, use compilation switches Code=far Data=far.
 
- at x section 69
+ at x section 75
 An omitted change file argument means that |"/dev/null"| should be used,
 @y
 An omitted change file argument means that |"nil:"| should be used,
 @z
 
- at x section 70
-  if (found_change<=0) strcpy(change_file_name,"/dev/null");
+ at x section 76
+  strcpy(change_file_name,"/dev/null");
 @y
-  if (found_change<=0) strcpy(change_file_name,"nil:");
+  strcpy(change_file_name,"nil:");
 @z

Modified: branches/stable/source/src/texk/web2c/cwebdir/comm-bs.ch
===================================================================
--- branches/stable/source/src/texk/web2c/cwebdir/comm-bs.ch	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/texk/web2c/cwebdir/comm-bs.ch	2021-02-15 19:17:20 UTC (rev 845)
@@ -12,48 +12,61 @@
 (This file contributed by Barry Schwartz, trashman at crud.mn.org, 28 Jun 94;
  revised 24 Jul 94.)
 
+(Update attempt by Andreas Scherer, 31 Jan 2021.  Good luck!)
 
- at x Section 23.
-    cur_file_name[l]='/'; /* \UNIX/ pathname separator */
- at y
-    cur_file_name[l]='/'; /* A valid {\mc MSDOS} pathname separator */
- at z
 
+ at x Section 6.
+ at d chunk_marker 0
 
- at x Section 27.
- at d max_names 4000 /* number of identifiers, strings, section names;
-  must be less than 10240 */
-
-@<Definitions that...@>=
+@<Common code...@>=
 typedef struct name_info {
   char *byte_start; /* beginning of the name in |byte_mem| */
-  @<More elements of |name_info| structure@>@;
+  struct name_info *link;
+  union {
+    struct name_info *Rlink; /* right link in binary search tree for section
+      names */
+    char Ilk; /* used by identifiers in \.{CWEAVE} only */
+  } dummy;
+  void *equiv_or_xref; /* info corresponding to names */
 } name_info; /* contains information about an identifier or section name */
-typedef name_info *name_pointer; /* pointer into array of |name_info|s */
-char byte_mem[max_bytes]; /* characters of names */
-char *byte_mem_end = byte_mem+max_bytes-1; /* end of |byte_mem| */
-name_info name_dir[max_names]; /* information about names */
-name_pointer name_dir_end = name_dir+max_names-1; /* end of |name_dir| */
+typedef name_info *name_pointer; /* pointer into array of \&{name\_info}s */
+typedef name_pointer *hash_pointer;
+extern char byte_mem[]; /* characters of names */
+extern char *byte_mem_end; /* end of |byte_mem| */
 @y
- at d max_names 4000 /* number of identifiers, strings, section names;
-  must be less than 10240 */
+ at d chunk_marker 0
 
 @f huge extern
 
-@<Definitions that...@>=
+@<Common code...@>=
 typedef struct name_info {
   char huge* byte_start; /* beginning of the name in |byte_mem| */
-  @<More elements of |name_info| structure@>@;
+  struct name_info *link;
+  union {
+    struct name_info *Rlink; /* right link in binary search tree for section
+      names */
+    char Ilk; /* used by identifiers in \.{CWEAVE} only */
+  } dummy;
+  union {
+    void huge* equiv_member;
+    void huge* xref_member;
+  } ptr_union;  /* info corresponding to names */
 } name_info; /* contains information about an identifier or section name */
-typedef name_info *name_pointer; /* pointer into array of |name_info|s */
-char huge byte_mem[max_bytes]; /* characters of names */
-char huge* byte_mem_end; /* end of |byte_mem| */
-name_info name_dir[max_names]; /* information about names */
-name_pointer name_dir_end = name_dir+max_names-1;
+typedef name_info *name_pointer; /* pointer into array of \&{name\_info}s */
+typedef name_pointer *hash_pointer;
+extern char huge byte_mem[]; /* characters of names */
+extern char huge* byte_mem_end; /* end of |byte_mem| */
 @z
 
 
- at x Section 29.
+ at x Section 39.
+    cur_file_name[l]='/'; /* \UNIX/ pathname separator */
+ at y
+    cur_file_name[l]='/'; /* A valid {\mc MSDOS} pathname separator */
+ at z
+
+
+ at x Section 44.
 char *byte_ptr; /* first unused position in |byte_mem| */
 @y
 char huge* byte_ptr; /* first unused position in |byte_mem| */
@@ -60,7 +73,7 @@
 @z
 
 
- at x Section 30.
+ at x Section 45.
 @ @<Init...@>=
 name_dir->byte_start=byte_ptr=byte_mem; /* position zero in both arrays */
 name_ptr=name_dir+1; /* |name_dir[0]| will be used only for error recovery */
@@ -74,72 +87,72 @@
 @z
 
 
- at x Section 42.
+ at x Section 52.
 void
-print_section_name(p)
-name_pointer p;
+print_section_name(
+name_pointer p)
 {
   char *ss, *s = first_chunk(p);
 @y
 void
-print_section_name(p)
-name_pointer p;
+print_section_name(
+name_pointer p)
 {
   char huge* ss, huge* s = first_chunk(p);
 @z
 
 
- at x Section 43.
+ at x Section 53.
 void
-sprint_section_name(dest,p)
-  char*dest;
-  name_pointer p;
+sprint_section_name(
+  char *dest,
+  name_pointer p)
 {
   char *ss, *s = first_chunk(p);
 @y
 void
-sprint_section_name(dest,p)
-  char*dest;
-  name_pointer p;
+sprint_section_name(
+  char huge* dest,
+  name_pointer p)
 {
   char huge* ss, huge* s = first_chunk(p);
 @z
 
 
- at x Section 44.
+ at x Section 54.
 void
-print_prefix_name(p)
-name_pointer p;
+print_prefix_name(
+name_pointer p)
 {
   char *s = first_chunk(p);
 @y
 void
-print_prefix_name(p)
-name_pointer p;
+print_prefix_name(
+name_pointer p)
 {
   char huge* s = first_chunk(p);
 @z
 
 
- at x Section 47.
-name_pointer
-add_section_name(par,c,first,last,ispref) /* install a new node in the tree */
-name_pointer par; /* parent of new node */
-int c; /* right or left? */
-char *first; /* first character of section name */
-char *last; /* last character of section name, plus one */
-int ispref; /* are we adding a prefix or a full name? */
+ at x Section 57.
+static name_pointer
+add_section_name(@t\1\1@> /* install a new node in the tree */
+name_pointer par, /* parent of new node */
+int c, /* right or left? */
+char *first, /* first character of section name */
+char *last, /* last character of section name, plus one */
+int ispref at t\2\2@>) /* are we adding a prefix or a full name? */
 {
   name_pointer p=name_ptr; /* new node */
   char *s=first_chunk(p);
 @y
-name_pointer
-add_section_name(par,c,first,last,ispref) /* install a new node in the tree */
-name_pointer par; /* parent of new node */
-int c; /* right or left? */
-char *first; /* first character of section name */
-char *last; /* last character of section name, plus one */
-int ispref; /* are we adding a prefix or a full name? */
+static name_pointer
+add_section_name(@t\1\1@> /* install a new node in the tree */
+name_pointer par, /* parent of new node */
+int c, /* right or left? */
+char huge* first, /* first character of section name */
+char huge* last, /* last character of section name, plus one */
+int ispref at t\2\2@>) /* are we adding a prefix or a full name? */
 {
   name_pointer p=name_ptr; /* new node */
   char huge* s=first_chunk(p);
@@ -146,84 +159,65 @@
 @z
 
 
- at x Section 48.
-void
-extend_section_name(p,first,last,ispref)
-name_pointer p; /* name to be extended */
-char *first; /* beginning of extension text */
-char *last; /* one beyond end of extension text */
-int ispref; /* are we adding a prefix or a full name? */
+ at x Section 58.
+static void
+extend_section_name(@t\1\1@>
+name_pointer p, /* name to be extended */
+char *first, /* beginning of extension text */
+char *last, /* one beyond end of extension text */
+int ispref at t\2\2@>) /* are we adding a prefix or a full name? */
 {
   char *s;
 @y
-void
-extend_section_name(p,first,last,ispref)
-name_pointer p; /* name to be extended */
-char *first; /* beginning of extension text */
-char *last; /* one beyond end of extension text */
-int ispref; /* are we adding a prefix or a full name? */
+static void
+extend_section_name(@t\1\1@>
+name_pointer p, /* name to be extended */
+char huge* first, /* beginning of extension text */
+char huge* last, /* one beyond end of extension text */
+int ispref at t\2\2@>) /* are we adding a prefix or a full name? */
 {
   char huge* s;
 @z
 
 
- at x Section 54.
-int section_name_cmp(pfirst,len,r)
-char **pfirst; /* pointer to beginning of comparison string */
-int len; /* length of string */
-name_pointer r; /* section name being compared */
+ at x Section 64.
+static int section_name_cmp(@t\1\1@>
+char **pfirst, /* pointer to beginning of comparison string */
+int len, /* length of string */
+name_pointer r at t\2\2@>) /* section name being compared */
 {
   char *first=*pfirst; /* beginning of comparison string */
   name_pointer q=r+1; /* access to subsequent chunks */
   char *ss, *s=first_chunk(r);
 @y
-int section_name_cmp(pfirst,len,r)
-char **pfirst; /* pointer to beginning of comparison string */
-int len; /* length of string */
-name_pointer r; /* section name being compared */
+static int section_name_cmp(@t\1\1@>
+char huge** pfirst, /* pointer to beginning of comparison string */
+int len, /* length of string */
+name_pointer r at t\2\2@>) /* section name being compared */
 {
-  char *first=*pfirst; /* beginning of comparison string */
+  char huge* first=*pfirst; /* beginning of comparison string */
   name_pointer q=r+1; /* access to subsequent chunks */
   char huge* ss, huge* s=first_chunk(r);
 @z
 
 
- at x Section 55.
-source files, respectively; here we just declare a common field
-|equiv_or_xref| as a pointer to a |char|.
-
-@<More elements of |name...@>=
-char *equiv_or_xref; /* info corresponding to names */
+ at x Section 75.
+An omitted change file argument means that |"/dev/null"| should be used,
 @y
-source files, respectively.  Here we just declare a common field
-|ptr_union| as a union of pointers to |char|, which happen to have
-different addressing attributes.
-
-@<More elements of |name...@>=
-union {
-  char *equiv_member;
-  char huge* xref_member;
-} ptr_union;  /* info corresponding to names */
+An omitted change file argument means that |"NUL"| should be used,
 @z
 
 
- at x Section 69.
-An omitted change file argument means that |"/dev/null"| should be used,
+ at x Section 76.
+  strcpy(change_file_name,"/dev/null");
 @y
-An omitted change file argument means that |"NUL"| should be used,
+  strcpy(change_file_name,"NUL");
 @z
 
 
- at x Section 70.
+ at x Section 76.
         else if (*s=='/') dot_pos=NULL,name_pos=++s;
 @y
         else if (*s == ':' || *s == '\\' || *s == '/')
 	  dot_pos=NULL,name_pos=++s;
 @z
-
-
- at x Section 70.
-  if (found_change<=0) strcpy(change_file_name,"/dev/null");
- at y
-  if (found_change<=0) strcpy(change_file_name,"NUL");
- at z

Modified: branches/stable/source/src/texk/web2c/cwebdir/comm-mac.ch
===================================================================
--- branches/stable/source/src/texk/web2c/cwebdir/comm-mac.ch	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/texk/web2c/cwebdir/comm-mac.ch	2021-02-15 19:17:20 UTC (rev 845)
@@ -4,19 +4,22 @@
 (Contributed 13 Oct 2000 by AndPio at aol.com; slightly edited by Don Knuth)
 
 @x in limbo, change the title page document to specify Mac version
-  \centerline{(Version 3.64)}
+  \centerline{(Version 4.0)}
 @y
-  \centerline{(Version 3.64 for MacOS)}
+  \centerline{(Version 4.0 for MacOS)}
 @z
 
- at x section 9: Make input_ln accept \n, \r, \n\r, or \r\n as line endings
+ at x sections 23/24: Make input_ln accept \n, \r, \n\r, or \r\n as line endings
 @ In the unlikely event that your standard I/O library does not
 support |feof|, |getc|, and |ungetc| you may have to change things here.
 @^system dependencies@>
 
- at c
-int input_ln(fp) /* copies a line into |buffer| or returns 0 */
-FILE *fp; /* what file to read from */
+@<Predecl...@>=
+static boolean input_ln(FILE *);@/
+
+@ @c
+static boolean input_ln(@t\1\1@> /* copies a line into |buffer| or returns 0 */
+FILE *fp at t\2\2@>) /* what file to read from */
 {
   register int  c=EOF; /* character read; initialized so some compilers won't complain */
   register char *k;  /* where next character goes */
@@ -28,7 +31,7 @@
     if ((c=getc(fp))!=EOF && c!='\n') {
       ungetc(c,fp); loc=buffer; err_print("! Input line too long");
 @.Input line too long@>
-  }
+    }
   if (c==EOF && limit==buffer) return(0);  /* there was nothing after
     the last newline */
   return(1);
@@ -43,8 +46,8 @@
 @^system dependencies@>
 
 @c
-int input_ln(fp) /* copies a line into |buffer| or returns 0 */
-FILE *fp; /* what file to read from */
+static boolean input_ln(@t\1\1@> /* copies a line into |buffer| or returns 0 */
+FILE *fp at t\2\2@>) /* what file to read from */
 {
   register int  c=EOF; /* character read; initialized so some compilers won't complain */
   register char *k;  /* where next character goes */
@@ -71,17 +74,17 @@
 }
 @z
 
- at x section 12, simply return if no change file was specified
+ at x section 28, simply return if no change file was specified
   change_limit=change_buffer; /* this value is used if the change file ends */
-  @<Skip over comment lines in the change file; |return| if end of file@>;
+  @<Skip over comment lines in the change file; |return| if end of file@>@;
 @y
   change_limit=change_buffer; /* this value is used if the change file ends */
   if (change_file_name[0] == '\0') /* no change file specified */
     return; /* so we have reached the end of that file */
-  @<Skip over comment lines in the change file; |return| if end of file@>;
+  @<Skip over comment lines in the change file; |return| if end of file@>@;
 @z
 
- at x section 19, don't try to open a change file if none was specified
+ at x section 36, don't try to open a change file if none was specified
 if ((change_file=fopen(change_file_name,"r"))==NULL)
        fatal("! Cannot open change file ", change_file_name);
 @y
@@ -91,7 +94,7 @@
        fatal("! Cannot open change file ", change_file_name);
 @z
 
- at x section 22, declare colon as Mac's path separator
+ at x section 39, declare colon as Mac's path separator
 (Colon-separated paths are not supported.)
 The remainder of the \.{@@i} line after the file name is ignored.
 
@@ -104,20 +107,24 @@
 @d PATH_SEP ':'   /* MacOS pathname separator */
 @^system dependencies@>
 @z
-
- at x section 23, use the path separator constant
+ at x section 39, use the path separator constant
     cur_file_name[l]='/'; /* \UNIX/ pathname separator */
 @y
     cur_file_name[l]=PATH_SEP; /* pathname separator */
 @z
 
- at x section 69, explain the convention for omitted change files
+ at x section 75, explain the convention for omitted change files
 An omitted change file argument means that |"/dev/null"| should be used,
 @y
 An omitted change file argument means that no change file should be used,
 @z
 
- at x section 70, use the Metrowerks |ccommand| to access command lines
+ at x section 76, make change file name empty when it is unspecified
+  strcpy(change_file_name,"/dev/null");
+ at y
+  change_file_name[0]='\0';   /* empty string */
+ at z
+ at x section 76, use the Metrowerks |ccommand| to access command lines
   while (--argc > 0) {
 @y
   argc = ccommand (&argv); /* use Mac interface to command line */
@@ -124,18 +131,13 @@
 @^system dependencies@>
   while (--argc > 0) {
 @z
- at x section 70, use the path separator constant
+ at x section 76, use the path separator constant
         else if (*s=='/') dot_pos=NULL,name_pos=++s;
 @y
         else if (*s==PATH_SEP) dot_pos=NULL,name_pos=++s;
 @z
- at x section 70, make change file name empty when it is unspecified
-  if (found_change<=0) strcpy(change_file_name,"/dev/null");
- at y
-  if (found_change<=0) change_file_name[0]='\0';   /* empty string */
- at z
 
- at x section 82, insert an extra module before the index
+ at x section 85, insert an extra module before the index
 @** Index.
 @y by putting the new module here, we preserve all the previous section numbers
 @ We assume an interface to \CEE/ command-line emulation as supplied by

Modified: branches/stable/source/src/texk/web2c/cwebdir/comm-os2.ch
===================================================================
--- branches/stable/source/src/texk/web2c/cwebdir/comm-os2.ch	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/texk/web2c/cwebdir/comm-os2.ch	2021-02-15 19:17:20 UTC (rev 845)
@@ -4,21 +4,21 @@
 These changes tested with WATCOM C v10.0a.
 No changes to CTANGLE or CWEAVE are needed with OS/2.
 
- at x section 69
+ at x section 75
 An omitted change file argument means that |"/dev/null"| should be used,
 @y
 An omitted change file argument means that |"NUL"| should be used,
 @z
 
- at x section 70 (this change copied from comm-pc.ch)
+ at x section 76
+  strcpy(change_file_name,"/dev/null");
+ at y
+  strcpy(change_file_name,"NUL");
+ at z
+
+ at x section 76 (this change copied from comm-pc.ch)
         else if (*s=='/') dot_pos=NULL,name_pos=++s;
 @y
         else if (*s == ':' || *s == '\\' || *s == '/')
 	  dot_pos=NULL,name_pos=++s;
 @z
-
- at x section 70
-  if (found_change<=0) strcpy(change_file_name,"/dev/null");
- at y
-  if (found_change<=0) strcpy(change_file_name,"NUL");
- at z

Modified: branches/stable/source/src/texk/web2c/cwebdir/comm-pc.ch
===================================================================
--- branches/stable/source/src/texk/web2c/cwebdir/comm-pc.ch	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/texk/web2c/cwebdir/comm-pc.ch	2021-02-15 19:17:20 UTC (rev 845)
@@ -4,30 +4,30 @@
 Changes necessary for compiling with Borland C/C++
 Use compilation switches -mc -w-pro -Ff=5000
 
-Note: The change to section 27 is not necessary if using a compiler
+Note: The change to section 16 is not necessary if using a compiler
 that allows >64K arrays.
 
- at x section 27
- at d max_bytes 90000 /* the number of bytes in identifiers,
+ at x section 16
+ at d max_bytes 1000000 /* the number of bytes in identifiers,
 @y
 @d max_bytes (unsigned)60000 /* the number of bytes in identifiers,
 @z
 
- at x section 69
+ at x section 75
 An omitted change file argument means that |"/dev/null"| should be used,
 @y
 An omitted change file argument means that |"NUL"| should be used,
 @z
 
- at x section 70 (this change copied from comm-bs.ch, July 94)
+ at x section 76
+  strcpy(change_file_name,"/dev/null");
+ at y
+  strcpy(change_file_name,"NUL");
+ at z
+
+ at x section 76 (this change copied from comm-bs.ch, July 94)
         else if (*s=='/') dot_pos=NULL,name_pos=++s;
 @y
         else if (*s == ':' || *s == '\\' || *s == '/')
 	  dot_pos=NULL,name_pos=++s;
 @z
-
- at x section 70
-  if (found_change<=0) strcpy(change_file_name,"/dev/null");
- at y
-  if (found_change<=0) strcpy(change_file_name,"NUL");
- at z

Modified: branches/stable/source/src/texk/web2c/cwebdir/comm-ql.ch
===================================================================
--- branches/stable/source/src/texk/web2c/cwebdir/comm-ql.ch	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/texk/web2c/cwebdir/comm-ql.ch	2021-02-15 19:17:20 UTC (rev 845)
@@ -10,12 +10,12 @@
 @x
 \def\v{\char'174} % vertical (|) in typewriter font
 
-\def\title{Common code for CTANGLE and CWEAVE (Version 3.64)}
+\def\title{Common code for CTANGLE and CWEAVE (Version 4.0)}
 \def\topofcontents{\null\vfill
   \centerline{\titlefont Common code for {\ttitlefont CTANGLE} and
     {\ttitlefont CWEAVE}}
   \vskip 15pt
-  \centerline{(Version 3.64)}
+  \centerline{(Version 4.0)}
   \vfill}
 \def\botofcontents{\vfill
 \noindent
@@ -22,49 +22,27 @@
 @y
 \def\v{\char'174} % vertical (|) in typewriter font
 
-\def\title{Common code for CTANGLE and CWEAVE (QL Version 3.64)}
+\def\title{Common code for CTANGLE and CWEAVE (QL Version 4.0)}
 \def\topofcontents{\null\vfill
   \centerline{\titlefont Common code for {\ttitlefont CTANGLE} and
     {\ttitlefont CWEAVE}}
   \vskip 15pt
-  \centerline{(Version 3.64)}
+  \centerline{(Version 4.0)}
   \vfill}
 \def\botofcontents{\vfill
 \noindent
 @z
 
- at x
-The line number of each open file is also kept for error reporting and
-for the benefit of \.{CTANGLE}.
 
- at f line x /* make |line| an unreserved word */
- at d max_include_depth 10 /* maximum number of source files open
-  simultaneously, not counting the change file */
- at d max_file_name_length 60
- at d cur_file file[include_depth] /* current file */
- at d cur_file_name file_name[include_depth] /* current file name */
- at d cur_line line[include_depth] /* number of current line in current file */
- at d web_file file[0] /* main source file */
- at d web_file_name file_name[0] /* main source file name */
- at y
-The line number of each open file is also kept for error reporting and
-for the benefit of \.{CTANGLE}.
-
 For use on QDOS/SMSQ systems the variable |max_file_name_length| is shortened
 to 42 characters, i.e. 5 characters for the device name, 36 characters
 for the file name plus one character as string terminator. (Note that
 (current) QDOS/SMSQ file systems have a limitation of 36 characters as
 maximum length for a file name.
-
- at f line x /* make |line| an unreserved word */
- at d max_include_depth 10 /* maximum number of source files open
-  simultaneously, not counting the change file */
+ at x
+ at d max_file_name_length 1024
+ at y
 @d max_file_name_length 42
- at d cur_file file[include_depth] /* current file */
- at d cur_file_name file_name[include_depth] /* current file name */
- at d cur_line line[include_depth] /* number of current line in current file */
- at d web_file file[0] /* main source file */
- at d web_file_name file_name[0] /* main source file name */
 @z
 
 
@@ -90,99 +68,6 @@
 @^system dependencies@>
 
 If there's a third file name, it will be the output file.
-
-@<Pred...@>=
-void scan_args();
-
-@ @c
-void
-scan_args()
-{
-  char *dot_pos; /* position of |'.'| in the argument */
-  char *name_pos; /* file name beginning, sans directory */
-  register char *s; /* register for scanning strings */
-  boolean found_web=0,found_change=0,found_out=0;
-             /* have these names have been seen? */
-  boolean flag_change;
-
-  while (--argc > 0) {
-    if ((**(++argv)=='-'||**argv=='+')&&*(*argv+1)) @<Handle flag argument@>@;
-    else {
-      s=name_pos=*argv;@+dot_pos=NULL;
-      while (*s) {
-        if (*s=='.') dot_pos=s++;
-        else if (*s=='/') dot_pos=NULL,name_pos=++s;
-        else s++;
-      }
-      if (!found_web) @<Make
-       |web_file_name|, |tex_file_name| and |C_file_name|@>@;
-      else if (!found_change) @<Make |change_file_name| from |fname|@>@;
-      else if (!found_out) @<Override |tex_file_name| and |C_file_name|@>@;
-        else @<Print usage error message and quit@>;
-    }
-  }
-  if (!found_web) @<Print usage error message and quit@>;
-  if (found_change<=0) strcpy(change_file_name,"/dev/null");
-}
-
-@ We use all of |*argv| for the |web_file_name| if there is a |'.'| in it,
-otherwise we add |".w"|. If this file can't be opened, we prepare an
-|alt_web_file_name| by adding |"web"| after the dot.
-The other file names come from adding other things
-after the dot.  We must check that there is enough room in
-|web_file_name| and the other arrays for the argument.
-
-@<Make |web_file_name|...@>=
-{
-  if (s-*argv > max_file_name_length-5)
-    @<Complain about argument length@>;
-  if (dot_pos==NULL)
-    sprintf(web_file_name,"%s.w",*argv);
-  else {
-    strcpy(web_file_name,*argv);
-    *dot_pos=0; /* string now ends where the dot was */
-  }
-  sprintf(alt_web_file_name,"%s.web",*argv);
-  sprintf(tex_file_name,"%s.tex",name_pos); /* strip off directory name */
-  sprintf(idx_file_name,"%s.idx",name_pos);
-  sprintf(scn_file_name,"%s.scn",name_pos);
-  sprintf(C_file_name,"%s.c",name_pos);
-  found_web=1;
-}
-
-@ @<Make |change_file_name|...@>=
-{
-  if (strcmp(*argv,"-")==0) found_change=-1;
-  else {
-    if (s-*argv > max_file_name_length-4)
-      @<Complain about argument length@>;
-    if (dot_pos==NULL)
-      sprintf(change_file_name,"%s.ch",*argv);
-    else strcpy(change_file_name,*argv);
-    found_change=1;
-  }
-}
-
-@ @<Override...@>=
-{
-  if (s-*argv > max_file_name_length-5)
-    @<Complain about argument length@>;
-  if (dot_pos==NULL) {
-    sprintf(tex_file_name,"%s.tex",*argv);
-    sprintf(idx_file_name,"%s.idx",*argv);
-    sprintf(scn_file_name,"%s.scn",*argv);
-    sprintf(C_file_name,"%s.c",*argv);
-  } else {
-    strcpy(tex_file_name,*argv);
-    strcpy(C_file_name,*argv);
-    if (flags['x']) { /* indexes will be generated */
-      *dot_pos=0;
-      sprintf(idx_file_name,"%s.idx",*argv);
-      sprintf(scn_file_name,"%s.scn",*argv);
-    }
-  }
-  found_out=1;
-}
 @y
 @ We now must look at the command line arguments and set the file names
 accordingly.  At least one file name must be present: the \.{CWEB}
@@ -204,41 +89,42 @@
 routine has been written to search for the last ``dot'', so the altered
 version will search for the last |"_"| (including directory separators),
 so we have what we want.
+ at z
 
-@<Pred...@>=
-void scan_args();
 
-@ @c
-void
-scan_args()
-{
+ at x
+  char *dot_pos; /* position of |'.'| in the argument */
+ at y
   char *dot_pos; /* position of |'_'| in the argument */
-  char *name_pos; /* file name beginning, sans directory */
-  register char *s; /* register for scanning strings */
-  boolean found_web=0,found_change=0,found_out=0;
-             /* have these names have been seen? */
-  boolean flag_change;
+ at z
 
-  while (--argc > 0) {
-    if ((**(++argv)=='-'||**argv=='+')&&*(*argv+1)) @<Handle flag argument@>@;
-    else {
-      s=name_pos=*argv;@+dot_pos=NULL;
-      while (*s) {
+
+ at x
+  strcpy(change_file_name,"/dev/null");
+ at y
+  strcpy(change_file_name,"NUL");
+ at z
+
+
+ at x
+        if (*s=='.') dot_pos=s++;
+        else if (*s=='/') dot_pos=NULL,name_pos=++s;
+        else s++;
+ at y
         if (*s=='_') dot_pos=s++;
         else if (*s=='_') dot_pos=NULL,name_pos=++s;
         else s++;
-      }
-      if (!found_web) @<Make
-       |web_file_name|, |tex_file_name| and |C_file_name|@>@;
-      else if (!found_change) @<Make |change_file_name| from |fname|@>@;
-      else if (!found_out) @<Override |tex_file_name| and |C_file_name|@>@;
-        else @<Print usage error message and quit@>;
-    }
-  }
-  if (!found_web) @<Print usage error message and quit@>;
-  if (found_change<=0) strcpy(change_file_name,"NUL");
-}
+ at z
 
+
+ at x
+@ We use all of |*argv| for the |web_file_name| if there is a |'.'| in it,
+otherwise we add |".w"|. If this file can't be opened, we prepare an
+|alt_web_file_name| by adding |"web"| after the dot.
+The other file names come from adding other things
+after the dot.  We must check that there is enough room in
+|web_file_name| and the other arrays for the argument.
+ at y
 @ We use all of |*argv| for the |web_file_name| if there is a |'_'| in it,
 otherwise we add |"_w"|. If this file can't be opened, we prepare an
 |alt_web_file_name| by adding |"web"| after the dot.
@@ -250,10 +136,31 @@
 QDOS/SMSQ file names contain almost a |"_"|, so this routine will not work,
 i.e. you'll {\em have} to add the |"_w"| always.  Nevertheless I adapted
 the routine as if it would work.
+ at z
 
+
+ at x
 @<Make |web_file_name|...@>=
 {
   if (s-*argv > max_file_name_length-5)
+    @<Complain about argument length@>@;
+  if (dot_pos==NULL)
+    sprintf(web_file_name,"%s.w",*argv);
+  else {
+    strcpy(web_file_name,*argv);
+    *dot_pos=0; /* string now ends where the dot was */
+  }
+  sprintf(alt_web_file_name,"%s.web",*argv);
+  sprintf(tex_file_name,"%s.tex",name_pos); /* strip off directory name */
+  sprintf(idx_file_name,"%s.idx",name_pos);
+  sprintf(scn_file_name,"%s.scn",name_pos);
+  sprintf(C_file_name,"%s.c",name_pos);
+  found_web=1;
+}
+ at y
+@<Make |web_file_name|...@>=
+{
+  if (s-*argv > max_file_name_length-5)
     @<Complain about argument length@>;
   if (dot_pos==NULL)
     sprintf(web_file_name,"%s_w",*argv);
@@ -268,12 +175,26 @@
   sprintf(C_file_name,"%s_c",name_pos);
   found_web=1;
 }
+ at z
 
+
+ at x
 @ @<Make |change_file_name|...@>=
 {
-  if (strcmp(*argv,"-")==0) found_change=-1;
-  else {
+  if (strcmp(*argv,"-")!=0) {
     if (s-*argv > max_file_name_length-4)
+      @<Complain about argument length@>@;
+    if (dot_pos==NULL)
+      sprintf(change_file_name,"%s.ch",*argv);
+    else strcpy(change_file_name,*argv);
+  }
+  found_change=1;
+}
+ at y
+@ @<Make |change_file_name|...@>=
+{
+  if (strcmp(*argv,"-")!=0) {
+    if (s-*argv > max_file_name_length-4)
       @<Complain about argument length@>;
     if (dot_pos==NULL)
       sprintf(change_file_name,"%s_ch",*argv);
@@ -281,10 +202,34 @@
     found_change=1;
   }
 }
+ at z
 
+
+ at x
 @ @<Override...@>=
 {
   if (s-*argv > max_file_name_length-5)
+    @<Complain about argument length@>@;
+  if (dot_pos==NULL) {
+    sprintf(tex_file_name,"%s.tex",*argv);
+    sprintf(idx_file_name,"%s.idx",*argv);
+    sprintf(scn_file_name,"%s.scn",*argv);
+    sprintf(C_file_name,"%s.c",*argv);
+  } else {
+    strcpy(tex_file_name,*argv);
+    strcpy(C_file_name,*argv);
+    if (make_xrefs) { /* indexes will be generated */
+      *dot_pos=0;
+      sprintf(idx_file_name,"%s.idx",*argv);
+      sprintf(scn_file_name,"%s.scn",*argv);
+    }
+  }
+  found_out=1;
+}
+ at y
+@ @<Override...@>=
+{
+  if (s-*argv > max_file_name_length-5)
     @<Complain about argument length@>;
   if (dot_pos==NULL) {
     sprintf(tex_file_name,"%s_tex",*argv);
@@ -294,7 +239,7 @@
   } else {
     strcpy(tex_file_name,*argv);
     strcpy(C_file_name,*argv);
-    if (flags['x']) { /* indexes will be generated */
+    if (make_xrefs) { /* indexes will be generated */
       *dot_pos=0;
       sprintf(idx_file_name,"%s_idx",*argv);
       sprintf(scn_file_name,"%s_scn",*argv);

Modified: branches/stable/source/src/texk/web2c/cwebdir/comm-vms.ch
===================================================================
--- branches/stable/source/src/texk/web2c/cwebdir/comm-vms.ch	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/texk/web2c/cwebdir/comm-vms.ch	2021-02-15 19:17:20 UTC (rev 845)
@@ -13,19 +13,26 @@
 (only the two changes by BL are necessary for initial bootstrapping
  via hand-editing of common.c)
 
- at x section 5 (01-FEB-1992 ST)
-#include <ctype.h>
+ at x section 3 (01-FEB-1992 ST)
+#include <ctype.h> /* definition of |@!isalpha|, |@!isdigit| and so on */
+#include <stdbool.h> /* definition of |@!bool|, |@!true| and |@!false| */
+#include <stddef.h> /* definition of |@!ptrdiff_t| */
+#include <stdint.h> /* definition of |@!uint8_t| and |@!uint16_t| */
+#include <stdlib.h> /* definition of |@!getenv| and |@!exit| */
+#include <stdio.h> /* definition of |@!printf| and friends */
+#include <string.h> /* definition of |@!strlen|, |@!strcmp| and so on */
 @y
-#include ctype /* VMS searches Textlibraries faster */
+#include ctype /* definition of |@!isalpha|, |@!isdigit| and so on */
+               /* VMS searches text libraries faster */
+#include stdbool /* definition of |@!bool|, |@!true| and |@!false| */
+#include stddef /* definition of |@!ptrdiff_t| */
+#include stdint /* definition of |@!uint8_t| and |@!uint16_t| */
+#include stdlib /* definition of |@!getenv| and |@!exit| */
+#include stdio /* definition of |@!printf| and friends */
+#include string /* definition of |@!strlen|, |@!strcmp| and so on */
 @z
 
- at x section 8  (01-FEB-1992 ST)
-#include <stdio.h>
- at y
-#include stdio /* VMS searches Textlibraries faster */
- at z
-
- at x section 61 (01-FEB-1992 ST)
+ at x section 68 (01-FEB-1992 ST)
 programs are started. Here, for instance, we pass the operating system
 a status of 0 if and only if only harmless messages were printed.
 @y
@@ -37,7 +44,7 @@
 print |"%SYSTEM-F-ABORT, abort"|, if |history > harmless_message|.
 @z
 
- at x section 61 (1987 BL) (01-FEB-1992 ST) (11-JAN-1993 DEK)
+ at x section 68 (1987 BL) (01-FEB-1992 ST) (11-JAN-1993 DEK)
   if (history > harmless_message) return(1);
   else return(0);
 @y
@@ -52,7 +59,7 @@
   else exit(SS$_NORMAL);
 @z
 
- at x section 69 (01-FEB-1992 ST)
+ at x section 75 (01-FEB-1992 ST)
 An omitted change file argument means that |"/dev/null"| should be used,
 when no changes are desired.
 @y
@@ -60,14 +67,14 @@
 null device |"NL:"| should be used, when no changes are desired.
 @z
 
- at x section 70 (1987 BL) (01-FEB-1992 ST) (05-APR-1992 DEK)
-  if (found_change<=0) strcpy(change_file_name,"/dev/null");
+ at x section 76 (1987 BL) (01-FEB-1992 ST) (05-APR-1992 DEK)
+  strcpy(change_file_name,"/dev/null");
 @y
-  if (found_change<=) strcpy(change_file_name,"NL:");
+  strcpy(change_file_name,"NL:");
 	/* {\tt NL:} is the VAX/VMS notation for {\tt /dev/null} */
 @z
 
- at x section 82 (01-FEB-1992 ST)
+ at x section 85 (01-FEB-1992 ST)
 @** Index.
 @y
 @* VAX/VMS specific code.

Modified: branches/stable/source/src/texk/web2c/cwebdir/comm-w2c.ch
===================================================================
--- branches/stable/source/src/texk/web2c/cwebdir/comm-w2c.ch	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/texk/web2c/cwebdir/comm-w2c.ch	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,31 +1,32 @@
- at q Changes for CWEB in TeX Live from numerous contributors. @>
- at q This file is in the Public Domain. @>
+ at q Changes for CWEB in TeX Live from numerous contributors.              @>
+ at q This file is in the Public Domain.                                    @>
 
- at q Most of the original Kpathsea changes by Wlodek Bzyl and Olaf Weber @>
- at q were merged with the set of change files of the CWEBbin project; @>
- at q see https://github.com/ascherer/cwebbin for the original parts. @>
+ at q Most of the original Kpathsea changes by Wlodek Bzyl and Olaf Weber   @>
+ at q were merged with the set of change files of the CWEBbin project;      @>
+ at q see https://github.com/ascherer/cwebbin for the original parts.       @>
 
- at q This stripped change file {comm,ctang,cweav,ctwill}-w2c.ch has been @>
- at q created from the set of change files {comm,ctang,cweav}-patch.ch, @>
- at q {comm,ctang,cweav}-ansi.ch, {comm,ctang,cweav}-extensions.ch, @>
- at q {comm,ctang,cweav}-output.ch, {comm,ctang,cweav}-i18n.ch, and @>
- at q cweav-twill.ch for CTWILL, and {comm,ctang,cweav,ctwill}-texlive.ch @>
- at q with the 'tie' processor and is used as a monolithic changefile for @>
- at q {common,ctangle,cweave}.w in TeX Live. @>
+ at q This stripped change file {comm,ctang,cweav,ctwill,cwebman}-w2c.ch    @>
+ at q has been created from the elaborate set of change files               @>
+ at q {comm,ctang,cweav,cwebman}-patch.ch,                                  @>
+ at q {comm,cweav,cwebman}-extensions.ch, {comm,ctang,cweav}-output.ch,     @>
+ at q {comm,ctang,cweav}-i18n.ch, and cweav-twill.ch for CTWILL, and        @>
+ at q {comm,ctang,cweav,ctwill,cwebman}-texlive.ch with the 'tie' processor @>
+ at q and is used as a monolithic changefile for {common,ctangle,cweave}.w  @>
+ at q and cwebman.tex in TeX Live.                                          @>
 
- at q Please send comments, suggestions, etc. to tex-k@@tug.org. @>
+ at q Please send comments, suggestions, etc. to tex-k@@tug.org.            @>
 
 @x
-\def\title{Common code for CTANGLE and CWEAVE (Version 3.64)}
+\def\title{Common code for CTANGLE and CWEAVE (Version 4.0)}
 @y
 \def\Kpathsea/{{\mc KPATHSEA\spacefactor1000}} \ifacro\sanitizecommand\Kpathsea{KPATHSEA}\fi
-\def\title{Common code for CTANGLE and CWEAVE (\TeX~Live)}
+\def\title{Common code for CTANGLE and CWEAVE (4.0 [\TeX~Live])}
 @z
 
 @x
-  \centerline{(Version 3.64)}
+  \centerline{(Version 4.0)}
 @y
-  \centerline{(Version 3.64 [\TeX~Live])}
+  \centerline{(Version 4.0 [\TeX~Live])}
 @z
 
 @x
@@ -37,19 +38,10 @@
 @x
 }
 @y
-}}
-\datecontentspage
+}}\datecontentspage
 @z
 
 @x
- at s not_eq normal @q unreserve a C++ keyword @>
- at y
- at s boolean int
- at s uint8_t int
- at s uint16_t int
- at z
-
- at x
 to both \.{CTANGLE} and \.{CWEAVE}, which roughly concerns the following
 @y
 to \.{CTANGLE}, \.{CWEAVE}, and \.{CTWILL},
@@ -63,107 +55,38 @@
 @z
 
 @x
-|program|.
-
- at d ctangle 0
- at d cweave 1
+ at i common.h
 @y
-|program|. And \.{CTWILL} adds some extra twists.
+ at i comm-w2c.h
 @z
 
 @x
-typedef short boolean;
+|program|.
 @y
-typedef uint8_t eight_bits;
-typedef uint16_t sixteen_bits;
+|program|. And \.{CTWILL} adds some extra twists.
 @z
 
 @x
 boolean program; /* \.{CWEAVE} or \.{CTANGLE}? */
 @y
-typedef enum {
-  @!ctangle, @!cweave, @!ctwill
-} cweb;
 cweb program; /* \.{CTANGLE} or \.{CWEAVE} or \.{CTWILL}? */
 @z
 
 @x
-void
-common_init()
+  @<Initialize pointers@>@;
 @y
-void
-common_init(void)
+  @<Initialize pointers@>@;
+  @<Set up |PROGNAME| feature and initialize the search path mechanism@>@;
 @z
 
 @x
-  @<Initialize pointers@>;
-  @<Set the default options common to \.{CTANGLE} and \.{CWEAVE}@>;
-  @<Scan arguments and open output files@>;
+  @<Set the default options common to \.{CTANGLE} and \.{CWEAVE}@>@;
 @y
-  @<Initialize pointers@>@;
-  @<Set up |PROGNAME| feature and initialize the search path mechanism@>@;
   @<Set locale and bind language catalogs@>@;
   @<Set the default options common to \.{CTANGLE} and \.{CWEAVE}@>@;
-  @<Scan arguments and open output files@>@;
 @z
 
 @x
-\.{ctype.h} header file.
-
-@<Include files@>=
-#include <ctype.h>
- at y
-\.{ctype.h} header file, included through the \Kpathsea/ interface.
- at z
-
- at x
- at d not_eq 032 /* `\.{!=}'\,;  corresponds to MIT's {\tentex\char'32} */
- at y
- at d non_eq 032 /* `\.{!=}'\,;  corresponds to MIT's {\tentex\char'32} */
- at z
-
- at x
- at d minus_gt_ast 027 /* `\.{->*}'\,;  corresponds to MIT's {\tentex\char'27} */
- at y
- at d minus_gt_ast 027 /* `\.{->*}'\,;  corresponds to MIT's {\tentex\char'27} */
-
-@<Definitions...@>=
-char section_text[longest_name+1]; /* name being sought for */
-char *section_text_end = section_text+longest_name; /* end of |section_text| */
-char *id_first; /* where the current identifier begins in the buffer */
-char *id_loc; /* just after the current identifier in the buffer */
- at z
-
- at x
- at d buf_size 100 /* for \.{CWEAVE} and \.{CTANGLE} */
- at y
- at d buf_size 1000 /* for \.{CWEAVE} and \.{CTANGLE} */
- at z
-
- at x
- at d xisspace(c) (isspace(c)&&((unsigned char)c<0200))
- at d xisupper(c) (isupper(c)&&((unsigned char)c<0200))
- at y
- at d xisspace(c) (isspace((eight_bits)c)&&((eight_bits)c<0200))
- at d xisupper(c) (isupper((eight_bits)c)&&((eight_bits)c<0200))
- at z
-
- at x
-@ @<Include files@>=
-#include <stdio.h>
- at y
-@ Most of the standard \CEE/ interface comes from \Kpathsea/.
- at z
-
- at x
-int input_ln(fp) /* copies a line into |buffer| or returns 0 */
-FILE *fp; /* what file to read from */
- at y
-static boolean input_ln(@t\1\1@> /* copies a line into |buffer| or returns 0 */
-FILE *fp at t\2\2@>) /* what file to read from */
- at z
-
- at x
     if ((*(k++) = c) != ' ') limit = k;
 @y
     if ((*(k++) = c) != ' ' && c != '\r') limit = k;
@@ -176,39 +99,11 @@
 @z
 
 @x
- at d max_file_name_length 60
- at y
- at d max_file_name_length 1024
- at z
-
- at x
 char alt_web_file_name[max_file_name_length]; /* alternate name to try */
 @y
 @z
 
 @x
- at d lines_dont_match (change_limit-change_buffer != limit-buffer ||
-  strncmp(buffer, change_buffer, limit-buffer))
- at y
- at d lines_dont_match (change_limit-change_buffer != limit-buffer || @|
-  strncmp(buffer, change_buffer, (size_t)(limit-buffer)))
- at z
-
- at x
-void
-prime_the_change_buffer()
- at y
-static void
-prime_the_change_buffer(void)
- at z
-
- at x
-  if (xisupper(buffer[1])) buffer[1]=tolower(buffer[1]);
- at y
-  if (xisupper(buffer[1])) buffer[1]=tolower((eight_bits)buffer[1]);
- at z
-
- at x
     err_print("! Missing @@x in change file");
 @y
     err_print(_("! Missing @@x in change file"));
@@ -221,22 +116,6 @@
 @z
 
 @x
-  change_limit=change_buffer+(limit-buffer);
-  strncpy(change_buffer,buffer,limit-buffer+1);
- at y
-  change_limit=change_buffer+(ptrdiff_t)(limit-buffer);
-  strncpy(change_buffer,buffer,(size_t)(limit-buffer+1));
- at z
-
- at x
-void
-check_change() /* switches to |change_file| if the buffers match */
- at y
-static void
-check_change(void) /* switches to |change_file| if the buffers match */
- at z
-
- at x
       err_print("! Change file ended before @@y");
 @y
       err_print(_("! Change file ended before @@y"));
@@ -243,12 +122,6 @@
 @z
 
 @x
-      char xyz_code=xisupper(buffer[1])? tolower(buffer[1]): buffer[1];
- at y
-      char xyz_code=xisupper(buffer[1])? tolower((eight_bits)buffer[1]): buffer[1];
- at z
-
- at x
         err_print("! CWEB file ended during a change");
 @y
         err_print(_("! CWEB file ended during a change"));
@@ -267,14 +140,6 @@
 @z
 
 @x
-void
-reset_input()
- at y
-void
-reset_input(void)
- at z
-
- at x
 if ((web_file=fopen(web_file_name,"r"))==NULL) {
   strcpy(web_file_name,alt_web_file_name);
   if ((web_file=fopen(web_file_name,"r"))==NULL)
@@ -310,25 +175,6 @@
 @z
 
 @x
- at d max_sections 2000 /* number of identifiers, strings, section names;
-  must be less than 10240 */
- at y
- at d max_sections 10239 /* number of identifiers, strings, section names;
-  must be less than 10240 */
- at z
-
- at x
-typedef unsigned short sixteen_bits;
- at y
- at z
-
- at x
-int get_line() /* inputs the next line */
- at y
-boolean get_line(void) /* inputs the next line */
- at z
-
- at x
       err_print("! Include file name not given");
 @y
       err_print(_("! Include file name not given"));
@@ -357,7 +203,7 @@
 \.{@@i} line should give a complete file name with or without
 double quotes.
 The actual file lookup is done with the help of the \Kpathsea/ library;
-see section~\X90:File lookup with \Kpathsea/\X~for details. % FIXME
+see section~\X91:File lookup with \Kpathsea/\X~for details. % FIXME
 The remainder of the \.{@@i} line after the file name is ignored.
 @^system dependencies@> @.CWEBINPUTS@>
 @z
@@ -369,18 +215,6 @@
 @z
 
 @x
-@<Include...@>=
-#include <stdlib.h> /* declaration of |getenv| and |exit| */
- at y
- at z
-
- at x
-@ @<Try to open...@>= {
- at y
-@ @.CWEBINPUTS@>@<Try to open...@>= {
- at z
-
- at x
   char temp_file_name[max_file_name_length];
   char *cur_file_name_end=cur_file_name+max_file_name_length-1;
   char *k=cur_file_name, *kk;
@@ -441,12 +275,6 @@
 @z
 
 @x
-      if (xisupper(buffer[1])) buffer[1]=tolower(buffer[1]);
- at y
-      if (xisupper(buffer[1])) buffer[1]=tolower((eight_bits)buffer[1]);
- at z
-
- at x
         err_print("! Where is the matching @@z?");
 @y
         err_print(_("! Where is the matching @@z?"));
@@ -453,20 +281,6 @@
 @z
 
 @x
-void
-check_complete(){
-  if (change_limit!=change_buffer) { /* |changing| is 0 */
-    strncpy(buffer,change_buffer,change_limit-change_buffer+1);
-    limit=buffer+(int)(change_limit-change_buffer);
- at y
-void
-check_complete(void) {
-  if (change_limit!=change_buffer) { /* |changing| is 0 */
-    strncpy(buffer,change_buffer,(size_t)(change_limit-change_buffer+1));
-    limit=buffer+(ptrdiff_t)(change_limit-change_buffer);
- at z
-
- at x
     err_print("! Change file entry did not match");
 @y
     err_print(_("! Change file entry did not match"));
@@ -473,66 +287,6 @@
 @z
 
 @x
- at d max_bytes 90000 /* the number of bytes in identifiers,
-  index entries, and section names; must be less than $2^{24}$ */
- at d max_names 4000 /* number of identifiers, strings, section names;
-  must be less than 10240 */
- at y
- at d max_bytes 1000000 /* the number of bytes in identifiers,
-  index entries, and section names; must be less than $2^{24}$ */
- at d max_names 10239 /* number of identifiers, strings, section names;
-  must be less than 10240 */
- at z
-
- at x
- at d length(c) (c+1)->byte_start-(c)->byte_start /* the length of a name */
- at y
- at d length(c) (size_t)((c+1)->byte_start-(c)->byte_start) /* the length of a name */
- at z
-
- at x
- at d hash_size 353 /* should be prime */
- at y
- at d hash_size 8501 /* should be prime */
- at z
-
- at x
-extern int names_match();
- at y
-extern boolean names_match(name_pointer,const char *,size_t,eight_bits);@/
- at z
-
- at x
-name_pointer
-id_lookup(first,last,t) /* looks up a string in the identifier table */
-char *first; /* first character of string */
-char *last; /* last character of string plus one */
-char t; /* the |ilk|; used by \.{CWEAVE} only */
-{
-  char *i=first; /* position in |buffer| */
- at y
-name_pointer
-id_lookup(@t\1\1@> /* looks up a string in the identifier table */
-const char *first, /* first character of string */
-const char *last, /* last character of string plus one */
-char t at t\2\2@>) /* the |ilk|; used by \.{CWEAVE} only */
-{
-  const char *i=first; /* position in |buffer| */
- at z
-
- at x
-  l=last-first; /* compute the length */
- at y
-  l=(int)(last-first); /* compute the length */
- at z
-
- at x
-void init_p();
- at y
-extern void init_p(name_pointer,eight_bits);@/
- at z
-
- at x
   if (byte_ptr+l>byte_mem_end) overflow("byte memory");
   if (name_ptr>=name_dir_end) overflow("name");
 @y
@@ -541,102 +295,6 @@
 @z
 
 @x
-  if (program==cweave) init_p(p,t);
- at y
-  init_p(p,t);
- at z
-
- at x
-void
-print_section_name(p)
-name_pointer p;
- at y
-void
-print_section_name(
-name_pointer p)
- at z
-
- at x
-      term_write(s,ss-s); p=q->link; q=p;
-    } else {
-      term_write(s,ss+1-s); p=name_dir; q=NULL;
- at y
-      term_write(s,(size_t)(ss-s)); p=q->link; q=p;
-    } else {
-      term_write(s,(size_t)(ss+1-s)); p=name_dir; q=NULL;
- at z
-
- at x
-void
-sprint_section_name(dest,p)
-  char*dest;
-  name_pointer p;
- at y
-void
-sprint_section_name(
-  char *dest,
-  name_pointer p)
- at z
-
- at x
-    strncpy(dest,s,ss-s), dest+=ss-s;
- at y
-    strncpy(dest,s,(size_t)(ss-s)), dest+=ss-s;
- at z
-
- at x
-void
-print_prefix_name(p)
-name_pointer p;
- at y
-void
-print_prefix_name(
-name_pointer p)
- at z
-
- at x
-int web_strcmp(j,j_len,k,k_len) /* fuller comparison than |strcmp| */
-  char *j, *k; /* beginning of first and second strings */
-  int j_len, k_len; /* length of strings */
- at y
-static int web_strcmp(@t\1\1@> /* fuller comparison than |strcmp| */
-  char *j, /* beginning of first string */
-  int j_len, /* length of first string */
-  char *k, /* beginning of second string */
-  int k_len at t\2\2@>) /* length of second string */
- at z
-
- at x
-extern void init_node();
- at y
-extern void init_node(name_pointer);@/
- at z
-
- at x
-name_pointer
-add_section_name(par,c,first,last,ispref) /* install a new node in the tree */
-name_pointer par; /* parent of new node */
-int c; /* right or left? */
-char *first; /* first character of section name */
-char *last; /* last character of section name, plus one */
-int ispref; /* are we adding a prefix or a full name? */
- at y
-static name_pointer
-add_section_name(@t\1\1@> /* install a new node in the tree */
-name_pointer par, /* parent of new node */
-int c, /* right or left? */
-char *first, /* first character of section name */
-char *last, /* last character of section name, plus one */
-int ispref at t\2\2@>) /* are we adding a prefix or a full name? */
- at z
-
- at x
-  int name_len=last-first+ispref; /* length of section name */
- at y
-  int name_len=(int)(last-first)+ispref; /* length of section name */
- at z
-
- at x
   if (s+name_len>byte_mem_end) overflow("byte memory");
   if (name_ptr+1>=name_dir_end) overflow("name");
 @y
@@ -645,28 +303,6 @@
 @z
 
 @x
-void
-extend_section_name(p,first,last,ispref)
-name_pointer p; /* name to be extended */
-char *first; /* beginning of extension text */
-char *last; /* one beyond end of extension text */
-int ispref; /* are we adding a prefix or a full name? */
- at y
-static void
-extend_section_name(@t\1\1@>
-name_pointer p, /* name to be extended */
-char *first, /* beginning of extension text */
-char *last, /* one beyond end of extension text */
-int ispref at t\2\2@>) /* are we adding a prefix or a full name? */
- at z
-
- at x
-  int name_len=last-first+ispref;
- at y
-  int name_len=(int)(last-first)+ispref;
- at z
-
- at x
   if (name_ptr>=name_dir_end) overflow("name");
 @y
   if (name_ptr>=name_dir_end) overflow(_("name"));
@@ -679,118 +315,42 @@
 @z
 
 @x
-name_pointer
-section_lookup(first,last,ispref) /* find or install section name in tree */
-char *first, *last; /* first and last characters of new name */
-int ispref; /* is the new name a prefix or a full name? */
+      fputs("\n! Ambiguous prefix: matches <",stdout);
 @y
-name_pointer
-section_lookup(@t\1\1@> /* find or install section name in tree */
-char *first,char *last, /* first and last characters of new name */
-int ispref at t\2\2@>) /* is the new name a prefix or a full name? */
- at z
-
- at x
-  int name_len=last-first+1;
- at y
-  int name_len=(int)(last-first)+1;
- at z
-
- at x
-      printf("\n! Ambiguous prefix: matches <");
- at y
       fputs(_("\n! Ambiguous prefix: matches <"),stdout);
 @z
 
 @x
-      printf(">\n and <");
+      fputs(">\n and <",stdout);
 @y
       fputs(_(">\n and <"),stdout);
 @z
 
 @x
-      printf("\n! New name is a prefix of <");
+      fputs("\n! New name is a prefix of <",stdout);
 @y
       fputs(_("\n! New name is a prefix of <"),stdout);
 @z
 
 @x
-      printf("\n! New name extends <");
+      fputs("\n! New name extends <",stdout);
 @y
       fputs(_("\n! New name extends <"),stdout);
 @z
 
 @x
-    printf("\n! Section name incompatible with <");
+    fputs("\n! Section name incompatible with <",stdout);
 @y
     fputs(_("\n! Section name incompatible with <"),stdout);
 @z
 
 @x
-    printf(">,\n which abbreviates <");
+    fputs(">,\n which abbreviates <",stdout);
 @y
     fputs(_(">,\n which abbreviates <"),stdout);
 @z
 
 @x
-int section_name_cmp();
- at y
-static int section_name_cmp(char **,int,name_pointer);@/
- at z
-
- at x
-int section_name_cmp(pfirst,len,r)
-char **pfirst; /* pointer to beginning of comparison string */
-int len; /* length of string */
-name_pointer r; /* section name being compared */
- at y
-static int section_name_cmp(@t\1\1@>
-char **pfirst, /* pointer to beginning of comparison string */
-int len, /* length of string */
-name_pointer r at t\2\2@>) /* section name being compared */
- at z
-
- at x
-          *pfirst=first+(ss-s);
- at y
-          *pfirst=first+(ptrdiff_t)(ss-s);
- at z
-
- at x
-      if (q!=name_dir) {len -= ss-s; s=q->byte_start; r=q; continue;}
- at y
-      if (q!=name_dir) {len -= (int)(ss-s); s=q->byte_start; r=q; continue;}
- at z
-
- at x
-|equiv_or_xref| as a pointer to a |char|.
-
-@<More elements of |name...@>=
-char *equiv_or_xref; /* info corresponding to names */
- at y
-|equiv_or_xref| as a pointer to |void|.
-
-@<More elements of |name...@>=
-void *equiv_or_xref; /* info corresponding to names */
- at z
-
- at x
-void  err_print();
- at y
-extern void err_print(const char *);@/
- at z
-
- at x
-void
-err_print(s) /* prints `\..' and location of error message */
-char *s;
- at y
-void
-err_print(@t\1\1@> /* prints `\..' and location of error message */
-const char *s at t\2\2@>)
- at z
-
- at x
   printf(". (l. %d of change file)\n", change_line);
 else if (include_depth==0) printf(". (l. %d)\n", cur_line);
   else printf(". (l. %d of include file %s)\n", cur_line, cur_file_name);
@@ -801,21 +361,13 @@
 @z
 
 @x
-int wrap_up();
-extern void print_stats();
- at y
-extern int wrap_up(void);@/
-extern void print_stats(void);@/
- at z
-
- at x
-@ Some implementations may wish to pass the |history| value to the
+Some implementations may wish to pass the |history| value to the
 operating system so that it can be used to govern whether or not other
 programs are started. Here, for instance, we pass the operating system
 a status of 0 if and only if only harmless messages were printed.
 @^system dependencies@>
 @y
-@ On multi-tasking systems like the {\mc AMIGA} it is very convenient to
+On multi-tasking systems like the {\mc AMIGA} it is very convenient to
 know a little bit more about the reasons why a program failed.  The four
 levels of return indicated by the |history| value are very suitable for
 this purpose.  Here, for instance, we pass the operating system a status
@@ -831,16 +383,8 @@
 @z
 
 @x
-int wrap_up() {
-  putchar('\n');
+  @<Print the job |history|@>@;
 @y
-int wrap_up(void) {
-  if (show_progress || show_happiness || (history > spotless)) new_line;
- at z
-
- at x
-  @<Print the job |history|@>;
- at y
   @<Print the job |history|@>@;
   @<Remove the temporary file if not already done@>@;
 @z
@@ -858,12 +402,12 @@
 @z
 
 @x
-case spotless: if (show_happiness) printf("(No errors were found.)\n"); break;
+case spotless: if (show_happiness) puts("(No errors were found.)"); break;
 case harmless_message:
-  printf("(Did you see the warning message above?)\n"); break;
+  puts("(Did you see the warning message above?)"); break;
 case error_message:
-  printf("(Pardon me, but I think I spotted something wrong.)\n"); break;
-case fatal_message: printf("(That was a fatal error, my friend.)\n");
+  puts("(Pardon me, but I think I spotted something wrong.)"); break;
+case fatal_message: puts("(That was a fatal error, my friend.)");
 @y
 case spotless:
   if (show_happiness) puts(_("(No errors were found.)")); break;
@@ -876,39 +420,6 @@
 @z
 
 @x
-void fatal(), overflow();
- at y
-extern void fatal(const char *,const char *);@/
-extern void overflow(const char *);@/
- at z
-
- at x
- at c void
-fatal(s,t)
-  char *s,*t;
- at y
- at c void
-fatal(
-  const char *s,const char *t)
- at z
-
- at x
-  if (*s) printf(s);
- at y
-  if (*s) err_print(s);
- at z
-
- at x
- at c void
-overflow(t)
-  char *t;
- at y
- at c void
-overflow(
-  const char *t)
- at z
-
- at x
   printf("\n! Sorry, %s capacity exceeded",t); fatal("","");
 @y
   printf(_("\n! Sorry, %s capacity exceeded"),t); fatal("","");
@@ -915,20 +426,6 @@
 @z
 
 @x
- at d confusion(s) fatal("! This can't happen: ",s)
- at y
- at d confusion(s) fatal(_("! This can't happen: "),s)
- at z
-
- at x
- at d show_happiness flags['h'] /* should lack of errors be announced? */
- at y
- at d show_happiness flags['h'] /* should lack of errors be announced? */
- at d temporary_output flags['t'] /* should temporary output take precedence? */
- at d make_xrefs flags['x'] /* should cross references be output? */
- at z
-
- at x
 char scn_file_name[max_file_name_length]; /* name of |scn_file| */
 @y
 char scn_file_name[max_file_name_length]; /* name of |scn_file| */
@@ -936,19 +433,13 @@
 @z
 
 @x
-boolean flags[128]; /* an option for each 7-bit code */
+show_banner=show_happiness=show_progress=make_xrefs=true;@/
 @y
-boolean flags[128]; /* an option for each 7-bit code */
-const char *use_language=""; /* prefix of \.{cwebmac.tex} in \TEX/ output */
+make_xrefs=true;@/
+temporary_output=true; /* Check temporary output for changes */
 @z
 
 @x
-show_banner=show_happiness=show_progress=1;
- at y
-temporary_output=1; /* Check temporary output for changes */
- at z
-
- at x
 file.  It may have an extension, or it may omit the extension to get |".w"| or
 |".web"| added.  The \TEX/ output file name is formed by replacing the \.{CWEB}
 @y
@@ -966,27 +457,8 @@
 @z
 
 @x
-void scan_args();
+  strcpy(change_file_name,"/dev/null");
 @y
-static void scan_args(void);@/
- at z
-
- at x
-void
-scan_args()
- at y
-static void
-scan_args(void)
- at z
-
- at x
-  boolean flag_change;
- at y
- at z
-
- at x
-  while (--argc > 0) {
- at y
 @#
 #if defined DEV_NULL
   strncpy(change_file_name,DEV_NULL,max_file_name_length-2);
@@ -998,7 +470,6 @@
   strcpy(change_file_name,"/dev/null");
 #endif
 @^system dependencies@>
-  while (--argc > 0) {
 @z
 
 @x
@@ -1018,11 +489,6 @@
 @z
 
 @x
-  if (found_change<=0) strcpy(change_file_name,"/dev/null");
- at y
- at z
-
- at x
 @ We use all of |*argv| for the |web_file_name| if there is a |'.'| in it,
 otherwise we add |".w"|. If this file can't be opened, we prepare an
 |alt_web_file_name| by adding |"web"| after the dot.
@@ -1037,34 +503,10 @@
 @z
 
 @x
-  if (strcmp(*argv,"-")==0) found_change=-1;
-  else {
- at y
-  if (strcmp(*argv,"-")!=0) {
- at z
-
- at x
-    found_change=1;
-  }
- at y
-  }
-  found_change=1;
- at z
-
- at x
-    if (flags['x']) { /* indexes will be generated */
- at y
-    if (make_xrefs) { /* indexes will be generated */
- at z
-
- at x
-@ @<Handle flag...@>=
+@<Handle flag...@>=
 {
-  if (**argv=='-') flag_change=0;
-  else flag_change=1;
   for(dot_pos=*argv+1;*dot_pos>'\0';dot_pos++)
 @y
-@ @d flag_change (**argv!='-')
 @<Handle flag...@>=
 {
   if (strcmp("-help",*argv)==0 || strcmp("--help",*argv)==0)
@@ -1098,12 +540,7 @@
 @z
 
 @x
-    flags[*dot_pos]=flag_change;
- at y
-    flags[(eight_bits)*dot_pos]=flag_change;
- at z
-
- at x
+@ @<Print usage error message and quit@>=
 {
 if (program==ctangle)
   fatal(
@@ -1115,6 +552,7 @@
    ,"");
 }
 @y
+@ @<Print usage error message and quit@>=
 cb_usage(program==ctangle ? "ctangle" : program==cweave ? "cweave" : "ctwill");
 @.Usage:@>
 @z
@@ -1143,12 +581,12 @@
 @ @<Scan arguments and open output files@>=
 scan_args();
 if (program==ctangle) {
-  if ((C_file=fopen(C_file_name,"w"))==NULL)
+  if ((C_file=fopen(C_file_name,"wb"))==NULL)
     fatal("! Cannot open output file ", C_file_name);
 @.Cannot open output file@>
 }
 else {
-  if ((tex_file=fopen(tex_file_name,"w"))==NULL)
+  if ((tex_file=fopen(tex_file_name,"wb"))==NULL)
     fatal("! Cannot open output file ", tex_file_name);
 }
 @y
@@ -1185,72 +623,25 @@
 @z
 
 @x
-@ We predeclare several standard system functions here instead of including
-their system header files, because the names of the header files are not as
-standard as the names of the functions. (For example, some \CEE/ environments
-have \.{<string.h>} where others have \.{<strings.h>}.)
-
-@<Predecl...@>=
-extern int strlen(); /* length of string */
-extern int strcmp(); /* compare strings lexicographically */
-extern char* strcpy(); /* copy one string to another */
-extern int strncmp(); /* compare up to $n$ string characters */
-extern char* strncpy(); /* copy up to $n$ string characters */
- at y
-@ For string handling we include the {\mc ANSI C} system header file---through
-the \Kpathsea/ interface---instead of predeclaring the standard system
-functions |strlen|, |strcmp|, |strcpy|, |strncmp|, and |strncpy|.
-@^system dependencies@>
- at z
-
- at x
 @** Index.
 @y
-@** Extensions for modern \.{CWEB}.  The following sections introduce changes
-and extensions to the code that have been created by numerous contributors over
-the course of a quarter century. They make \.{CWEB} adhere to modern coding
-standards and introduce new or improved features.
+@** Extensions to \.{CWEB}.  The following sections introduce new or improved
+features that have been created by numerous contributors over the course of a
+quarter century.
 
 Care has been taken to keep the original section numbering intact, so this new
-section should have the same number as the original ``\&{82.~Index},'' and
-additional material follows below.
+material should nicely integrate with the original ``\&{85.~Index}.''
 
-@* Function declarations. Here are declarations---conforming to
-{\mc ANSI~C}---of all functions in this code that appear in \.{common.h}
-and thus should agree with \.{CTANGLE} and \.{CWEAVE}.
+@* Language setting.  This global variable is set by the argument of the
+`\.{+l}' (or `\.{-l}') command-line option.
 
-@<Predecl...@>=
-boolean get_line(void);@/
-name_pointer id_lookup(const char *,const char *,char);@/
-name_pointer section_lookup(char *,char *,int);@/
-void check_complete(void);@/
-void common_init(void);@/
-void print_prefix_name(name_pointer);@/
-void print_section_name(name_pointer);@/
-void reset_input(void);@/
-void sprint_section_name(char *,name_pointer);@/
+@<Global var...@>=
+const char *use_language=""; /* prefix of \.{cwebmac.tex} in \TEX/ output */
 
-@ The following functions are private to \.{common.w}.
 
-@<Predecl...@>=
-static boolean input_ln(FILE *);@/
-static int web_strcmp(char *,int,char *,int);@/
-static name_pointer add_section_name(name_pointer,int,char *,char *,int);@/
-static void extend_section_name(name_pointer,char *,char *,int);@/
-static void check_change(void);@/
-static void prime_the_change_buffer(void);@/
+@* User communication.  The |scan_args| and |cb_show_banner| routines and the
+|bindtextdomain| argument string need a few extra variables.
 
-@* Standard C library interfaces.  This updated version of \.{CWEB} uses
-standard C types for boolean values, pointers, and objects with fixed sizes
-(|@!uint8_t|, |@!uint16_t|; already in \Kpathsea/).
-
-@<Include files@>=
-#include <stdbool.h> /* type definition of |bool| */
-#include <stddef.h> /* type definition of |ptrdiff_t| */
-
-@ The |scan_args| and |cb_show_banner| routines and the |bindtextdomain|
-argument string need a few extra variables.
-
 @d max_banner 50
 
 @d PATH_SEPARATOR   separators[0]
@@ -1257,7 +648,7 @@
 @d DIR_SEPARATOR    separators[1]
 @d DEVICE_SEPARATOR separators[2]
 
-@<Other...@>=
+@<Global var...@>=
 char cb_banner[max_banner];@/
 string texmf_locale;@/
 #ifndef SEPARATORS
@@ -1275,35 +666,12 @@
 if(strlen(check_file_name)) /* Delete the temporary file in case of a break */
    remove(check_file_name);
 
-@* Internationalization.  You may have noticed that almost all \.{"strings"}
-in the \.{CWEB} sources are placed in the context of the `|_|'~macro.
-This is just a shortcut for the `|@!gettext|' function from the ``GNU~gettext
-utilities.'' For systems that do not have this library installed, we wrap
-things for neutral behavior without internationalization.
-
- at d _(S) gettext(S)
-
-@<Include files@>=
-#ifndef HAVE_GETTEXT
-#define HAVE_GETTEXT 0
-#endif
-@#
-#if HAVE_GETTEXT
-#include <locale.h> /* |@!LC_MESSAGES|, |@!LC_CTYPE| */
-#include <libintl.h>
-#else
-#define setlocale(A,B) ""
-#define bindtextdomain(A,B) ""
-#define textdomain(A) ""
-#define gettext(A) A
-#endif
-
-@ If translation catalogs for your personal \.{LANGUAGE} are installed at the
-appropriate place, \.{CTANGLE} and \.{CWEAVE} will talk to you in your favorite
-language.  Catalog \.{cweb} contains all strings from ``plain \.{CWEB},''
-catalog \.{cweb-tl} contains a few extra strings specific to the \TeX~Live
-interface, and catalog \.{web2c-help} contains the ``\.{--help}'' texts for
-\.{CTANGLE} and \.{CWEAVE}.
+@* Internationalization.  If translation catalogs for your personal
+\.{LANGUAGE} are installed at the appropriate place, \.{CTANGLE} and \.{CWEAVE}
+will talk to you in your favorite language.  Catalog \.{cweb} contains all
+strings from ``plain \.{CWEB},'' catalog \.{cweb-tl} contains a few extra
+strings specific to the \TeX~Live interface, and catalog \.{web2c-help}
+contains the ``\.{--help}'' texts for \.{CTANGLE} and \.{CWEAVE}.
 @.cweb.mo@>
 @.cweb-tl.mo@>
 @.web2c-help.mo@>
@@ -1339,7 +707,16 @@
     e.g., \.{TEXMFLOCALEDIR=\$TEXMFMAIN/locale}\hfil\break
     or \.{TEXMFLOCALEDIR.cweb=\$TEXMFMAIN/locale}.\par}
 
-@<Set locale...@>=
+@<Include files@>=
+#if HAVE_GETTEXT
+#include <locale.h> /* |@!LC_MESSAGES|, |@!LC_CTYPE| */
+#else
+#define setlocale(A,B) ""
+#define bindtextdomain(A,B) ""
+#define textdomain(A) ""
+#endif
+
+@ @<Set locale...@>=
 setlocale(LC_MESSAGES, setlocale(LC_CTYPE, ""));
 texmf_locale = kpse_var_expand ("${TEXMFLOCALEDIR}");
 
@@ -1429,7 +806,11 @@
 \.{i18n}/\.{t10n}.  We simply filter the strings through the catalogs
 (if available).
 
- at c
+@<Predecl...@>=
+static void cb_usage (const_string str);@/
+static void cb_usagehelp (const_string *message, const_string bug_email);@/
+
+@ @c
 static void cb_usage (const_string str)
 {
   textdomain("cweb-tl");
@@ -1466,7 +847,7 @@
 @<Display version information and |exit|@>=
 printversionandexit(cb_banner,
   program == ctwill ? "Donald E. Knuth" : "Silvio Levy and Donald E. Knuth",
-  NULL, "Contemporary development on https://github.com/ascherer/cwebbin.\n");
+  NULL, "Contemporary development on https://github.com/ascherer/cweb.\n");
 @.--version@>
 
 @ But the ``banner'' is, at least the first part.
@@ -1482,10 +863,5 @@
 @.cweb.mo@>
 }
 
-@ @<Predecl...@>=
-static void cb_usage (const_string str);@/
-static void cb_usagehelp (const_string *message, const_string bug_email);@/
-void cb_show_banner (void); /* |extern| for option \.{+b} */
-
 @** Index.
 @z

Modified: branches/stable/source/src/texk/web2c/cwebdir/comm-w2c.h
===================================================================
--- branches/stable/source/src/texk/web2c/cwebdir/comm-w2c.h	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/texk/web2c/cwebdir/comm-w2c.h	2021-02-15 19:17:20 UTC (rev 845)
@@ -2,7 +2,7 @@
 % This program by Silvio Levy and Donald E. Knuth
 % is based on a program by Knuth.
 % It is distributed WITHOUT ANY WARRANTY, express or implied.
-% Version 3.64 --- February 2017 (works also with later versions)
+% Version 4.0 --- February 2021 (works also with later versions)
 
 % Copyright (C) 1987,1990,1993 Silvio Levy and Donald E. Knuth
 
@@ -15,23 +15,24 @@
 % entire resulting derived work is distributed under the terms of a
 % permission notice identical to this one.
 
-% Amendments to 'common.h' resulting in this extended 'comm-w2c.h' were
-% created by numerous collaborators over the course of many years.
+% Amendments to 'common.h' resulting in this updated version were created
+% by numerous collaborators over the course of many years.
 
 % Please send comments, suggestions, etc. to tex-k@@tug.org.
 
 % The next few sections contain stuff from the file |"common.w"| that has
 % to be included in both |"ctangle.w"| and |"cweave.w"|. It appears in this
-% file |"common.h"|, which needs to be updated when |"common.w"| changes.
+% file |"common.h"|, which is also included in |"common.w"| to propagate
+% possible changes from this single source consistently.
 
 First comes general stuff:
 
-
 @s boolean int
 @s uint8_t int
 @s uint16_t int
 
-@<Common code for \.{CWEAVE} and \.{CTANGLE}@>=
+
+@<Common code...@>=
 typedef bool boolean;
 typedef uint8_t eight_bits;
 typedef uint16_t sixteen_bits;
@@ -60,9 +61,13 @@
 #define gettext(A) A
 #endif
 @#
-#include <stdbool.h> /* |@!bool|, |@!true|, |@!false| */
-#include <stdint.h> /* |@!uint8_t|, |@!uint16_t| */
-#include <stdio.h>
+#include <ctype.h> /* definition of |@!isalpha|, |@!isdigit| and so on */
+#include <stdbool.h> /* definition of |@!bool|, |@!true| and |@!false| */
+#include <stddef.h> /* definition of |@!ptrdiff_t| */
+#include <stdint.h> /* definition of |@!uint8_t| and |@!uint16_t| */
+#include <stdlib.h> /* definition of |@!getenv| and |@!exit| */
+#include <stdio.h> /* definition of |@!printf| and friends */
+#include <string.h> /* definition of |@!strlen|, |@!strcmp| and so on */
 
 @ Code related to the character set:
 @^ASCII code dependencies@>
@@ -84,13 +89,12 @@
 @d minus_gt_ast 027 /* `\.{->*}'\,;  corresponds to MIT's {\tentex\char'27} */
 
 @<Common code...@>=
-extern char section_text[]; /* name being sought for */
+extern char section_text[]; /* text being sought for */
 extern char *section_text_end; /* end of |section_text| */
 extern char *id_first; /* where the current identifier begins in the buffer */
 extern char *id_loc; /* just after the current identifier in the buffer */
 
 @ Code related to input routines:
-
 @d xisalpha(c) (isalpha((eight_bits)c)&&((eight_bits)c<0200))
 @d xisdigit(c) (isdigit((eight_bits)c)&&((eight_bits)c<0200))
 @d xisspace(c) (isspace((eight_bits)c)&&((eight_bits)c<0200))
@@ -101,7 +105,7 @@
 @<Common code...@>=
 extern char buffer[]; /* where each line of input goes */
 extern char *buffer_end; /* end of |buffer| */
-extern char *loc; /* points to the next character to be read from the buffer*/
+extern char *loc; /* points to the next character to be read from the buffer */
 extern char *limit; /* points to the last character in the buffer */
 
 @ Code related to identifier and section name storage:
@@ -135,6 +139,8 @@
 extern name_pointer hash[]; /* heads of hash lists */
 extern hash_pointer hash_end; /* end of |hash| */
 extern hash_pointer h; /* index into hash-head array */
+
+@ @<Predecl...@>=
 extern boolean names_match(name_pointer,const char *,size_t,eight_bits);@/
 extern name_pointer id_lookup(const char *,const char *,char);
    /* looks up a string in the identifier table */
@@ -153,9 +159,12 @@
 @d mark_harmless {if (history==spotless) history=harmless_message;}
 @d mark_error history=error_message
 @d confusion(s) fatal(_("! This can't happen: "),s)
+ at .This can't happen@>
 
-@<Common...@>=
+@<Common code...@>=
 extern int history; /* indicates how bad this run was */
+
+@ @<Predecl...@>=
 extern int wrap_up(void); /* indicate |history| and exit */
 extern void err_print(const char *); /* print error message and context */
 extern void fatal(const char *,const char *); /* issue error message and die */
@@ -163,11 +172,14 @@
 
 @ Code related to file handling:
 @f line x /* make |line| an unreserved word */
+ at d max_include_depth 10 /* maximum number of source files open
+  simultaneously, not counting the change file */
 @d max_file_name_length 1024
 @d cur_file file[include_depth] /* current file */
 @d cur_file_name file_name[include_depth] /* current file name */
+ at d cur_line line[include_depth] /* number of current line in current file */
+ at d web_file file[0] /* main source file */
 @d web_file_name file_name[0] /* main source file name */
- at d cur_line line[include_depth] /* number of current line in current file */
 
 @<Common code...@>=
 extern int include_depth; /* current level of nesting */
@@ -177,10 +189,10 @@
 extern char tex_file_name[]; /* name of |tex_file| */
 extern char idx_file_name[]; /* name of |idx_file| */
 extern char scn_file_name[]; /* name of |scn_file| */
-extern char check_file_name[]; /* name of |check_file| */
 extern char file_name[][max_file_name_length];
   /* stack of non-change file names */
 extern char change_file_name[]; /* name of change file */
+extern char check_file_name[]; /* name of |check_file| */
 extern int line[]; /* number of current line in the stacked files */
 extern int change_line; /* number of current line in change file */
 extern int change_depth; /* where \.{@@y} originated during a change */
@@ -187,6 +199,8 @@
 extern boolean input_has_ended; /* if there is no more input */
 extern boolean changing; /* if the current line is from |change_file| */
 extern boolean web_file_open; /* if the web file is being read */
+
+@ @<Predecl...@>=
 extern boolean get_line(void); /* inputs the next line */
 extern void check_complete(void); /* checks that all changes were picked up */
 extern void reset_input(void); /* initialize to read the web file and change file */
@@ -201,6 +215,7 @@
 @ Code related to command line arguments:
 @d show_banner flags['b'] /* should the banner line be printed? */
 @d show_progress flags['p'] /* should progress reports be printed? */
+ at d show_stats flags['s'] /* should statistics be printed at end of run? */
 @d show_happiness flags['h'] /* should lack of errors be announced? */
 @d temporary_output flags['t'] /* should temporary output take precedence? */
 @d make_xrefs flags['x'] /* should cross references be output? */
@@ -209,6 +224,7 @@
 extern int argc; /* copy of |ac| parameter to |main| */
 extern char **argv; /* copy of |av| parameter to |main| */
 extern boolean flags[]; /* an option for each 7-bit code */
+extern const char *use_language; /* prefix to \.{cwebmac.tex} in \TEX/ output */
 
 @ Code relating to output:
 @d update_terminal fflush(stdout) /* empty the terminal output buffer */
@@ -215,7 +231,7 @@
 @d new_line putchar('\n') @d putxchar putchar
 @d term_write(a,b) fflush(stdout),fwrite(a,sizeof(char),b,stdout)
 @d C_printf(c,a) fprintf(C_file,c,a)
- at d C_putc(c) putc(c,C_file)
+ at d C_putc(c) putc(c,C_file) /* isn't \CEE/ wonderfully consistent? */
 
 @<Common code...@>=
 extern FILE *C_file; /* where output of \.{CTANGLE} goes */
@@ -222,12 +238,29 @@
 extern FILE *tex_file; /* where output of \.{CWEAVE} goes */
 extern FILE *idx_file; /* where index from \.{CWEAVE} goes */
 extern FILE *scn_file; /* where list of sections from \.{CWEAVE} goes */
+extern FILE *active_file; /* currently active file for \.{CWEAVE} output */
 extern FILE *check_file; /* temporary output file */
-extern FILE *active_file; /* currently active file for \.{CWEAVE} output */
 
 @ The procedure that gets everything rolling:
-
-@<Common code...@>=
+@<Predecl...@>=
 extern void common_init(void);@/
 extern void print_stats(void);@/
 extern void cb_show_banner(void);@/
+
+@ The following parameters were sufficient in the original \.{WEB} to
+handle \TEX/, so they should be sufficient for most applications of
+\.{CWEB}.
+
+ at d max_bytes 1000000 /* the number of bytes in identifiers,
+  index entries, and section names */
+ at d max_toks 1000000 /* number of bytes in compressed \CEE/ code */
+ at d max_names 10239 /* number of identifiers, strings, section names;
+  must be less than 10240 */
+ at d max_sections 4000 /* greater than the total number of sections */
+ at d max_texts 10239 /* number of replacement texts, must be less than 10240 */
+ at d longest_name 10000 /* file and section names and section texts shouldn't be longer than this */
+ at d stack_size 500 /* number of simultaneous levels of macro expansion */
+ at d buf_size 1000 /* for \.{CWEAVE} */
+ at d long_buf_size (buf_size+longest_name) /* for \.{CWEAVE} */
+
+@ End of \.{COMMON} interface.

Modified: branches/stable/source/src/texk/web2c/cwebdir/comm-w32.ch
===================================================================
--- branches/stable/source/src/texk/web2c/cwebdir/comm-w32.ch	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/texk/web2c/cwebdir/comm-w32.ch	2021-02-15 19:17:20 UTC (rev 845)
@@ -35,60 +35,32 @@
 set of programs using the __fastcall convention.
 
 @x
-@<Include files@>=
-#include <ctype.h>
+extern boolean names_match(name_pointer,const char *,size_t,eight_bits);@/
 @y
-@<Include files@>=
-#include <ctype.h>
-#include <string.h>
+extern boolean __cdecl names_match(name_pointer,const char *,size_t,eight_bits);@/
 @z
 
 @x
-@ @<Predec...@>=
-extern int names_match();
+extern void init_p(name_pointer,eight_bits);@/
 @y
-@ @<Predec...@>=
-extern int __cdecl names_match();
+extern void __cdecl init_p(name_pointer,eight_bits);@/
 @z
 
- at x
-@<Pred...@>=
-void init_p();
+ at x section 75
+An omitted change file argument means that |"/dev/null"| should be used,
 @y
-@<Pred...@>=
-void __cdecl init_p();
+An omitted change file argument means that |"NUL"| should be used,
 @z
 
- at x section 69
-An omitted change file argument means that |"/dev/null"| should be used,
+ at x section 76
+  strcpy(change_file_name,"/dev/null");
 @y
-An omitted change file argument means that |"NUL"| should be used,
+  strcpy(change_file_name,"NUL");
 @z
 
- at x section 70 (this change copied from comm-bs.ch, July 94)
+ at x section 76 (this change copied from comm-bs.ch, July 94)
         else if (*s=='/') dot_pos=NULL,name_pos=++s;
 @y
         else if (*s == ':' || *s == '\\' || *s == '/')
 	  dot_pos=NULL,name_pos=++s;
 @z
-
- at x section 70
-  if (found_change<=0) strcpy(change_file_name,"/dev/null");
- at y
-  if (found_change<=0) strcpy(change_file_name,"NUL");
- at z
-
- at x
-@ We predeclare several standard system functions here instead of including
-their system header files, because the names of the header files are not as
-standard as the names of the functions. (For example, some \CEE/ environments
-have \.{<string.h>} where others have \.{<strings.h>}.)
-
-@<Predecl...@>=
-extern int strlen(); /* length of string */
-extern int strcmp(); /* compare strings lexicographically */
-extern char* strcpy(); /* copy one string to another */
-extern int strncmp(); /* compare up to $n$ string characters */
-extern char* strncpy(); /* copy up to $n$ string characters */
- at y
- at z

Modified: branches/stable/source/src/texk/web2c/cwebdir/common.c
===================================================================
--- branches/stable/source/src/texk/web2c/cwebdir/common.c	2021-01-20 18:48:45 UTC (rev 844)
+++ branches/stable/source/src/texk/web2c/cwebdir/common.c	2021-02-15 19:17:20 UTC (rev 845)
@@ -1,23 +1,19 @@
 /*1:*/
-#line 58 "common.w"
+#line 66 "common.w"
 
-/*5:*/
-#line 102 "common.w"
+/*3:*/
+#line 46 "common.h"
 
-#include <ctype.h> 
-
-/*:5*//*8:*/
-#line 165 "common.w"
-
-#include <stdio.h> 
-
-/*:8*//*22:*/
-#line 471 "common.w"
-
+#include <ctype.h>  
+#include <stdbool.h>  
+#include <stddef.h>  
+#include <stdint.h>  
 #include <stdlib.h>  
+#include <stdio.h>  
+#include <string.h>  
 
-/*:22*/
-#line 59 "common.w"
+/*:3*/
+#line 67 "common.w"
 
 #define ctangle 0
 #define cweave 1 \
@@ -28,7 +24,7 @@
 #define plus_plus 013
 #define minus_minus 01
 #define minus_gt 031
-#define not_eq 032
+#define non_eq 032
 #define lt_eq 034
 #define gt_eq 035
 #define eq_eq 036
@@ -38,15 +34,33 @@
 #define period_ast 026
 #define minus_gt_ast 027 \
 
-#define buf_size 100
-#define longest_name 10000
-#define long_buf_size (buf_size+longest_name) 
-#define xisspace(c) (isspace(c) &&((unsigned char) c<0200) ) 
-#define xisupper(c) (isupper(c) &&((unsigned char) c<0200) )  \
+#define xisalpha(c) (isalpha((eight_bits) c) &&((eight_bits) c<0200) ) 
+#define xisdigit(c) (isdigit((eight_bits) c) &&((eight_bits) c<0200) ) 
+#define xisspace(c) (isspace((eight_bits) c) &&((eight_bits) c<0200) ) 

@@ Diff output truncated at 1234567 characters. @@


More information about the pdftex-commits mailing list.