diff options
author | Akira Kakuto <kakuto@fuk.kindai.ac.jp> | 2019-09-29 10:00:12 +0000 |
---|---|---|
committer | Akira Kakuto <kakuto@fuk.kindai.ac.jp> | 2019-09-29 10:00:12 +0000 |
commit | 268dff1b06a01bd6be5f1ae08216c0beff08336c (patch) | |
tree | c8f90365823a9711e674704157dff65babb709b9 | |
parent | ee6ffc65c0eb84ded1fc7d19eeb90a87541f896d (diff) |
xpdf 4.02
git-svn-id: svn://tug.org/texlive/trunk@52203 c570f23f-e606-0410-a88d-b1316a301751
101 files changed, 4326 insertions, 965 deletions
diff --git a/Build/source/libs/README b/Build/source/libs/README index 94bc8899a8d..08341cc7513 100644 --- a/Build/source/libs/README +++ b/Build/source/libs/README @@ -59,7 +59,7 @@ poppler 0.68.0 - checked 20aug18 teckit 2.5.9 - checked 03may19 https://github.com/silnrsi/teckit/archive/2.5.9.tar.gz -xpdf 4.01.01 - checked 03may19 +xpdf 4.02 - checked 29sep19 http://www.xpdfreader.com/download.html with modifications for pdftex diff --git a/Build/source/libs/xpdf/ChangeLog b/Build/source/libs/xpdf/ChangeLog index c27bc8cd203..7b963d2a8ee 100644 --- a/Build/source/libs/xpdf/ChangeLog +++ b/Build/source/libs/xpdf/ChangeLog @@ -1,3 +1,8 @@ +2019-09-29 Akira Kakuto <kakuto@w32tex.org> + + * Import xpdf-4.02. + * version.ac: Adjust. + 2019-05-03 Akira Kakuto <kakuto@w32tex.org> * Import xpdf-4.01.01. diff --git a/Build/source/libs/xpdf/TLpatches/ChangeLog b/Build/source/libs/xpdf/TLpatches/ChangeLog index 4069c13a8fb..50d6fb98c82 100644 --- a/Build/source/libs/xpdf/TLpatches/ChangeLog +++ b/Build/source/libs/xpdf/TLpatches/ChangeLog @@ -1,3 +1,7 @@ +2019-09-29 Akira Kakuto <kakuto@w32tex.org> + + * patch-bunched: Adjust. + 2019-05-03 Akira Kakuto <kakuto@w32tex.org> * patch-bunched: Adjust. diff --git a/Build/source/libs/xpdf/TLpatches/TL-Changes b/Build/source/libs/xpdf/TLpatches/TL-Changes index 15f6253ca51..af5874a4765 100644 --- a/Build/source/libs/xpdf/TLpatches/TL-Changes +++ b/Build/source/libs/xpdf/TLpatches/TL-Changes @@ -1,4 +1,4 @@ -Changes applied to the xpdf-4.01.01/ tree as obtained from: +Changes applied to the xpdf-4.02/ tree as obtained from: http://www.xpdfreader.com/download.html Removed: diff --git a/Build/source/libs/xpdf/TLpatches/patch-bunched b/Build/source/libs/xpdf/TLpatches/patch-bunched index 10885d1ad33..b842eb4d2ef 100644 --- a/Build/source/libs/xpdf/TLpatches/patch-bunched +++ b/Build/source/libs/xpdf/TLpatches/patch-bunched @@ -1,6 +1,6 @@ -diff -ur xpdf-4.01.01/goo/gfile.cc xpdf-src/goo/gfile.cc ---- xpdf-4.01.01/goo/gfile.cc Fri Mar 15 06:01:02 2019 -+++ xpdf-src/goo/gfile.cc Mon Feb 25 11:09:32 2019 +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 @@ -7,6 +7,9 @@ // Copyright 1996-2003 Glyph & Cog, LLC // @@ -11,7 +11,7 @@ diff -ur xpdf-4.01.01/goo/gfile.cc xpdf-src/goo/gfile.cc #include <aconf.h> -@@ -52,7 +55,11 @@ +@@ -54,7 +57,11 @@ char *s; GString *ret; @@ -23,7 +23,7 @@ diff -ur xpdf-4.01.01/goo/gfile.cc xpdf-src/goo/gfile.cc ret = new GString(s); else ret = new GString("."); -@@ -401,6 +408,7 @@ +@@ -403,6 +410,7 @@ #endif } @@ -31,7 +31,7 @@ diff -ur xpdf-4.01.01/goo/gfile.cc xpdf-src/goo/gfile.cc GBool openTempFile(GString **name, FILE **f, const char *mode, const char *ext) { #if defined(_WIN32) -@@ -515,10 +523,11 @@ +@@ -517,10 +525,11 @@ return gTrue; #endif } @@ -44,7 +44,7 @@ diff -ur xpdf-4.01.01/goo/gfile.cc xpdf-src/goo/gfile.cc #else return !mkdir(path, mode); #endif -@@ -572,6 +581,8 @@ +@@ -574,6 +583,8 @@ FILE *openFile(const char *path, const char *mode) { #if defined(_WIN32) @@ -53,7 +53,7 @@ diff -ur xpdf-4.01.01/goo/gfile.cc xpdf-src/goo/gfile.cc OSVERSIONINFO version; wchar_t wPath[_MAX_PATH + 1]; char nPath[_MAX_PATH + 1]; -@@ -628,6 +639,7 @@ +@@ -630,6 +641,7 @@ nPath[i] = '\0'; return fopen(nPath, mode); } @@ -61,7 +61,7 @@ diff -ur xpdf-4.01.01/goo/gfile.cc xpdf-src/goo/gfile.cc #elif defined(VMS) return fopen(path, mode, "ctx=stm"); #else -@@ -688,6 +700,7 @@ +@@ -690,6 +702,7 @@ #endif } @@ -69,15 +69,15 @@ diff -ur xpdf-4.01.01/goo/gfile.cc xpdf-src/goo/gfile.cc void fixCommandLine(int *argc, char **argv[]) { #ifdef _WIN32 int argcw; -@@ -713,3 +726,4 @@ +@@ -715,3 +728,4 @@ LocalFree(argvw); #endif } +#endif /* !PDF_PARSER_ONLY */ -diff -ur xpdf-4.01.01/goo/gfile.h xpdf-src/goo/gfile.h ---- xpdf-4.01.01/goo/gfile.h Fri Mar 15 06:01:02 2019 -+++ xpdf-src/goo/gfile.h Mon Feb 25 11:07:26 2019 -@@ -114,6 +114,8 @@ +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 @@ // On Windows, this gets the Unicode command line and converts it to // UTF-8. On other systems, this is a nop. @@ -86,9 +86,9 @@ diff -ur xpdf-4.01.01/goo/gfile.h xpdf-src/goo/gfile.h +#endif /* !PDF_PARSER_ONLY */ #endif -diff -ur xpdf-4.01.01/xpdf/GlobalParams.cc xpdf-src/xpdf/GlobalParams.cc ---- xpdf-4.01.01/xpdf/GlobalParams.cc Fri Mar 15 06:01:02 2019 -+++ xpdf-src/xpdf/GlobalParams.cc Mon Feb 25 08:01:11 2019 +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 @@ -5,6 +5,9 @@ // Copyright 2001-2003 Glyph & Cog, LLC // @@ -99,7 +99,7 @@ diff -ur xpdf-4.01.01/xpdf/GlobalParams.cc xpdf-src/xpdf/GlobalParams.cc #include <aconf.h> -@@ -39,8 +42,12 @@ +@@ -44,8 +47,12 @@ #include "GlobalParams.h" #ifdef _WIN32 @@ -114,7 +114,7 @@ diff -ur xpdf-4.01.01/xpdf/GlobalParams.cc xpdf-src/xpdf/GlobalParams.cc #endif #if MULTITHREADED -@@ -684,6 +691,7 @@ +@@ -803,6 +810,7 @@ f = NULL; fileName = NULL; if (cfgFileName && cfgFileName[0]) { @@ -122,7 +122,7 @@ diff -ur xpdf-4.01.01/xpdf/GlobalParams.cc xpdf-src/xpdf/GlobalParams.cc fileName = new GString(cfgFileName); if (!(f = fopen(fileName->getCString(), "r"))) { delete fileName; -@@ -716,6 +724,7 @@ +@@ -835,6 +843,7 @@ parseFile(fileName, f); delete fileName; fclose(f); @@ -130,7 +130,7 @@ diff -ur xpdf-4.01.01/xpdf/GlobalParams.cc xpdf-src/xpdf/GlobalParams.cc } } -@@ -2092,8 +2101,11 @@ +@@ -2265,8 +2274,11 @@ base14->fontNum, displayFontTab[i].obliqueFactor)); } else { @@ -142,9 +142,9 @@ diff -ur xpdf-4.01.01/xpdf/GlobalParams.cc xpdf-src/xpdf/GlobalParams.cc } } } -diff -ur xpdf-4.01.01/xpdf/GlobalParams.h xpdf-src/xpdf/GlobalParams.h ---- xpdf-4.01.01/xpdf/GlobalParams.h Fri Mar 15 06:01:02 2019 -+++ xpdf-src/xpdf/GlobalParams.h Mon Feb 25 08:02:36 2019 +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 @@ -5,6 +5,9 @@ // Copyright 2001-2003 Glyph & Cog, LLC // @@ -155,7 +155,7 @@ diff -ur xpdf-4.01.01/xpdf/GlobalParams.h xpdf-src/xpdf/GlobalParams.h #ifndef GLOBALPARAMS_H #define GLOBALPARAMS_H -@@ -218,7 +221,7 @@ +@@ -219,7 +222,7 @@ // Initialize the global parameters by attempting to read a config // file. @@ -164,10 +164,10 @@ diff -ur xpdf-4.01.01/xpdf/GlobalParams.h xpdf-src/xpdf/GlobalParams.h ~GlobalParams(); -diff -ur xpdf-4.01.01/xpdf/PDFDoc.cc xpdf-src/xpdf/PDFDoc.cc ---- xpdf-4.01.01/xpdf/PDFDoc.cc Fri Mar 15 06:01:02 2019 -+++ xpdf-src/xpdf/PDFDoc.cc Sun Mar 17 08:59:43 2019 -@@ -147,20 +147,25 @@ +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 @@ PDFDoc::PDFDoc(char *fileNameA, GString *ownerPassword, GString *userPassword, PDFCore *coreA) { @@ -193,20 +193,19 @@ diff -ur xpdf-4.01.01/xpdf/PDFDoc.cc xpdf-src/xpdf/PDFDoc.cc n = 0; i = 0; while (getUTF8(fileName, &i, &u)) { -@@ -178,8 +183,12 @@ +@@ -187,8 +192,11 @@ if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) { - file = _wfopen(fileNameU, L"rb"); + file = _wfopen(fileNameU, wfopenReadMode); } else { +#endif /* 0 */ - file = fopen(fileName->getCString(), "rb"); + file = fopen(fileName->getCString(), fopenReadMode); +#if 0 } +#endif /* 0 */ -+ #elif defined(VMS) - file = fopen(fileName->getCString(), "rb", "ctx=stm"); + file = fopen(fileName->getCString(), fopenReadMode, "ctx=stm"); #else -@@ -572,6 +581,7 @@ +@@ -581,6 +589,7 @@ GBool ret; // NB: _wfopen is only available in NT @@ -214,7 +213,7 @@ diff -ur xpdf-4.01.01/xpdf/PDFDoc.cc xpdf-src/xpdf/PDFDoc.cc version.dwOSVersionInfoSize = sizeof(version); GetVersionEx(&version); if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) { -@@ -581,12 +591,15 @@ +@@ -590,12 +599,15 @@ path2w[i] = 0; f = _wfopen(path2w, L"wb"); } else { @@ -230,9 +229,9 @@ diff -ur xpdf-4.01.01/xpdf/PDFDoc.cc xpdf-src/xpdf/PDFDoc.cc if (!f) { return gFalse; } -diff -ur xpdf-4.01.01/xpdf/Page.cc xpdf-src/xpdf/Page.cc ---- xpdf-4.01.01/xpdf/Page.cc Fri Mar 15 06:01:02 2019 -+++ xpdf-src/xpdf/Page.cc Mon Feb 25 08:19:00 2019 +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 @@ delete links; } @@ -251,10 +250,10 @@ diff -ur xpdf-4.01.01/xpdf/Page.cc xpdf-src/xpdf/Page.cc -} #endif +} -diff -ur xpdf-4.01.01/xpdf/XFAForm.cc xpdf-src/xpdf/XFAForm.cc ---- xpdf-4.01.01/xpdf/XFAForm.cc Fri Mar 15 06:01:02 2019 -+++ xpdf-src/xpdf/XFAForm.cc Mon Feb 25 08:20:00 2019 -@@ -28,8 +28,10 @@ +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 @@ -267,9 +266,9 @@ diff -ur xpdf-4.01.01/xpdf/XFAForm.cc xpdf-src/xpdf/XFAForm.cc #endif //------------------------------------------------------------------------ -diff -ur xpdf-4.01.01/xpdf/config.h xpdf-src/xpdf/config.h ---- xpdf-4.01.01/xpdf/config.h Fri Mar 15 06:01:02 2019 -+++ xpdf-src/xpdf/config.h Sun Mar 17 16:09:03 2019 +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 @@ // popen //------------------------------------------------------------------------ diff --git a/Build/source/libs/xpdf/configure b/Build/source/libs/xpdf/configure index 4c19707f4cf..f4f5004df77 100755 --- a/Build/source/libs/xpdf/configure +++ b/Build/source/libs/xpdf/configure @@ -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.01.01. +# Generated by GNU Autoconf 2.69 for xpdf (TeX Live) 4.02. # # Report bugs to <tex-k@tug.org>. # @@ -580,8 +580,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='xpdf (TeX Live)' PACKAGE_TARNAME='xpdf--tex-live-' -PACKAGE_VERSION='4.01.01' -PACKAGE_STRING='xpdf (TeX Live) 4.01.01' +PACKAGE_VERSION='4.02' +PACKAGE_STRING='xpdf (TeX Live) 4.02' PACKAGE_BUGREPORT='tex-k@tug.org' PACKAGE_URL='' @@ -1290,7 +1290,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures xpdf (TeX Live) 4.01.01 to adapt to many kinds of systems. +\`configure' configures xpdf (TeX Live) 4.02 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1356,7 +1356,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of xpdf (TeX Live) 4.01.01:";; + short | recursive ) echo "Configuration of xpdf (TeX Live) 4.02:";; esac cat <<\_ACEOF @@ -1460,7 +1460,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -xpdf (TeX Live) configure 4.01.01 +xpdf (TeX Live) configure 4.02 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1867,7 +1867,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by xpdf (TeX Live) $as_me 4.01.01, which was +It was created by xpdf (TeX Live) $as_me 4.02, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -3791,7 +3791,7 @@ fi # Define the identity of the package. PACKAGE='xpdf--tex-live-' - VERSION='4.01.01' + VERSION='4.02' # Some tools Automake needs. @@ -6704,7 +6704,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by xpdf (TeX Live) $as_me 4.01.01, which was +This file was extended by xpdf (TeX Live) $as_me 4.02, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -6774,7 +6774,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -xpdf (TeX Live) config.status 4.01.01 +xpdf (TeX Live) config.status 4.02 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/Build/source/libs/xpdf/version.ac b/Build/source/libs/xpdf/version.ac index 0a757d708db..71f3a1da85d 100644 --- a/Build/source/libs/xpdf/version.ac +++ b/Build/source/libs/xpdf/version.ac @@ -8,4 +8,4 @@ dnl dnl -------------------------------------------------------- dnl dnl m4-include this file to define the current xpdf version -m4_define([xpdf_version], [4.01.01]) +m4_define([xpdf_version], [4.02]) diff --git a/Build/source/libs/xpdf/xpdf-src/ANNOUNCE b/Build/source/libs/xpdf/xpdf-src/ANNOUNCE index 67ef1bad48b..025303c44de 100644 --- a/Build/source/libs/xpdf/xpdf-src/ANNOUNCE +++ b/Build/source/libs/xpdf/xpdf-src/ANNOUNCE @@ -1,25 +1,27 @@ -Subject: ANNOUNCE: Xpdf 4.01 - a PDF viewer and related tools +Subject: ANNOUNCE: Xpdf 4.02 - 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 also includes a PDF text extractor, PDF-to-PostScript converter, and various other utilities. -*** The Xpdf web site has moved to www.xpdfreader.com *** - Xpdf uses the Qt toolkit and runs on Linux and Windows. The non-graphical components (pdftops, pdftotext, etc.) run on Linux, Unix, Windows, MacOSX, and pretty much any other system with a decent C++ compiler. -4.01 is primarily a bug fix release. There are some new features: -* Added remote server mode back into xpdf. -* Added support for Unicode file names for the command line tools on - Windows. -* Added the tabStateFile setting, the saveTabState/loadTabState - commands, and the "-tabstate" switch to xpdf. [Thanks to Christian - Barthel for the suggestion.] -* Added the defaultPrinter xpdfrc setting. +4.02 is primarily a bug fix release. There are some new features: + +* Pdftohtml now extracts embedded fonts. + +* 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. + +* 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. diff --git a/Build/source/libs/xpdf/xpdf-src/CHANGES b/Build/source/libs/xpdf/xpdf-src/CHANGES index 0114145987c..e707ff01afa 100644 --- a/Build/source/libs/xpdf/xpdf-src/CHANGES +++ b/Build/source/libs/xpdf/xpdf-src/CHANGES @@ -2550,3 +2550,99 @@ If the "U" string used for RC4 decryption is short, Adobe apparently Pdffonts now checks more carefully for loops between objects. Fixed a problem parsing large real numbers. [Thanks to Loginsoft for the bug report.] + +4.02 (2019-sep-25) +------------------ +Pdftohtml now extracts embedded fonts (TrueType and CFF only). +Added the margin settings (-marginl -marginr -margint -marginb) to + pdftotext. +Various user interface tweaks: + - added a toolbar button to toggle (show/hide) the sidebar + - added view menu items to toggle (show/hide) the sidebar and + toolbar + - added the 'showToolbar', 'hideToolbar', 'toggleToolbar', + 'expandSidebar', and 'shrinkSidebar' commands + - added the 'initialDisplayMode', 'initialToolbarState', and + 'initialSelectMode' xpdfrc settings + - rearranged the xpdf toolbar +Implemented drag-and-drop, so that PDF files can be drag-and-dropped + onto an already-open xpdf window. +Added the option to display page labels, rather than page numbers. +Implemented the missing 'openInNewWin' command. +Added the 'openFileIn', 'openFileAtDestIn', 'openFileAtPageIn', and + 'openIn' commands; removed the 'openInNewWin' command. +Added the '-open' switch to xpdf. +Added the reverseVideoInvertImages setting. +Page-up and page-down now "snap" to the nearest page, if it's within a + few pixels. This avoids annoying behavior when the window is a tiny + bit too short or too tall for a page. +Properly handle overprint in non-isolated transparency groups. +Missing null check in Gfx::opSetExtGState(). [Thanks to + pwd@360TeamSeri0us for the bug report.] +The DCT decoder doesn't handle a sampling factor of 3 -- check for + this and report an error. [Thanks for Agostino Sarubbo of Gentoo + for the bug report.] +Check for images with a Pattern color space, and report an error. + [Thanks to TeamSeri0us for the bug report.] +Check that the Width, Height, and BitsPerComponent are valid in image + soft masks. [Thanks to TeamSeri0us for the bug report.] +Check for zero page width/height in PSOutputDev. [Thanks to + TeamSeri0us for the bug report.] +Check for divide-by-zero in PostScript functions. [Thanks to + TeamSeri0us for the bug report.] +Properly handle overprint in shading pattern strokes. +The "save image" feature in Xpdf wasn't getting the user-specified + page number correctly. +PostScript doesn't support progressive or non-interleaved DCT (JPEG) + streams, so check for those and re-encode them in PS output. +Splash now caches the most recent scaled image, in case it is + immediately reused -- this results in a significant speedup in + certain cases. +Fixed a problem with parsing the TrueType loca table. [Thanks to + Pangu Lab for the bug report.] +Fixed a problem with int overflow on image bounds. [Thanks to + Pangu Lab for the bug report.] +Fixed a problem with TrueType font parsing where there is gibberish in + the TrueType table directory. [Thanks to Pangu Lab for the bug + report.] +Fixed a problem with JPX image resolution reduction. [Thanks to Pangu + Lab for the bug report.] +Fixed a problem with non-isolated transparency groups in 1-bit + monochrome mode. [Thanks to Pangu Lab for the bug report.] +Fixed various bugs in FoFi. [Thanks to Pangu Lab for the bug + reports.] +Added a missing bounds check to Annot::setFillColor(). [Thanks to + Pangu Lab for the bug report.] +Added a check on the DCT quant table selector. [Thanks to Pangu Lab + for the bug report.] +Fixed a problem with the Type 3 font cache running out of entries. + [Thanks to Pangu Lab for the bug report.] +Fixed an integer overflow bug in SampledFunction. [Thanks to Pangu + Lab for the bug report.] +Fixed an integer overflow bug in the tiling pattern size. [Thanks to + Martin Muskens at Ergosoft for the bug report.] +Fixed a read-past-end-of-buffer in the Type 1 font parser. [Thanks to + Pangu Lab for the bug report.] +Fixed an int overflow bug in the JBIG2 decoder. [Thanks to + TeamSeri0us for the bug report.] +Added a missing bounds check to GfxPatchMeshShading::parse(). [Thanks + to TeamSeri0us for the bug report.] +JPEG 2000 tile indexes were being computed incorrectly. [Thanks to + TeamSeri0us for the bug report.] +Large sample separation values in a JPX stream were resulting in + zero-width/height tiles, which caused problems. [Thanks to Pangu + Lab for the bug report.] +The XFA parser now looks for "ancestor matches" when searching for + data to fill a form field. +Fixed an uninitialized variable in BuiltinFontWidths::getWidth(). + [Thanks to Martin Muskens at Ergosoft for the bug report.] +If there are no popupMenuCmd instances, construct a popup menu with + basic instructions pointing to 'popupMenuCmd'. +Ignore color operators in uncolored tiling patterns. [Thanks to + Martin Muskens at Ergosoft for the bug report.] +Pdftotext raw mode output looks for space characters. +Increased the width of the font name column in the pdffonts output. +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.] diff --git a/Build/source/libs/xpdf/xpdf-src/INSTALL b/Build/source/libs/xpdf/xpdf-src/INSTALL index f45ce6bad37..b7e184538c8 100644 --- a/Build/source/libs/xpdf/xpdf-src/INSTALL +++ b/Build/source/libs/xpdf/xpdf-src/INSTALL @@ -1,8 +1,8 @@ Xpdf ==== -version 4.01.01 -2019-mar-14 +version 4.02 +2019-sep-25 The Xpdf software and documentation are copyright 1996-2019 Glyph & Cog, LLC. @@ -97,6 +97,11 @@ different systems. Enables support for generation of OPI (Open Prepress Interface) comments with pdftops. + -DNO_FONTCONFIG=ON + Disables use of libfontconfig, which is used to locate system + fonts on Linux/Unix systems. The default is to search for the + library, and to use it if found. + -DMULTITHREADED=0 Disables multithreading, which also disables building the GUI viewer (xpdf). This does not affect the command line tools. @@ -104,13 +109,18 @@ different systems. building with a compiler other than gcc, clang, or Microsoft Visual Studio. + -DXPDFWIDGET_PRINTING=OFF + Disable printing support. + -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 Do not search for the Qt4/Qt5 libraries. This will disable - building the GUI viewer (xpdf). + 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="..." diff --git a/Build/source/libs/xpdf/xpdf-src/README b/Build/source/libs/xpdf/xpdf-src/README index 25e4f110eba..ebecfe97c3e 100644 --- a/Build/source/libs/xpdf/xpdf-src/README +++ b/Build/source/libs/xpdf/xpdf-src/README @@ -1,8 +1,8 @@ Xpdf ==== -version 4.01.01 -2019-mar-14 +version 4.02 +2019-sep-25 The Xpdf software and documentation are copyright 1996-2019 Glyph & Cog, LLC. diff --git a/Build/source/libs/xpdf/xpdf-src/aconf2.h b/Build/source/libs/xpdf/xpdf-src/aconf2.h index 8bef688075d..05d785c274a 100644 --- a/Build/source/libs/xpdf/xpdf-src/aconf2.h +++ b/Build/source/libs/xpdf/xpdf-src/aconf2.h @@ -28,4 +28,14 @@ # endif #endif +/* + * Speed up Windows compilation. This will only work for the command + * line tools. + */ +/* + *#ifdef _WIN32 + *# define WIN32_LEAN_AND_MEAN + *#endif + */ + #endif diff --git a/Build/source/libs/xpdf/xpdf-src/cmake-config.txt b/Build/source/libs/xpdf/xpdf-src/cmake-config.txt index 1fbd6e59eb6..3fe2faf125c 100644 --- a/Build/source/libs/xpdf/xpdf-src/cmake-config.txt +++ b/Build/source/libs/xpdf/xpdf-src/cmake-config.txt @@ -81,6 +81,7 @@ option(MULTITHREADED "include support for multithreading" ON) option(USE_EXCEPTIONS "use C++ exceptions" ON) option(USE_FIXEDPOINT "use fixed point (instead of floating point) arithmetic" OFF) option(SPLASH_CMYK "include support for CMYK rasterization" OFF) +option(NO_FONTCONFIG "disable support for libfontconfig" OFF) option(SYSTEM_XPDFRC "full path for system-wide xpdfrc file" "") if (SYSTEM_XPDFRC) set(SYSTEM_XPDFRC_DEFINE "#define SYSTEM_XPDFRC \"${SYSTEM_XPDFRC}\"") @@ -193,20 +194,14 @@ if (Qt5Widgets_FOUND) find_package(Qt5Network) find_package(Qt5PrintSupport) else () - find_package(Qt4) + find_package(Qt4 COMPONENTS QtCore QtGui QtNetwork REQUIRED) endif () if(Qt5Widgets_FOUND) message(STATUS "Qt5 found") if (XPDFWIDGET_PRINTING) set(QT_INCLUDES "${Qt5Widgets_INCLUDE_DIRS} ${Qt5Network_INCLUDE_DIRS} ${Qt5PrintSupport_INCLUDE_DIRS}") set(QT_DEFINITIONS "${Qt5Widgets_DEFINITIONS} ${Qt5Network_DEFINITIONS} ${Qt5PrintSupport_DEFINITIONS}") - if (APPLE) - set(QT_LIBRARIES Qt5::Widgets Qt5::Network Qt5::PrintSupport "-framework ApplicationServices") - elseif (UNIX) - set(QT_LIBRARIES Qt5::Widgets Qt5::Network Qt5::PrintSupport cups) - else () - set(QT_LIBRARIES Qt5::Widgets Qt5::Network Qt5::PrintSupport) - endif () + set(QT_LIBRARIES Qt5::Widgets Qt5::Network Qt5::PrintSupport) else () set(QT_INCLUDES "${Qt5Widgets_INCLUDE_DIRS} ${Qt5Network_INCLUDE_DIRS}") set(QT_DEFINITIONS "${Qt5Widgets_DEFINITIONS} ${Qt5Network_DEFINITIONS}") @@ -216,7 +211,12 @@ if(Qt5Widgets_FOUND) if (APPLE) set(EXTRA_QT_LIBRARIES "-framework ApplicationServices") elseif (UNIX) - set(EXTRA_QT_LIBRARIES cups) + find_package(Cups) + if (CUPS_FOUND) + set(EXTRA_QT_LIBRARIES ${CUPS_LIBRARIES}) + else () + set (XPDFWIDGET_PRINTING OFF) + endif () else () set(EXTRA_QT_LIBRARIES "") endif () @@ -229,7 +229,12 @@ elseif(QT4_FOUND) if (APPLE) set(EXTRA_QT_LIBRARIES "-framework ApplicationServices") elseif (UNIX) - set(EXTRA_QT_LIBRARIES cups) + find_package(Cups) + if (CUPS_FOUND) + set(EXTRA_QT_LIBRARIES ${CUPS_LIBRARIES}) + else () + set (XPDFWIDGET_PRINTING OFF) + endif () else () set(EXTRA_QT_LIBRARIES "") endif () @@ -250,8 +255,30 @@ else () set(PAPER_LIBRARY "") endif () +#--- look for fontconfig +if (NOT NO_FONTCONFIG) + find_library(FONTCONFIG_LIBRARY + NAMES fontconfig libfontconfig + PATH_SUFFIXES lib64 lib + ) + if (FONTCONFIG_LIBRARY) + set(HAVE_FONTCONFIG TRUE) + message(STATUS "Found fontconfig") + else () + set(HAVE_FONTCONFIG FALSE) + set(FONTCONFIG_LIBRARY "") + endif () +else () + set(HAVE_FONTCONFIG FALSE) + set(FONTCONFIG_LIBRARY "") +endif () + #--- look for pthreads -find_package(Threads) +if (MULTITHREADED) + find_package(Threads) +else () + set(CMAKE_THREAD_LIBS_INIT "") +endif () #--- create aconf.h configure_file("aconf.h.in" "aconf.h") diff --git a/Build/source/libs/xpdf/xpdf-src/doc/pdfdetach.1 b/Build/source/libs/xpdf/xpdf-src/doc/pdfdetach.1 index bed56b58b56..82497df84fc 100644 --- a/Build/source/libs/xpdf/xpdf-src/doc/pdfdetach.1 +++ b/Build/source/libs/xpdf/xpdf-src/doc/pdfdetach.1 @@ -1,8 +1,8 @@ .\" Copyright 2013-2019 Glyph & Cog, LLC -.TH pdfdetach 1 "18 Feb 2019" +.TH pdfdetach 1 "25 Sep 2019" .SH NAME pdfdetach \- Portable Document Format (PDF) document embedded file -extractor (version 4.01) +extractor (version 4.02) .SH SYNOPSIS .B pdfdetach [options] diff --git a/Build/source/libs/xpdf/xpdf-src/doc/pdfdetach.cat b/Build/source/libs/xpdf/xpdf-src/doc/pdfdetach.cat index 30fc3ce53ed..3d4b026e701 100644 --- a/Build/source/libs/xpdf/xpdf-src/doc/pdfdetach.cat +++ b/Build/source/libs/xpdf/xpdf-src/doc/pdfdetach.cat @@ -4,7 +4,7 @@ pdfdetach(1) General Commands Manual pdfdetach(1) NAME pdfdetach - Portable Document Format (PDF) document embedded file - extractor (version 4.01) + extractor (version 4.02) SYNOPSIS pdfdetach [options] [PDF-file] @@ -89,4 +89,4 @@ SEE ALSO - 18 Feb 2019 pdfdetach(1) + 25 Sep 2019 pdfdetach(1) diff --git a/Build/source/libs/xpdf/xpdf-src/doc/pdffonts.1 b/Build/source/libs/xpdf/xpdf-src/doc/pdffonts.1 index c57ce66706e..b8ffaa22b2b 100644 --- a/Build/source/libs/xpdf/xpdf-src/doc/pdffonts.1 +++ b/Build/source/libs/xpdf/xpdf-src/doc/pdffonts.1 @@ -1,8 +1,8 @@ .\" Copyright 1999-2019 Glyph & Cog, LLC -.TH pdffonts 1 "18 Feb 2019" +.TH pdffonts 1 "25 Sep 2019" .SH NAME pdffonts \- Portable Document Format (PDF) font analyzer (version -4.01) +4.02) .SH SYNOPSIS .B pdffonts [options] diff --git a/Build/source/libs/xpdf/xpdf-src/doc/pdffonts.cat b/Build/source/libs/xpdf/xpdf-src/doc/pdffonts.cat index a1dab79714d..363699cf1c5 100644 --- a/Build/source/libs/xpdf/xpdf-src/doc/pdffonts.cat +++ b/Build/source/libs/xpdf/xpdf-src/doc/pdffonts.cat @@ -3,7 +3,7 @@ pdffonts(1) General Commands Manual pdffonts(1) NAME - pdffonts - Portable Document Format (PDF) font analyzer (version 4.01) + pdffonts - Portable Document Format (PDF) font analyzer (version 4.02) SYNOPSIS pdffonts [options] [PDF-file] @@ -115,4 +115,4 @@ SEE ALSO - 18 Feb 2019 pdffonts(1) + 25 Sep 2019 pdffonts(1) diff --git a/Build/source/libs/xpdf/xpdf-src/doc/pdfimages.1 b/Build/source/libs/xpdf/xpdf-src/doc/pdfimages.1 index cc16c197d90..bef93eeaba8 100644 --- a/Build/source/libs/xpdf/xpdf-src/doc/pdfimages.1 +++ b/Build/source/libs/xpdf/xpdf-src/doc/pdfimages.1 @@ -1,8 +1,8 @@ .\" Copyright 1998-2019 Glyph & Cog, LLC -.TH pdfimages 1 "18 Feb 2019" +.TH pdfimages 1 "25 Sep 2019" .SH NAME pdfimages \- Portable Document Format (PDF) image extractor -(version 4.01) +(version 4.02) .SH SYNOPSIS .B pdfimages [options] diff --git a/Build/source/libs/xpdf/xpdf-src/doc/pdfimages.cat b/Build/source/libs/xpdf/xpdf-src/doc/pdfimages.cat index 0830f1d86e8..74b7ace12d0 100644 --- a/Build/source/libs/xpdf/xpdf-src/doc/pdfimages.cat +++ b/Build/source/libs/xpdf/xpdf-src/doc/pdfimages.cat @@ -4,7 +4,7 @@ pdfimages(1) General Commands Manual pdfimages(1) NAME pdfimages - Portable Document Format (PDF) image extractor (version - 4.01) + 4.02) SYNOPSIS pdfimages [options] PDF-file image-root @@ -95,4 +95,4 @@ SEE ALSO - 18 Feb 2019 pdfimages(1) + 25 Sep 2019 pdfimages(1) diff --git a/Build/source/libs/xpdf/xpdf-src/doc/pdfinfo.1 b/Build/source/libs/xpdf/xpdf-src/doc/pdfinfo.1 index 9811ac01b96..c095e88bbfa 100644 --- a/Build/source/libs/xpdf/xpdf-src/doc/pdfinfo.1 +++ b/Build/source/libs/xpdf/xpdf-src/doc/pdfinfo.1 @@ -1,8 +1,8 @@ .\" Copyright 1999-2019 Glyph & Cog, LLC -.TH pdfinfo 1 "18 Feb 2019" +.TH pdfinfo 1 "25 Sep 2019" .SH NAME pdfinfo \- Portable Document Format (PDF) document information -extractor (version 4.01) +extractor (version 4.02) .SH SYNOPSIS .B pdfinfo [options] diff --git a/Build/source/libs/xpdf/xpdf-src/doc/pdfinfo.cat b/Build/source/libs/xpdf/xpdf-src/doc/pdfinfo.cat index 6fce0425b7c..1f2ed6bd637 100644 --- a/Build/source/libs/xpdf/xpdf-src/doc/pdfinfo.cat +++ b/Build/source/libs/xpdf/xpdf-src/doc/pdfinfo.cat @@ -4,7 +4,7 @@ pdfinfo(1) General Commands Manual pdfinfo(1) NAME pdfinfo - Portable Document Format (PDF) document information extractor - (version 4.01) + (version 4.02) SYNOPSIS pdfinfo [options] [PDF-file] @@ -114,4 +114,4 @@ SEE ALSO - 18 Feb 2019 pdfinfo(1) + 25 Sep 2019 pdfinfo(1) diff --git a/Build/source/libs/xpdf/xpdf-src/doc/pdftohtml.1 b/Build/source/libs/xpdf/xpdf-src/doc/pdftohtml.1 index 5217b268d0a..f37bf5c4424 100644 --- a/Build/source/libs/xpdf/xpdf-src/doc/pdftohtml.1 +++ b/Build/source/libs/xpdf/xpdf-src/doc/pdftohtml.1 @@ -1,8 +1,8 @@ .\" Copyright 1997-2019 Glyph & Cog, LLC -.TH pdftohtml 1 "18 Feb 2019" +.TH pdftohtml 1 "25 Sep 2019" .SH NAME pdftohtml \- Portable Document Format (PDF) to HTML converter -(version 4.01) +(version 4.02) .SH SYNOPSIS .B pdftohtml [options] diff --git a/Build/source/libs/xpdf/xpdf-src/doc/pdftohtml.cat b/Build/source/libs/xpdf/xpdf-src/doc/pdftohtml.cat index d29a01ecdad..5f3a0bb8fad 100644 --- a/Build/source/libs/xpdf/xpdf-src/doc/pdftohtml.cat +++ b/Build/source/libs/xpdf/xpdf-src/doc/pdftohtml.cat @@ -4,7 +4,7 @@ pdftohtml(1) General Commands Manual pdftohtml(1) NAME pdftohtml - Portable Document Format (PDF) to HTML converter (version - 4.01) + 4.02) SYNOPSIS pdftohtml [options] PDF-file HTML-dir @@ -107,4 +107,4 @@ SEE ALSO - 18 Feb 2019 pdftohtml(1) + 25 Sep 2019 pdftohtml(1) diff --git a/Build/source/libs/xpdf/xpdf-src/doc/pdftopng.1 b/Build/source/libs/xpdf/xpdf-src/doc/pdftopng.1 index 5d9cd44a7e7..c0745ced65b 100644 --- a/Build/source/libs/xpdf/xpdf-src/doc/pdftopng.1 +++ b/Build/source/libs/xpdf/xpdf-src/doc/pdftopng.1 @@ -1,8 +1,8 @@ .\" Copyright 2017-2019 Glyph & Cog, LLC -.TH pdftopng 1 "18 Feb 2019" +.TH pdftopng 1 "25 Sep 2019" .SH NAME pdftopng \- Portable Document Format (PDF) to Portable Network Graphics -(PNG) converter (version 4.01) +(PNG) converter (version 4.02) .SH SYNOPSIS .B pdftopng [options] diff --git a/Build/source/libs/xpdf/xpdf-src/doc/pdftopng.cat b/Build/source/libs/xpdf/xpdf-src/doc/pdftopng.cat index 7e6de4654a8..0241fee5956 100644 --- a/Build/source/libs/xpdf/xpdf-src/doc/pdftopng.cat +++ b/Build/source/libs/xpdf/xpdf-src/doc/pdftopng.cat @@ -4,7 +4,7 @@ pdftopng(1) General Commands Manual pdftopng(1) NAME pdftopng - Portable Document Format (PDF) to Portable Network Graphics - (PNG) converter (version 4.01) + (PNG) converter (version 4.02) SYNOPSIS pdftopng [options] PDF-file PNG-root @@ -97,4 +97,4 @@ SEE ALSO - 18 Feb 2019 pdftopng(1) + 25 Sep 2019 pdftopng(1) diff --git a/Build/source/libs/xpdf/xpdf-src/doc/pdftoppm.1 b/Build/source/libs/xpdf/xpdf-src/doc/pdftoppm.1 index 05424a3a9fa..5ad6541d5bb 100644 --- a/Build/source/libs/xpdf/xpdf-src/doc/pdftoppm.1 +++ b/Build/source/libs/xpdf/xpdf-src/doc/pdftoppm.1 @@ -1,8 +1,8 @@ .\" Copyright 2005-2019 Glyph & Cog, LLC -.TH pdftoppm 1 "18 Feb 2019" +.TH pdftoppm 1 "25 Sep 2019" .SH NAME pdftoppm \- Portable Document Format (PDF) to Portable Pixmap (PPM) -converter (version 4.01) +converter (version 4.02) .SH SYNOPSIS .B pdftoppm [options] diff --git a/Build/source/libs/xpdf/xpdf-src/doc/pdftoppm.cat b/Build/source/libs/xpdf/xpdf-src/doc/pdftoppm.cat index cad6636e274..45e1bf1f255 100644 --- a/Build/source/libs/xpdf/xpdf-src/doc/pdftoppm.cat +++ b/Build/source/libs/xpdf/xpdf-src/doc/pdftoppm.cat @@ -4,7 +4,7 @@ pdftoppm(1) General Commands Manual pdftoppm(1) NAME pdftoppm - Portable Document Format (PDF) to Portable Pixmap (PPM) con- - verter (version 4.01) + verter (version 4.02) SYNOPSIS pdftoppm [options] PDF-file PPM-root @@ -96,4 +96,4 @@ SEE ALSO - 18 Feb 2019 pdftoppm(1) + 25 Sep 2019 pdftoppm(1) diff --git a/Build/source/libs/xpdf/xpdf-src/doc/pdftops.1 b/Build/source/libs/xpdf/xpdf-src/doc/pdftops.1 index 6089566d528..360e042121f 100644 --- a/Build/source/libs/xpdf/xpdf-src/doc/pdftops.1 +++ b/Build/source/libs/xpdf/xpdf-src/doc/pdftops.1 @@ -1,8 +1,8 @@ .\" Copyright 1996-2019 Glyph & Cog, LLC -.TH pdftops 1 "18 Feb 2019" +.TH pdftops 1 "25 Sep 2019" .SH NAME pdftops \- Portable Document Format (PDF) to PostScript converter -(version 4.01) +(version 4.02) .SH SYNOPSIS .B pdftops [options] diff --git a/Build/source/libs/xpdf/xpdf-src/doc/pdftops.cat b/Build/source/libs/xpdf/xpdf-src/doc/pdftops.cat index 5669e050500..5b2d9d3e0bb 100644 --- a/Build/source/libs/xpdf/xpdf-src/doc/pdftops.cat +++ b/Build/source/libs/xpdf/xpdf-src/doc/pdftops.cat @@ -4,7 +4,7 @@ pdftops(1) General Commands Manual pdftops(1) NAME pdftops - Portable Document Format (PDF) to PostScript converter (ver- - sion 4.01) + sion 4.02) SYNOPSIS pdftops [options] [PDF-file [PS-file]] @@ -211,4 +211,4 @@ SEE ALSO - 18 Feb 2019 pdftops(1) + 25 Sep 2019 pdftops(1) diff --git a/Build/source/libs/xpdf/xpdf-src/doc/pdftotext.1 b/Build/source/libs/xpdf/xpdf-src/doc/pdftotext.1 index 96b6a68ea3f..d0190491ac6 100644 --- a/Build/source/libs/xpdf/xpdf-src/doc/pdftotext.1 +++ b/Build/source/libs/xpdf/xpdf-src/doc/pdftotext.1 @@ -1,8 +1,8 @@ .\" Copyright 1997-2019 Glyph & Cog, LLC -.TH pdftotext 1 "18 Feb 2019" +.TH pdftotext 1 "25 Sep 2019" .SH NAME pdftotext \- Portable Document Format (PDF) to text converter -(version 4.01) +(version 4.02) .SH SYNOPSIS .B pdftotext [options] @@ -125,6 +125,26 @@ Don't insert page breaks (form feed characters) between pages. Insert a Unicode byte order marker (BOM) at the start of the text output. .TP +.BI \-marginl " number" +Specifies the left margin, in points. Text in the left margin (i.e., +within that many points of the left edge of the page) is discarded. +The default value is zero. +.TP +.BI \-marginr " number" +Specifies the right margin, in points. Text in the right margin +(i.e., within that many points of the right edge of the page) is +discarded. The default value is zero. +.TP +.BI \-margint " number" +Specifies the top margin, in points. Text in the top margin (i.e., +within that many points of the top edge of the page) is discarded. +The default value is zero. +.TP +.BI \-marginb " number" +Specifies the bottom margin, in points. Text in the bottom margin +(i.e., within that many points of the bottom edge of the page) is +discarded. The default value is zero. +.TP .BI \-opw " password" Specify the owner password for the PDF file. Providing this will bypass all security restrictions. diff --git a/Build/source/libs/xpdf/xpdf-src/doc/pdftotext.cat b/Build/source/libs/xpdf/xpdf-src/doc/pdftotext.cat index 2de518cb3b0..ec51212f332 100644 --- a/Build/source/libs/xpdf/xpdf-src/doc/pdftotext.cat +++ b/Build/source/libs/xpdf/xpdf-src/doc/pdftotext.cat @@ -4,7 +4,7 @@ pdftotext(1) General Commands Manual pdftotext(1) NAME pdftotext - Portable Document Format (PDF) to text converter (version - 4.01) + 4.02) SYNOPSIS pdftotext [options] [PDF-file [text-file]] @@ -102,6 +102,26 @@ OPTIONS -bom Insert a Unicode byte order marker (BOM) at the start of the text output. + -marginl number + Specifies the left margin, in points. Text in the left margin + (i.e., within that many points of the left edge of the page) is + discarded. The default value is zero. + + -marginr number + Specifies the right margin, in points. Text in the right margin + (i.e., within that many points of the right edge of the page) is + discarded. The default value is zero. + + -margint number + Specifies the top margin, in points. Text in the top margin + (i.e., within that many points of the top edge of the page) is + discarded. The default value is zero. + + -marginb number + Specifies the bottom margin, in points. Text in the bottom mar- + gin (i.e., within that many points of the bottom edge of the + page) is discarded. The default value is zero. + -opw password Specify the owner password for the PDF file. Providing this will bypass all security restrictions. @@ -148,4 +168,4 @@ SEE ALSO - 18 Feb 2019 pdftotext(1) + 25 Sep 2019 pdftotext(1) diff --git a/Build/source/libs/xpdf/xpdf-src/doc/xpdf.1 b/Build/source/libs/xpdf/xpdf-src/doc/xpdf.1 index 63f3efd3fc9..c1aedbd80cc 100644 --- a/Build/source/libs/xpdf/xpdf-src/doc/xpdf.1 +++ b/Build/source/libs/xpdf/xpdf-src/doc/xpdf.1 @@ -1,7 +1,7 @@ .\" Copyright 1996-2019 Glyph & Cog, LLC -.TH xpdf 1 "18 Feb 2019" +.TH xpdf 1 "25 Sep 2019" .SH NAME -xpdf \- Portable Document Format (PDF) file viewer (version 4.01) +xpdf \- Portable Document Format (PDF) file viewer (version 4.02) .SH SYNOPSIS .B xpdf [options] @@ -12,6 +12,11 @@ xpdf \- Portable Document Format (PDF) file viewer (version 4.01) [options] .B -remote .IR remote-name " [" command " ...]" +.PP +.B xpdf +[options] +.B -open +.RI "[" PDF-file "]" .SH DESCRIPTION .B Xpdf is a viewer for Portable Document Format (PDF) files. (These are also @@ -74,6 +79,14 @@ Set the initial window geometry. .BI \-title " title" Set the window title. By default, the title will be "xpdf: foo.pdf". .TP +.BI \-open " \fR[\fPPDF-file\fR]\fP" +This option sets up a default remote server. If Xpdf is already +running (with the "-open" switch), the PDF file (if any) is opened in +a new tab. If Xpdf (with the "-open" switch) is not already running, +starts Xpdf and opens the PDF file (if any). This is useful for GUI +desktop environments, e.g., the typical double-click on a PDF file +case. +.TP .B \-rv Set reverse video mode. This reverses the colors of everything except images. It may not always produce great results for PDF files which @@ -155,11 +168,25 @@ and are equivalent.) .PP .SH CONTROLS -.SS Tool bar +.SS Toolbar .TP -.B "\'page' entry box" +.B "toggle sidebar button" +Toggles (i.e., shows or hides) the sidebar. +.TP +.B "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 opens the +error dialog. +.TP +.B "selection mode" +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. +.TP +.B "page number entry box" Move to a specific page number. Click in the box to activate it, type -the page number, then hit return. +the page number, then hit return. This will instead display and +accept page labels, if the "view - page labels" menu item is checked. .TP .B "left/right arrow buttons" Go backward or forward along the history path. @@ -176,12 +203,7 @@ Change the zoom factor to fit the page width to the window width. .B "fit page button" Change the zoom factor to fit the page to the window size. .TP -.B "working/error 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 opens the -error dialog. -.TP -.B "\'find' box" +.B "find entry box" Find a text string. Click in the box to activate it, type a search string, then hit return. .TP @@ -196,11 +218,11 @@ Display the current find settings: case sensitive (on/off), find whole words (on/off). .PP .SS Menu bar -The menu bar is above the tool bar. The menu items should be +The menu bar is above the toolbar. The menu items should be self-explanatory. .PP .SS Tab list -The tab list is on the left, just below the tool bar. It lists all +The tab list is on the left, just below the toolbar. It lists all open tabs. .PP .SS Outline/layers/attachments pane @@ -291,6 +313,9 @@ Open a new window. Close the current tab. Closes the window if this was the last open tab. Quits the application if this was the last open window. .TP +.B control-l +Toggle between full-screen and window modes. +.TP .B control-q Quit. .TP @@ -433,6 +458,11 @@ End a pan operation. .B endSelection End a selection. .TP +.BI expandSidebar( n ) +Expand the sidebar by +.I n +pixels. Opens the sidebar if it is currently closed. +.TP .B find Set keyboard focus to the \'find' box. .TP @@ -497,6 +527,9 @@ Go to the specified page. .BI help Open the help URL. .TP +.B hideToolbar +Hide the toolbar. +.TP .B horizontalContinuousMode Switch to horizontal continuous view mode. .TP @@ -526,7 +559,7 @@ Go to the next page, with the current relative scroll position. Switch to the next tab. .TP .B open -Open a PDF file in this tab, using the open dialog. +Open a PDF file in the current tab, using the open dialog. .TP .B openErrorWindow Open the error window. @@ -538,9 +571,25 @@ Open the specified file in the current tab. Open the specified file in the current tab at the specified named destination. .TP +.BI openFileAtDestIn( file, dest, location ) +Open the specified file at the specified named destination. Location +must be "win" for a new window or "tab" for a new tab. +.TP .BI openFileAtPage( file, page ) Open the specified file in the current tab at the specified page. .TP +.BI openFileAtPageIn( file, page, location ) +Open the specified file at the specified page. Location must be "win" +for a new window or "tab" for a new tab. +.TP +.BI openFileIn( file, location ) +Open the specified file. Location must be "win" for a new window or +"tab" for a new tab. +.TP +.BI openIn( location ) +Open a PDF file, using the open dialog. Location must be "win" for a +new window or "tab" for a new tab. +.TP .B openSidebar Open the sidebar. .TP @@ -705,6 +754,15 @@ pixels, moving to the previous page if appropriate. .BI setSelection( pg , ulx , uly , lrx , lry ) Set the selection to the specified coordinates on the specified page. .TP +.B showToolbar +Show the toolbar. +.TP +.BI shrinkSidebar( n ) +Shrink the sidebar by +.I n +pixels. Closes the sidebar if shrinking it would go below the minimum +allowed side. +.TP .B sideBySideContinuousMode Switch to side-by-side continuous view mode. .TP @@ -743,6 +801,15 @@ the document stays in the same place on the screen. Toggle the sidebar between open and closed, resizing the window so that the document size doesn't change. .TP +.B toggleToolbar +Toggle the toolbar between shown and hidden. +.TP +.B viewPageLabels +Show page labels (if the PDF file has them), rather than page numbers. +.TP +.B viewPageNumbers +Show page numbers, rather than page labels. +.TP .B windowMode Go to window (non-full-screen) mode. .TP diff --git a/Build/source/libs/xpdf/xpdf-src/doc/xpdf.cat b/Build/source/libs/xpdf/xpdf-src/doc/xpdf.cat index b3c6ce7cabc..30c841c45ad 100644 --- a/Build/source/libs/xpdf/xpdf-src/doc/xpdf.cat +++ b/Build/source/libs/xpdf/xpdf-src/doc/xpdf.cat @@ -3,13 +3,15 @@ xpdf(1) General Commands Manual xpdf(1) NAME - xpdf - Portable Document Format (PDF) file viewer (version 4.01) + xpdf - Portable Document Format (PDF) file viewer (version 4.02) SYNOPSIS xpdf [options] [PDF-file [:page | +dest]] ... xpdf [options] -remote remote-name [command ...] + xpdf [options] -open [PDF-file] + DESCRIPTION Xpdf is a viewer for Portable Document Format (PDF) files. (These are also sometimes also called 'Acrobat' files, from the name of Adobe's @@ -61,15 +63,23 @@ OPTIONS Set the window title. By default, the title will be "xpdf: foo.pdf". - -rv Set reverse video mode. This reverses the colors of everything - except images. It may not always produce great results for PDF - files which do weird things with color. This also causes the + -open [PDF-file] + This option sets up a default remote server. If Xpdf is already + running (with the "-open" switch), the PDF file (if any) is + opened in a new tab. If Xpdf (with the "-open" switch) is not + already running, starts Xpdf and opens the PDF file (if any). + This is useful for GUI desktop environments, e.g., the typical + double-click on a PDF file case. + + -rv Set reverse video mode. This reverses the colors of everything + except images. It may not always produce great results for PDF + files which do weird things with color. This also causes the paper color to default to black. -papercolor color Set the "paper color", i.e., the background of the page display. - The color can be #RRGGBB (hexadecimal) or a named color. This - option will not work well with PDF files that do things like + The color can be #RRGGBB (hexadecimal) or a named color. This + option will not work well with PDF files that do things like filling in white behind the text. [config file: paperColor] -mattecolor color @@ -78,18 +88,18 @@ OPTIONS a named color. [config file: matteColor] -fsmattecolor color - Set the matte color for full-screen mode. The color can be - #RRGGBB (hexadecimal) or a named color. [config file: + Set the matte color for full-screen mode. The color can be + #RRGGBB (hexadecimal) or a named color. [config file: fullScreenMatteColor] -z zoom Set the initial zoom factor. A number specifies a zoom percent- - age, where 100 means 72 dpi. You may also specify 'page', to - fit the page to the window size, or 'width', to fit the page + age, where 100 means 72 dpi. You may also specify 'page', to + fit the page to the window size, or 'width', to fit the page width to the window width. [config file: initialZoom] -aa yes | no - Enable or disable font anti-aliasing. This defaults to "yes". + Enable or disable font anti-aliasing. This defaults to "yes". [config file: antialias] -aaVector yes | no @@ -97,27 +107,27 @@ OPTIONS [config file: vectorAntialias] -enc encoding-name - Sets the encoding to use for text output. The encoding-name - must be defined with the unicodeMap command (see xpdfrc(5)). + Sets the encoding to use for text output. The encoding-name + must be defined with the unicodeMap command (see xpdfrc(5)). This defaults to "Latin1" (which is a built-in encoding). [con- fig file: textEncoding] -pw password - Specify the password for the PDF file. This can be either the - owner password (which will bypass all security restrictions) or + Specify the password for the PDF file. This can be either the + owner password (which will bypass all security restrictions) or the user password. -fullscreen Open xpdf in full-screen mode, useful for presentations. -remote remote-name - Start Xpdf in remote server mode. See the REMOVE SERVER MODE + Start Xpdf in remote server mode. See the REMOVE SERVER MODE section. -display display Set the X display (only available with X11). - -cmd Print commands as they're executed (useful for debugging). + -cmd Print commands as they're executed (useful for debugging). [config file: printCommands] -cfg config-file @@ -129,10 +139,25 @@ OPTIONS -h Print usage information. (-help and --help are equivalent.) CONTROLS - Tool bar - 'page' entry box - Move to a specific page number. Click in the box to activate - it, type the page number, then hit return. + Toolbar + toggle sidebar button + 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 + opens the error dialog. + + selection mode + 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 + display and accept page labels, if the "view - page labels" menu + item is checked. left/right arrow buttons Go backward or forward along the history path. @@ -141,23 +166,18 @@ CONTROLS 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 Change the zoom factor to fit the page to the window size. - working/error 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 - opens the error dialog. - - 'find' box - Find a text string. Click in the box to activate it, type a + find entry box + Find a text string. Click in the box to activate it, type a search string, then hit return. find next button @@ -171,41 +191,41 @@ CONTROLS whole words (on/off). Menu bar - The menu bar is above the tool bar. The menu items should be self- + The menu bar is above the toolbar. The menu items should be self- explanatory. Tab list - The tab list is on the left, just below the tool bar. It lists all - open tabs. + The tab list is on the left, just below the toolbar. It lists all open + 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- + 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. 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 @@ -215,19 +235,19 @@ CONTROLS 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 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 @@ -261,10 +281,13 @@ CONTROLS 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 + Toggle between full-screen and window modes. + control-q Quit. @@ -294,11 +317,11 @@ CONTROLS 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> @@ -306,7 +329,7 @@ CONTROLS 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. @@ -320,20 +343,20 @@ CONTROLS 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. The following commands are supported: @@ -349,11 +372,11 @@ COMMANDS 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 @@ -385,6 +408,10 @@ COMMANDS endSelection End a selection. + expandSidebar(n) + Expand the sidebar by n pixels. Opens the sidebar if it is cur- + rently closed. + find Set keyboard focus to the 'find' box. findFirst @@ -448,6 +475,9 @@ COMMANDS help Open the help URL. + hideToolbar + Hide the toolbar. + horizontalContinuousMode Switch to horizontal continuous view mode. @@ -475,7 +505,7 @@ COMMANDS nextTab Switch to the next tab. - open Open a PDF file in this tab, using the open dialog. + open Open a PDF file in the current tab, using the open dialog. openErrorWindow Open the error window. @@ -487,10 +517,26 @@ COMMANDS Open the specified file in the current tab at the specified named destination. + openFileAtDestIn(file,dest,location) + Open the specified file at the specified named destination. + Location must be "win" for a new window or "tab" for a new tab. + openFileAtPage(file,page) - Open the specified file in the current tab at the specified + Open the specified file in the current tab at the specified page. + openFileAtPageIn(file,page,location) + Open the specified file at the specified page. Location must be + "win" for a new window or "tab" for a new tab. + + openFileIn(file,location) + Open the specified file. Location must be "win" for a new win- + dow or "tab" for a new tab. + + openIn(location) + Open a PDF file, using the open dialog. Location must be "win" + for a new window or "tab" for a new tab. + openSidebar Open the sidebar. @@ -632,6 +678,13 @@ COMMANDS Set the selection to the specified coordinates on the specified page. + showToolbar + Show the toolbar. + + shrinkSidebar(n) + Shrink the sidebar by n pixels. Closes the sidebar if shrinking + it would go below the minimum allowed side. + sideBySideContinuousMode Switch to side-by-side continuous view mode. @@ -642,11 +695,11 @@ COMMANDS Switch to single-page view mode. 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 @@ -662,14 +715,24 @@ COMMANDS 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 + Toggle the toolbar between shown and hidden. + + viewPageLabels + Show page labels (if the PDF file has them), rather than page + numbers. + + viewPageNumbers + Show page numbers, rather than page labels. + windowMode Go to window (non-full-screen) mode. @@ -732,4 +795,4 @@ SEE ALSO - 18 Feb 2019 xpdf(1) + 25 Sep 2019 xpdf(1) diff --git a/Build/source/libs/xpdf/xpdf-src/doc/xpdfrc.5 b/Build/source/libs/xpdf/xpdf-src/doc/xpdfrc.5 index 2e440f72c59..bde3b5a5973 100644 --- a/Build/source/libs/xpdf/xpdf-src/doc/xpdfrc.5 +++ b/Build/source/libs/xpdf/xpdf-src/doc/xpdfrc.5 @@ -1,7 +1,7 @@ .\" Copyright 2002-2019 Glyph & Cog, LLC -.TH xpdfrc 5 "18 Feb 2019" +.TH xpdfrc 5 "25 Sep 2019" .SH NAME -xpdfrc \- configuration file for Xpdf tools (version 4.01) +xpdfrc \- configuration file for Xpdf tools (version 4.02) .SH DESCRIPTION All of the Xpdf tools read a single configuration file. If you have a .I .xpdfrc @@ -537,11 +537,21 @@ be chosen such that exactly one page will fit in the window at this zoom factor (which must be a percentage). The default value is based on the screen resolution. .TP +.BR initialDisplayMode " single | continuous | sideBySideSingle | sideBySideContinuous | horizontalContinuous" +Sets the initial display mode. The default setting is "continuous". +.TP +.BI initialToolbarState " yes | no" +If set to "yes", xpdf opens with the toolbar visible. If set to "no", +xpdf opens with the toolbar hidden. The default is "yes". +.TP .BI initialSidebarState " yes | no" If set to "yes", xpdf opens with the sidebar (tabs, outline, etc.) visible. If set to "no", xpdf opens with the sidebar collapsed. The default is "yes". .TP +.BR initialSelectMode " block | linear" +Sets the initial selection mode. The default setting is "linear". +.TP .BI paperColor " color" Set the "paper color", i.e., the background of the page display. The color can be #RRGGBB (hexadecimal) or a named color. This option will @@ -557,6 +567,11 @@ color. Set the matte color for full-screen mode. 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 +as well. The default is "no". +.TP .BI popupMenuCmd " title command ..." Add a command to the popup menu. .I Title diff --git a/Build/source/libs/xpdf/xpdf-src/doc/xpdfrc.cat b/Build/source/libs/xpdf/xpdf-src/doc/xpdfrc.cat index d1e6e07ebce..f2412bd3420 100644 --- a/Build/source/libs/xpdf/xpdf-src/doc/xpdfrc.cat +++ b/Build/source/libs/xpdf/xpdf-src/doc/xpdfrc.cat @@ -3,7 +3,7 @@ xpdfrc(5) File Formats Manual xpdfrc(5) NAME - xpdfrc - configuration file for Xpdf tools (version 4.01) + xpdfrc - configuration file for Xpdf tools (version 4.02) DESCRIPTION All of the Xpdf tools read a single configuration file. If you have a @@ -493,11 +493,24 @@ VIEWER SETTINGS window at this zoom factor (which must be a percentage). The default value is based on the screen resolution. + initialDisplayMode single | continuous | sideBySideSingle | sideBySide- + Continuous | horizontalContinuous + Sets the initial display mode. The default setting is "continu- + ous". + + initialToolbarState yes | no + If set to "yes", xpdf opens with the toolbar visible. If set to + "no", xpdf opens with the toolbar hidden. The default is "yes". + initialSidebarState yes | no - If set to "yes", xpdf opens with the sidebar (tabs, outline, - etc.) visible. If set to "no", xpdf opens with the sidebar + If set to "yes", xpdf opens with the sidebar (tabs, outline, + etc.) visible. If set to "no", xpdf opens with the sidebar collapsed. The default is "yes". + initialSelectMode block | linear + Sets the initial selection mode. The default setting is "lin- + ear". + paperColor color Set the "paper color", i.e., the background of the page display. The color can be #RRGGBB (hexadecimal) or a named color. This @@ -513,6 +526,11 @@ VIEWER SETTINGS Set the matte color for full-screen mode. 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 + 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- @@ -716,4 +734,4 @@ SEE ALSO - 18 Feb 2019 xpdfrc(5) + 25 Sep 2019 xpdfrc(5) diff --git a/Build/source/libs/xpdf/xpdf-src/fofi/FoFiBase.cc b/Build/source/libs/xpdf/xpdf-src/fofi/FoFiBase.cc index 07cc3fcd52f..e1951b08b9f 100644 --- a/Build/source/libs/xpdf/xpdf-src/fofi/FoFiBase.cc +++ b/Build/source/libs/xpdf/xpdf-src/fofi/FoFiBase.cc @@ -171,6 +171,7 @@ Guint FoFiBase::getUVarBE(int pos, int size, GBool *ok) { GBool FoFiBase::checkRegion(int pos, int size) { return pos >= 0 && - pos + size >= pos && + size >= 0 && + size <= INT_MAX - pos && pos + size <= len; } diff --git a/Build/source/libs/xpdf/xpdf-src/fofi/FoFiTrueType.cc b/Build/source/libs/xpdf/xpdf-src/fofi/FoFiTrueType.cc index 3709a1f2809..0f5b5bc7230 100644 --- a/Build/source/libs/xpdf/xpdf-src/fofi/FoFiTrueType.cc +++ b/Build/source/libs/xpdf/xpdf-src/fofi/FoFiTrueType.cc @@ -320,6 +320,7 @@ FoFiTrueType::FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA, nCmaps = 0; nameToGID = NULL; isDfont = isDfontA; + isTTC = gFalse; parsedOk = gFalse; parse(fontNum, allowHeadlessCFF); @@ -985,7 +986,8 @@ void FoFiTrueType::convertToType0(char *psName, int *cidMap, int nCIDs, GBool FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, void *outputStream, char *name, - int *codeToGID) { + int *codeToGID, Guchar *replacementCmapTable, + int replacementCmapTableLen) { // this substitute cmap table maps char code ffff to glyph 0, // with tables for MacRoman and MS Unicode static char cmapTab[44] = { @@ -1188,7 +1190,7 @@ GBool FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, if (!missingCmap && !missingName && !missingPost && !missingOS2 && !unsortedLoca && !emptyCmap && !badCmapLen && !abbrevHMTX && nZeroLengthTables == 0 && nBogusTables == 0 && - !name && !codeToGID && !isDfont) { + !name && !codeToGID && !replacementCmapTable && !isDfont && !isTTC) { (*outputFunc)(outputStream, (char *)file, len); gfree(locaTable); return gFalse; @@ -1306,7 +1308,7 @@ GBool FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, } // construct the new cmap table - if (codeToGID) { + if (codeToGID && !replacementCmapTable) { newCmapLen = 44 + 256 * 2; newCmapTab = (char *)gmalloc(newCmapLen); newCmapTab[0] = 0; // table version number = 0 @@ -1435,8 +1437,15 @@ GBool FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, // don't include the file checksum newTables[j].checksum -= getU32BE(tables[i].offset + 8, &ok); } + } else { + // we'll write four zero bytes for this table + newTables[j].len = 4; } - if (newTables[j].tag == cmapTag && codeToGID) { + if (newTables[j].tag == cmapTag && replacementCmapTable) { + newTables[j].len = replacementCmapTableLen; + newTables[j].checksum = computeTableChecksum(replacementCmapTable, + replacementCmapTableLen); + } else if (newTables[j].tag == cmapTag && codeToGID) { newTables[j].len = newCmapLen; newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab, newCmapLen); @@ -1470,7 +1479,11 @@ GBool FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, } if (missingCmap) { newTables[j].tag = cmapTag; - if (codeToGID) { + if (replacementCmapTable) { + newTables[j].checksum = computeTableChecksum(replacementCmapTable, + replacementCmapTableLen); + newTables[j].len = replacementCmapTableLen; + } else if (codeToGID) { newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab, newCmapLen); newTables[j].len = newCmapLen; @@ -1588,6 +1601,9 @@ GBool FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, (*outputFunc)(outputStream, "\0", 1); } } + } else if (newTables[i].tag == cmapTag && replacementCmapTable) { + (*outputFunc)(outputStream, (char *)replacementCmapTable, + newTables[i].len); } else if (newTables[i].tag == cmapTag && codeToGID) { (*outputFunc)(outputStream, newCmapTab, newTables[i].len); } else if (newTables[i].tag == cmapTag && missingCmap) { @@ -1816,7 +1832,8 @@ void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc, } else { locaTable[i].origOffset = 2 * getU16BE(pos + i*2, &ok); } - if (locaTable[i].origOffset > glyfTableLen) { + if (locaTable[i].origOffset < 0 || + locaTable[i].origOffset > glyfTableLen) { locaTable[i].origOffset = glyfTableLen; } } @@ -2172,7 +2189,9 @@ void FoFiTrueType::parse(int fontNum, GBool allowHeadlessCFF) { tables[j].checksum = getU32BE(offset + pos + 4, &parsedOk); tables[j].offset = offset + (int)getU32BE(offset + pos + 8, &parsedOk); tables[j].len = (int)getU32BE(offset + pos + 12, &parsedOk); - if (tables[j].offset + tables[j].len >= tables[j].offset && + if (tables[j].offset >= 0 && + tables[j].len >= 0 && + tables[j].offset + tables[j].len >= tables[j].offset && tables[j].offset + tables[j].len <= len) { // ignore any bogus entries in the table directory ++j; @@ -2274,6 +2293,7 @@ void FoFiTrueType::parse(int fontNum, GBool allowHeadlessCFF) { void FoFiTrueType::parseTTC(int fontNum, int *pos) { int nFonts; + isTTC = gTrue; nFonts = getU32BE(8, &parsedOk); if (!parsedOk) { return; diff --git a/Build/source/libs/xpdf/xpdf-src/fofi/FoFiTrueType.h b/Build/source/libs/xpdf/xpdf-src/fofi/FoFiTrueType.h index a0f759b2a6f..619e1bd6676 100644 --- a/Build/source/libs/xpdf/xpdf-src/fofi/FoFiTrueType.h +++ b/Build/source/libs/xpdf/xpdf-src/fofi/FoFiTrueType.h @@ -95,6 +95,9 @@ public: // for OpenType CFF fonts.) void getFontMatrix(double *mat); + // Return the number of glyphs in the font. + int getNumGlyphs() { return nGlyphs; } + // Returns true if this looks like a CJK font that uses bytecode // instructions to assemble glyphs. GBool checkForTrickyCJK(); @@ -154,10 +157,15 @@ public: // various other errors. If <name> is non-NULL, the font is renamed // to <name>. If <codeToGID> is non-NULL, the font is re-encoded, // using a Windows Unicode cmap. If <name> is NULL and the font is - // complete and correct, it will be written unmodified. (Not useful - // for OpenType CFF fonts.) Returns true if the font was modified. + // complete and correct, it will be written unmodified. If + // <replacementCmapTable> is non-NULL it will be used as the cmap + // table in the written font (overriding any existing cmap table + // and/or the codeToGID arg). (Not useful for OpenType CFF fonts.) + // Returns true if the font was modified. GBool writeTTF(FoFiOutputFunc outputFunc, void *outputStream, - char *name = NULL, int *codeToGID = NULL); + char *name = NULL, int *codeToGID = NULL, + Guchar *replacementCmapTable = NULL, + int replacementCmapTableLen = 0); // Returns a pointer to the CFF font embedded in this OpenType font. // If successful, sets *<start> and *<length>, and returns true. @@ -200,6 +208,7 @@ private: GBool openTypeCFF; GBool headlessCFF; GBool isDfont; + GBool isTTC; GBool parsedOk; }; diff --git a/Build/source/libs/xpdf/xpdf-src/fofi/FoFiType1.cc b/Build/source/libs/xpdf/xpdf-src/fofi/FoFiType1.cc index 4f5972a7bbb..0d067b5c5a9 100644 --- a/Build/source/libs/xpdf/xpdf-src/fofi/FoFiType1.cc +++ b/Build/source/libs/xpdf/xpdf-src/fofi/FoFiType1.cc @@ -99,7 +99,7 @@ void FoFiType1::writeEncoded(const char **newEncoding, // copy everything up to the encoding for (line = (char *)file; - line && strncmp(line, "/Encoding", 9); + line && line + 9 <= (char *)file + len && strncmp(line, "/Encoding", 9); line = getNextLine(line)) ; if (!line) { // no encoding - just copy the whole font file @@ -122,7 +122,8 @@ void FoFiType1::writeEncoded(const char **newEncoding, // find the end of the encoding data //~ this ought to parse PostScript tokens - if (!strncmp(line, "/Encoding StandardEncoding def", 30)) { + if (line + 30 <= (char *)file + len && + !strncmp(line, "/Encoding StandardEncoding def", 30)) { line = getNextLine(line); } else { // skip "/Encoding" + one whitespace char, @@ -144,16 +145,18 @@ void FoFiType1::writeEncoded(const char **newEncoding, // check for a second one here if (line) { for (line2 = line, i = 0; - i < 20 && line2 && strncmp(line2, "/Encoding", 9); + i < 20 && line2 && line2 + 9 <= (char *)file + len && + strncmp(line2, "/Encoding", 9); line2 = getNextLine(line2), ++i) ; if (i < 20 && line2) { (*outputFunc)(outputStream, line, (int)(line2 - line)); - if (!strncmp(line2, "/Encoding StandardEncoding def", 30)) { + if (line2 + 30 <= (char *)file + len && + !strncmp(line2, "/Encoding StandardEncoding def", 30)) { line = getNextLine(line2); } else { - // skip "/Encoding" + one whitespace char, + // skip "/Encoding", // then look for 'def' preceded by PostScript whitespace - p = line2 + 10; + p = line2 + 9; line = NULL; for (; p < (char *)file + len; ++p) { if ((*p == ' ' || *p == '\t' || *p == '\x0a' || @@ -203,9 +206,14 @@ void FoFiType1::parse() { ++i) { // get font name - if (!name && !strncmp(line, "/FontName", 9)) { - strncpy(buf, line, 255); - buf[255] = '\0'; + if (!name && line + 9 <= (char *)file + len && + !strncmp(line, "/FontName", 9)) { + n = 255; + if (line + n > (char *)file + len) { + n = (int)(((char *)file + len) - line); + } + strncpy(buf, line, n); + buf[n] = '\0'; if ((p = strchr(buf+9, '/')) && (p = strtok(p+1, " \t\n\r"))) { name = copyString(p); @@ -213,10 +221,10 @@ void FoFiType1::parse() { line = getNextLine(line); // get encoding - } else if (!encoding && + } else if (!encoding && line + 30 <= (char *)file + len && !strncmp(line, "/Encoding StandardEncoding def", 30)) { encoding = (char **)fofiType1StandardEncoding; - } else if (!encoding && + } else if (!encoding && line + 19 <= (char *)file + len && !strncmp(line, "/Encoding 256 array", 19)) { encoding = (char **)gmallocn(256, sizeof(char *)); for (j = 0; j < 256; ++j) { @@ -284,9 +292,14 @@ void FoFiType1::parse() { } //~ check for getinterval/putinterval junk - } else if (!gotMatrix && !strncmp(line, "/FontMatrix", 11)) { - strncpy(buf, line + 11, 255); - buf[255] = '\0'; + } else if (!gotMatrix && line + 11 <= (char *)file + len && + !strncmp(line, "/FontMatrix", 11)) { + n = 255; + if (line + 11 + n > (char *)file + len) { + n = (int)(((char *)file + len) - (line + 11)); + } + strncpy(buf, line + 11, n); + buf[n] = '\0'; if ((p = strchr(buf, '['))) { ++p; if ((p2 = strchr(p, ']'))) { diff --git a/Build/source/libs/xpdf/xpdf-src/fofi/FoFiType1C.cc b/Build/source/libs/xpdf/xpdf-src/fofi/FoFiType1C.cc index cdb767ae8bf..13c045f8b97 100644 --- a/Build/source/libs/xpdf/xpdf-src/fofi/FoFiType1C.cc +++ b/Build/source/libs/xpdf/xpdf-src/fofi/FoFiType1C.cc @@ -18,6 +18,7 @@ #include "gmem.h" #include "gmempp.h" #include "GString.h" +#include "GHash.h" #include "FoFiEncodings.h" #include "FoFiType1C.h" @@ -152,6 +153,23 @@ GString *FoFiType1C::getGlyphName(int gid) { return new GString(buf); } +GHash *FoFiType1C::getNameToGIDMap() { + GHash *map; + char name[256]; + GBool ok; + int gid; + + map = new GHash(gTrue); + for (gid = 0; gid < nGlyphs; ++gid) { + ok = gTrue; + getString(charset[gid], name, &ok); + if (ok) { + map->add(new GString(name), gid); + } + } + return map; +} + int *FoFiType1C::getCIDToGIDMap(int *nCIDs) { int *map; int n, i; @@ -2183,6 +2201,371 @@ void FoFiType1C::writePSString(char *s, FoFiOutputFunc outputFunc, (*outputFunc)(outputStream, buf, i); } +void FoFiType1C::convertToOpenType(FoFiOutputFunc outputFunc, + void *outputStream, + int nWidths, Gushort *widths, + Guchar *cmapTable, int cmapTableLen) { + // dummy OS/2 table (taken from FoFiTrueType::writeTTF) + static Guchar os2Tab[86] = { + 0, 1, // version + 0, 1, // xAvgCharWidth + 0x01, 0x90, // usWeightClass + 0, 5, // usWidthClass + 0, 0, // fsType + 0, 0, // ySubscriptXSize + 0, 0, // ySubscriptYSize + 0, 0, // ySubscriptXOffset + 0, 0, // ySubscriptYOffset + 0, 0, // ySuperscriptXSize + 0, 0, // ySuperscriptYSize + 0, 0, // ySuperscriptXOffset + 0, 0, // ySuperscriptYOffset + 0, 0, // yStrikeoutSize + 0, 0, // yStrikeoutPosition + 0, 0, // sFamilyClass + 0, 0, 0, 0, 0, // panose + 0, 0, 0, 0, 0, + 0, 0, 0, 0, // ulUnicodeRange1 + 0, 0, 0, 0, // ulUnicodeRange2 + 0, 0, 0, 0, // ulUnicodeRange3 + 0, 0, 0, 0, // ulUnicodeRange4 + 0, 0, 0, 0, // achVendID + 0, 0, // fsSelection + 0, 0, // usFirstCharIndex + 0, 0, // usLastCharIndex + 0, 0, // sTypoAscender + 0, 0, // sTypoDescender + 0, 0, // sTypoLineGap + 0x20, 0x00, // usWinAscent + 0x20, 0x00, // usWinDescent + 0, 0, 0, 1, // ulCodePageRange1 + 0, 0, 0, 0 // ulCodePageRange2 + }; + Guchar headTable[54], hheaTable[36], maxpTable[6]; + Guchar nameTable[26], postTable[32]; + Guchar *hmtxTable; + static const char *tableTag[9] = { + "CFF ", + "OS/2", + "cmap", + "head", + "hhea", + "hmtx", + "maxp", + "name", + "post" + }; + Guchar *tableData[9]; + int tableLength[9]; + Guchar header[12 + 9*16]; + double mat[6]; + Gushort maxWidth; + Guint checksum, fileChecksum; + int unitsPerEm, xMin, yMin, xMax, yMax, offset, i; + + //--- CFF_ table + tableData[0] = file; + tableLength[0] = len; + + //--- OS/2 table + tableData[1] = os2Tab; + tableLength[1] = 86; + + //--- cmap table + tableData[2] = cmapTable; + tableLength[2] = cmapTableLen; + + //--- head table + getFontMatrix(mat); + if (mat[0] == 0) { + unitsPerEm = 1000; + } else { + unitsPerEm = (int)(1 / mat[0] + 0.5); + } + xMin = (int)(topDict.fontBBox[0] + 0.5); + yMin = (int)(topDict.fontBBox[1] + 0.5); + xMax = (int)(topDict.fontBBox[2] + 0.5); + yMax = (int)(topDict.fontBBox[3] + 0.5); + headTable[ 0] = 0x00; // version + headTable[ 1] = 0x01; + headTable[ 2] = 0x00; + headTable[ 3] = 0x00; + headTable[ 4] = 0x00; // revision + headTable[ 5] = 0x00; + headTable[ 6] = 0x00; + headTable[ 7] = 0x00; + headTable[ 8] = 0x00; // checksumAdjustment + headTable[ 9] = 0x00; // (set later) + headTable[10] = 0x00; + headTable[11] = 0x00; + headTable[12] = 0x5f; // magicNumber + headTable[13] = 0x0f; + headTable[14] = 0x3c; + headTable[15] = 0xf5; + headTable[16] = 0x00; // flags + headTable[17] = 0x03; + headTable[18] = (Guchar)(unitsPerEm >> 8); // unitsPerEm + headTable[19] = (Guchar)unitsPerEm; + headTable[20] = 0x00; // created + headTable[21] = 0x00; + headTable[22] = 0x00; + headTable[23] = 0x00; + headTable[24] = 0x00; + headTable[25] = 0x00; + headTable[26] = 0x00; + headTable[27] = 0x00; + headTable[28] = 0x00; // modified + headTable[29] = 0x00; + headTable[30] = 0x00; + headTable[31] = 0x00; + headTable[32] = 0x00; + headTable[33] = 0x00; + headTable[34] = 0x00; + headTable[35] = 0x00; + headTable[36] = (Guchar)(xMin >> 8); // xMin + headTable[37] = (Guchar)xMin; + headTable[38] = (Guchar)(yMin >> 8); // yMin + headTable[39] = (Guchar)yMin; + headTable[40] = (Guchar)(xMax >> 8); // xMax + headTable[41] = (Guchar)xMax; + headTable[42] = (Guchar)(yMax >> 8); // yMax + headTable[43] = (Guchar)yMax; + headTable[44] = 0; // macStyle + headTable[45] = 0; + headTable[46] = 0; // lowestRecPPEM + headTable[47] = 3; + headTable[48] = 0; // fontDirectionHint + headTable[49] = 2; // (deprecated) + headTable[50] = 0; // indexToLocFormat + headTable[51] = 0; // (n/a to CFF fonts) + headTable[52] = 0; // glyphDataFormat + headTable[53] = 0; // (n/a to CFF fonts) + tableData[3] = headTable; + tableLength[3] = 54; + + //--- hhea table + maxWidth = widths[0]; + for (i = 1; i < nWidths; ++i) { + if (widths[i] > maxWidth) { + maxWidth = widths[i]; + } + } + hheaTable[ 0] = 0x00; // version + hheaTable[ 1] = 0x01; + hheaTable[ 2] = 0x00; + hheaTable[ 3] = 0x00; + hheaTable[ 4] = (Guchar)(yMax >> 8); // ascender + hheaTable[ 5] = (Guchar)yMax; + hheaTable[ 6] = (Guchar)(yMin >> 8); // descender + hheaTable[ 7] = (Guchar)yMin; + hheaTable[ 8] = 0; // lineGap + hheaTable[ 9] = 0; + hheaTable[10] = (Guchar)(maxWidth >> 8); // advanceWidthMax + hheaTable[11] = (Guchar)maxWidth; + hheaTable[12] = 0; // minLeftSideBearing + hheaTable[13] = 0; + hheaTable[14] = 0; // minRightSideBearing + hheaTable[15] = 0; + hheaTable[16] = (Guchar)(maxWidth >> 8); // xMaxExtent + hheaTable[17] = (Guchar)maxWidth; + hheaTable[18] = 0; // caretSlopeRise + hheaTable[19] = 1; + hheaTable[20] = 0; // caretSlopeRun + hheaTable[21] = 0; + hheaTable[22] = 0; // caretOffset + hheaTable[23] = 0; + hheaTable[24] = 0; // reserved + hheaTable[25] = 0; + hheaTable[26] = 0; // reserved + hheaTable[27] = 0; + hheaTable[28] = 0; // reserved + hheaTable[29] = 0; + hheaTable[30] = 0; // reserved + hheaTable[31] = 0; + hheaTable[32] = 0; // metricDataFormat + hheaTable[33] = 0; + hheaTable[34] = (Guchar)(nWidths >> 8); // numberOfHMetrics + hheaTable[35] = (Guchar)nWidths; + tableData[4] = hheaTable; + tableLength[4] = 36; + + //--- hmtx table + //~ this currently sets LSB to 0 for all glyphs + hmtxTable = (Guchar *)gmallocn(nWidths, 4); + for (i = 0; i < nWidths; ++i) { + hmtxTable[4*i ] = (Guchar)(widths[i] >> 8); + hmtxTable[4*i+1] = (Guchar)widths[i]; + hmtxTable[4*i+2] = 0; + hmtxTable[4*i+3] = 0; + } + tableData[5] = hmtxTable; + tableLength[5] = 4 * nWidths; + + //--- maxp table + maxpTable[0] = 0x00; // version = 0.5 + maxpTable[1] = 0x00; + maxpTable[2] = 0x50; + maxpTable[3] = 0x00; + maxpTable[4] = (Guchar)(nGlyphs >> 8); // numGlyphs + maxpTable[5] = (Guchar)nGlyphs; + tableData[6] = maxpTable; + tableLength[6] = 6; + + //--- name table + nameTable[ 0] = 0x00; // format + nameTable[ 1] = 0x00; + nameTable[ 2] = 0x00; // count + nameTable[ 3] = 0x01; + nameTable[ 4] = 0x00; // stringOffset + nameTable[ 5] = 0x12; + nameTable[ 6] = 0x00; // platformID + nameTable[ 7] = 0x00; + nameTable[ 8] = 0x00; // encodingID + nameTable[ 9] = 0x03; + nameTable[10] = 0x00; // languageID + nameTable[11] = 0x00; + nameTable[12] = 0x00; // nameID + nameTable[13] = 0x00; + nameTable[14] = 0x00; // length + nameTable[15] = 0x08; + nameTable[16] = 0x00; // offset + nameTable[17] = 0x00; + nameTable[18] = 0x00; // string data + nameTable[19] = (Guchar)'n'; + nameTable[20] = 0x00; + nameTable[21] = (Guchar)'o'; + nameTable[22] = 0x00; + nameTable[23] = (Guchar)'n'; + nameTable[24] = 0x00; + nameTable[25] = (Guchar)'e'; + tableData[7] = nameTable; + tableLength[7] = 26; + + //--- post table + postTable[ 0] = 0x00; // version = 3.0 + postTable[ 1] = 0x03; + postTable[ 2] = 0x00; + postTable[ 3] = 0x00; + postTable[ 4] = 0x00; // italicAngle + postTable[ 5] = 0x00; + postTable[ 6] = 0x00; + postTable[ 7] = 0x00; + postTable[ 8] = 0x00; // underlinePosition + postTable[ 9] = 0x00; + postTable[10] = 0x00; // underlineThickness + postTable[11] = 0x00; + postTable[12] = 0x00; // isFixedPitch + postTable[13] = 0x00; + postTable[14] = 0x00; + postTable[15] = 0x00; + postTable[16] = 0x00; // minMemType42 + postTable[17] = 0x00; + postTable[18] = 0x00; + postTable[19] = 0x00; + postTable[20] = 0x00; // maxMemType42 + postTable[21] = 0x00; + postTable[22] = 0x00; + postTable[23] = 0x00; + postTable[24] = 0x00; // minMemType1 + postTable[25] = 0x00; + postTable[26] = 0x00; + postTable[27] = 0x00; + postTable[28] = 0x00; // maxMemType1 + postTable[29] = 0x00; + postTable[30] = 0x00; + postTable[31] = 0x00; + tableData[8] = postTable; + tableLength[8] = 32; + + //--- header and table directory + header[ 0] = 'O'; // sfnt version + header[ 1] = 'T'; + header[ 2] = 'T'; + header[ 3] = 'O'; + header[ 4] = 0x00; // numTables + header[ 5] = 0x09; + header[ 6] = 0x00; // searchRange + header[ 7] = 0x80; + header[ 8] = 0x00; // entrySelector + header[ 9] = 0x03; + header[10] = 0x00; // rangeShift + header[11] = 0x10; + offset = 12 + 9*16; + fileChecksum = 0; + for (i = 0; i < 9; ++i) { + header[12 + i*16 + 0] = tableTag[i][0]; + header[12 + i*16 + 1] = tableTag[i][1]; + header[12 + i*16 + 2] = tableTag[i][2]; + header[12 + i*16 + 3] = tableTag[i][3]; + checksum = computeOpenTypeTableChecksum(tableData[i], tableLength[i]); + fileChecksum += checksum; + header[12 + i*16 + 4] = (Guchar)(checksum >> 24); + header[12 + i*16 + 5] = (Guchar)(checksum >> 16); + header[12 + i*16 + 6] = (Guchar)(checksum >> 8); + header[12 + i*16 + 7] = (Guchar)checksum; + header[12 + i*16 + 8] = (Guchar)(offset >> 24); + header[12 + i*16 + 9] = (Guchar)(offset >> 16); + header[12 + i*16 + 10] = (Guchar)(offset >> 8); + header[12 + i*16 + 11] = (Guchar)offset; + header[12 + i*16 + 12] = (Guchar)(tableLength[i] >> 24); + header[12 + i*16 + 13] = (Guchar)(tableLength[i] >> 16); + header[12 + i*16 + 14] = (Guchar)(tableLength[i] >> 8); + header[12 + i*16 + 15] = (Guchar)tableLength[i]; + offset += tableLength[i]; + if (tableLength[i] & 3) { + offset += 4 - (tableLength[i] & 3); + } + } + + //--- file checksum + fileChecksum += computeOpenTypeTableChecksum(header, 12 + 9*16); + fileChecksum = 0xb1b0afba - fileChecksum; + headTable[ 8] = (Guchar)(fileChecksum >> 24); + headTable[ 9] = (Guchar)(fileChecksum >> 16); + headTable[10] = (Guchar)(fileChecksum >> 8); + headTable[11] = (Guchar)fileChecksum; + + //--- write the OpenType font + (*outputFunc)(outputStream, (char *)header, 12 + 9*16); + for (i = 0; i < 9; ++i) { + (*outputFunc)(outputStream, (char *)tableData[i], tableLength[i]); + if (tableLength[i] & 3) { + (*outputFunc)(outputStream, "\0\0\0", 4 - (tableLength[i] & 3)); + } + } + + gfree(hmtxTable); +} + +Guint FoFiType1C::computeOpenTypeTableChecksum(Guchar *data, int length) { + Guint checksum, word; + int i; + + checksum = 0; + for (i = 0; i+3 < length; i += 4) { + word = ((data[i ] & 0xff) << 24) + + ((data[i+1] & 0xff) << 16) + + ((data[i+2] & 0xff) << 8) + + (data[i+3] & 0xff); + checksum += word; + } + if (length & 3) { + word = 0; + i = length & ~3; + switch (length & 3) { + case 3: + word |= (data[i+2] & 0xff) << 8; + case 2: + word |= (data[i+1] & 0xff) << 16; + case 1: + word |= (data[i ] & 0xff) << 24; + break; + } + checksum += word; + } + return checksum; +} + GBool FoFiType1C::parse() { Type1CIndex fdIdx; Type1CIndexVal val; @@ -2577,7 +2960,14 @@ void FoFiType1C::readFDSelect() { parsedOk = gFalse; return; } - memcpy(fdSelect, file + pos, nGlyphs); + for (gid0 = 0; gid0 < nGlyphs; ++gid0) { + if (file[pos + gid0] >= nFDs) { + //~ error(-1, "Bad FDSelect table in CID font"); + parsedOk = gFalse; + return; + } + fdSelect[gid0] = file[pos + gid0]; + } } else if (fdSelectFmt == 3) { nRanges = getU16BE(pos, &parsedOk); pos += 2; @@ -2590,7 +2980,7 @@ void FoFiType1C::readFDSelect() { return; } pos += 2; - if (gid0 > gid1 || gid1 > nGlyphs) { + if (gid0 > gid1 || gid1 > nGlyphs || fd >= nFDs) { //~ error(-1, "Bad FDSelect table in CID font"); parsedOk = gFalse; return; @@ -2703,10 +3093,19 @@ GBool FoFiType1C::readCharset() { if (topDict.charsetOffset == 0) { charset = fofiType1CISOAdobeCharset; + if (nGlyphs > 229) { + nGlyphs = 229; + } } else if (topDict.charsetOffset == 1) { charset = fofiType1CExpertCharset; + if (nGlyphs > 166) { + nGlyphs = 166; + } } else if (topDict.charsetOffset == 2) { charset = fofiType1CExpertSubsetCharset; + if (nGlyphs > 87) { + nGlyphs = 87; + } } else { charset = (Gushort *)gmallocn(nGlyphs, sizeof(Gushort)); for (i = 0; i < nGlyphs; ++i) { diff --git a/Build/source/libs/xpdf/xpdf-src/fofi/FoFiType1C.h b/Build/source/libs/xpdf/xpdf-src/fofi/FoFiType1C.h index ae869687898..eb75dce330d 100644 --- a/Build/source/libs/xpdf/xpdf-src/fofi/FoFiType1C.h +++ b/Build/source/libs/xpdf/xpdf-src/fofi/FoFiType1C.h @@ -18,6 +18,7 @@ #include "gtypes.h" #include "FoFiBase.h" +class GHash; class GString; //------------------------------------------------------------------------ @@ -169,6 +170,10 @@ public: int getNumGlyphs() { return nGlyphs; } GString *getGlyphName(int gid); + // Returns a hash mapping glyph names to GIDs. This is only useful + // with 8-bit fonts. + GHash *getNameToGIDMap(); + // Return the mapping from CIDs to GIDs, and return the number of // CIDs in *<nCIDs>. This is only useful for CID fonts. int *getCIDToGIDMap(int *nCIDs); @@ -208,6 +213,13 @@ public: void convertToType0(char *psName, int *codeMap, int nCodes, FoFiOutputFunc outputFunc, void *outputStream); + // Write an OpenType file, encapsulating the CFF font. <widths> + // provides the glyph widths (in design units) for <nWidths> glyphs. + // The cmap table must be supplied by the caller. + void convertToOpenType(FoFiOutputFunc outputFunc, void *outputStream, + int nWidths, Gushort *widths, + Guchar *cmapTable, int cmapTableLen); + private: FoFiType1C(char *fileA, int lenA, GBool freeFileDataA); @@ -224,6 +236,7 @@ private: void eexecWrite(Type1CEexecBuf *eb, const char *s); void eexecWriteCharstring(Type1CEexecBuf *eb, Guchar *s, int n); void writePSString(char *s, FoFiOutputFunc outputFunc, void *outputStream); + Guint computeOpenTypeTableChecksum(Guchar *data, int length); GBool parse(); void readTopDict(); void readFD(int offset, int length, Type1CPrivateDict *pDict); diff --git a/Build/source/libs/xpdf/xpdf-src/goo/FixedPoint.h b/Build/source/libs/xpdf/xpdf-src/goo/FixedPoint.h index 438343fc585..a0baa70b61f 100644 --- a/Build/source/libs/xpdf/xpdf-src/goo/FixedPoint.h +++ b/Build/source/libs/xpdf/xpdf-src/goo/FixedPoint.h @@ -36,7 +36,7 @@ public: FixedPoint(const FixedPoint &x) { val = x.val; } FixedPoint(double x) { val = (int)(x * (1 << fixptShift) + 0.5); } FixedPoint(int x) { val = x << fixptShift; } - FixedPoint(long x) { val = x << fixptShift; } + FixedPoint(long x) { val = (int)x << fixptShift; } operator float() { return (float) val * ((float)1 / (float)(1 << fixptShift)); } diff --git a/Build/source/libs/xpdf/xpdf-src/goo/GMutex.h b/Build/source/libs/xpdf/xpdf-src/goo/GMutex.h index d73366bddd0..aef4aec4859 100644 --- a/Build/source/libs/xpdf/xpdf-src/goo/GMutex.h +++ b/Build/source/libs/xpdf/xpdf-src/goo/GMutex.h @@ -12,6 +12,7 @@ #ifndef GMUTEX_H #define GMUTEX_H +#include <aconf.h> #ifdef _WIN32 # include <windows.h> # include <intrin.h> diff --git a/Build/source/libs/xpdf/xpdf-src/goo/gfile.cc b/Build/source/libs/xpdf/xpdf-src/goo/gfile.cc index 40cf9054153..e7112b2039d 100644 --- a/Build/source/libs/xpdf/xpdf-src/goo/gfile.cc +++ b/Build/source/libs/xpdf/xpdf-src/goo/gfile.cc @@ -14,6 +14,8 @@ #include <aconf.h> #ifdef _WIN32 +# undef WIN32_LEAN_AND_MEAN +# include <windows.h> # include <time.h> # include <direct.h> #else @@ -613,7 +615,7 @@ FILE *openFile(const char *path, const char *mode) { } } wPath[i] = (wchar_t)0; - for (i = 0; mode[i] && i < sizeof(wMode) - 1; ++i) { + 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; diff --git a/Build/source/libs/xpdf/xpdf-src/goo/gfile.h b/Build/source/libs/xpdf/xpdf-src/goo/gfile.h index 6bd870ecb90..c0e75073ed0 100644 --- a/Build/source/libs/xpdf/xpdf-src/goo/gfile.h +++ b/Build/source/libs/xpdf/xpdf-src/goo/gfile.h @@ -11,6 +11,7 @@ #ifndef GFILE_H #define GFILE_H +#include <aconf.h> #include <stdio.h> #include <stdlib.h> #include <stddef.h> diff --git a/Build/source/libs/xpdf/xpdf-src/goo/gmem.cc b/Build/source/libs/xpdf/xpdf-src/goo/gmem.cc index 7cf9581321f..7291f2099bb 100644 --- a/Build/source/libs/xpdf/xpdf-src/goo/gmem.cc +++ b/Build/source/libs/xpdf/xpdf-src/goo/gmem.cc @@ -11,7 +11,9 @@ #include <stdlib.h> #include <stddef.h> // older compilers won't define SIZE_MAX in stdint.h without this -#define __STDC_LIMIT_MACROS 1 +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS 1 +#endif #include <stdint.h> #include <string.h> #include <limits.h> @@ -107,12 +109,12 @@ void *gmalloc(int size, int ignore) GMEM_EXCEP { trl = (unsigned long *)(mem + gMemHdrSize + size1); hdr->magic = gMemMagic; hdr->size = size; + gMemLock; if (ignore) { hdr->index = -1; } else { hdr->index = gMemIndex++; } - gMemLock; if (gMemTail) { gMemTail->next = hdr; hdr->prev = gMemTail; @@ -233,12 +235,12 @@ void *gmalloc64(size_t size, int ignore) GMEM_EXCEP { trl = (unsigned long *)(mem + gMemHdrSize + size1); hdr->magic = gMemMagic; hdr->size = size; + gMemLock; if (ignore) { hdr->index = -1; } else { hdr->index = gMemIndex++; } - gMemLock; if (gMemTail) { gMemTail->next = hdr; hdr->prev = gMemTail; diff --git a/Build/source/libs/xpdf/xpdf-src/goo/gmem.h b/Build/source/libs/xpdf/xpdf-src/goo/gmem.h index e152199325b..87a32f0324c 100644 --- a/Build/source/libs/xpdf/xpdf-src/goo/gmem.h +++ b/Build/source/libs/xpdf/xpdf-src/goo/gmem.h @@ -20,7 +20,11 @@ public: ~GMemException() {} }; -#define GMEM_EXCEP throw(GMemException) +// This used to be: +// #define GMEM_EXCEP throw(GMemException) +// but the throw decl was never really very useful, and is deprecated +// as of C++11 and illegal as of C++17. +#define GMEM_EXCEP #else // USE_EXCEPTIONS diff --git a/Build/source/libs/xpdf/xpdf-src/splash/Splash.cc b/Build/source/libs/xpdf/xpdf-src/splash/Splash.cc index 77718abbe70..44f87a9dcd2 100644 --- a/Build/source/libs/xpdf/xpdf-src/splash/Splash.cc +++ b/Build/source/libs/xpdf/xpdf-src/splash/Splash.cc @@ -18,6 +18,7 @@ #include <math.h> #include "gmem.h" #include "gmempp.h" +#include "GString.h" #include "SplashErrorCodes.h" #include "SplashMath.h" #include "SplashBitmap.h" @@ -257,6 +258,22 @@ inline void Splash::pipeInit(SplashPipe *pipe, SplashPattern *pattern, pipe->run = &Splash::pipeRunAACMYK8; #endif } + } else if (!pipe->pattern && !pipe->noTransparency && !state->softMask && + usesShape && + state->inNonIsolatedGroup && groupBackBitmap->alpha && + !state->inKnockoutGroup && + !state->blendFunc && !pipe->nonIsolatedGroup) { + if (mode == splashModeMono8 && bitmap->alpha) { + pipe->run = &Splash::pipeRunNonIsoMono8; + } else if (mode == splashModeRGB8 && bitmap->alpha) { + pipe->run = &Splash::pipeRunNonIsoRGB8; + } else if (mode == splashModeBGR8 && bitmap->alpha) { + pipe->run = &Splash::pipeRunNonIsoBGR8; +#if SPLASH_CMYK + } else if (mode == splashModeCMYK8 && bitmap->alpha) { + pipe->run = &Splash::pipeRunNonIsoCMYK8; +#endif + } } } @@ -276,6 +293,7 @@ void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y, Guchar *alpha0Ptr; SplashColorPtr softMaskPtr; #if SPLASH_CMYK + Guchar aPrev; SplashColor cSrc2, cDest2; #endif @@ -514,25 +532,38 @@ void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y, break; #if SPLASH_CMYK case splashModeCMYK8: + if (alpha0Ptr) { // non-isolated group + if (color0Ptr) { // non-isolated, knockout group + aPrev = *alpha0Ptr; + } else { // non-isolated, non-knockout group + aPrev = (Guchar)(*alpha0Ptr + aDest - div255(*alpha0Ptr * aDest)); + } + } else { // isolated group + if (color0Ptr) { // isolated, knockout group + aPrev = 0; + } else { // isolated, non-knockout group + aPrev = aDest; + } + } if (state->overprintMask & 0x01) { cSrc[0] = state->cmykTransferC[cSrcPtr[0]]; } else { - cSrc[0] = div255(aDest * cDest[0]); + cSrc[0] = div255(aPrev * cDest[0]); } if (state->overprintMask & 0x02) { cSrc[1] = state->cmykTransferM[cSrcPtr[1]]; } else { - cSrc[1] = div255(aDest * cDest[1]); + cSrc[1] = div255(aPrev * cDest[1]); } if (state->overprintMask & 0x04) { cSrc[2] = state->cmykTransferY[cSrcPtr[2]]; } else { - cSrc[2] = div255(aDest * cDest[2]); + cSrc[2] = div255(aPrev * cDest[2]); } if (state->overprintMask & 0x08) { cSrc[3] = state->cmykTransferK[cSrcPtr[3]]; } else { - cSrc[3] = div255(aDest * cDest[3]); + cSrc[3] = div255(aPrev * cDest[3]); } break; #endif @@ -1986,6 +2017,398 @@ void Splash::pipeRunAACMYK8(SplashPipe *pipe, int x0, int x1, int y, #endif +void Splash::pipeRunNonIsoMono8(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr) { + Guchar shape, aSrc, aDest, alphaI, alpha0, aResult; + Guchar cSrc0, cDest0, cResult0; + SplashColorPtr destColorPtr; + Guchar *destAlphaPtr; + Guchar *alpha0Ptr; + 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; + + destColorPtr = &bitmap->data[y * bitmap->rowSize + x0]; + destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; + alpha0Ptr = &groupBackBitmap->alpha[(groupBackY + y) + * groupBackBitmap->alphaRowSize + + (groupBackX + x0)]; + + for (x = x0; x <= x1; ++x) { + + //----- shape + shape = *shapePtr; + if (!shape) { + destColorPtr += 1; + ++destAlphaPtr; + ++alpha0Ptr; + cSrcPtr += cSrcStride; + ++shapePtr; + continue; + } + lastX = x; + + //----- read destination pixel + cDest0 = destColorPtr[0]; + aDest = *destAlphaPtr; + + //----- source color + cSrc0 = state->grayTransfer[cSrcPtr[0]]; + + //----- source alpha + aSrc = div255(pipe->aInput * shape); + + //----- result alpha and non-isolated group element correction + aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest)); + alpha0 = *alpha0Ptr++; + alphaI = (Guchar)(aResult + alpha0 - div255(aResult * alpha0)); + + //----- result color + if (alphaI == 0) { + cResult0 = 0; + } else { + cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI); + } + + //----- write destination pixel + *destColorPtr++ = cResult0; + *destAlphaPtr++ = aResult; + + cSrcPtr += cSrcStride; + ++shapePtr; + } // for (x ...) + + updateModX(lastX); +} + +void Splash::pipeRunNonIsoRGB8(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr) { + Guchar shape, aSrc, aDest, alphaI, alpha0, aResult; + Guchar cSrc0, cSrc1, cSrc2; + Guchar cDest0, cDest1, cDest2; + Guchar cResult0, cResult1, cResult2; + SplashColorPtr destColorPtr; + Guchar *destAlphaPtr; + Guchar *alpha0Ptr; + 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; + + destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * 3]; + destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; + alpha0Ptr = &groupBackBitmap->alpha[(groupBackY + y) + * groupBackBitmap->alphaRowSize + + (groupBackX + x0)]; + + for (x = x0; x <= x1; ++x) { + + //----- shape + shape = *shapePtr; + if (!shape) { + destColorPtr += 3; + ++destAlphaPtr; + ++alpha0Ptr; + cSrcPtr += cSrcStride; + ++shapePtr; + continue; + } + lastX = x; + + //----- read destination pixel + cDest0 = destColorPtr[0]; + cDest1 = destColorPtr[1]; + cDest2 = destColorPtr[2]; + aDest = *destAlphaPtr; + + //----- source color + cSrc0 = state->rgbTransferR[cSrcPtr[0]]; + cSrc1 = state->rgbTransferG[cSrcPtr[1]]; + cSrc2 = state->rgbTransferB[cSrcPtr[2]]; + + //----- source alpha + aSrc = div255(pipe->aInput * shape); + + //----- result alpha and non-isolated group element correction + aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest)); + alpha0 = *alpha0Ptr++; + alphaI = (Guchar)(aResult + alpha0 - div255(aResult * alpha0)); + + //----- result color + if (alphaI == 0) { + cResult0 = 0; + cResult1 = 0; + cResult2 = 0; + } else { + 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; + } // for (x ...) + + updateModX(lastX); +} + +void Splash::pipeRunNonIsoBGR8(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr) { + Guchar shape, aSrc, aDest, alphaI, alpha0, aResult; + Guchar cSrc0, cSrc1, cSrc2; + Guchar cDest0, cDest1, cDest2; + Guchar cResult0, cResult1, cResult2; + SplashColorPtr destColorPtr; + Guchar *destAlphaPtr; + Guchar *alpha0Ptr; + 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; + + destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * 3]; + destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; + alpha0Ptr = &groupBackBitmap->alpha[(groupBackY + y) + * groupBackBitmap->alphaRowSize + + (groupBackX + x0)]; + + for (x = x0; x <= x1; ++x) { + + //----- shape + shape = *shapePtr; + if (!shape) { + destColorPtr += 3; + ++destAlphaPtr; + ++alpha0Ptr; + cSrcPtr += cSrcStride; + ++shapePtr; + continue; + } + lastX = x; + + //----- read destination pixel + cDest0 = destColorPtr[2]; + cDest1 = destColorPtr[1]; + cDest2 = destColorPtr[0]; + aDest = *destAlphaPtr; + + //----- source color + cSrc0 = state->rgbTransferR[cSrcPtr[0]]; + cSrc1 = state->rgbTransferG[cSrcPtr[1]]; + cSrc2 = state->rgbTransferB[cSrcPtr[2]]; + + //----- source alpha + aSrc = div255(pipe->aInput * shape); + + //----- result alpha and non-isolated group element correction + aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest)); + alpha0 = *alpha0Ptr++; + alphaI = (Guchar)(aResult + alpha0 - div255(aResult * alpha0)); + + //----- result color + if (alphaI == 0) { + cResult0 = 0; + cResult1 = 0; + cResult2 = 0; + } else { + 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] = cResult2; + destColorPtr[1] = cResult1; + destColorPtr[2] = cResult0; + destColorPtr += 3; + *destAlphaPtr++ = aResult; + + cSrcPtr += cSrcStride; + ++shapePtr; + } // for (x ...) + + updateModX(lastX); +} + +#if SPLASH_CMYK +void Splash::pipeRunNonIsoCMYK8(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr) { + Guchar shape, aSrc, aDest, alphaI, alpha0, aResult, aPrev; + Guchar cSrc0, cSrc1, cSrc2, cSrc3; + Guchar cDest0, cDest1, cDest2, cDest3; + Guchar cResult0, cResult1, cResult2, cResult3; + SplashColorPtr destColorPtr; + Guchar *destAlphaPtr; + Guchar *alpha0Ptr; + 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; + + destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * 4]; + destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; + alpha0Ptr = &groupBackBitmap->alpha[(groupBackY + y) + * groupBackBitmap->alphaRowSize + + (groupBackX + x0)]; + + for (x = x0; x <= x1; ++x) { + + //----- shape + shape = *shapePtr; + if (!shape) { + destColorPtr += 4; + ++destAlphaPtr; + ++alpha0Ptr; + cSrcPtr += cSrcStride; + ++shapePtr; + continue; + } + lastX = x; + + //----- read destination pixel + cDest0 = destColorPtr[0]; + cDest1 = destColorPtr[1]; + cDest2 = destColorPtr[2]; + cDest3 = destColorPtr[3]; + aDest = *destAlphaPtr; + + //----- overprint + aPrev = (Guchar)(*alpha0Ptr + aDest - div255(*alpha0Ptr * aDest)); + if (state->overprintMask & 0x01) { + cSrc0 = state->cmykTransferC[cSrcPtr[0]]; + } else { + cSrc0 = div255(aPrev * cDest0); + } + if (state->overprintMask & 0x02) { + cSrc1 = state->cmykTransferM[cSrcPtr[1]]; + } else { + cSrc1 = div255(aPrev * cDest1); + } + if (state->overprintMask & 0x04) { + cSrc2 = state->cmykTransferY[cSrcPtr[2]]; + } else { + cSrc2 = div255(aPrev * cDest2); + } + if (state->overprintMask & 0x08) { + cSrc3 = state->cmykTransferK[cSrcPtr[3]]; + } else { + cSrc3 = div255(aPrev * cDest3); + } + + //----- source alpha + aSrc = div255(pipe->aInput * shape); + + //----- result alpha and non-isolated group element correction + aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest)); + alpha0 = *alpha0Ptr++; + alphaI = (Guchar)(aResult + alpha0 - div255(aResult * alpha0)); + + //----- result color + if (alphaI == 0) { + cResult0 = 0; + cResult1 = 0; + cResult2 = 0; + cResult3 = 0; + } else { + 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; + } // for (x ...) + + updateModX(lastX); +} +#endif + + //------------------------------------------------------------------------ // Transform a point from user space to device space. @@ -2000,10 +2423,41 @@ inline void Splash::transform(SplashCoord *matrix, } //------------------------------------------------------------------------ +// SplashImageCache +//------------------------------------------------------------------------ + +SplashImageCache::SplashImageCache() { + tag = NULL; + image = NULL; + refCount = 1; +} + +SplashImageCache::~SplashImageCache() { + if (tag) { + delete tag; + } + if (image) { + delete image; + } +} + +void SplashImageCache::incRefCount() { + ++refCount; +} + +void SplashImageCache::decRefCount() { + --refCount; + if (refCount == 0) { + delete this; + } +} + +//------------------------------------------------------------------------ // Splash //------------------------------------------------------------------------ Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA, + SplashImageCache *imageCacheA, SplashScreenParams *screenParams) { bitmap = bitmapA; bitmapComps = splashColorModeNComps[bitmap->mode]; @@ -2021,10 +2475,17 @@ Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA, minLineWidth = 0; clearModRegion(); debugMode = gFalse; + + if (imageCacheA) { + imageCache = imageCacheA; + imageCache->incRefCount(); + } else { + imageCache = new SplashImageCache(); + } } Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA, - SplashScreen *screenA) { + SplashImageCache *imageCacheA, SplashScreen *screenA) { bitmap = bitmapA; bitmapComps = splashColorModeNComps[bitmap->mode]; vectorAntialias = vectorAntialiasA; @@ -2041,9 +2502,18 @@ Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA, minLineWidth = 0; clearModRegion(); debugMode = gFalse; + + if (imageCacheA) { + imageCache = imageCacheA; + imageCache->incRefCount(); + } else { + imageCache = new SplashImageCache(); + } } Splash::~Splash() { + imageCache->decRefCount(); + while (state->next) { restoreState(); } @@ -3335,6 +3805,30 @@ SplashError Splash::fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph) { void Splash::getImageBounds(SplashCoord xyMin, SplashCoord xyMax, int *xyMinI, int *xyMaxI) { if (state->strokeAdjust == splashStrokeAdjustOff) { + // make sure the coords fit in 32-bit ints +#if USE_FIXEDPOINT + if (xyMin < -32767) { + xyMin = -32767; + } else if (xyMin > 32767) { + xyMin = 32767; + } + if (xyMax < -32767) { + xyMax = -32767; + } else if (xyMax > 32767) { + xyMax = 32767; + } +#else + if (xyMin < -1e9) { + xyMin = -1e9; + } else if (xyMin > 1e9) { + xyMin = 1e9; + } + if (xyMax < -1e9) { + xyMax = -1e9; + } else if (xyMax > 1e9) { + xyMax = 1e9; + } +#endif *xyMinI = splashFloor(xyMin); *xyMaxI = splashFloor(xyMax); if (*xyMaxI <= *xyMinI) { @@ -3347,7 +3841,8 @@ void Splash::getImageBounds(SplashCoord xyMin, SplashCoord xyMax, // The glyphMode flag is not currently used, but may be useful if the // stroke adjustment behavior is changed. -SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData, +SplashError Splash::fillImageMask(GString *imageTag, + SplashImageMaskSource src, void *srcData, int w, int h, SplashCoord *mat, GBool glyphMode, GBool interpolate) { SplashBitmap *scaledMask; @@ -3401,10 +3896,17 @@ SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData, if (clipRes != splashClipAllOutside) { scaledWidth = x1 - x0; scaledHeight = y1 - y0; - scaledMask = scaleMask(src, srcData, w, h, scaledWidth, scaledHeight, - interpolate); + 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 = gFalse; + } blitMask(scaledMask, x0, y0, clipRes); - delete scaledMask; } // scaling plus vertical flip @@ -3417,11 +3919,17 @@ SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData, if (clipRes != splashClipAllOutside) { scaledWidth = x1 - x0; scaledHeight = y1 - y0; - scaledMask = scaleMask(src, srcData, w, h, scaledWidth, scaledHeight, - interpolate); - vertFlipImage(scaledMask, scaledWidth, scaledHeight, 1); + 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); - delete scaledMask; } // scaling plus horizontal flip @@ -3434,11 +3942,17 @@ SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData, if (clipRes != splashClipAllOutside) { scaledWidth = x1 - x0; scaledHeight = y1 - y0; - scaledMask = scaleMask(src, srcData, w, h, scaledWidth, scaledHeight, - interpolate); - horizFlipImage(scaledMask, scaledWidth, scaledHeight, 1); + 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); - delete scaledMask; } // scaling plus horizontal and vertical flips @@ -3451,17 +3965,23 @@ SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData, if (clipRes != splashClipAllOutside) { scaledWidth = x1 - x0; scaledHeight = y1 - y0; - scaledMask = scaleMask(src, srcData, w, h, scaledWidth, scaledHeight, - interpolate); - vertFlipImage(scaledMask, scaledWidth, scaledHeight, 1); - horizFlipImage(scaledMask, scaledWidth, scaledHeight, 1); + 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); - delete scaledMask; } // all other cases } else { - arbitraryTransformMask(src, srcData, w, h, mat, glyphMode, interpolate); + arbitraryTransformMask(imageTag, src, srcData, w, h, + mat, glyphMode, interpolate); } return splashOk; @@ -3634,7 +4154,8 @@ void Splash::upscaleMask(SplashImageMaskSource src, void *srcData, // The glyphMode flag is not currently used, but may be useful if the // stroke adjustment behavior is changed. -void Splash::arbitraryTransformMask(SplashImageMaskSource src, void *srcData, +void Splash::arbitraryTransformMask(GString *imageTag, + SplashImageMaskSource src, void *srcData, int srcWidth, int srcHeight, SplashCoord *mat, GBool glyphMode, GBool interpolate) { @@ -3727,8 +4248,16 @@ void Splash::arbitraryTransformMask(SplashImageMaskSource src, void *srcData, ir11 = r00 / det; // scale the input image - scaledMask = scaleMask(src, srcData, srcWidth, srcHeight, + 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; @@ -3901,42 +4430,61 @@ void Splash::arbitraryTransformMask(SplashImageMaskSource src, void *srcData, (this->*pipe.run)(&pipe, xa, xb - 1, y, scanBuf + xa, NULL); } } - - delete scaledMask; } // Scale an image mask into a SplashBitmap. -SplashBitmap *Splash::scaleMask(SplashImageMaskSource src, void *srcData, +SplashBitmap *Splash::scaleMask(GString *imageTag, + SplashImageMaskSource src, void *srcData, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, GBool interpolate) { - SplashBitmap *dest; - - dest = new SplashBitmap(scaledWidth, scaledHeight, 1, splashModeMono8, - gFalse); + if (imageCache->tag && imageTag && + !imageCache->tag->cmp(imageTag) && + imageCache->isMask && + imageCache->width == scaledWidth && + imageCache->height == scaledHeight && + 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 = 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, dest); + scaledWidth, scaledHeight, imageCache->image); } else { scaleMaskYdXu(src, srcData, srcWidth, srcHeight, - scaledWidth, scaledHeight, dest); + scaledWidth, scaledHeight, imageCache->image); } } else { if (scaledWidth < srcWidth) { scaleMaskYuXd(src, srcData, srcWidth, srcHeight, - scaledWidth, scaledHeight, dest); + scaledWidth, scaledHeight, imageCache->image); } else { if (interpolate) { scaleMaskYuXuI(src, srcData, srcWidth, srcHeight, - scaledWidth, scaledHeight, dest); + scaledWidth, scaledHeight, imageCache->image); } else { scaleMaskYuXu(src, srcData, srcWidth, srcHeight, - scaledWidth, scaledHeight, dest); + scaledWidth, scaledHeight, imageCache->image); } } } - return dest; + return imageCache->image; } void Splash::scaleMaskYdXd(SplashImageMaskSource src, void *srcData, @@ -4009,7 +4557,7 @@ void Splash::scaleMaskYdXd(SplashImageMaskSource src, void *srcData, pix += pixBuf[xx++]; } // (255 * pix) / xStep * yStep - pix = (pix * d) >> 23; + pix = (pix * d + (1 << 22)) >> 23; // store the pixel *destPtr++ = (Guchar)pix; @@ -4083,7 +4631,7 @@ void Splash::scaleMaskYdXu(SplashImageMaskSource src, void *srcData, // compute the final pixel pix = pixBuf[x]; // (255 * pix) / yStep - pix = (pix * d) >> 23; + pix = (pix * d + (1 << 22)) >> 23; // store the pixel for (i = 0; i < xStep; ++i) { @@ -4158,7 +4706,7 @@ void Splash::scaleMaskYuXd(SplashImageMaskSource src, void *srcData, pix += lineBuf[xx++]; } // (255 * pix) / xStep - pix = (pix * d) >> 23; + pix = (pix * d + (1 << 22)) >> 23; // store the pixel for (i = 0; i < yStep; ++i) { @@ -4403,7 +4951,8 @@ void Splash::blitMask(SplashBitmap *src, int xDest, int yDest, } } -SplashError Splash::drawImage(SplashImageSource src, void *srcData, +SplashError Splash::drawImage(GString *imageTag, + SplashImageSource src, void *srcData, SplashColorMode srcMode, GBool srcAlpha, int w, int h, SplashCoord *mat, GBool interpolate) { @@ -4489,10 +5038,18 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData, if (clipRes != splashClipAllOutside) { scaledWidth = x1 - x0; scaledHeight = y1 - y0; - scaledImg = scaleImage(src, srcData, srcMode, nComps, srcAlpha, w, h, + 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 = gFalse; + } blitImage(scaledImg, srcAlpha, x0, y0, clipRes); - delete scaledImg; } // scaling plus vertical flip @@ -4505,11 +5062,18 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData, if (clipRes != splashClipAllOutside) { scaledWidth = x1 - x0; scaledHeight = y1 - y0; - scaledImg = scaleImage(src, srcData, srcMode, nComps, srcAlpha, w, h, + scaledImg = scaleImage(imageTag, + src, srcData, srcMode, nComps, srcAlpha, w, h, scaledWidth, scaledHeight, interpolate); - vertFlipImage(scaledImg, scaledWidth, scaledHeight, nComps); + 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); - delete scaledImg; } // scaling plus horizontal flip @@ -4522,11 +5086,18 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData, if (clipRes != splashClipAllOutside) { scaledWidth = x1 - x0; scaledHeight = y1 - y0; - scaledImg = scaleImage(src, srcData, srcMode, nComps, srcAlpha, w, h, + scaledImg = scaleImage(imageTag, + src, srcData, srcMode, nComps, srcAlpha, w, h, scaledWidth, scaledHeight, interpolate); - horizFlipImage(scaledImg, scaledWidth, scaledHeight, nComps); + 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); - delete scaledImg; } // scaling plus horizontal and vertical flips @@ -4539,17 +5110,23 @@ SplashError Splash::drawImage(SplashImageSource src, void *srcData, if (clipRes != splashClipAllOutside) { scaledWidth = x1 - x0; scaledHeight = y1 - y0; - scaledImg = scaleImage(src, srcData, srcMode, nComps, srcAlpha, w, h, + scaledImg = scaleImage(imageTag, + src, srcData, srcMode, nComps, srcAlpha, w, h, scaledWidth, scaledHeight, interpolate); - vertFlipImage(scaledImg, scaledWidth, scaledHeight, nComps); - horizFlipImage(scaledImg, scaledWidth, scaledHeight, nComps); + 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); - delete scaledImg; } // all other cases } else { - arbitraryTransformImage(src, srcData, srcMode, nComps, srcAlpha, + arbitraryTransformImage(imageTag, src, srcData, srcMode, nComps, srcAlpha, w, h, mat, interpolate); } @@ -4765,7 +5342,8 @@ void Splash::upscaleImage(SplashImageSource src, void *srcData, gfree(unscaledAlpha); } -void Splash::arbitraryTransformImage(SplashImageSource src, void *srcData, +void Splash::arbitraryTransformImage(GString *imageTag, + SplashImageSource src, void *srcData, SplashColorMode srcMode, int nComps, GBool srcAlpha, int srcWidth, int srcHeight, @@ -4860,9 +5438,17 @@ void Splash::arbitraryTransformImage(SplashImageSource src, void *srcData, ir11 = r00 / det; // scale the input image - scaledImg = scaleImage(src, srcData, srcMode, nComps, srcAlpha, + 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; @@ -5045,41 +5631,70 @@ void Splash::arbitraryTransformImage(SplashImageSource src, void *srcData, } gfree(pixelBuf); - delete scaledImg; } // Scale an image into a SplashBitmap. -SplashBitmap *Splash::scaleImage(SplashImageSource src, void *srcData, +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) { - SplashBitmap *dest; - - dest = new SplashBitmap(scaledWidth, scaledHeight, 1, srcMode, srcAlpha); + 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, dest); + srcWidth, srcHeight, scaledWidth, scaledHeight, + imageCache->image); } else { scaleImageYdXu(src, srcData, srcMode, nComps, srcAlpha, - srcWidth, srcHeight, scaledWidth, scaledHeight, dest); + srcWidth, srcHeight, scaledWidth, scaledHeight, + imageCache->image); } } else { if (scaledWidth < srcWidth) { scaleImageYuXd(src, srcData, srcMode, nComps, srcAlpha, - srcWidth, srcHeight, scaledWidth, scaledHeight, dest); + srcWidth, srcHeight, scaledWidth, scaledHeight, + imageCache->image); } else { if (interpolate) { scaleImageYuXuI(src, srcData, srcMode, nComps, srcAlpha, - srcWidth, srcHeight, scaledWidth, scaledHeight, dest); + srcWidth, srcHeight, scaledWidth, scaledHeight, + imageCache->image); } else { scaleImageYuXu(src, srcData, srcMode, nComps, srcAlpha, - srcWidth, srcHeight, scaledWidth, scaledHeight, dest); + srcWidth, srcHeight, scaledWidth, scaledHeight, + imageCache->image); } } } - return dest; + return imageCache->image; } void Splash::scaleImageYdXd(SplashImageSource src, void *srcData, @@ -5177,7 +5792,7 @@ void Splash::scaleImageYdXd(SplashImageSource src, void *srcData, pix0 += pixBuf[xx++]; } // pix / xStep * yStep - pix0 = (pix0 * d) >> 23; + pix0 = (pix0 * d + (1 << 22)) >> 23; // store the pixel *destPtr++ = (Guchar)pix0; @@ -5194,9 +5809,9 @@ void Splash::scaleImageYdXd(SplashImageSource src, void *srcData, xx += 3; } // pix / xStep * yStep - pix0 = (pix0 * d) >> 23; - pix1 = (pix1 * d) >> 23; - pix2 = (pix2 * d) >> 23; + pix0 = (pix0 * d + (1 << 22)) >> 23; + pix1 = (pix1 * d + (1 << 22)) >> 23; + pix2 = (pix2 * d + (1 << 22)) >> 23; // store the pixel *destPtr++ = (Guchar)pix0; @@ -5217,10 +5832,10 @@ void Splash::scaleImageYdXd(SplashImageSource src, void *srcData, xx += 4; } // pix / xStep * yStep - pix0 = (pix0 * d) >> 23; - pix1 = (pix1 * d) >> 23; - pix2 = (pix2 * d) >> 23; - pix3 = (pix3 * d) >> 23; + 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; @@ -5244,7 +5859,7 @@ void Splash::scaleImageYdXd(SplashImageSource src, void *srcData, alpha += alphaPixBuf[xxa]; } // alpha / xStep * yStep - alpha = (alpha * d) >> 23; + alpha = (alpha * d + (1 << 22)) >> 23; *destAlphaPtr++ = (Guchar)alpha; } } @@ -5343,7 +5958,7 @@ void Splash::scaleImageYdXu(SplashImageSource src, void *srcData, // compute the final pixel for (i = 0; i < nComps; ++i) { // pixBuf[] / yStep - pix[i] = (pixBuf[x * nComps + i] * d) >> 23; + pix[i] = (pixBuf[x * nComps + i] * d + (1 << 22)) >> 23; } // store the pixel @@ -5379,7 +5994,7 @@ void Splash::scaleImageYdXu(SplashImageSource src, void *srcData, // process alpha if (srcAlpha) { // alphaPixBuf[] / yStep - alpha = (alphaPixBuf[x] * d) >> 23; + alpha = (alphaPixBuf[x] * d + (1 << 22)) >> 23; for (i = 0; i < xStep; ++i) { *destAlphaPtr++ = (Guchar)alpha; } @@ -5474,7 +6089,7 @@ void Splash::scaleImageYuXd(SplashImageSource src, void *srcData, } for (i = 0; i < nComps; ++i) { // pix[] / xStep - pix[i] = (pix[i] * d) >> 23; + pix[i] = (pix[i] * d + (1 << 22)) >> 23; } // store the pixel @@ -5517,7 +6132,7 @@ void Splash::scaleImageYuXd(SplashImageSource src, void *srcData, alpha += alphaLineBuf[xxa]; } // alpha / xStep - alpha = (alpha * d) >> 23; + alpha = (alpha * d + (1 << 22)) >> 23; for (i = 0; i < yStep; ++i) { destAlphaPtr = destAlphaPtr0 + i * scaledWidth + x; *destAlphaPtr = (Guchar)alpha; diff --git a/Build/source/libs/xpdf/xpdf-src/splash/Splash.h b/Build/source/libs/xpdf/xpdf-src/splash/Splash.h index 423ed360573..f35aa7eafd9 100644 --- a/Build/source/libs/xpdf/xpdf-src/splash/Splash.h +++ b/Build/source/libs/xpdf/xpdf-src/splash/Splash.h @@ -18,6 +18,7 @@ #include "SplashTypes.h" #include "SplashClip.h" +class GString; class Splash; class SplashBitmap; struct SplashGlyphBitmap; @@ -65,6 +66,34 @@ enum SplashPipeResultColorCtrl { }; //------------------------------------------------------------------------ +// SplashImageCache +//------------------------------------------------------------------------ + +// This holds a cached image, and is shared by multiple Splash objects +// in the same thread. +class SplashImageCache { +public: + + SplashImageCache(); + ~SplashImageCache(); + void incRefCount(); + void decRefCount(); + + GString *tag; + GBool isMask; + int width; + int height; + SplashColorMode mode; + GBool alpha; + GBool interpolate; + GBool vertFlip; + GBool horizFlip; + SplashBitmap *image; + + int refCount; +}; + +//------------------------------------------------------------------------ // Splash //------------------------------------------------------------------------ @@ -73,9 +102,10 @@ public: // Create a new rasterizer object. Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA, + SplashImageCache *imageCacheA, SplashScreenParams *screenParams = NULL); Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA, - SplashScreen *screenA); + SplashImageCache *imageCacheA, SplashScreen *screenA); ~Splash(); @@ -173,7 +203,8 @@ public: // Note that the Splash y axis points downward, and the image source // is assumed to produce pixels in raster order, starting from the // top line. - SplashError fillImageMask(SplashImageMaskSource src, void *srcData, + SplashError fillImageMask(GString *imageTag, + SplashImageMaskSource src, void *srcData, int w, int h, SplashCoord *mat, GBool glyphMode, GBool interpolate); @@ -191,7 +222,8 @@ public: // BGR8 RGB8 // CMYK8 CMYK8 // The matrix behaves as for fillImageMask. - SplashError drawImage(SplashImageSource src, void *srcData, + SplashError drawImage(GString *imageTag, + SplashImageSource src, void *srcData, SplashColorMode srcMode, GBool srcAlpha, int w, int h, SplashCoord *mat, GBool interpolate); @@ -255,6 +287,8 @@ public: // Toggle debug mode on or off. void setDebugMode(GBool debugModeA) { debugMode = debugModeA; } + SplashImageCache *getImageCache() { return imageCache; } + #if 1 //~tmp: turn off anti-aliasing temporarily void setInShading(GBool sh) { inShading = sh; } #endif @@ -303,6 +337,16 @@ private: void pipeRunAACMYK8(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, + Guchar *shapePtr, SplashColorPtr cSrcPtr); + void pipeRunNonIsoBGR8(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr); +#if SPLASH_CMYK + void pipeRunNonIsoCMYK8(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr); +#endif void transform(SplashCoord *matrix, SplashCoord xi, SplashCoord yi, SplashCoord *xo, SplashCoord *yo); void updateModX(int x); @@ -331,11 +375,13 @@ private: int srcWidth, int srcHeight, SplashCoord *mat, GBool glyphMode, GBool interpolate); - void arbitraryTransformMask(SplashImageMaskSource src, void *srcData, + void arbitraryTransformMask(GString *imageTag, + SplashImageMaskSource src, void *srcData, int srcWidth, int srcHeight, SplashCoord *mat, GBool glyphMode, GBool interpolate); - SplashBitmap *scaleMask(SplashImageMaskSource src, void *srcData, + SplashBitmap *scaleMask(GString *imageTag, + SplashImageMaskSource src, void *srcData, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, GBool interpolate); @@ -365,12 +411,14 @@ private: SplashColorMode srcMode, int nComps, GBool srcAlpha, int srcWidth, int srcHeight, SplashCoord *mat, GBool interpolate); - void arbitraryTransformImage(SplashImageSource src, void *srcData, + void arbitraryTransformImage(GString *imageTag, + SplashImageSource src, void *srcData, SplashColorMode srcMode, int nComps, GBool srcAlpha, int srcWidth, int srcHeight, SplashCoord *mat, GBool interpolate); - SplashBitmap *scaleImage(SplashImageSource src, void *srcData, + SplashBitmap *scaleImage(GString *imageTag, + SplashImageSource src, void *srcData, SplashColorMode srcMode, int nComps, GBool srcAlpha, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, @@ -432,6 +480,8 @@ private: GBool vectorAntialias; GBool inShading; GBool debugMode; + + SplashImageCache *imageCache; }; #endif diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashBitmap.cc b/Build/source/libs/xpdf/xpdf-src/splash/SplashBitmap.cc index aa916179df3..88ce49ca3b4 100644 --- a/Build/source/libs/xpdf/xpdf-src/splash/SplashBitmap.cc +++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashBitmap.cc @@ -25,7 +25,7 @@ SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPad, SplashColorMode modeA, GBool alphaA, - GBool topDown) { + GBool topDown, SplashBitmap *parentA) { // NB: this code checks that rowSize fits in a signed 32-bit // integer, because some code (outside this class) makes that // assumption @@ -63,14 +63,35 @@ SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPad, } rowSize += rowPad - 1; rowSize -= rowSize % rowPad; - data = (SplashColorPtr)gmallocn64(height, rowSize); + + parent = parentA; + oldData = NULL; + oldAlpha = NULL; + oldRowSize = 0; + oldAlphaRowSize = 0; + oldHeight = 0; + if (parent && parent->oldData && + parent->oldRowSize == rowSize && + parent->oldHeight == height) { + data = parent->oldData; + parent->oldData = NULL; + } else { + data = (SplashColorPtr)gmallocn64(height, rowSize); + } if (!topDown) { data += (height - 1) * rowSize; rowSize = -rowSize; } if (alphaA) { alphaRowSize = width; - alpha = (Guchar *)gmallocn64(height, alphaRowSize); + if (parent && parent->oldAlpha && + parent->oldAlphaRowSize == alphaRowSize && + parent->oldHeight == height) { + alpha = parent->oldAlpha; + parent->oldAlpha = NULL; + } else { + alpha = (Guchar *)gmallocn64(height, alphaRowSize); + } } else { alphaRowSize = 0; alpha = NULL; @@ -78,14 +99,24 @@ SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPad, } SplashBitmap::~SplashBitmap() { - if (data) { - if (rowSize < 0) { - gfree(data + (height - 1) * rowSize); - } else { - gfree(data); - } + if (data && rowSize < 0) { + rowSize = -rowSize; + data -= (height - 1) * rowSize; + } + if (parent && rowSize > 10000000 / height) { + gfree(parent->oldData); + gfree(parent->oldAlpha); + parent->oldData = data; + parent->oldAlpha = alpha; + parent->oldRowSize = rowSize; + parent->oldAlphaRowSize = alphaRowSize; + parent->oldHeight = height; + } else { + gfree(data); + gfree(alpha); } - gfree(alpha); + gfree(oldData); + gfree(oldAlpha); } SplashError SplashBitmap::writePNMFile(char *fileName) { diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashBitmap.h b/Build/source/libs/xpdf/xpdf-src/splash/SplashBitmap.h index d03f44c0884..44980833668 100644 --- a/Build/source/libs/xpdf/xpdf-src/splash/SplashBitmap.h +++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashBitmap.h @@ -44,7 +44,7 @@ public: // upside-down, i.e., with the last row first in memory. SplashBitmap(int widthA, int heightA, int rowPad, SplashColorMode modeA, GBool alphaA, - GBool topDown = gTrue); + GBool topDown, SplashBitmap *parentA); ~SplashBitmap(); @@ -79,6 +79,14 @@ private: Guchar *alpha; // pointer to row zero of the alpha data // (always top-down) + // save the last-allocated (large) bitmap data and reuse if possible + SplashBitmap *parent; + SplashColorPtr oldData; + Guchar *oldAlpha; + SplashBitmapRowSize oldRowSize; + size_t oldAlphaRowSize; + int oldHeight; + friend class Splash; }; diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashFontEngine.cc b/Build/source/libs/xpdf/xpdf-src/splash/SplashFontEngine.cc index 2d0542d152b..fe377fe25f4 100644 --- a/Build/source/libs/xpdf/xpdf-src/splash/SplashFontEngine.cc +++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashFontEngine.cc @@ -132,10 +132,14 @@ SplashFontFile *SplashFontEngine::loadType1CFont(SplashFontFileID *idA, char *fileName, GBool deleteFile, #endif + int *codeToGID, const char **enc) { SplashFontFile *fontFile; fontFile = NULL; + if (!fontFile) { + gfree(codeToGID); + } #if HAVE_FREETYPE_H if (!fontFile && ftEngine) { fontFile = ftEngine->loadType1CFont(idA, @@ -168,10 +172,14 @@ SplashFontFile *SplashFontEngine::loadOpenTypeT1CFont(SplashFontFileID *idA, char *fileName, GBool deleteFile, #endif + int *codeToGID, const char **enc) { SplashFontFile *fontFile; fontFile = NULL; + if (!fontFile) { + gfree(codeToGID); + } #if HAVE_FREETYPE_H if (!fontFile && ftEngine) { fontFile = ftEngine->loadOpenTypeT1CFont(idA, @@ -221,6 +229,10 @@ SplashFontFile *SplashFontEngine::loadCIDFont(SplashFontFileID *idA, } #endif + if (!fontFile) { + gfree(codeToGID); + } + #if !LOAD_FONTS_FROM_MEM && !defined(_WIN32) && !defined(__ANDROID__) // delete the (temporary) font file -- with Unix hard link // semantics, this will remove the last link; otherwise it will @@ -258,6 +270,10 @@ SplashFontFile *SplashFontEngine::loadOpenTypeCFFFont(SplashFontFileID *idA, } #endif + if (!fontFile) { + gfree(codeToGID); + } + #if !LOAD_FONTS_FROM_MEM && !defined(_WIN32) && !defined(__ANDROID__) // delete the (temporary) font file -- with Unix hard link // semantics, this will remove the last link; otherwise it will diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashFontEngine.h b/Build/source/libs/xpdf/xpdf-src/splash/SplashFontEngine.h index ac2558ee52d..f9eab4d00f4 100644 --- a/Build/source/libs/xpdf/xpdf-src/splash/SplashFontEngine.h +++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashFontEngine.h @@ -68,14 +68,14 @@ public: #else char *fileName, GBool deleteFile, #endif - const char **enc); + int *codeToGID, const char **enc); SplashFontFile *loadOpenTypeT1CFont(SplashFontFileID *idA, #if LOAD_FONTS_FROM_MEM GString *fontBuf, #else char *fileName, GBool deleteFile, #endif - const char **enc); + int *codeToGID, const char **enc); SplashFontFile *loadCIDFont(SplashFontFileID *idA, #if LOAD_FONTS_FROM_MEM GString *fontBuf, diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashMath.h b/Build/source/libs/xpdf/xpdf-src/splash/SplashMath.h index 71afa3cb5c7..45f4e53e6bb 100644 --- a/Build/source/libs/xpdf/xpdf-src/splash/SplashMath.h +++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashMath.h @@ -47,17 +47,13 @@ static inline int splashFloor(SplashCoord x) { // NB: 64-bit x86 guarantees availability of SSE2. __m128d m1, m2; - __m128i m3; - int s, i; - - m1 = _mm_set_sd(x); // m1 = x - i = _mm_cvttsd_si32(m1); // i = trunc(x) - m2 = _mm_cvtsi32_sd(m1, i); // m2 = (double)trunc(x) - m1 = _mm_sub_sd(m1, m2); // m1 = x - trunc(x) - m3 = _mm_castpd_si128(m1); // m3 = m1 (as 64-bit int) - m3 = _mm_srli_epi64(m3, 63); // m3 = m3 >> 63 - s = _mm_cvtsi128_si32(m3); // s = m3 = sign bit of x - trunc(x) - return i - s; // trunc(x) - sign bit + int i, s; + + m1 = _mm_set_sd(x); + i = _mm_cvttsd_si32(m1); + m2 = _mm_cvtsi32_sd(m1, i); + s = _mm_ucomigt_sd(m2, m1); + return i - s; #elif defined(__GNUC__) && defined(__i386__) && !defined(__APPLE__) @@ -123,17 +119,13 @@ static inline int splashCeil(SplashCoord x) { // NB: 64-bit x86 guarantees availability of SSE2. __m128d m1, m2; - __m128i m3; - int s, i; - - m1 = _mm_set_sd(x); // m1 = x - i = _mm_cvttsd_si32(m1); // i = trunc(x) - m2 = _mm_cvtsi32_sd(m1, i); // m2 = (double)trunc(x) - m2 = _mm_sub_sd(m2, m1); // m2 = trunc(x) - x - m3 = _mm_castpd_si128(m2); // m3 = m2 (as 64-bit int) - m3 = _mm_srli_epi64(m3, 63); // m3 = m3 >> 63 - s = _mm_cvtsi128_si32(m3); // s = m3 = sign bit of x - trunc(x) - return i + s; // trunc(x) + sign bit + int i, s; + + m1 = _mm_set_sd(x); + i = _mm_cvttsd_si32(m1); + m2 = _mm_cvtsi32_sd(m1, i); + s = _mm_ucomilt_sd(m2, m1); + return i + s; #elif defined(__GNUC__) && defined(__i386__) && !defined(__APPLE__) @@ -315,6 +307,31 @@ static inline void splashStrokeAdjust(SplashCoord xMin, SplashCoord xMax, SplashCoord w = -1) { int x0, x1; + // make sure the coords fit in 32-bit ints +#if USE_FIXEDPOINT + if (xMin < -32767) { + xMin = -32767; + } else if (xMin > 32767) { + xMin = 32767; + } + if (xMax < -32767) { + xMax = -32767; + } else if (xMax > 32767) { + xMax = 32767; + } +#else + if (xMin < -1e9) { + xMin = -1e9; + } else if (xMin > 1e9) { + xMin = 1e9; + } + if (xMax < -1e9) { + xMax = -1e9; + } else if (xMax > 1e9) { + xMax = 1e9; + } +#endif + // this will never be called with strokeAdjMode == splashStrokeAdjustOff if (strokeAdjMode == splashStrokeAdjustCAD) { x0 = splashRound(xMin); diff --git a/Build/source/libs/xpdf/xpdf-src/splash/SplashXPath.cc b/Build/source/libs/xpdf/xpdf-src/splash/SplashXPath.cc index f0164a85bd4..01a94987637 100644 --- a/Build/source/libs/xpdf/xpdf-src/splash/SplashXPath.cc +++ b/Build/source/libs/xpdf/xpdf-src/splash/SplashXPath.cc @@ -247,14 +247,14 @@ GBool SplashXPath::strokeAdjust(SplashXPathPoint *pts, x2 = pts[hint->ctrl1 ].x; y2 = pts[hint->ctrl1 ].y; x3 = pts[hint->ctrl1 + 1].x; y3 = pts[hint->ctrl1 + 1].y; w = -1; - if (x0 == x1 && x2 == x3) { + if (splashAbs(x0 - x1) < 0.01 && splashAbs(x2 - x3) < 0.01) { adjusts[i].vert = gTrue; adj0 = x0; adj1 = x2; if (hint->projectingCap) { w = splashAbs(y1 - y0); } - } else if (y0 == y1 && y2 == y3) { + } else if (splashAbs(y0 - y1) < 0.01 && splashAbs(y2 - y3) < 0.01) { adjusts[i].vert = gFalse; adj0 = y0; adj1 = y2; diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/AcroForm.cc b/Build/source/libs/xpdf/xpdf-src/xpdf/AcroForm.cc index 1d312e97428..c7f30405483 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/AcroForm.cc +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/AcroForm.cc @@ -1542,10 +1542,11 @@ void AcroFormField::drawText(GString *text, GString *da, GfxFontDict *fontDict, fontSize = atof(tok->getCString()); } else { error(errSyntaxError, -1, "Missing 'Tf' operator in field's DA string"); - fontSize = 10; + fontSize = 0; if (!daToks) { daToks = new GList(); } + tfPos = daToks->getLength(); daToks->append(new GString("/xpdf_default_font")); daToks->append(new GString("10")); daToks->append(new GString("Tf")); @@ -1583,7 +1584,7 @@ void AcroFormField::drawText(GString *text, GString *da, GfxFontDict *fontDict, // compute font autosize if (fontSize == 0) { - for (fontSize = 20; fontSize > 1; --fontSize) { + for (fontSize = 10; fontSize > 1; --fontSize) { y = dy - 3; w2 = 0; i = 0; @@ -1596,7 +1597,7 @@ void AcroFormField::drawText(GString *text, GString *da, GfxFontDict *fontDict, y -= fontSize; } // approximate the descender for the last line - if (y >= 0.33 * fontSize) { + if (y >= 0.33 * fontSize && w <= wMax) { break; } } @@ -1697,6 +1698,9 @@ void AcroFormField::drawText(GString *text, GString *da, GfxFontDict *fontDict, fontSize = w; } fontSize = floor(fontSize); + if (fontSize > 10) { + fontSize = 10; + } if (tfPos >= 0) { tok = (GString *)daToks->get(tfPos + 1); tok->clear(); @@ -1783,6 +1787,9 @@ void AcroFormField::drawText(GString *text, GString *da, GfxFontDict *fontDict, fontSize = fontSize2; } fontSize = floor(fontSize); + if (fontSize > 10) { + fontSize = 10; + } if (tfPos >= 0) { tok = (GString *)daToks->get(tfPos + 1); tok->clear(); @@ -1936,6 +1943,9 @@ void AcroFormField::drawListBox(GString **text, GBool *selection, fontSize = fontSize2; } fontSize = floor(fontSize); + if (fontSize > 10) { + fontSize = 10; + } if (tfPos >= 0) { tok = (GString *)daToks->get(tfPos + 1); tok->clear(); diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/Annot.cc b/Build/source/libs/xpdf/xpdf-src/xpdf/Annot.cc index 850c6b25651..61a1d434abf 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/Annot.cc +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/Annot.cc @@ -845,7 +845,7 @@ GBool Annot::setFillColor(Object *colorObj) { if (!colorObj->isArray()) { return gFalse; } - for (i = 0; i < colorObj->arrayGetLength(); ++i) { + for (i = 0; i < colorObj->arrayGetLength() && i < 4; ++i) { if (colorObj->arrayGet(i, &obj)->isNum()) { color[i] = obj.getNum(); } else { diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/BuiltinFont.cc b/Build/source/libs/xpdf/xpdf-src/xpdf/BuiltinFont.cc index 01dbd110dca..d2f875e45fd 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/BuiltinFont.cc +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/BuiltinFont.cc @@ -51,6 +51,7 @@ GBool BuiltinFontWidths::getWidth(const char *name, Gushort *width) { return gTrue; } } + *width = 0; return gFalse; } diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/CMakeLists.txt b/Build/source/libs/xpdf/xpdf-src/xpdf/CMakeLists.txt index 8fb3f2050bb..4c88d1d351f 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/CMakeLists.txt +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/CMakeLists.txt @@ -111,7 +111,9 @@ if (HAVE_SPLASH) ${PAPER_LIBRARY} ${FREETYPE_LIBRARY} ${FREETYPE_OTHER_LIBS} ${DTYPE_LIBRARY} - ${LCMS_LIBRARY}) + ${LCMS_LIBRARY} + ${FONTCONFIG_LIBRARY} + ${CMAKE_THREAD_LIBS_INIT}) else () add_executable(pdftops $<TARGET_OBJECTS:xpdf_objs> @@ -119,7 +121,11 @@ else () PSOutputDev.cc pdftops.cc ) - target_link_libraries(pdftops goo fofi ${PAPER_LIBRARY} ${LCMS_LIBRARY}) + target_link_libraries(pdftops goo fofi + ${PAPER_LIBRARY} + ${LCMS_LIBRARY} + ${FONTCONFIG_LIBRARY} + ${CMAKE_THREAD_LIBS_INIT}) endif () install(TARGETS pdftops RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) install(FILES ${PROJECT_SOURCE_DIR}/doc/pdftops.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) @@ -131,7 +137,11 @@ add_executable(pdftotext TextOutputDev.cc pdftotext.cc ) -target_link_libraries(pdftotext goo fofi ${PAPER_LIBRARY} ${LCMS_LIBRARY}) +target_link_libraries(pdftotext goo fofi + ${PAPER_LIBRARY} + ${LCMS_LIBRARY} + ${FONTCONFIG_LIBRARY} + ${CMAKE_THREAD_LIBS_INIT}) install(TARGETS pdftotext RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) install(FILES ${PROJECT_SOURCE_DIR}/doc/pdftotext.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) @@ -143,13 +153,17 @@ if (HAVE_SPLASH AND PNG_FOUND) HTMLGen.cc SplashOutputDev.cc TextOutputDev.cc + WebFont.cc pdftohtml.cc ) target_link_libraries(pdftohtml goo fofi splash ${PAPER_LIBRARY} ${FREETYPE_LIBRARY} ${FREETYPE_OTHER_LIBS} ${DTYPE_LIBRARY} - ${LCMS_LIBRARY} ${PNG_LIBRARIES}) + ${LCMS_LIBRARY} + ${PNG_LIBRARIES} + ${FONTCONFIG_LIBRARY} + ${CMAKE_THREAD_LIBS_INIT}) install(TARGETS pdftohtml RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) install(FILES ${PROJECT_SOURCE_DIR}/doc/pdftohtml.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) endif () @@ -160,7 +174,11 @@ add_executable(pdfinfo $<TARGET_OBJECTS:xpdf_objs> pdfinfo.cc ) -target_link_libraries(pdfinfo goo fofi ${PAPER_LIBRARY} ${LCMS_LIBRARY}) +target_link_libraries(pdfinfo goo fofi + ${PAPER_LIBRARY} + ${LCMS_LIBRARY} + ${FONTCONFIG_LIBRARY} + ${CMAKE_THREAD_LIBS_INIT}) install(TARGETS pdfinfo RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) install(FILES ${PROJECT_SOURCE_DIR}/doc/pdfinfo.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) @@ -170,7 +188,11 @@ add_executable(pdffonts $<TARGET_OBJECTS:xpdf_objs> pdffonts.cc ) -target_link_libraries(pdffonts goo fofi ${PAPER_LIBRARY} ${LCMS_LIBRARY}) +target_link_libraries(pdffonts goo fofi + ${PAPER_LIBRARY} + ${LCMS_LIBRARY} + ${FONTCONFIG_LIBRARY} + ${CMAKE_THREAD_LIBS_INIT}) install(TARGETS pdffonts RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) install(FILES ${PROJECT_SOURCE_DIR}/doc/pdffonts.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) @@ -180,7 +202,11 @@ add_executable(pdfdetach $<TARGET_OBJECTS:xpdf_objs> pdfdetach.cc ) -target_link_libraries(pdfdetach goo fofi ${PAPER_LIBRARY} ${LCMS_LIBRARY}) +target_link_libraries(pdfdetach goo fofi + ${PAPER_LIBRARY} + ${LCMS_LIBRARY} + ${FONTCONFIG_LIBRARY} + ${CMAKE_THREAD_LIBS_INIT}) install(TARGETS pdfdetach RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) install(FILES ${PROJECT_SOURCE_DIR}/doc/pdfdetach.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) @@ -196,7 +222,9 @@ if (HAVE_SPLASH) ${PAPER_LIBRARY} ${FREETYPE_LIBRARY} ${FREETYPE_OTHER_LIBS} ${DTYPE_LIBRARY} - ${LCMS_LIBRARY}) + ${LCMS_LIBRARY} + ${FONTCONFIG_LIBRARY} + ${CMAKE_THREAD_LIBS_INIT}) install(TARGETS pdftoppm RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) install(FILES ${PROJECT_SOURCE_DIR}/doc/pdftoppm.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) endif () @@ -213,7 +241,10 @@ if (HAVE_SPLASH AND PNG_FOUND) ${PAPER_LIBRARY} ${FREETYPE_LIBRARY} ${FREETYPE_OTHER_LIBS} ${DTYPE_LIBRARY} - ${LCMS_LIBRARY} ${PNG_LIBRARIES}) + ${LCMS_LIBRARY} + ${PNG_LIBRARIES} + ${FONTCONFIG_LIBRARY} + ${CMAKE_THREAD_LIBS_INIT}) install(TARGETS pdftopng RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) install(FILES ${PROJECT_SOURCE_DIR}/doc/pdftopng.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) endif () @@ -225,7 +256,11 @@ add_executable(pdfimages ImageOutputDev.cc pdfimages.cc ) -target_link_libraries(pdfimages goo fofi ${PAPER_LIBRARY} ${LCMS_LIBRARY}) +target_link_libraries(pdfimages goo fofi + ${PAPER_LIBRARY} + ${LCMS_LIBRARY} + ${FONTCONFIG_LIBRARY} + ${CMAKE_THREAD_LIBS_INIT}) install(TARGETS pdfimages RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) install(FILES ${PROJECT_SOURCE_DIR}/doc/pdfimages.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/Catalog.cc b/Build/source/libs/xpdf/xpdf-src/xpdf/Catalog.cc index 470807314a6..bec30a8dcfd 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/Catalog.cc +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/Catalog.cc @@ -89,6 +89,59 @@ EmbeddedFile::~EmbeddedFile() { } //------------------------------------------------------------------------ +// PageLabelNode +//------------------------------------------------------------------------ + +class PageLabelNode { +public: + + PageLabelNode(int firstPageA, Dict *dict); + ~PageLabelNode(); + + int firstPage; // first page number covered by this node + int lastPage; // last page number covered by this node + TextString *prefix; // label prefix (may be empty) + int start; // value of the numeric portion of this + // label for the first page in the range + char style; // page label style +}; + +PageLabelNode::PageLabelNode(int firstPageA, Dict *dict) { + Object prefixObj, styleObj, startObj; + + // convert page index to page number + firstPage = firstPageA + 1; + + // lastPage will be filled in later + lastPage = -1; + + if (dict->lookup("P", &prefixObj)->isString()) { + prefix = new TextString(prefixObj.getString()); + } else { + prefix = new TextString(); + } + prefixObj.free(); + + style = '\0'; + if (dict->lookup("S", &styleObj)->isName()) { + if (strlen(styleObj.getName()) == 1) { + style = styleObj.getName()[0]; + } + } + styleObj.free(); + + start = 1; + if (dict->lookup("St", &startObj)->isInt()) { + start = startObj.getInt(); + } + startObj.free(); +} + +PageLabelNode::~PageLabelNode() { + delete prefix; +} + +//------------------------------------------------------------------------ // Catalog //------------------------------------------------------------------------ @@ -185,6 +238,15 @@ Catalog::Catalog(PDFDoc *docA) { // get the list of embedded files readEmbeddedFileList(catDict.getDict()); + // get the ViewerPreferences object + catDict.dictLookupNF("ViewerPreferences", &viewerPrefs); + + pageLabels = NULL; + if (catDict.dictLookup("PageLabels", &obj)->isDict()) { + readPageLabelTree(&obj); + } + obj.free(); + catDict.free(); return; @@ -229,6 +291,10 @@ Catalog::~Catalog() { if (embeddedFiles) { deleteGList(embeddedFiles, EmbeddedFile); } + if (pageLabels) { + deleteGList(pageLabels, PageLabelNode); + } + viewerPrefs.free(); } Page *Catalog::getPage(int i) { @@ -833,107 +899,45 @@ Object *Catalog::getEmbeddedFileStreamObj(int idx, Object *strObj) { return strObj; } -TextString *Catalog::getPageLabel(int pageNum) { - Object catDict, node, pageLabelObj, start, prefix, style; - GString *label, *s; - TextString *ts; - int firstPageIndex, pageRangeNum; - - if (!xref->getCatalog(&catDict)->isDict()) { - catDict.free(); - return NULL; - } +void Catalog::readPageLabelTree(Object *root) { + PageLabelNode *label0, *label1; + int i; - label = NULL; - catDict.dictLookup("PageLabels", &node); - if (findPageLabel(&node, pageNum - 1, &pageLabelObj, &firstPageIndex)) { - if (pageLabelObj.isDict()) { - if (pageLabelObj.dictLookup("P", &prefix)->isString()) { - label = prefix.getString()->copy(); - } else { - label = new GString(); - } - prefix.free(); + pageLabels = new GList(); + readPageLabelTree2(root); - pageRangeNum = pageNum - firstPageIndex; - if (pageLabelObj.dictLookup("St", &start)->isInt()) { - pageRangeNum += start.getInt() - 1; - } - start.free(); - - if (pageLabelObj.dictLookup("S", &style)->isName()) { - if (style.isName("D")) { - label->appendf("{0:d}", pageRangeNum); - } else if (style.isName("R")) { - s = makeRomanNumeral(pageRangeNum, gTrue); - label->append(s); - delete s; - } else if (style.isName("r")) { - s = makeRomanNumeral(pageRangeNum, gFalse); - label->append(s); - delete s; - } else if (style.isName("A")) { - s = makeLetterLabel(pageRangeNum, gTrue); - label->append(s); - delete s; - } else if (style.isName("a")) { - s = makeLetterLabel(pageRangeNum, gFalse); - label->append(s); - delete s; - } - } - style.free(); - } - pageLabelObj.free(); + if (pageLabels->getLength() == 0) { + deleteGList(pageLabels, PageLabelNode); + pageLabels = NULL; + return; } - node.free(); - catDict.free(); - ts = new TextString(label); - delete label; - return ts; + // set lastPage in each node + label0 = (PageLabelNode *)pageLabels->get(0); + for (i = 1; i < pageLabels->getLength(); ++i) { + label1 = (PageLabelNode *)pageLabels->get(i); + label0->lastPage = label1->firstPage - 1; + label0 = label1; + } + label0->lastPage = numPages; } -GBool Catalog::findPageLabel(Object *node, int pageIndex, - Object *pageLabelObj, int *firstPageIndex) { - Object limits, limit, nums, num, kids, kid; +void Catalog::readPageLabelTree2(Object *node) { + Object nums, num, labelObj, kids, kid; int i; if (!node->isDict()) { - return gFalse; - } - - // we only check the lower limit because page labels are organized - // into ranges based on their first page number -- the Nums and Kids - // arrays are searched backward for the same reason - if (node->dictLookup("Limits", &limits)->isArray() && - limits.arrayGetLength() == 2) { - if (limits.arrayGet(0, &limit)->isInt()) { - if (pageIndex < limit.getInt()) { - limit.free(); - limits.free(); - return gFalse; - } - } - limit.free(); + return; } - limits.free(); if (node->dictLookup("Nums", &nums)->isArray()) { - for (i = nums.arrayGetLength() / 2 - 1; i >= 0; --i) { - if (nums.arrayGet(2*i, &num)->isInt()) { - if (num.getInt() <= pageIndex) { - nums.arrayGet(2*i + 1, pageLabelObj); - *firstPageIndex = num.getInt(); - num.free(); - nums.free(); - return gTrue; + for (i = 0; i < nums.arrayGetLength() - 1; i += 2) { + if (nums.arrayGet(i, &num)->isInt()) { + if (nums.arrayGet(i+1, &labelObj)->isDict()) { + pageLabels->append(new PageLabelNode(num.getInt(), + labelObj.getDict())); } - } else { - error(errSyntaxError, -1, "Invalid key in page label number tree"); - num.free(); - nums.free(); - return gFalse; + labelObj.free(); } num.free(); } @@ -941,20 +945,61 @@ GBool Catalog::findPageLabel(Object *node, int pageIndex, nums.free(); if (node->dictLookup("Kids", &kids)->isArray()) { - for (i = kids.arrayGetLength() - 1; i >= 0; --i) { - if (kids.arrayGet(i, &kid)->isDict()) { - if (findPageLabel(&kid, pageIndex, pageLabelObj, firstPageIndex)) { - kid.free(); - kids.free(); - return gTrue; - } - } + for (i = 0; i < kids.arrayGetLength(); ++i) { + kids.arrayGet(i, &kid); + readPageLabelTree2(&kid); kid.free(); } } kids.free(); +} - return gFalse; +TextString *Catalog::getPageLabel(int pageNum) { + PageLabelNode *label; + TextString *ts; + int pageRangeNum; + GString *suffix; + + if (!pageLabels || !(label = findPageLabel(pageNum))) { + return NULL; + } + + ts = new TextString(label->prefix); + + pageRangeNum = label->start + (pageNum - label->firstPage); + + suffix = NULL; + if (label->style == 'D') { + suffix = GString::format("{0:d}", pageRangeNum); + } else if (label->style == 'R') { + suffix = makeRomanNumeral(pageRangeNum, gTrue); + } else if (label->style == 'r') { + suffix = makeRomanNumeral(pageRangeNum, gFalse); + } else if (label->style == 'A') { + suffix = makeLetterLabel(pageRangeNum, gTrue); + } else if (label->style == 'a') { + suffix = makeLetterLabel(pageRangeNum, gFalse); + } + if (suffix) { + ts->append(suffix); + delete suffix; + } + + return ts; +} + +PageLabelNode *Catalog::findPageLabel(int pageNum) { + PageLabelNode *label; + int i; + + //~ this could use a binary search + for (i = 0; i < pageLabels->getLength(); ++i) { + label = (PageLabelNode *)pageLabels->get(i); + if (pageNum >= label->firstPage && pageNum <= label->lastPage) { + return label; + } + } + return NULL; } GString *Catalog::makeRomanNumeral(int num, GBool uppercase) { @@ -1022,3 +1067,131 @@ GString *Catalog::makeLetterLabel(int num, GBool uppercase) { } return s; } + +int Catalog::getPageNumFromPageLabel(TextString *pageLabel) { + PageLabelNode *label; + int pageNum, prefixLength, i, n; + + if (!pageLabels) { + return -1; + } + for (i = 0; i < pageLabels->getLength(); ++i) { + label = (PageLabelNode *)pageLabels->get(i); + prefixLength = label->prefix->getLength(); + if (pageLabel->getLength() < prefixLength || + memcmp(pageLabel->getUnicode(), label->prefix->getUnicode(), + prefixLength * sizeof(Unicode))) { + continue; + } + if (label->style == '\0' && pageLabel->getLength() == prefixLength) { + return label->firstPage; + } + if (!convertPageLabelToInt(pageLabel, prefixLength, label->style, &n)) { + continue; + } + if (n < label->start) { + continue; + } + pageNum = label->firstPage + n - label->start; + if (pageNum <= label->lastPage) { + return pageNum; + } + } + return -1; +} + +// Attempts to convert pageLabel[prefixLength .. end] to an integer, +// following the specified page label style. If successful, sets *n +// and returns true; else returns false. +GBool Catalog::convertPageLabelToInt(TextString *pageLabel, int prefixLength, + char style, int *n) { + Unicode *u; + Unicode delta; + int len, i; + + len = pageLabel->getLength(); + if (len <= prefixLength) { + return gFalse; + } + u = pageLabel->getUnicode(); + if (style == 'D') { + *n = 0; + for (i = prefixLength; i < len; ++i) { + if (u[i] < (Unicode)'0' || u[i] > (Unicode)'9') { + return gFalse; + } + *n = *n * 10 + (u[i] - (Unicode)'0'); + } + return gTrue; + } else if (style == 'R' || style == 'r') { + delta = style - 'R'; + *n = 0; + i = prefixLength; + while (i < len && u[i] == (Unicode)'M' + delta) { + *n += 1000; + ++i; + } + if (i+1 < len && u[i] == (Unicode)'C' + delta && + u[i+1] == (Unicode)'M' + delta) { + *n += 900; + i += 2; + } else if (i < len && u[i] == (Unicode)'D' + delta) { + *n += 500; + ++i; + } else if (i+1 < len && u[i] == (Unicode)'C' + delta && + u[i+1] == (Unicode)'D' + delta) { + *n += 400; + i += 2; + } + while (i < len && u[i] == (Unicode)'C' + delta) { + *n += 100; + ++i; + } + if (i+1 < len && u[i] == (Unicode)'X' + delta && + u[i+1] == (Unicode)'C' + delta) { + *n += 90; + i += 2; + } else if (i < len && u[i] == (Unicode)'L' + delta) { + *n += 50; + ++i; + } else if (i+1 < len && u[i] == (Unicode)'X' + delta && + u[i+1] == (Unicode)'L' + delta) { + *n += 40; + i += 2; + } + while (i < len && u[i] == (Unicode)'X' + delta) { + *n += 10; + ++i; + } + if (i+1 < len && u[i] == (Unicode)'I' + delta && + u[i+1] == (Unicode)'X' + delta) { + *n += 9; + i += 2; + } else if (i < len && u[i] == (Unicode)'V' + delta) { + *n += 5; + ++i; + } else if (i+1 < len && u[i] == (Unicode)'I' + delta && + u[i+1] == (Unicode)'V' + delta) { + *n += 4; + i += 2; + } + while (i < len && u[i] == (Unicode)'I' + delta) { + *n += 1; + ++i; + } + return i == len; + } else if (style == 'A' || style == 'a') { + if (u[prefixLength] < (Unicode)style || + u[prefixLength] > (Unicode)style + 25) { + return gFalse; + } + for (i = prefixLength + 1; i < len; ++i) { + if (u[i] != u[prefixLength]) { + return gFalse; + } + } + *n = (len - prefixLength - 1) * 26 + (u[i] - (Unicode)style) + 1; + return gTrue; + } + return gFalse; +} diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/Catalog.h b/Build/source/libs/xpdf/xpdf-src/xpdf/Catalog.h index 803550d7f96..b775ae9b9b8 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/Catalog.h +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/Catalog.h @@ -29,6 +29,7 @@ class PageAttrs; struct Ref; class LinkDest; class PageTreeNode; +class PageLabelNode; class Form; class TextString; @@ -103,10 +104,20 @@ public: Object *getEmbeddedFileStreamRef(int idx); Object *getEmbeddedFileStreamObj(int idx, Object *strObj); + // Return true if the document has page labels. + GBool hasPageLabels() { return pageLabels != NULL; } + // Get the page label for page number [pageNum]. Returns NULL if // the PDF file doesn't have page labels. TextString *getPageLabel(int pageNum); + // Returns the page number corresponding to [pageLabel]. Returns -1 + // if there is no matching page label, or if the document doesn't + // have page labels. + int getPageNumFromPageLabel(TextString *pageLabel); + + Object *getViewerPreferences() { return &viewerPrefs; } + private: PDFDoc *doc; @@ -129,6 +140,8 @@ private: Form *form; // parsed form Object ocProperties; // OCProperties dictionary GList *embeddedFiles; // embedded file list [EmbeddedFile] + GList *pageLabels; // page labels [PageLabelNode] + Object viewerPrefs; // ViewerPreferences object GBool ok; // true if catalog is valid Object *findDestInTree(Object *tree, GString *name, Object *obj); @@ -141,10 +154,13 @@ private: void readFileAttachmentAnnots(Object *pageNodeRef, char *touchedObjs); void readEmbeddedFile(Object *fileSpec, Object *name1); - GBool findPageLabel(Object *node, int pageIndex, - Object *pageLabelObj, int *firstPageIndex); + void readPageLabelTree(Object *root); + void readPageLabelTree2(Object *node); + PageLabelNode *findPageLabel(int pageNum); GString *makeRomanNumeral(int num, GBool uppercase); GString *makeLetterLabel(int num, GBool uppercase); + GBool convertPageLabelToInt(TextString *pageLabel, int prefixLength, + char style, int *n); }; #endif diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/Function.cc b/Build/source/libs/xpdf/xpdf-src/xpdf/Function.cc index 72cadd9bed1..82f32b9dd93 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/Function.cc +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/Function.cc @@ -41,7 +41,8 @@ Function::Function() { Function::~Function() { } -Function *Function::parse(Object *funcObj, int recursion) { +Function *Function::parse(Object *funcObj, int expectedInputs, + int expectedOutputs, int recursion) { Function *func; Dict *dict; int funcType; @@ -57,7 +58,11 @@ Function *Function::parse(Object *funcObj, int recursion) { } else if (funcObj->isDict()) { dict = funcObj->getDict(); } else if (funcObj->isName("Identity")) { - return new IdentityFunction(); + if (expectedInputs != expectedOutputs) { + error(errSyntaxError, -1, "Invalid use of identity function"); + return NULL; + } + return new IdentityFunction(expectedInputs); } else { error(errSyntaxError, -1, "Expected function dictionary or stream"); return NULL; @@ -76,7 +81,8 @@ Function *Function::parse(Object *funcObj, int recursion) { } else if (funcType == 2) { func = new ExponentialFunction(funcObj, dict); } else if (funcType == 3) { - func = new StitchingFunction(funcObj, dict, recursion); + func = new StitchingFunction(funcObj, dict, expectedInputs, + expectedOutputs, recursion); } else if (funcType == 4) { func = new PostScriptFunction(funcObj, dict); } else { @@ -88,6 +94,14 @@ Function *Function::parse(Object *funcObj, int recursion) { return NULL; } + if (func->getInputSize() != expectedInputs || + (expectedOutputs >= 0 && func->getOutputSize() != expectedOutputs)) { + error(errSyntaxError, -1, + "Incorrect number of function inputs or outputs"); + delete func; + return NULL; + } + return func; } @@ -169,14 +183,12 @@ GBool Function::init(Dict *dict) { // IdentityFunction //------------------------------------------------------------------------ -IdentityFunction::IdentityFunction() { +IdentityFunction::IdentityFunction(int nInputs) { int i; - // fill these in with arbitrary values just in case they get used - // somewhere - m = funcMaxInputs; - n = funcMaxOutputs; - for (i = 0; i < funcMaxInputs; ++i) { + m = n = nInputs; + // domain info shouldn't be used anywhere + for (i = 0; i < nInputs; ++i) { domain[i][0] = 0; domain[i][1] = 1; } @@ -189,7 +201,7 @@ IdentityFunction::~IdentityFunction() { void IdentityFunction::transform(double *in, double *out) { int i; - for (i = 0; i < funcMaxOutputs; ++i) { + for (i = 0; i < m; ++i) { out[i] = in[i]; } } @@ -347,8 +359,13 @@ SampledFunction::SampledFunction(Object *funcObj, Dict *dict) { //----- samples nSamples = n; - for (i = 0; i < m; ++i) + for (i = 0; i < m; ++i) { + if (nSamples > INT_MAX / sampleSize[i]) { + error(errSyntaxError, -1, "Integer overflow in sampled function setup"); + goto err1; + } nSamples *= sampleSize[i]; + } samples = (double *)gmallocn(nSamples, sizeof(double)); buf = 0; bits = 0; @@ -623,6 +640,7 @@ void ExponentialFunction::transform(double *in, double *out) { //------------------------------------------------------------------------ StitchingFunction::StitchingFunction(Object *funcObj, Dict *dict, + int expectedInputs, int expectedOutputs, int recursion) { Object obj1, obj2; int i; @@ -643,7 +661,8 @@ StitchingFunction::StitchingFunction(Object *funcObj, Dict *dict, } //----- Functions - if (!dict->lookup("Functions", &obj1)->isArray()) { + if (!dict->lookup("Functions", &obj1)->isArray() || + obj1.arrayGetLength() < 1) { error(errSyntaxError, -1, "Missing 'Functions' entry in stitching function"); goto err1; @@ -658,11 +677,14 @@ StitchingFunction::StitchingFunction(Object *funcObj, Dict *dict, } for (i = 0; i < k; ++i) { if (!(funcs[i] = Function::parse(obj1.arrayGet(i, &obj2), + expectedInputs, expectedOutputs, recursion + 1))) { goto err2; } - if (funcs[i]->getInputSize() != 1 || - (i > 0 && funcs[i]->getOutputSize() != funcs[0]->getOutputSize())) { + if (i == 0) { + n = funcs[0]->getOutputSize(); + } + if (funcs[i]->getInputSize() != 1 || funcs[i]->getOutputSize() != n) { error(errSyntaxError, -1, "Incompatible subfunctions in stitching function"); goto err2; @@ -1305,6 +1327,9 @@ int PostScriptFunction::exec(double *stack, int sp0) { if (sp + 1 >= psStackSize) { goto underflow; } + if (stack[sp] == 0) { + goto invalidArg; + } stack[sp + 1] = stack[sp + 1] / stack[sp]; ++sp; break; @@ -1371,7 +1396,11 @@ int PostScriptFunction::exec(double *stack, int sp0) { if (sp + 1 >= psStackSize) { goto underflow; } - stack[sp + 1] = (int)stack[sp + 1] / (int)stack[sp]; + k = (int)stack[sp]; + if (k == 0) { + goto invalidArg; + } + stack[sp + 1] = (int)stack[sp + 1] / k; ++sp; break; case psOpIndex: @@ -1417,7 +1446,11 @@ int PostScriptFunction::exec(double *stack, int sp0) { if (sp + 1 >= psStackSize) { goto underflow; } - stack[sp + 1] = (int)stack[sp + 1] % (int)stack[sp]; + k = (int)stack[sp]; + if (k == 0) { + goto invalidArg; + } + stack[sp + 1] = (int)stack[sp + 1] % k; ++sp; break; case psOpMul: @@ -1468,22 +1501,24 @@ int PostScriptFunction::exec(double *stack, int sp0) { if (nn < 0) { goto invalidArg; } - if (sp + nn > psStackSize) { - goto underflow; - } - if (k >= 0) { - k %= nn; - } else { - k = -k % nn; - if (k) { - k = nn - k; + if (nn > 0) { + if (sp + nn > psStackSize) { + goto underflow; + } + if (k >= 0) { + k %= nn; + } else { + k = -k % nn; + if (k) { + k = nn - k; + } + } + for (i = 0; i < nn; ++i) { + tmp[i] = stack[sp + i]; + } + for (i = 0; i < nn; ++i) { + stack[sp + i] = tmp[(i + k) % nn]; } - } - for (i = 0; i < nn; ++i) { - tmp[i] = stack[sp + i]; - } - for (i = 0; i < nn; ++i) { - stack[sp + i] = tmp[(i + k) % nn]; } break; case psOpRound: diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/Function.h b/Build/source/libs/xpdf/xpdf-src/xpdf/Function.h index 5cf45169a49..bf1f25e51cc 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/Function.h +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/Function.h @@ -38,8 +38,11 @@ public: virtual ~Function(); - // Construct a function. Returns NULL if unsuccessful. - static Function *parse(Object *funcObj, int recursion = 0); + // Construct a function, with [expectedInputs] inputs and + // [expectedOutputs] outputs. [expectedOutputs] can be -1 to + // indicate unknown. Returns NULL if unsuccessful. + static Function *parse(Object *funcObj, int expectedInputs, + int expectedOutputs, int recursion = 0); // Initialize the entries common to all function types. GBool init(Dict *dict); @@ -86,9 +89,9 @@ protected: class IdentityFunction: public Function { public: - IdentityFunction(); + IdentityFunction(int nInputs); virtual ~IdentityFunction(); - virtual Function *copy() { return new IdentityFunction(); } + virtual Function *copy() { return new IdentityFunction(m); } virtual int getType() { return -1; } virtual void transform(double *in, double *out); virtual GBool isOk() { return gTrue; } @@ -173,7 +176,8 @@ private: class StitchingFunction: public Function { public: - StitchingFunction(Object *funcObj, Dict *dict, int recursion); + StitchingFunction(Object *funcObj, Dict *dict, int expectedInputs, + int expectedOutputs, int recursion); virtual ~StitchingFunction(); virtual Function *copy() { return new StitchingFunction(this); } virtual int getType() { return 3; } diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/Gfx.cc b/Build/source/libs/xpdf/xpdf-src/xpdf/Gfx.cc index 5d34eb9f9ab..7a0c9c6a9a5 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/Gfx.cc +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/Gfx.cc @@ -919,12 +919,24 @@ void Gfx::opSetFlat(Object args[], int numArgs) { } void Gfx::opSetLineJoin(Object args[], int numArgs) { - state->setLineJoin(args[0].getInt()); + int lineJoin; + + lineJoin = args[0].getInt(); + if (lineJoin < 0 || lineJoin > 2) { + lineJoin = 0; + } + state->setLineJoin(lineJoin); out->updateLineJoin(state); } void Gfx::opSetLineCap(Object args[], int numArgs) { - state->setLineCap(args[0].getInt()); + int lineCap; + + lineCap = args[0].getInt(); + if (lineCap < 0 || lineCap > 2) { + lineCap = 0; + } + state->setLineCap(lineCap); out->updateLineCap(state); } @@ -1041,17 +1053,17 @@ void Gfx::opSetExtGState(Object args[], int numArgs) { // fill/stroke overprint, overprint mode if ((haveFillOP = (obj1.dictLookup("op", &obj2)->isBool()))) { - if (!state->getInCachedT3Char()) { + if (!state->getIgnoreColorOps()) { state->setFillOverprint(obj2.getBool()); out->updateFillOverprint(state); } else { - error(errSyntaxWarning, getPos(), - "Ignoring overprint setting in cached Type 3 character"); + error(errSyntaxWarning, getPos(), "Ignoring overprint setting" + " in uncolored Type 3 char or tiling pattern"); } } obj2.free(); if (obj1.dictLookup("OP", &obj2)->isBool()) { - if (!state->getInCachedT3Char()) { + if (!state->getIgnoreColorOps()) { state->setStrokeOverprint(obj2.getBool()); out->updateStrokeOverprint(state); if (!haveFillOP) { @@ -1059,18 +1071,18 @@ void Gfx::opSetExtGState(Object args[], int numArgs) { out->updateFillOverprint(state); } } else { - error(errSyntaxWarning, getPos(), - "Ignoring overprint setting in cached Type 3 character"); + error(errSyntaxWarning, getPos(), "Ignoring overprint setting" + " in uncolored Type 3 char or tiling pattern"); } } obj2.free(); if (obj1.dictLookup("OPM", &obj2)->isInt()) { - if (!state->getInCachedT3Char()) { + if (!state->getIgnoreColorOps()) { state->setOverprintMode(obj2.getInt()); out->updateOverprintMode(state); } else { - error(errSyntaxWarning, getPos(), - "Ignoring overprint setting in cached Type 3 character"); + error(errSyntaxWarning, getPos(), "Ignoring overprint setting" + " in uncolored Type 3 char or tiling pattern"); } } obj2.free(); @@ -1088,7 +1100,7 @@ void Gfx::opSetExtGState(Object args[], int numArgs) { obj1.dictLookup("TR", &obj2); } if (!obj2.isNull()) { - if (!state->getInCachedT3Char()) { + if (!state->getIgnoreColorOps()) { if (obj2.isName("Default") || obj2.isName("Identity")) { funcs[0] = funcs[1] = funcs[2] = funcs[3] = NULL; @@ -1097,7 +1109,7 @@ void Gfx::opSetExtGState(Object args[], int numArgs) { } else if (obj2.isArray() && obj2.arrayGetLength() == 4) { for (i = 0; i < 4; ++i) { obj2.arrayGet(i, &obj3); - funcs[i] = Function::parse(&obj3); + funcs[i] = Function::parse(&obj3, 1, 1); obj3.free(); if (!funcs[i]) { break; @@ -1108,7 +1120,7 @@ void Gfx::opSetExtGState(Object args[], int numArgs) { out->updateTransfer(state); } } else if (obj2.isName() || obj2.isDict() || obj2.isStream()) { - if ((funcs[0] = Function::parse(&obj2))) { + if ((funcs[0] = Function::parse(&obj2, 1, 1))) { funcs[1] = funcs[2] = funcs[3] = NULL; state->setTransfer(funcs); out->updateTransfer(state); @@ -1118,8 +1130,8 @@ void Gfx::opSetExtGState(Object args[], int numArgs) { "Invalid transfer function in ExtGState"); } } else { - error(errSyntaxWarning, getPos(), - "Ignoring transfer function setting in cached Type 3 character"); + error(errSyntaxWarning, getPos(), "Ignoring transfer function setting" + " in uncolored Type 3 char or tiling pattern"); } } obj2.free(); @@ -1129,9 +1141,14 @@ void Gfx::opSetExtGState(Object args[], int numArgs) { if (obj2.isName("None")) { out->clearSoftMask(state); } else if (obj2.isDict()) { - if (obj2.dictLookup("S", &obj3)->isName("Alpha")) { + obj2.dictLookup("S", &obj3); + if (obj3.isName("Alpha")) { alpha = gTrue; - } else { // "Luminosity" + } else if (obj3.isName("Luminosity")) { + alpha = gFalse; + } else { + error(errSyntaxError, getPos(), + "Missing S (subtype) entry in soft mask"); alpha = gFalse; } obj3.free(); @@ -1141,9 +1158,7 @@ void Gfx::opSetExtGState(Object args[], int numArgs) { obj3.isName("Identity")) { funcs[0] = NULL; } else { - funcs[0] = Function::parse(&obj3); - if (funcs[0]->getInputSize() != 1 || - funcs[0]->getOutputSize() != 1) { + if (!(funcs[0] = Function::parse(&obj3, 1, 1))) { error(errSyntaxError, getPos(), "Invalid transfer function in soft mask in ExtGState"); delete funcs[0]; @@ -1290,9 +1305,9 @@ void Gfx::doSoftMask(Object *str, Object *strRef, GBool alpha, void Gfx::opSetRenderingIntent(Object args[], int numArgs) { GfxRenderingIntent ri; - if (state->getInCachedT3Char()) { - error(errSyntaxWarning, getPos(), - "Ignoring rendering intent setting in cached Type 3 character"); + if (state->getIgnoreColorOps()) { + error(errSyntaxWarning, getPos(), "Ignoring rendering intent setting" + " in uncolored Type 3 char or tiling pattern"); return; } ri = parseRenderingIntent(args[0].getName()); @@ -1320,9 +1335,9 @@ GfxRenderingIntent Gfx::parseRenderingIntent(const char *name) { void Gfx::opSetFillGray(Object args[], int numArgs) { GfxColor color; - if (state->getInCachedT3Char()) { - error(errSyntaxWarning, getPos(), - "Ignoring color setting in cached Type 3 character"); + if (state->getIgnoreColorOps()) { + error(errSyntaxWarning, getPos(), "Ignoring color setting" + " in uncolored Type 3 char or tiling pattern"); return; } state->setFillPattern(NULL); @@ -1336,9 +1351,9 @@ void Gfx::opSetFillGray(Object args[], int numArgs) { void Gfx::opSetStrokeGray(Object args[], int numArgs) { GfxColor color; - if (state->getInCachedT3Char()) { - error(errSyntaxWarning, getPos(), - "Ignoring color setting in cached Type 3 character"); + if (state->getIgnoreColorOps()) { + error(errSyntaxWarning, getPos(), "Ignoring color setting" + " in uncolored Type 3 char or tiling pattern"); return; } state->setStrokePattern(NULL); @@ -1353,9 +1368,9 @@ void Gfx::opSetFillCMYKColor(Object args[], int numArgs) { GfxColor color; int i; - if (state->getInCachedT3Char()) { - error(errSyntaxWarning, getPos(), - "Ignoring color setting in cached Type 3 character"); + if (state->getIgnoreColorOps()) { + error(errSyntaxWarning, getPos(), "Ignoring color setting" + " in uncolored Type 3 char or tiling pattern"); return; } state->setFillPattern(NULL); @@ -1372,9 +1387,9 @@ void Gfx::opSetStrokeCMYKColor(Object args[], int numArgs) { GfxColor color; int i; - if (state->getInCachedT3Char()) { - error(errSyntaxWarning, getPos(), - "Ignoring color setting in cached Type 3 character"); + if (state->getIgnoreColorOps()) { + error(errSyntaxWarning, getPos(), "Ignoring color setting" + " in uncolored Type 3 char or tiling pattern"); return; } state->setStrokePattern(NULL); @@ -1391,9 +1406,9 @@ void Gfx::opSetFillRGBColor(Object args[], int numArgs) { GfxColor color; int i; - if (state->getInCachedT3Char()) { - error(errSyntaxWarning, getPos(), - "Ignoring color setting in cached Type 3 character"); + if (state->getIgnoreColorOps()) { + error(errSyntaxWarning, getPos(), "Ignoring color setting" + " in uncolored Type 3 char or tiling pattern"); return; } state->setFillPattern(NULL); @@ -1410,9 +1425,9 @@ void Gfx::opSetStrokeRGBColor(Object args[], int numArgs) { GfxColor color; int i; - if (state->getInCachedT3Char()) { - error(errSyntaxWarning, getPos(), - "Ignoring color setting in cached Type 3 character"); + if (state->getIgnoreColorOps()) { + error(errSyntaxWarning, getPos(), "Ignoring color setting" + " in uncolored Type 3 char or tiling pattern"); return; } state->setStrokePattern(NULL); @@ -1430,9 +1445,9 @@ void Gfx::opSetFillColorSpace(Object args[], int numArgs) { GfxColorSpace *colorSpace; GfxColor color; - if (state->getInCachedT3Char()) { - error(errSyntaxWarning, getPos(), - "Ignoring color space setting in cached Type 3 character"); + if (state->getIgnoreColorOps()) { + error(errSyntaxWarning, getPos(), "Ignoring color space setting" + " in uncolored Type 3 char or tiling pattern"); return; } state->setFillPattern(NULL); @@ -1461,9 +1476,9 @@ void Gfx::opSetStrokeColorSpace(Object args[], int numArgs) { GfxColorSpace *colorSpace; GfxColor color; - if (state->getInCachedT3Char()) { - error(errSyntaxWarning, getPos(), - "Ignoring color space setting in cached Type 3 character"); + if (state->getIgnoreColorOps()) { + error(errSyntaxWarning, getPos(), "Ignoring color space setting" + " in uncolored Type 3 char or tiling pattern"); return; } state->setStrokePattern(NULL); @@ -1491,9 +1506,9 @@ void Gfx::opSetFillColor(Object args[], int numArgs) { GfxColor color; int i; - if (state->getInCachedT3Char()) { - error(errSyntaxWarning, getPos(), - "Ignoring color setting in cached Type 3 character"); + if (state->getIgnoreColorOps()) { + error(errSyntaxWarning, getPos(), "Ignoring color setting" + " in uncolored Type 3 char or tiling pattern"); return; } if (numArgs != state->getFillColorSpace()->getNComps()) { @@ -1531,9 +1546,9 @@ void Gfx::opSetFillColorN(Object args[], int numArgs) { GfxPattern *pattern; int i; - if (state->getInCachedT3Char()) { - error(errSyntaxWarning, getPos(), - "Ignoring color setting in cached Type 3 character"); + if (state->getIgnoreColorOps()) { + error(errSyntaxWarning, getPos(), "Ignoring color setting" + " in uncolored Type 3 char or tiling pattern"); return; } if (state->getFillColorSpace()->getMode() == csPattern) { @@ -1585,9 +1600,9 @@ void Gfx::opSetStrokeColorN(Object args[], int numArgs) { GfxPattern *pattern; int i; - if (state->getInCachedT3Char()) { - error(errSyntaxWarning, getPos(), - "Ignoring color setting in cached Type 3 character"); + if (state->getIgnoreColorOps()) { + error(errSyntaxWarning, getPos(), "Ignoring color setting" + " in uncolored Type 3 char or tiling pattern"); return; } if (state->getStrokeColorSpace()->getMode() == csPattern) { @@ -2068,6 +2083,7 @@ void Gfx::doTilingPatternFill(GfxTilingPattern *tPat, state->setStrokeColor(state->getFillColor()); out->updateFillColor(state); out->updateStrokeColor(state); + state->setIgnoreColorOps(gTrue); } else { state->setFillColorSpace(GfxColorSpace::create(csDeviceGray)); out->updateFillColorSpace(state); @@ -2223,6 +2239,7 @@ void Gfx::doShadingPatternFill(GfxShadingPattern *sPat, if (stroke) { state->clipToStrokePath(); out->clipToStrokePath(state); + state->setFillOverprint(state->getStrokeOverprint()); } else if (!text) { state->clip(); if (eoFill) { @@ -2241,6 +2258,7 @@ void Gfx::doShadingPatternFill(GfxShadingPattern *sPat, det = ctm[0] * ctm[3] - ctm[1] * ctm[2]; if (fabs(det) <= 1e-10) { error(errSyntaxError, getPos(), "Singular matrix in shading pattern fill"); + restoreStateStack(savedState); return; } det = 1 / det; @@ -2338,9 +2356,9 @@ void Gfx::opShFill(Object args[], int numArgs) { GfxState *savedState; double xMin, yMin, xMax, yMax; - if (state->getInCachedT3Char()) { - error(errSyntaxWarning, getPos(), - "Ignoring shaded fill in cached Type 3 character"); + if (state->getIgnoreColorOps()) { + error(errSyntaxWarning, getPos(), "Ignoring shaded fill" + " in uncolored Type 3 char or tiling pattern"); return; } @@ -4123,7 +4141,7 @@ void Gfx::opXObject(Object args[], int numArgs) { ocState = ocSaved; } -void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { +GBool Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { Dict *dict, *maskDict; int width, height; int bits, maskBits; @@ -4145,7 +4163,7 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { // check for optional content if (!ocState && !inlineImg) { - return; + return gTrue; } // get info from the stream @@ -4309,6 +4327,11 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { if (!colorSpace) { goto err1; } + if (colorSpace->getMode() == csPattern) { + error(errSyntaxError, getPos(), "Image with a Pattern color space"); + delete colorSpace; + goto err1; + } dict->lookup("Decode", &obj1); if (obj1.isNull()) { obj1.free(); @@ -4365,6 +4388,12 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { } maskHeight = obj1.getInt(); obj1.free(); + if (maskWidth <= 0 || maskHeight <= 0) { + delete colorMap; + maskObj.free(); + smaskObj.free(); + goto err1; + } maskDict->lookup("BitsPerComponent", &obj1); if (obj1.isNull()) { obj1.free(); @@ -4378,6 +4407,12 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { } maskBits = obj1.getInt(); obj1.free(); + if (maskBits < 1 || maskBits > 16) { + delete colorMap; + maskObj.free(); + smaskObj.free(); + goto err1; + } maskDict->lookup("ColorSpace", &obj1); if (obj1.isNull()) { obj1.free(); @@ -4501,6 +4536,12 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { } maskHeight = obj1.getInt(); obj1.free(); + if (maskWidth <= 0 || maskHeight <= 0) { + delete colorMap; + maskObj.free(); + smaskObj.free(); + goto err2; + } maskDict->lookup("ImageMask", &obj1); if (obj1.isNull()) { obj1.free(); @@ -4534,10 +4575,10 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { } // if drawing is disabled, skip over inline image data - if (state->getInCachedT3Char() || !ocState) { - if (state->getInCachedT3Char()) { - error(errSyntaxWarning, getPos(), - "Ignoring image in cached Type 3 character"); + if (state->getIgnoreColorOps() || !ocState) { + if (state->getIgnoreColorOps()) { + error(errSyntaxWarning, getPos(), "Ignoring image" + " in uncolored Type 3 char or tiling pattern"); } if (inlineImg) { str->reset(); @@ -4582,7 +4623,7 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { } opCounter += i; - return; + return gTrue; err2: obj1.free(); @@ -4594,6 +4635,8 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { state->setRenderingIntent(riSaved); out->updateRenderingIntent(state); } + + return gFalse; } void Gfx::doForm(Object *strRef, Object *str) { @@ -4826,11 +4869,12 @@ void Gfx::opBeginImage(Object args[], int numArgs) { // display the image if (str) { - doImage(NULL, str, gTrue); + if (!doImage(NULL, str, gTrue)) { + delete str; // if we have the stream length, skip to end-of-stream and then // skip 'EI' in the original stream - if (haveLength) { + } else if (haveLength) { while ((c1 = str->getChar()) != EOF) ; delete str; str = parser->getStream(); @@ -4935,7 +4979,7 @@ void Gfx::opSetCharWidth(Object args[], int numArgs) { } void Gfx::opSetCacheDevice(Object args[], int numArgs) { - state->setInCachedT3Char(gTrue); + state->setIgnoreColorOps(gTrue); out->type3D1(state, args[0].getNum(), args[1].getNum(), args[2].getNum(), args[3].getNum(), args[4].getNum(), args[5].getNum()); diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/Gfx.h b/Build/source/libs/xpdf/xpdf-src/xpdf/Gfx.h index 9d175825f97..2159eaaf2e9 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/Gfx.h +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/Gfx.h @@ -330,7 +330,7 @@ private: // XObject operators void opXObject(Object args[], int numArgs); - void doImage(Object *ref, Stream *str, GBool inlineImg); + GBool doImage(Object *ref, Stream *str, GBool inlineImg); void doForm(Object *strRef, Object *str); // in-line image operators diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/GfxFont.cc b/Build/source/libs/xpdf/xpdf-src/xpdf/GfxFont.cc index 640cf81db02..b10c81779ff 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/GfxFont.cc +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/GfxFont.cc @@ -164,7 +164,8 @@ GfxFontLoc::~GfxFontLoc() { // GfxFont //------------------------------------------------------------------------ -GfxFont *GfxFont::makeFont(XRef *xref, char *tagA, Ref idA, Dict *fontDict) { +GfxFont *GfxFont::makeFont(XRef *xref, const char *tagA, + Ref idA, Dict *fontDict) { GString *nameA; Ref embFontIDA; GfxFontType typeA; @@ -197,7 +198,7 @@ GfxFont *GfxFont::makeFont(XRef *xref, char *tagA, Ref idA, Dict *fontDict) { return font; } -GfxFont::GfxFont(char *tagA, Ref idA, GString *nameA, +GfxFont::GfxFont(const char *tagA, Ref idA, GString *nameA, GfxFontType typeA, Ref embFontIDA) { ok = gFalse; tag = new GString(tagA); @@ -541,6 +542,7 @@ CharCodeToUnicode *GfxFont::readToUnicodeCMap(Dict *fontDict, int nBits, GfxFontLoc *GfxFont::locateFont(XRef *xref, GBool ps) { GfxFontLoc *fontLoc; SysFontType sysFontType; + FoFiIdentifierType fft; GString *path, *base14Name, *substName; PSFontParam16 *psFont16; Object refObj, embFontObj; @@ -635,32 +637,43 @@ GfxFontLoc *GfxFont::locateFont(XRef *xref, GBool ps) { //----- system font if (name && (path = globalParams->findSystemFontFile(name, &sysFontType, &fontNum))) { + fontLoc = new GfxFontLoc(); + fontLoc->locType = gfxFontLocExternal; + fontLoc->path = path; + fontLoc->fontNum = fontNum; if (isCIDFont()) { if (sysFontType == sysFontTTF || sysFontType == sysFontTTC) { - fontLoc = new GfxFontLoc(); - fontLoc->locType = gfxFontLocExternal; fontLoc->fontType = fontCIDType2; - fontLoc->path = path; - fontLoc->fontNum = fontNum; return fontLoc; + } else if (sysFontType == sysFontOTF) { + fft = FoFiIdentifier::identifyFile(fontLoc->path->getCString()); + if (fft == fofiIdOpenTypeCFFCID) { + fontLoc->fontType = fontCIDType0COT; + return fontLoc; + } else if (fft == fofiIdTrueType) { + fontLoc->fontType = fontCIDType2; + return fontLoc; + } } } else { if (sysFontType == sysFontTTF || sysFontType == sysFontTTC) { - fontLoc = new GfxFontLoc(); - fontLoc->locType = gfxFontLocExternal; fontLoc->fontType = fontTrueType; - fontLoc->path = path; - fontLoc->fontNum = fontNum; return fontLoc; } else if (sysFontType == sysFontPFA || sysFontType == sysFontPFB) { - fontLoc = new GfxFontLoc(); - fontLoc->locType = gfxFontLocExternal; fontLoc->fontType = fontType1; - fontLoc->path = path; return fontLoc; + } else if (sysFontType == sysFontOTF) { + fft = FoFiIdentifier::identifyFile(fontLoc->path->getCString()); + if (fft == fofiIdOpenTypeCFF8Bit) { + fontLoc->fontType = fontType1COT; + return fontLoc; + } else if (fft == fofiIdTrueType) { + fontLoc->fontType = fontTrueTypeOT; + return fontLoc; + } } } - delete path; + delete fontLoc; } if (!isCIDFont()) { @@ -863,7 +876,7 @@ char *GfxFont::readEmbFontFile(XRef *xref, int *len) { // Gfx8BitFont //------------------------------------------------------------------------ -Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, +Gfx8BitFont::Gfx8BitFont(XRef *xref, const char *tagA, Ref idA, GString *nameA, GfxFontType typeA, Ref embFontIDA, Dict *fontDict): GfxFont(tagA, idA, nameA, typeA, embFontIDA) { @@ -1490,6 +1503,33 @@ int *Gfx8BitFont::getCodeToGIDMap(FoFiTrueType *ff) { return map; } +int *Gfx8BitFont::getCodeToGIDMap(FoFiType1C *ff) { + int *map; + GHash *nameToGID; + int i, gid; + + map = (int *)gmallocn(256, sizeof(int)); + for (i = 0; i < 256; ++i) { + map[i] = 0; + } + + nameToGID = ff->getNameToGIDMap(); + for (i = 0; i < 256; ++i) { + if (!enc[i]) { + continue; + } + gid = nameToGID->lookupInt(enc[i]); + if (gid < 0 || gid >= 65536) { + continue; + } + map[i] = gid; + } + + delete nameToGID; + + return map; +} + Dict *Gfx8BitFont::getCharProcs() { return charProcs.isDict() ? charProcs.getDict() : (Dict *)NULL; } @@ -1575,7 +1615,7 @@ GBool Gfx8BitFont::problematicForUnicode() { // GfxCIDFont //------------------------------------------------------------------------ -GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA, +GfxCIDFont::GfxCIDFont(XRef *xref, const char *tagA, Ref idA, GString *nameA, GfxFontType typeA, Ref embFontIDA, Dict *fontDict): GfxFont(tagA, idA, nameA, typeA, embFontIDA) { @@ -2001,6 +2041,13 @@ GString *GfxCIDFont::getCollection() { return cMap ? cMap->getCollection() : (GString *)NULL; } +double GfxCIDFont::getWidth(CID cid) { + double w; + + getHorizontalMetrics(cid, &w); + return w; +} + GBool GfxCIDFont::problematicForUnicode() { GString *nameLC; GBool symbolic; diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/GfxFont.h b/Build/source/libs/xpdf/xpdf-src/xpdf/GfxFont.h index b2d8637a46d..3b63fa69fe0 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/GfxFont.h +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/GfxFont.h @@ -26,6 +26,7 @@ class Dict; class CMap; class CharCodeToUnicode; class FoFiTrueType; +class FoFiType1C; struct GfxFontCIDWidths; struct Base14FontMapEntry; class FNVHash; @@ -131,9 +132,10 @@ class GfxFont { public: // Build a GfxFont object. - static GfxFont *makeFont(XRef *xref, char *tagA, Ref idA, Dict *fontDict); + static GfxFont *makeFont(XRef *xref, const char *tagA, + Ref idA, Dict *fontDict); - GfxFont(char *tagA, Ref idA, GString *nameA, + GfxFont(const char *tagA, Ref idA, GString *nameA, GfxFontType typeA, Ref embFontIDA); virtual ~GfxFont(); @@ -243,7 +245,7 @@ protected: class Gfx8BitFont: public GfxFont { public: - Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, + Gfx8BitFont(XRef *xref, const char *tagA, Ref idA, GString *nameA, GfxFontType typeA, Ref embFontIDA, Dict *fontDict); virtual ~Gfx8BitFont(); @@ -274,6 +276,10 @@ public: // (This is only useful for TrueType fonts.) int *getCodeToGIDMap(FoFiTrueType *ff); + // Return a char code-to-GID mapping for the provided font file. + // (This is only useful for Type1C fonts.) + int *getCodeToGIDMap(FoFiType1C *ff); + // Return the Type 3 CharProc dictionary, or NULL if none. Dict *getCharProcs(); @@ -311,7 +317,7 @@ private: class GfxCIDFont: public GfxFont { public: - GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA, + GfxCIDFont(XRef *xref, const char *tagA, Ref idA, GString *nameA, GfxFontType typeA, Ref embFontIDA, Dict *fontDict); virtual ~GfxCIDFont(); @@ -331,6 +337,9 @@ public: // Get the collection name (<registry>-<ordering>). GString *getCollection(); + // Return the horizontal width for <cid>. + double getWidth(CID cid); + // Return the CID-to-GID mapping table. These should only be called // if type is fontCIDType2. int *getCIDToGID() { return cidToGID; } diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/GfxState.cc b/Build/source/libs/xpdf/xpdf-src/xpdf/GfxState.cc index 9a43608c2fe..60b5f577054 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/GfxState.cc +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/GfxState.cc @@ -1281,7 +1281,7 @@ GfxColorSpace *GfxSeparationColorSpace::parse(Array *arr, } obj1.free(); arr->get(3, &obj1); - if (!(funcA = Function::parse(&obj1))) { + if (!(funcA = Function::parse(&obj1, 1, altA->getNComps()))) { goto err4; } obj1.free(); @@ -1476,7 +1476,7 @@ GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr, } obj1.free(); arr->get(3, &obj1); - if (!(funcA = Function::parse(&obj1))) { + if (!(funcA = Function::parse(&obj1, nCompsA, altA->getNComps()))) { goto err4; } obj1.free(); @@ -2117,14 +2117,14 @@ GfxFunctionShading *GfxFunctionShading::parse(Dict *dict } for (i = 0; i < nFuncsA; ++i) { obj1.arrayGet(i, &obj2); - if (!(funcsA[i] = Function::parse(&obj2))) { + if (!(funcsA[i] = Function::parse(&obj2, 2, 1))) { goto err2; } obj2.free(); } } else { nFuncsA = 1; - if (!(funcsA[0] = Function::parse(&obj1))) { + if (!(funcsA[0] = Function::parse(&obj1, 2, -1))) { goto err1; } } @@ -2137,6 +2137,16 @@ GfxFunctionShading *GfxFunctionShading::parse(Dict *dict delete shading; return NULL; } + + for (i = 0; i < shading->nFuncs; ++i) { + if (shading->funcs[i]->getOutputSize() + != shading->getColorSpace()->getNComps()) { + error(errSyntaxError, -1, "Invalid function in shading dictionary"); + delete shading; + return NULL; + } + } + return shading; err2: @@ -2274,7 +2284,7 @@ GfxAxialShading *GfxAxialShading::parse(Dict *dict } for (i = 0; i < nFuncsA; ++i) { obj1.arrayGet(i, &obj2); - if (!(funcsA[i] = Function::parse(&obj2))) { + if (!(funcsA[i] = Function::parse(&obj2, 1, 1))) { obj1.free(); obj2.free(); goto err1; @@ -2283,7 +2293,7 @@ GfxAxialShading *GfxAxialShading::parse(Dict *dict } } else { nFuncsA = 1; - if (!(funcsA[0] = Function::parse(&obj1))) { + if (!(funcsA[0] = Function::parse(&obj1, 1, -1))) { obj1.free(); goto err1; } @@ -2307,6 +2317,16 @@ GfxAxialShading *GfxAxialShading::parse(Dict *dict delete shading; return NULL; } + + for (i = 0; i < shading->nFuncs; ++i) { + if (shading->funcs[i]->getOutputSize() + != shading->getColorSpace()->getNComps()) { + error(errSyntaxError, -1, "Invalid function in shading dictionary"); + delete shading; + return NULL; + } + } + return shading; err1: @@ -2446,7 +2466,7 @@ GfxRadialShading *GfxRadialShading::parse(Dict *dict } for (i = 0; i < nFuncsA; ++i) { obj1.arrayGet(i, &obj2); - if (!(funcsA[i] = Function::parse(&obj2))) { + if (!(funcsA[i] = Function::parse(&obj2, 1, 1))) { obj1.free(); obj2.free(); goto err1; @@ -2455,7 +2475,7 @@ GfxRadialShading *GfxRadialShading::parse(Dict *dict } } else { nFuncsA = 1; - if (!(funcsA[0] = Function::parse(&obj1))) { + if (!(funcsA[0] = Function::parse(&obj1, 1, -1))) { obj1.free(); goto err1; } @@ -2479,6 +2499,16 @@ GfxRadialShading *GfxRadialShading::parse(Dict *dict delete shading; return NULL; } + + for (i = 0; i < shading->nFuncs; ++i) { + if (shading->funcs[i]->getOutputSize() + != shading->getColorSpace()->getNComps()) { + error(errSyntaxError, -1, "Invalid function in shading dictionary"); + delete shading; + return NULL; + } + } + return shading; err1: @@ -2719,7 +2749,7 @@ GfxGouraudTriangleShading *GfxGouraudTriangleShading::parse( } for (i = 0; i < nFuncsA; ++i) { obj1.arrayGet(i, &obj2); - if (!(funcsA[i] = Function::parse(&obj2))) { + if (!(funcsA[i] = Function::parse(&obj2, 1, 1))) { obj1.free(); obj2.free(); goto err1; @@ -2728,7 +2758,7 @@ GfxGouraudTriangleShading *GfxGouraudTriangleShading::parse( } } else { nFuncsA = 1; - if (!(funcsA[0] = Function::parse(&obj1))) { + if (!(funcsA[0] = Function::parse(&obj1, 1, -1))) { obj1.free(); goto err1; } @@ -2832,6 +2862,16 @@ GfxGouraudTriangleShading *GfxGouraudTriangleShading::parse( delete shading; return NULL; } + + for (i = 0; i < shading->nFuncs; ++i) { + if (shading->funcs[i]->getOutputSize() + != shading->getColorSpace()->getNComps()) { + error(errSyntaxError, -1, "Invalid function in shading dictionary"); + delete shading; + return NULL; + } + } + return shading; err2: @@ -3017,7 +3057,7 @@ GfxPatchMeshShading *GfxPatchMeshShading::parse(int typeA, Dict *dict, } for (i = 0; i < nFuncsA; ++i) { obj1.arrayGet(i, &obj2); - if (!(funcsA[i] = Function::parse(&obj2))) { + if (!(funcsA[i] = Function::parse(&obj2, 1, 1))) { obj1.free(); obj2.free(); goto err1; @@ -3026,7 +3066,7 @@ GfxPatchMeshShading *GfxPatchMeshShading::parse(int typeA, Dict *dict, } } else { nFuncsA = 1; - if (!(funcsA[0] = Function::parse(&obj1))) { + if (!(funcsA[0] = Function::parse(&obj1, 1, -1))) { obj1.free(); goto err1; } @@ -3044,6 +3084,12 @@ GfxPatchMeshShading *GfxPatchMeshShading::parse(int typeA, Dict *dict, if (!bitBuf->getBits(flagBits, &flag)) { break; } + flag &= 3; + if (flag != 0 && nPatchesA == 0) { + error(errSyntaxError, -1, "Invalid patch in patch mesh shading"); + delete bitBuf; + goto err1; + } if (typeA == 6) { switch (flag) { case 0: nPts = 12; nColors = 4; break; @@ -3445,6 +3491,16 @@ GfxPatchMeshShading *GfxPatchMeshShading::parse(int typeA, Dict *dict, delete shading; return NULL; } + + for (i = 0; i < shading->nFuncs; ++i) { + if (shading->funcs[i]->getOutputSize() + != shading->getColorSpace()->getNComps()) { + error(errSyntaxError, -1, "Invalid function in shading dictionary"); + delete shading; + return NULL; + } + } + return shading; err2: @@ -4122,7 +4178,7 @@ GfxState::GfxState(double hDPIA, double vDPIA, PDFRectangle *pageBox, clipXMax = pageWidth; clipYMax = pageHeight; - inCachedT3Char = gFalse; + ignoreColorOps = gFalse; saved = NULL; } diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/GfxState.h b/Build/source/libs/xpdf/xpdf-src/xpdf/GfxState.h index 8e5d3b0b7a5..50507040fed 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/GfxState.h +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/GfxState.h @@ -1183,7 +1183,7 @@ public: void getUserClipBBox(double *xMin, double *yMin, double *xMax, double *yMax); double getLineX() { return lineX; } double getLineY() { return lineY; } - GBool getInCachedT3Char() { return inCachedT3Char; } + GBool getIgnoreColorOps() { return ignoreColorOps; } // Is there a current point/path? GBool isCurPt() { return path->isCurPt(); } @@ -1280,8 +1280,9 @@ public: void textShift(double tx, double ty); void shift(double dx, double dy); - // Cached Type 3 char status. - void setInCachedT3Char(GBool in) { inCachedT3Char = in; } + // Ignore color operators (in cached/uncolored Type 3 chars, and + // uncolored tiling patterns). Cached Type 3 char status. + void setIgnoreColorOps(GBool ignore) { ignoreColorOps = ignore; } // Push/pop GfxState on/off stack. GfxState *save(); @@ -1344,7 +1345,9 @@ private: double clipXMin, clipYMin, // bounding box for clip region clipXMax, clipYMax; - GBool inCachedT3Char; // in a cached (uncolored) Type 3 char + GBool ignoreColorOps; // ignore color ops (in cached/uncolored + // Type 3 chars, and uncolored tiling + // patterns) GfxState *saved; // next GfxState on stack diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/GlobalParams.cc b/Build/source/libs/xpdf/xpdf-src/xpdf/GlobalParams.cc index 2205a621322..56bfba8e3cc 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/GlobalParams.cc +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/GlobalParams.cc @@ -17,13 +17,18 @@ #include <string.h> #include <stdio.h> +#include <stdarg.h> #include <ctype.h> +#include <time.h> #ifdef _WIN32 # include <shlobj.h> #endif #if HAVE_PAPER_H #include <paper.h> #endif +#if HAVE_FONTCONFIG +# include <fontconfig/fontconfig.h> +#endif #include "gmem.h" #include "gmempp.h" #include "GString.h" @@ -91,14 +96,14 @@ static struct { {"Courier-BoldOblique", "n022024l.pfb", "courbi.ttf", "Courier", "Courier Bold Oblique", "Courier-Bold", 0.212557}, {"Courier-Oblique", "n022023l.pfb", "couri.ttf", "Courier", "Courier Oblique", "Courier", 0.212557}, {"Helvetica", "n019003l.pfb", "arial.ttf", "Helvetica", "Helvetica", NULL, 0}, - {"Helvetica-Bold", "n019004l.pfb", "arialbd.ttf", "Helvetica", "Helvetica-Bold", NULL, 0}, + {"Helvetica-Bold", "n019004l.pfb", "arialbd.ttf", "Helvetica", "Helvetica Bold", NULL, 0}, {"Helvetica-BoldOblique", "n019024l.pfb", "arialbi.ttf", "Helvetica", "Helvetica Bold Oblique", "Helvetica-Bold", 0.212557}, {"Helvetica-Oblique", "n019023l.pfb", "ariali.ttf", "Helvetica", "Helvetica Oblique", "Helvetica", 0.212557}, {"Symbol", "s050000l.pfb", NULL, "Symbol", "Symbol", NULL, 0}, - {"Times-Bold", "n021004l.pfb", "timesbd.ttf", "Times", "Times-Bold", NULL, 0}, - {"Times-BoldItalic", "n021024l.pfb", "timesbi.ttf", "Times", "Times-BoldItalic", NULL, 0}, - {"Times-Italic", "n021023l.pfb", "timesi.ttf", "Times", "Times-Italic", NULL, 0}, - {"Times-Roman", "n021003l.pfb", "times.ttf", "Times", "Times-Roman", NULL, 0}, + {"Times-Bold", "n021004l.pfb", "timesbd.ttf", "Times", "Times Bold", NULL, 0}, + {"Times-BoldItalic", "n021024l.pfb", "timesbi.ttf", "Times", "Times Bold Italic", NULL, 0}, + {"Times-Italic", "n021023l.pfb", "timesi.ttf", "Times", "Times Italic", NULL, 0}, + {"Times-Roman", "n021003l.pfb", "times.ttf", "Times", "Times Roman", NULL, 0}, {"ZapfDingbats", "d050000l.pfb", NULL, "ZapfDingbats", "Zapf Dingbats", NULL, 0}, {NULL} }; @@ -226,6 +231,10 @@ public: void scanWindowsFonts(char *winFontDir); #endif +#if HAVE_FONTCONFIG + void scanFontconfigFonts(); +#endif + private: #ifdef _WIN32 @@ -458,6 +467,8 @@ SysFontInfo *SysFontList::makeWindowsFont(char *name, int fontNum, if (!strcasecmp(path + strlen(path) - 4, ".ttc")) { type = sysFontTTC; + } else if (!strcasecmp(path + strlen(path) - 4, ".otf")) { + type = sysFontOTF; } else { type = sysFontTTF; } @@ -465,6 +476,109 @@ SysFontInfo *SysFontList::makeWindowsFont(char *name, int fontNum, } #endif +#if HAVE_FONTCONFIG +void SysFontList::scanFontconfigFonts() { + FcPattern *pattern; + FcObjectSet *objSet; + FcFontSet *fontSet; + char *family, *file, *styleLang, *style; + GString *family2; + SysFontType type; + GBool bold, italic; + char c; + int fontNum, i, j, n; + + FcInit(); + + 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); + FcPatternDestroy(pattern); + FcObjectSetDestroy(objSet); + + if (fontSet) { + for (i = 0; i < fontSet->nfont; ++i) { + + //--- font file, font type + if (FcPatternGetString(fontSet->fonts[i], FC_FILE, 0, + (FcChar8 **)&file) + != FcResultMatch) { + continue; + } + n = (int)strlen(file); + if (n > 4 && !strcasecmp(file + n - 4, ".pfa")) { + type = sysFontPFA; + } else if (n > 4 && !strcasecmp(file + n - 4, ".pfb")) { + type = sysFontPFB; + } else if (n > 4 && !strcasecmp(file + n - 4, ".ttf")) { + type = sysFontTTF; + } else if (n > 4 && !strcasecmp(file + n - 4, ".otf")) { + type = sysFontOTF; + } else { + continue; + } + + //--- font number + if (FcPatternGetInteger(fontSet->fonts[i], FC_INDEX, 0, &fontNum) + != FcResultMatch) { + fontNum = 0; + } + + //--- font family + if (FcPatternGetString(fontSet->fonts[i], FC_FAMILY, 0, + (FcChar8 **)&family) + != 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)); + } + + FcFontSetDestroy(fontSet); + } + + FcFini(); +} +#endif // HAVE_FONTCONFIG + //------------------------------------------------------------------------ // KeyBinding //------------------------------------------------------------------------ @@ -619,7 +733,10 @@ GlobalParams::GlobalParams(const char *cfgFileName) { textKeepTinyChars = gTrue; initialZoom = new GString("125"); defaultFitZoom = 0; + initialDisplayMode = new GString("continuous"); + initialToolbarState = gTrue; initialSidebarState = gTrue; + initialSelectMode = new GString("linear"); maxTileWidth = 1500; maxTileHeight = 1500; tileCacheSize = 10; @@ -644,6 +761,7 @@ GlobalParams::GlobalParams(const char *cfgFileName) { paperColor = new GString("#ffffff"); matteColor = new GString("#808080"); fullScreenMatteColor = new GString("#000000"); + reverseVideoInvertImages = gFalse; launchCommand = NULL; movieCommand = NULL; defaultPrinter = NULL; @@ -657,6 +775,7 @@ GlobalParams::GlobalParams(const char *cfgFileName) { tabStateFile = appendToPath(getHomeDir(), ".xpdf.tab-state"); printCommands = gFalse; errQuiet = gFalse; + debugLogFile = NULL; cidToUnicodeCache = new CharCodeToUnicodeCache(cidToUnicodeCacheSize); unicodeToUnicodeCache = @@ -787,6 +906,9 @@ void GlobalParams::createDefaultKeyBindings() { xpdfKeyContextAny, "newWindow")); keyBindings->append(new KeyBinding('w', xpdfKeyModCtrl, xpdfKeyContextAny, "closeTabOrQuit")); + keyBindings->append(new KeyBinding('l', xpdfKeyModCtrl, + xpdfKeyContextAny, + "toggleFullScreenMode")); keyBindings->append(new KeyBinding('q', xpdfKeyModCtrl, xpdfKeyContextAny, "quit")); keyBindings->append(new KeyBinding(xpdfKeyCodeTab, xpdfKeyModCtrl, @@ -1022,9 +1144,18 @@ void GlobalParams::parseLine(char *buf, GString *fileName, int line) { parseString("initialZoom", &initialZoom, tokens, fileName, line); } else if (!cmd->cmp("defaultFitZoom")) { parseInteger("defaultFitZoom", &defaultFitZoom, tokens, fileName, line); + } else if (!cmd->cmp("initialDisplayMode")) { + parseString("initialDisplayMode", &initialDisplayMode, + tokens, fileName, line); + } else if (!cmd->cmp("initialToolbarState")) { + parseYesNo("initialToolbarState", &initialToolbarState, + tokens, fileName, line); } else if (!cmd->cmp("initialSidebarState")) { parseYesNo("initialSidebarState", &initialSidebarState, tokens, fileName, line); + } else if (!cmd->cmp("initialSelectMode")) { + parseString("initialSelectMode", &initialSelectMode, + tokens, fileName, line); } else if (!cmd->cmp("maxTileWidth")) { parseInteger("maxTileWidth", &maxTileWidth, tokens, fileName, line); } else if (!cmd->cmp("maxTileHeight")) { @@ -1086,6 +1217,9 @@ void GlobalParams::parseLine(char *buf, GString *fileName, int line) { } else if (!cmd->cmp("fullScreenMatteColor")) { parseString("fullScreenMatteColor", &fullScreenMatteColor, tokens, fileName, line); + } else if (!cmd->cmp("reverseVideoInvertImages")) { + parseYesNo("reverseVideoInvertImages", &reverseVideoInvertImages, + tokens, fileName, line); } else if (!cmd->cmp("launchCommand")) { parseString("launchCommand", &launchCommand, tokens, fileName, line); } else if (!cmd->cmp("movieCommand")) { @@ -1118,6 +1252,8 @@ void GlobalParams::parseLine(char *buf, GString *fileName, int line) { parseYesNo("printCommands", &printCommands, tokens, fileName, line); } else if (!cmd->cmp("errQuiet")) { parseYesNo("errQuiet", &errQuiet, tokens, fileName, line); + } else if (!cmd->cmp("debugLogFile")) { + parseString("debugLogFile", &debugLogFile, tokens, fileName, line); } else { error(errConfig, -1, "Unknown config file command '{0:t}' ({1:t}:{2:d})", cmd, fileName, line); @@ -1862,6 +1998,8 @@ GlobalParams::~GlobalParams() { deleteGList(psResidentFontsCC, PSFontParam16); delete textEncoding; delete initialZoom; + delete initialDisplayMode; + delete initialSelectMode; if (paperColor) { delete paperColor; } @@ -1943,6 +2081,7 @@ static void getWinFontDir(char *winFontDir) { } } } + FreeLibrary(shell32Lib); } // if something went wrong, or we're on a Terminal Server, try using // %SYSTEMROOT%\Fonts @@ -1958,6 +2097,40 @@ static void getWinFontDir(char *winFontDir) { } #endif +#ifdef __APPLE__ +// Apple dfonts and ttc fonts seem to randomly and interchangeably use +// space and hyphen, and sometimes drop the separator entirely. +static GBool macFontNameMatches(GString *name1, const char *name2) { + const char *p1, *p2; + char c1, c2; + + p1 = name1->getCString(); + p2 = name2; + while (*p1 && *p2) { + c1 = *p1; + c2 = *p2; + if (c2 == ' ') { + // * space or hyphen matches a space in the pattern + // * separators can also be dropped, in which case we move to + // the next char in the pattern + if (c1 == ' ' || c1 == '-') { + ++p1; + } + } else { + if (c1 != c2) { + return gFalse; + } + ++p1; + } + ++p2; + } + if (*p1 || *p2) { + return gFalse; + } + return gTrue; +} +#endif + void GlobalParams::setupBaseFonts(const char *dir) { GString *fontName; GString *fileName; @@ -2036,8 +2209,8 @@ void GlobalParams::setupBaseFonts(const char *dir) { } if (dfontFontNames) { for (k = 0; k < dfontFontNames->getLength(); ++k) { - if (!((GString *)dfontFontNames->get(k)) - ->cmp(displayFontTab[i].macFontName)) { + if (macFontNameMatches((GString *)dfontFontNames->get(k), + displayFontTab[i].macFontName)) { fontNum = k; found = gTrue; break; @@ -2114,6 +2287,9 @@ void GlobalParams::setupBaseFonts(const char *dir) { sysFonts->scanWindowsFonts(winFontDir); } #endif +#if HAVE_FONTCONFIG + sysFonts->scanFontconfigFonts(); +#endif } //------------------------------------------------------------------------ @@ -2653,6 +2829,24 @@ int GlobalParams::getDefaultFitZoom() { return z; } +GString *GlobalParams::getInitialDisplayMode() { + GString *s; + + lockGlobalParams; + s = initialDisplayMode->copy(); + unlockGlobalParams; + return s; +} + +GBool GlobalParams::getInitialToolbarState() { + GBool state; + + lockGlobalParams; + state = initialToolbarState; + unlockGlobalParams; + return state; +} + GBool GlobalParams::getInitialSidebarState() { GBool state; @@ -2662,6 +2856,15 @@ GBool GlobalParams::getInitialSidebarState() { return state; } +GString *GlobalParams::getInitialSelectMode() { + GString *s; + + lockGlobalParams; + s = initialSelectMode->copy(); + unlockGlobalParams; + return s; +} + int GlobalParams::getMaxTileWidth() { int w; @@ -2872,6 +3075,15 @@ GString *GlobalParams::getFullScreenMatteColor() { return s; } +GBool GlobalParams::getReverseVideoInvertImages() { + GBool invert; + + lockGlobalParams; + invert = reverseVideoInvertImages; + unlockGlobalParams; + return invert; +} + GString *GlobalParams::getDefaultPrinter() { GString *s; @@ -2998,6 +3210,51 @@ GBool GlobalParams::getErrQuiet() { return errQuiet; } +GString *GlobalParams::getDebugLogFile() { + return debugLogFile; +} + +void GlobalParams::debugLogPrintf(char *fmt, ...) { + GString *path; + FILE *f; + GBool needClose; + time_t t; + struct tm tm; + va_list args; + + if (!(path = getDebugLogFile())) { + return; + } + needClose = gFalse; + if (!path->cmp("-")) { + f = stdout; + } else if (!path->cmp("+")) { + f = stderr; + } else { + f = fopen(path->getCString(), "a"); + needClose = gTrue; + } + if (!f) { + return; + } + t = time(NULL); +#ifdef _WIN32 + localtime_s(&tm, &t); +#else + localtime_r(&t, &tm); +#endif + fprintf(f, "[%04d-%02d-%02d %02d:%02d:%02d] ", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); + va_start(args, fmt); + vfprintf(f, fmt, args); + va_end(args); + fflush(f); + if (needClose) { + fclose(f); + } +} + CharCodeToUnicode *GlobalParams::getCIDToUnicode(GString *collection) { GString *fileName; CharCodeToUnicode *ctu; diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/GlobalParams.h b/Build/source/libs/xpdf/xpdf-src/xpdf/GlobalParams.h index 066b420dfa8..ed1fed3152d 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/GlobalParams.h +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/GlobalParams.h @@ -55,7 +55,8 @@ enum SysFontType { sysFontPFA, sysFontPFB, sysFontTTF, - sysFontTTC + sysFontTTC, + sysFontOTF }; //------------------------------------------------------------------------ @@ -283,7 +284,10 @@ public: GBool getTextKeepTinyChars(); GString *getInitialZoom(); int getDefaultFitZoom(); + GString *getInitialDisplayMode(); + GBool getInitialToolbarState(); GBool getInitialSidebarState(); + GString *getInitialSelectMode(); int getMaxTileWidth(); int getMaxTileHeight(); int getTileCacheSize(); @@ -308,6 +312,7 @@ public: GString *getPaperColor(); GString *getMatteColor(); GString *getFullScreenMatteColor(); + GBool getReverseVideoInvertImages(); GString *getLaunchCommand() { return launchCommand; } GString *getMovieCommand() { return movieCommand; } GString *getDefaultPrinter(); @@ -322,6 +327,8 @@ public: GString *getTabStateFile(); GBool getPrintCommands(); GBool getErrQuiet(); + GString *getDebugLogFile(); + void debugLogPrintf(char *fmt, ...); CharCodeToUnicode *getCIDToUnicode(GString *collection); CharCodeToUnicode *getUnicodeToUnicode(GString *fontName); @@ -509,8 +516,13 @@ private: GString *initialZoom; // initial zoom level int defaultFitZoom; // default zoom factor if initialZoom is // 'page' or 'width'. + GString *initialDisplayMode; // initial display mode (single, + // continuous, etc.) + GBool initialToolbarState; // initial toolbar state - open (true) + // or closed (false) GBool initialSidebarState; // initial sidebar state - open (true) // or closed (false) + GString *initialSelectMode; // initial selection mode (block or linear) int maxTileWidth; // maximum rasterization tile width int maxTileHeight; // maximum rasterization tile height int tileCacheSize; // number of rasterization tiles in cache @@ -536,6 +548,7 @@ private: GString *paperColor; // paper (page background) color GString *matteColor; // matte (background outside of page) color GString *fullScreenMatteColor; // matte color in full-screen mode + GBool reverseVideoInvertImages; // invert images in reverse video mode GString *launchCommand; // command executed for 'launch' links GString *movieCommand; // command executed for movie annotations GString *defaultPrinter; // default printer (for interactive printing @@ -551,6 +564,7 @@ private: GString *tabStateFile; // path for the tab state save file GBool printCommands; // print the drawing commands GBool errQuiet; // suppress error messages? + GString *debugLogFile; // path for debug log file CharCodeToUnicodeCache *cidToUnicodeCache; CharCodeToUnicodeCache *unicodeToUnicodeCache; diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/HTMLGen.cc b/Build/source/libs/xpdf/xpdf-src/xpdf/HTMLGen.cc index d6cbc24680d..036f1116c01 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/HTMLGen.cc +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/HTMLGen.cc @@ -34,9 +34,11 @@ #include "GList.h" #include "SplashBitmap.h" #include "PDFDoc.h" +#include "GfxFont.h" #include "TextOutputDev.h" #include "SplashOutputDev.h" #include "ErrorCodes.h" +#include "WebFont.h" #include "HTMLGen.h" #ifdef _WIN32 @@ -62,11 +64,14 @@ static FontStyleTagInfo fontStyleTags[] = { {"CondensedBold", 13, gTrue, gFalse}, {"CondensedLight", 14, gFalse, gFalse}, {"SemiBold", 8, gTrue, gFalse}, + {"BoldItalicMT", 12, gTrue, gTrue}, {"BoldItalic", 10, gTrue, gTrue}, {"Bold_Italic", 11, gTrue, gTrue}, {"BoldOblique", 11, gTrue, gTrue}, {"Bold_Oblique", 12, gTrue, gTrue}, + {"BoldMT", 6, gTrue, gFalse}, {"Bold", 4, gTrue, gFalse}, + {"ItalicMT", 8, gFalse, gTrue}, {"Italic", 6, gFalse, gTrue}, {"Oblique", 7, gFalse, gTrue}, {"Light", 5, gFalse, gFalse}, @@ -171,6 +176,26 @@ static const char *vertAlignNames[] = { //------------------------------------------------------------------------ +class HTMLGenFontDefn { +public: + + HTMLGenFontDefn(Ref fontIDA, GString *fontFaceA, GString *fontSpecA, + double scaleA) + : fontID(fontIDA), fontFace(fontFaceA), fontSpec(fontSpecA) + , scale(scaleA), used(gFalse) {} + ~HTMLGenFontDefn() { delete fontFace; delete fontSpec; } + GBool match(Ref fontIDA) + { return fontIDA.num == fontID.num && fontIDA.gen == fontID.gen; } + + Ref fontID; + GString *fontFace; // NULL for substituted fonts + GString *fontSpec; + double scale; + GBool used; // set when used (per page) +}; + +//------------------------------------------------------------------------ + //------------------------------------------------------------------------ @@ -184,6 +209,7 @@ HTMLGen::HTMLGen(double backgroundResolutionA) { zoom = 1.0; drawInvisibleText = gTrue; allTextInvisible = gFalse; + extractFontFiles = gFalse; // set up the TextOutputDev textOutControl.mode = textOutReadingOrder; @@ -196,16 +222,27 @@ HTMLGen::HTMLGen(double backgroundResolutionA) { // set up the SplashOutputDev paperColor[0] = paperColor[1] = paperColor[2] = 0xff; splashOut = new SplashOutputDev(splashModeRGB8, 1, gFalse, paperColor); + + fontDefns = NULL; } HTMLGen::~HTMLGen() { delete textOut; delete splashOut; + if (fontDefns) { + deleteGList(fontDefns, HTMLGenFontDefn); + } } void HTMLGen::startDoc(PDFDoc *docA) { doc = docA; splashOut->startDoc(doc->getXRef()); + + if (fontDefns) { + deleteGList(fontDefns, HTMLGenFontDefn); + } + fontDefns = new GList(); + nextFontFaceIdx = 0; } static inline int pr(int (*writeFunc)(void *stream, const char *data, int size), @@ -240,7 +277,7 @@ static void pngWriteFunc(png_structp png, png_bytep data, png_size_t size) { } int HTMLGen::convertPage( - int pg, const char *pngURL, + int pg, const char *pngURL, const char *htmlDir, int (*writeHTML)(void *stream, const char *data, int size), void *htmlStream, int (*writePNG)(void *stream, const char *data, int size), @@ -257,6 +294,7 @@ int HTMLGen::convertPage( TextColumn *col; TextParagraph *par; TextLine *line; + HTMLGenFontDefn *fontDefn; GString *s; double base; int primaryDir, spanDir; @@ -269,7 +307,7 @@ int HTMLGen::convertPage( 0, gFalse, gTrue, gFalse); bitmap = splashOut->getBitmap(); if (!(png = png_create_write_struct(PNG_LIBPNG_VER_STRING, - NULL, NULL, NULL)) || + NULL, NULL, NULL)) || !(pngInfo = png_create_info_struct(png))) { return errFileIO; } @@ -314,11 +352,19 @@ int HTMLGen::convertPage( pr(writeHTML, htmlStream, ".txt { white-space:nowrap; }\n"); fonts = text->getFonts(); fontScales = (double *)gmallocn(fonts->getLength(), sizeof(double)); + for (i = 0; i < fontDefns->getLength(); ++i) { + fontDefn = (HTMLGenFontDefn *)fontDefns->get(i); + fontDefn->used = gFalse; + } for (i = 0; i < fonts->getLength(); ++i) { font = (TextFontInfo *)fonts->get(i); - s = getFontDefn(font, &fontScales[i]); - pf(writeHTML, htmlStream, "#f{0:d} {{ {1:t} }}\n", i, s); - delete s; + fontDefn = getFontDefn(font, htmlDir); + if (!fontDefn->used && fontDefn->fontFace) { + pr(writeHTML, htmlStream, fontDefn->fontFace->getCString()); + } + pf(writeHTML, htmlStream, "#f{0:d} {{ {1:t} }}\n", i, fontDefn->fontSpec); + fontScales[i] = fontDefn->scale; + fontDefn->used = gTrue; } pr(writeHTML, htmlStream, "</style>\n"); pr(writeHTML, htmlStream, "</head>\n"); @@ -592,7 +638,112 @@ void HTMLGen::appendUTF8(Unicode u, GString *s) { } } -GString *HTMLGen::getFontDefn(TextFontInfo *font, double *scale) { +HTMLGenFontDefn *HTMLGen::getFontDefn(TextFontInfo *font, + const char *htmlDir) { + Ref id; + HTMLGenFontDefn *fontDefn; + int i; + + // check the existing font defns + id = font->getFontID(); + if (id.num >= 0) { + for (i = 0; i < fontDefns->getLength(); ++i) { + fontDefn = (HTMLGenFontDefn *)fontDefns->get(i); + if (fontDefn->match(id)) { + return fontDefn; + } + } + } + + // try to extract a font file + if (!extractFontFiles || + !(fontDefn = getFontFile(font, htmlDir))) { + + // get a substitute font + fontDefn = getSubstituteFont(font); + } + + fontDefns->append(fontDefn); + return fontDefn; +} + +HTMLGenFontDefn *HTMLGen::getFontFile(TextFontInfo *font, + const char *htmlDir) { + Ref id; + HTMLGenFontDefn *fontDefn; + Object fontObj; + GfxFont *gfxFont; + WebFont *webFont; + GString *fontFile, *fontPath, *fontFace, *fontSpec; + const char *family, *weight, *style; + double scale; + + id = font->getFontID(); + if (id.num < 0) { + return NULL; + } + + doc->getXRef()->fetch(id.num, id.gen, &fontObj); + if (!fontObj.isDict()) { + fontObj.free(); + return NULL; + } + + gfxFont = GfxFont::makeFont(doc->getXRef(), "F", id, fontObj.getDict()); + webFont = new WebFont(gfxFont, doc->getXRef()); + fontDefn = NULL; + + if (webFont->canWriteTTF()) { + fontFile = GString::format("{0:d}.ttf", nextFontFaceIdx); + fontPath = GString::format("{0:s}/{1:t}", htmlDir, fontFile); + if (webFont->writeTTF(fontPath->getCString())) { + fontFace = GString::format("@font-face {{ font-family: ff{0:d}; src: url(\"{1:t}\"); }}\n", + nextFontFaceIdx, fontFile); + 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; + delete fontFile; + + } else if (webFont->canWriteOTF()) { + fontFile = GString::format("{0:d}.otf", nextFontFaceIdx); + fontPath = GString::format("{0:s}/{1:t}", htmlDir, fontFile); + if (webFont->writeOTF(fontPath->getCString())) { + fontFace = GString::format("@font-face {{ font-family: ff{0:d}; src: url(\"{1:t}\"); }}\n", + nextFontFaceIdx, fontFile); + 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); + fontDefn = new HTMLGenFontDefn(id, fontFace, fontSpec, 1.0); + } + delete fontPath; + delete fontFile; + } + + delete webFont; + delete gfxFont; + fontObj.free(); + + return fontDefn; +} + +HTMLGenFontDefn *HTMLGen::getSubstituteFont(TextFontInfo *font) { + const char *family, *weight, *style; + double scale; + GString *fontSpec; + + getFontDetails(font, &family, &weight, &style, &scale); + fontSpec = GString::format("font-family:{0:s}; font-weight:{1:s}; font-style:{2:s};", + family, weight, style); + return new HTMLGenFontDefn(font->getFontID(), NULL, fontSpec, scale); +} + +void HTMLGen::getFontDetails(TextFontInfo *font, const char **family, + const char **weight, const char **style, + double *scale) { GString *fontName; char *fontName2; FontStyleTagInfo *fst; @@ -666,11 +817,7 @@ GString *HTMLGen::getFontDefn(TextFontInfo *font, double *scale) { } } - // generate the CSS markup - return GString::format("font-family:{0:s}; font-weight:{1:s}; font-style:{2:s};", - fixedWidth ? "monospace" - : serif ? "serif" - : "sans-serif", - bold ? "bold" : "normal", - italic ? "italic" : "normal"); + *family = fixedWidth ? "monospace" : serif ? "serif" : "sans-serif"; + *weight = bold ? "bold" : "normal"; + *style = italic ? "italic" : "normal"; } diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/HTMLGen.h b/Build/source/libs/xpdf/xpdf-src/xpdf/HTMLGen.h index e870d8ef842..d09eea3f266 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/HTMLGen.h +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/HTMLGen.h @@ -20,6 +20,7 @@ class PDFDoc; class TextOutputDev; class TextFontInfo; class SplashOutputDev; +class HTMLGenFontDefn; //------------------------------------------------------------------------ @@ -46,8 +47,11 @@ public: void setAllTextInvisible(GBool allTextInvisibleA) { allTextInvisible = allTextInvisibleA; } + void setExtractFontFiles(GBool extractFontFilesA) + { extractFontFiles = extractFontFilesA; } + void startDoc(PDFDoc *docA); - int convertPage(int pg, const char *pngURL, + int convertPage(int pg, const char *pngURL, const char *htmlDir, int (*writeHTML)(void *stream, const char *data, int size), void *htmlStream, int (*writePNG)(void *stream, const char *data, int size), @@ -61,20 +65,29 @@ private: int primaryDir, int spanDir, double base, GBool dropCapLine, GString *s); void appendUTF8(Unicode u, GString *s); - GString *getFontDefn(TextFontInfo *font, double *scale); + HTMLGenFontDefn *getFontDefn(TextFontInfo *font, const char *htmlDir); + HTMLGenFontDefn *getFontFile(TextFontInfo *font, const char *htmlDir); + HTMLGenFontDefn *getSubstituteFont(TextFontInfo *font); + void getFontDetails(TextFontInfo *font, const char **family, + const char **weight, const char **style, + double *scale); double backgroundResolution; double zoom; GBool drawInvisibleText; GBool allTextInvisible; + GBool extractFontFiles; PDFDoc *doc; TextOutputDev *textOut; SplashOutputDev *splashOut; - GList *fonts; + GList *fonts; // [TextFontInfo] double *fontScales; + GList *fontDefns; // [HTMLGenFontDefn] + int nextFontFaceIdx; + GBool ok; }; diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/JBIG2Stream.cc b/Build/source/libs/xpdf/xpdf-src/xpdf/JBIG2Stream.cc index d3c9b6f8c4d..fcb9d6d0e3a 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/JBIG2Stream.cc +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/JBIG2Stream.cc @@ -838,6 +838,9 @@ void JBIG2Bitmap::combine(JBIG2Bitmap *bitmap, int x, int y, } else { y0 = 0; } + if (y > INT_MAX - bitmap->h) { + return; + } if (y + bitmap->h > h) { y1 = h - y; } else { @@ -1202,10 +1205,13 @@ Stream *JBIG2Stream::copy() { } void JBIG2Stream::reset() { - // read the globals stream + GList *t; + + segments = new GList(); globalSegments = new GList(); + + // read the globals stream if (globalsStream.isStream()) { - segments = globalSegments; curStr = globalsStream.getStream(); curStr->reset(); arithDecoder->setStream(curStr); @@ -1213,10 +1219,13 @@ void JBIG2Stream::reset() { mmrDecoder->setStream(curStr); readSegments(); curStr->close(); + // swap the newly read segments list into globalSegments + t = segments; + segments = globalSegments; + globalSegments = t; } // read the main stream - segments = new GList(); curStr = str; curStr->reset(); arithDecoder->setStream(curStr); @@ -1280,7 +1289,8 @@ int JBIG2Stream::getBlock(char *blk, int size) { return n; } -GString *JBIG2Stream::getPSFilter(int psLevel, const char *indent) { +GString *JBIG2Stream::getPSFilter(int psLevel, const char *indent, + GBool okToReadStream) { return NULL; } @@ -1506,7 +1516,7 @@ GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length, Guint symHeight, symWidth, totalWidth, x, symID; int dh, dw, refAggNum, refDX, refDY, bmSize; GBool ex; - int run, cnt; + int run, prevRun, cnt; Guint i, j, k; symWidths = NULL; @@ -1853,12 +1863,21 @@ GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length, // exported symbol list i = j = 0; ex = gFalse; + prevRun = 1; while (i < numInputSyms + numNewSyms) { if (huff) { huffDecoder->decodeInt(&run, huffTableA); } else { arithDecoder->decodeInt(&run, iaexStats); } + if (run == 0 && prevRun == 0) { + // this avoids infinite loops with damaged files (consecutive + // zero runs are never useful) + error(errSyntaxError, getPos(), + "Invalid exported symbol list in JBIG2 symbol dictionary"); + delete symbolDict; + goto syntaxError; + } if (i + run > numInputSyms + numNewSyms || (ex && j + run > numExSyms)) { error(errSyntaxError, getPos(), @@ -1874,6 +1893,7 @@ GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length, i += run; } ex = !ex; + prevRun = run; } if (j != numExSyms) { error(errSyntaxError, getPos(), "Too few symbols in JBIG2 symbol dictionary"); @@ -2143,18 +2163,23 @@ void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm, runLengthTab[i].val = i; runLengthTab[i].prefixLen = huffDecoder->readBits(4); runLengthTab[i].rangeLen = 0; + runLengthTab[i].prefix = 0; } runLengthTab[32].val = 0x103; runLengthTab[32].prefixLen = huffDecoder->readBits(4); runLengthTab[32].rangeLen = 2; + runLengthTab[32].prefix = 0; runLengthTab[33].val = 0x203; runLengthTab[33].prefixLen = huffDecoder->readBits(4); runLengthTab[33].rangeLen = 3; + runLengthTab[33].prefix = 0; runLengthTab[34].val = 0x20b; runLengthTab[34].prefixLen = huffDecoder->readBits(4); runLengthTab[34].rangeLen = 7; + runLengthTab[34].prefix = 0; runLengthTab[35].prefixLen = 0; runLengthTab[35].rangeLen = jbig2HuffmanEOT; + runLengthTab[35].prefix = 0; huffDecoder->buildTable(runLengthTab, 35); symCodeTab = (JBIG2HuffmanTable *)gmallocn(numSyms + 1, sizeof(JBIG2HuffmanTable)); @@ -2170,6 +2195,12 @@ void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm, symCodeTab[i++].prefixLen = 0; } } else if (j > 0x100) { + if (i == 0) { + error(errSyntaxError, getPos(), "Invalid code in JBIG2 text region"); + gfree(syms); + gfree(symCodeTab); + return; + } for (j -= 0x100; j && i < numSyms; --j) { symCodeTab[i].prefixLen = symCodeTab[i-1].prefixLen; ++i; @@ -2226,8 +2257,8 @@ void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm, codeTableError: error(errSyntaxError, getPos(), "Missing code table in JBIG2 text region"); - gfree(codeTables); - delete syms; + delete codeTables; + gfree(syms); return; eofError: diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/JBIG2Stream.h b/Build/source/libs/xpdf/xpdf-src/xpdf/JBIG2Stream.h index 17181d72038..7aa4d9d8edb 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/JBIG2Stream.h +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/JBIG2Stream.h @@ -42,7 +42,8 @@ public: virtual int getChar(); virtual int lookChar(); virtual int getBlock(char *blk, int size); - virtual GString *getPSFilter(int psLevel, const char *indent); + virtual GString *getPSFilter(int psLevel, const char *indent, + GBool okToReadStream); virtual GBool isBinary(GBool last = gTrue); private: diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/JPXStream.cc b/Build/source/libs/xpdf/xpdf-src/xpdf/JPXStream.cc index 79a7c51eda9..a5dd6f0db0e 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/JPXStream.cc +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/JPXStream.cc @@ -414,18 +414,17 @@ void JPXStream::fillReadBuf() { if (curY >= (img.ySize >> reduction)) { return; } - tileIdx = ((curY - img.yTileOffsetR) / img.yTileSizeR) * img.nXTiles - + (curX - img.xTileOffsetR) / img.xTileSizeR; + tileIdx = (((curY << reduction) - img.yTileOffset) / img.yTileSize) + * img.nXTiles + + ((curX << reduction) - img.xTileOffset) / img.xTileSize; #if 1 //~ ignore the palette, assume the PDF ColorSpace object is valid tileComp = &img.tiles[tileIdx].tileComps[curComp]; #else tileComp = &img.tiles[tileIdx].tileComps[havePalette ? 0 : curComp]; #endif - //~ can curX/curY be less than x/yTileOffsetR? - //~ if yes, we need to use tx = max(0, ....) - tx = jpxFloorDiv((curX - img.xTileOffsetR) % img.xTileSizeR, + tx = jpxFloorDiv(curX - jpxCeilDivPow2(img.tiles[tileIdx].x0, reduction), tileComp->hSep); - ty = jpxFloorDiv((curY - img.yTileOffsetR) % img.yTileSizeR, + ty = jpxFloorDiv(curY - jpxCeilDivPow2(img.tiles[tileIdx].y0, reduction), tileComp->vSep); pix = (int)tileComp->data[ty * tileComp->w + tx]; pixBits = tileComp->prec; @@ -463,7 +462,8 @@ void JPXStream::fillReadBuf() { } while (readBufLen < 8); } -GString *JPXStream::getPSFilter(int psLevel, const char *indent) { +GString *JPXStream::getPSFilter(int psLevel, const char *indent, + GBool okToReadStream) { return NULL; } @@ -960,10 +960,6 @@ JPXDecodeResult JPXStream::readCodestream(Guint len) { img.ySizeR = jpxCeilDivPow2(img.ySize, reduction); img.xOffsetR = jpxCeilDivPow2(img.xOffset, reduction); img.yOffsetR = jpxCeilDivPow2(img.yOffset, reduction); - img.xTileSizeR = jpxCeilDivPow2(img.xTileSize, reduction); - img.yTileSizeR = jpxCeilDivPow2(img.yTileSize, reduction); - img.xTileOffsetR = jpxCeilDivPow2(img.xTileOffset, reduction); - img.yTileOffsetR = jpxCeilDivPow2(img.yTileOffset, reduction); img.nXTiles = (img.xSize - img.xTileOffset + img.xTileSize - 1) / img.xTileSize; img.nYTiles = (img.ySize - img.yTileOffset + img.yTileSize - 1) @@ -1449,8 +1445,7 @@ JPXDecodeResult JPXStream::readCodestream(Guint len) { ok = gTrue; while (1) { if (!readTilePart()) { - ok = gFalse; - break; + return jpxDecodeFatalError; } if (!readMarkerHdr(&segType, &segLen)) { error(errSyntaxError, getPos(), "Error in JPX codestream"); @@ -1913,6 +1908,7 @@ GBool JPXStream::readTilePart() { tile->res = 0; tile->precinct = 0; tile->layer = 0; + tile->done = gFalse; tile->maxNDecompLevels = 0; for (comp = 0; comp < img.nComps; ++comp) { tileComp = &tile->tileComps[comp]; @@ -1925,8 +1921,15 @@ GBool JPXStream::readTilePart() { tileComp->y1 = jpxCeilDiv(tile->y1, tileComp->vSep); tileComp->cbW = 1 << tileComp->codeBlockW; tileComp->cbH = 1 << tileComp->codeBlockH; - tileComp->w = jpxCeilDivPow2(tileComp->x1 - tileComp->x0, reduction); - tileComp->h = jpxCeilDivPow2(tileComp->y1 - tileComp->y0, reduction); + tileComp->w = jpxCeilDivPow2(tileComp->x1, reduction) + - jpxCeilDivPow2(tileComp->x0, reduction); + tileComp->h = jpxCeilDivPow2(tileComp->y1, reduction) + - jpxCeilDivPow2(tileComp->y0, reduction); + if (tileComp->w == 0 || tileComp->h == 0) { + error(errSyntaxError, getPos(), + "Invalid tile size or sample separation in JPX stream"); + return gFalse; + } tileComp->data = (int *)gmallocn(tileComp->w * tileComp->h, sizeof(int)); if (tileComp->x1 - tileComp->x0 > tileComp->y1 - tileComp->y0) { n = tileComp->x1 - tileComp->x0; @@ -1942,13 +1945,20 @@ GBool JPXStream::readTilePart() { resLevel->y0 = jpxCeilDivPow2(tileComp->y0, k); resLevel->x1 = jpxCeilDivPow2(tileComp->x1, k); resLevel->y1 = jpxCeilDivPow2(tileComp->y1, k); + // 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 + // AND the subbands are all completely empty + resLevel->empty = resLevel->x0 == resLevel->x1 || + resLevel->y0 == resLevel->y1; if (r == 0) { resLevel->bx0[0] = resLevel->x0; resLevel->by0[0] = resLevel->y0; resLevel->bx1[0] = resLevel->x1; resLevel->by1[0] = resLevel->y1; - resLevel->empty = resLevel->bx0[0] == resLevel->bx1[0] || - resLevel->by0[0] == resLevel->by1[0]; + resLevel->empty = resLevel->empty && + (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; @@ -1962,7 +1972,8 @@ GBool JPXStream::readTilePart() { 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); - resLevel->empty = (resLevel->bx0[0] == resLevel->bx1[0] || + resLevel->empty = resLevel->empty && + (resLevel->bx0[0] == resLevel->bx1[0] || resLevel->by0[0] == resLevel->by1[0]) && (resLevel->bx0[1] == resLevel->bx1[1] || resLevel->by0[1] == resLevel->by1[1]) && @@ -2117,6 +2128,12 @@ GBool JPXStream::readTilePartData(Guint tileIdx, tile = &img.tiles[tileIdx]; + // if the tile is finished, just skip this tile part + if (tile->done) { + bufStr->discardChars(tilePartLen); + return gTrue; + } + // read all packets from this tile-part while (1) { if (tilePartToEOC) { @@ -2373,6 +2390,7 @@ GBool JPXStream::readTilePartData(Guint tileIdx, tile->res = 0; if (++tile->layer == tile->nLayers) { tile->layer = 0; + tile->done = gTrue; } } } @@ -2385,6 +2403,7 @@ GBool JPXStream::readTilePartData(Guint tileIdx, tile->layer = 0; if (++tile->res == tile->maxNDecompLevels + 1) { tile->res = 0; + tile->done = gTrue; } } } @@ -2398,6 +2417,7 @@ GBool JPXStream::readTilePartData(Guint tileIdx, tile->comp = 0; if (++tile->res == tile->maxNDecompLevels + 1) { tile->res = 0; + tile->done = gTrue; } } } @@ -2411,6 +2431,7 @@ GBool JPXStream::readTilePartData(Guint tileIdx, tile->res = 0; if (++tile->comp == img.nComps) { tile->comp = 0; + tile->done = gTrue; } } } @@ -2424,6 +2445,7 @@ GBool JPXStream::readTilePartData(Guint tileIdx, tile->res = 0; if (++tile->comp == img.nComps) { tile->comp = 0; + tile->done = gTrue; } } } diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/JPXStream.h b/Build/source/libs/xpdf/xpdf-src/xpdf/JPXStream.h index f1a66f5310d..bc5eac4f5ee 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/JPXStream.h +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/JPXStream.h @@ -230,10 +230,11 @@ struct JPXTile { // in any component in this tile //----- progression order loop counters - Guint comp; // component - Guint res; // resolution level - Guint precinct; // precinct - Guint layer; // layer + Guint comp; // component + Guint res; // resolution level + Guint precinct; // precinct + Guint layer; // layer + GBool done; // set when this tile is done //----- tile part info Guint nextTilePart; // next expected tile-part @@ -253,9 +254,6 @@ struct JPXImage { yTileOffset; Guint xSizeR, ySizeR; // size of reference grid >> reduction Guint xOffsetR, yOffsetR; // image offset >> reduction - Guint xTileSizeR, yTileSizeR; // size of tiles >> reduction - Guint xTileOffsetR, // offset of first tile >> reduction - yTileOffsetR; Guint nComps; // number of components //----- computed @@ -287,7 +285,8 @@ public: virtual void close(); virtual int getChar(); virtual int lookChar(); - virtual GString *getPSFilter(int psLevel, const char *indent); + virtual GString *getPSFilter(int psLevel, const char *indent, + GBool okToReadStream); virtual GBool isBinary(GBool last = gTrue); virtual void getImageParams(int *bitsPerComponent, StreamColorSpaceMode *csMode); diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/Lexer.cc b/Build/source/libs/xpdf/xpdf-src/xpdf/Lexer.cc index 05e9df9f24c..6ff75b0b621 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/Lexer.cc +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/Lexer.cc @@ -112,7 +112,7 @@ int Lexer::lookChar() { Object *Lexer::getObj(Object *obj) { char *p; int c, c2; - GBool comment, neg, doubleMinus, done; + GBool comment, neg, doubleMinus, done, invalid; int numParen; int xi; double xf, scale; @@ -343,6 +343,7 @@ Object *Lexer::getObj(Object *obj) { p = tokBuf; n = 0; s = NULL; + invalid = gFalse; while ((c = lookChar()) != EOF && !specialChars[c]) { getChar(); if (c == '#') { @@ -370,6 +371,9 @@ Object *Lexer::getObj(Object *obj) { goto notEscChar; } getChar(); + if (c == 0) { + invalid = gTrue; + } } notEscChar: // the PDF spec claims that names are limited to 127 chars, but @@ -385,7 +389,13 @@ Object *Lexer::getObj(Object *obj) { s->append((char)c); } } - if (n < tokBufSize) { + if (invalid) { + error(errSyntaxError, getPos(), "Null character in name"); + obj->initError(); + if (s) { + delete s; + } + } else if (n < tokBufSize) { *p = '\0'; obj->initName(tokBuf); } else { diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/PDFCore.cc b/Build/source/libs/xpdf/xpdf-src/xpdf/PDFCore.cc index 70919f48947..09b5b99759a 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/PDFCore.cc +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/PDFCore.cc @@ -39,7 +39,7 @@ PDFCore::PDFCore(SplashColorMode colorMode, int bitmapRowPad, GBool reverseVideo, SplashColorPtr paperColor) { - GString *initialZoom; + GString *initialZoom, *initialDisplayMode; int z, i; doc = NULL; @@ -81,6 +81,19 @@ PDFCore::PDFCore(SplashColorMode colorMode, int bitmapRowPad, state->setZoom(z); } delete initialZoom; + initialDisplayMode = globalParams->getInitialDisplayMode(); + if (!initialDisplayMode->cmp("single")) { + state->setDisplayMode(displaySingle); + } else if (!initialDisplayMode->cmp("sideBySideSingle")) { + state->setDisplayMode(displaySideBySideSingle); + } else if (!initialDisplayMode->cmp("sideBySideContinuous")) { + state->setDisplayMode(displaySideBySideContinuous); + } else if (!initialDisplayMode->cmp("horizontalContinuous")) { + state->setDisplayMode(displayHorizontalContinuous); + } else { + state->setDisplayMode(displayContinuous); + } + delete initialDisplayMode; selectMode = selectModeBlock; selectPage = 0; @@ -615,8 +628,8 @@ void PDFCore::scrollRight(int nCols) { scrollTo(state->getScrollX() + nCols, state->getScrollY()); } -void PDFCore::scrollUp(int nLines) { - scrollTo(state->getScrollX(), state->getScrollY() - nLines); +void PDFCore::scrollUp(int nLines, GBool snapToPage) { + scrollTo(state->getScrollX(), state->getScrollY() - nLines, snapToPage); } void PDFCore::scrollUpPrevPage(int nLines) { @@ -624,12 +637,12 @@ void PDFCore::scrollUpPrevPage(int nLines) { state->getScrollY() == 0) { gotoPrevPage(1, gFalse, gTrue); } else { - scrollUp(nLines); + scrollUp(nLines, gTrue); } } -void PDFCore::scrollDown(int nLines) { - scrollTo(state->getScrollX(), state->getScrollY() + nLines); +void PDFCore::scrollDown(int nLines, GBool snapToPage) { + scrollTo(state->getScrollX(), state->getScrollY() + nLines, snapToPage); } void PDFCore::scrollDownNextPage(int nLines) { @@ -643,7 +656,7 @@ void PDFCore::scrollDownNextPage(int nLines) { scrollDown(nLines); } } else { - scrollDown(nLines); + scrollDown(nLines, gTrue); } } @@ -655,9 +668,35 @@ void PDFCore::scrollPageDown() { scrollDownNextPage(state->getWinH()); } -void PDFCore::scrollTo(int x, int y) { +void PDFCore::scrollTo(int x, int y, GBool snapToPage) { + int next, topPage, topPageY, sy, dy; + startUpdate(); state->setScrollPosition(state->getScrollPage(), x, y); + + if (snapToPage) { + if (state->getDisplayMode() == displayContinuous || + 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; + topPageY = tileMap->getPageTopY(topPage); + dy = sy - topPageY; + if (-16 < dy && dy < 0) { + state->setScrollPosition(state->getScrollPage(), x, topPageY); + } + } + } + } + finishUpdate(gTrue, gTrue); } diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/PDFCore.h b/Build/source/libs/xpdf/xpdf-src/xpdf/PDFCore.h index 0fa089ff949..510c01a1a76 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/PDFCore.h +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/PDFCore.h @@ -135,13 +135,13 @@ public: virtual GBool goBackward(); virtual void scrollLeft(int nCols = 16); virtual void scrollRight(int nCols = 16); - virtual void scrollUp(int nLines = 16); + virtual void scrollUp(int nLines = 16, GBool snapToPage = gFalse); virtual void scrollUpPrevPage(int nLines = 16); - virtual void scrollDown(int nLines = 16); + virtual void scrollDown(int nLines = 16, GBool snapToPage = gFalse); virtual void scrollDownNextPage(int nLines = 16); virtual void scrollPageUp(); virtual void scrollPageDown(); - virtual void scrollTo(int x, int y); + virtual void scrollTo(int x, int y, GBool snapToPage = gFalse); virtual void scrollToLeftEdge(); virtual void scrollToRightEdge(); virtual void scrollToTopEdge(); diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/PDFDoc.cc b/Build/source/libs/xpdf/xpdf-src/xpdf/PDFDoc.cc index 8bc14eb47ad..a130b164f91 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/PDFDoc.cc +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/PDFDoc.cc @@ -46,6 +46,15 @@ #define headerSearchSize 1024 // read this many bytes at beginning of // file to look for '%PDF' +// Avoid sharing files with child processes on Windows, where sharing +// can cause problems. +#ifdef _WIN32 +# define fopenReadMode "rbN" +# define wfopenReadMode L"rbN" +#else +# define fopenReadMode "rb" +#endif + //------------------------------------------------------------------------ // PDFDoc //------------------------------------------------------------------------ @@ -75,18 +84,18 @@ PDFDoc::PDFDoc(GString *fileNameA, GString *ownerPassword, // try to open file fileName2 = NULL; #ifdef VMS - if (!(file = fopen(fileName1->getCString(), "rb", "ctx=stm"))) { + if (!(file = fopen(fileName1->getCString(), fopenReadMode, "ctx=stm"))) { error(errIO, -1, "Couldn't open file '{0:t}'", fileName1); errCode = errOpenFile; return; } #else - if (!(file = fopen(fileName1->getCString(), "rb"))) { + if (!(file = fopen(fileName1->getCString(), fopenReadMode))) { fileName2 = fileName->copy(); fileName2->lowerCase(); - if (!(file = fopen(fileName2->getCString(), "rb"))) { + if (!(file = fopen(fileName2->getCString(), fopenReadMode))) { fileName2->upperCase(); - if (!(file = fopen(fileName2->getCString(), "rb"))) { + if (!(file = fopen(fileName2->getCString(), fopenReadMode))) { error(errIO, -1, "Couldn't open file '{0:t}'", fileName); delete fileName2; errCode = errOpenFile; @@ -127,9 +136,9 @@ PDFDoc::PDFDoc(wchar_t *fileNameA, int fileNameLen, GString *ownerPassword, version.dwOSVersionInfoSize = sizeof(version); GetVersionEx(&version); if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) { - file = _wfopen(fileNameU, L"rb"); + file = _wfopen(fileNameU, wfopenReadMode); } else { - file = fopen(fileName->getCString(), "rb"); + file = fopen(fileName->getCString(), fopenReadMode); } if (!file) { error(errIO, -1, "Couldn't open file '{0:t}'", fileName); @@ -181,18 +190,17 @@ PDFDoc::PDFDoc(char *fileNameA, GString *ownerPassword, version.dwOSVersionInfoSize = sizeof(version); GetVersionEx(&version); if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) { - file = _wfopen(fileNameU, L"rb"); + file = _wfopen(fileNameU, wfopenReadMode); } else { #endif /* 0 */ - file = fopen(fileName->getCString(), "rb"); + file = fopen(fileName->getCString(), fopenReadMode); #if 0 } #endif /* 0 */ - #elif defined(VMS) - file = fopen(fileName->getCString(), "rb", "ctx=stm"); + file = fopen(fileName->getCString(), fopenReadMode, "ctx=stm"); #else - file = fopen(fileName->getCString(), "rb"); + file = fopen(fileName->getCString(), fopenReadMode); #endif if (!file) { diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/PDFDocEncoding.cc b/Build/source/libs/xpdf/xpdf-src/xpdf/PDFDocEncoding.cc index c4eef7c24b8..8258395b543 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/PDFDocEncoding.cc +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/PDFDocEncoding.cc @@ -6,6 +6,7 @@ // //======================================================================== +#include <aconf.h> #include "gmempp.h" #include "PDFDocEncoding.h" diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/PSOutputDev.cc b/Build/source/libs/xpdf/xpdf-src/xpdf/PSOutputDev.cc index 15a2a233990..f39a72e9015 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/PSOutputDev.cc +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/PSOutputDev.cc @@ -77,6 +77,7 @@ static const char *prolog[] = { " put", " } for", "~123ngs", + "/bdef { bind def } bind def", "/pdfSetup {", " /pdfDuplex exch def", " /setpagedevice where {", @@ -393,9 +394,9 @@ static const char *prolog[] = { "/f { fCol fill } def", "/f* { fCol eofill } def", "% clipping operators", - "/W { clip newpath } def", - "/W* { eoclip newpath } def", - "/Ws { strokepath clip newpath } def", + "/W { clip newpath } bdef", + "/W* { eoclip newpath } bdef", + "/Ws { strokepath clip newpath } bdef", "% text state operators", "/Tc { /pdfCharSpacing exch def } def", "/Tf { dup /pdfFontSize exch def", @@ -985,7 +986,9 @@ public: { return (bufIdx >= bufSize && !fillBuf()) ? EOF : buf[bufIdx++]; } virtual int lookChar() { return (bufIdx >= bufSize && !fillBuf()) ? EOF : buf[bufIdx]; } - virtual GString *getPSFilter(int psLevel, const char *indent) { return NULL; } + virtual GString *getPSFilter(int psLevel, const char *indent, + GBool okToReadStream) + { return NULL; } virtual GBool isBinary(GBool last = gTrue) { return gTrue; } virtual GBool isEncoder() { return gTrue; } @@ -1084,7 +1087,9 @@ public: { return (bufIdx >= width && !fillBuf()) ? EOF : buf[bufIdx++]; } virtual int lookChar() { return (bufIdx >= width && !fillBuf()) ? EOF : buf[bufIdx]; } - virtual GString *getPSFilter(int psLevel, const char *indent) { return NULL; } + virtual GString *getPSFilter(int psLevel, const char *indent, + GBool okToReadStream) + { return NULL; } virtual GBool isBinary(GBool last = gTrue) { return gTrue; } virtual GBool isEncoder() { return gTrue; } @@ -1167,7 +1172,9 @@ public: { return (bufIdx >= bufSize && !fillBuf()) ? EOF : buf[bufIdx++]; } virtual int lookChar() { return (bufIdx >= bufSize && !fillBuf()) ? EOF : buf[bufIdx]; } - virtual GString *getPSFilter(int psLevel, const char *indent) { return NULL; } + virtual GString *getPSFilter(int psLevel, const char *indent, + GBool okToReadStream) + { return NULL; } virtual GBool isBinary(GBool last = gTrue) { return gTrue; } virtual GBool isEncoder() { return gTrue; } @@ -3841,7 +3848,7 @@ void PSOutputDev::setupImage(Ref id, Stream *str, GBool mask, useLZW = useRLE = gFalse; useCompressed = gFalse; } else { - s = str->getPSFilter(level < psLevel3 ? 2 : 3, ""); + s = str->getPSFilter(level < psLevel3 ? 2 : 3, "", gTrue); if (s) { useLZW = useRLE = gFalse; useCompressed = gTrue; @@ -4191,7 +4198,13 @@ GBool PSOutputDev::checkPageSlice(Page *page, double hDPI, double vDPI, } sliceX = sliceY = 0; sliceW = (int)((box.x2 - box.x1) * hDPI2 / 72.0); + if (sliceW == 0) { + sliceW = 1; + } sliceH = (int)((box.y2 - box.y1) * vDPI2 / 72.0); + if (sliceH == 0) { + sliceH = 1; + } } nStripes = (int)ceil(((double)sliceW * (double)sliceH) / (double)globalParams->getPSRasterSliceSize()); @@ -5223,6 +5236,7 @@ void PSOutputDev::tilingPatternFillL2(GfxState *state, Gfx *gfx, // set the pattern if (paintType == 2) { + writePS("fCol\n"); writePS("currentcolor "); } writePSFmt("xpdfTile{0:d} setpattern\n", numTilingPatterns); @@ -6315,7 +6329,7 @@ void PSOutputDev::doImageL2(Object *ref, GfxState *state, useASCII = gFalse; } else { s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3, - " "); + " ", !inlineImg); if ((colorMap && (colorMap->getColorSpace()->getMode() == csDeviceN || level == psLevel2Gray || level == psLevel3Gray)) || inlineImg || !s) { @@ -6790,7 +6804,7 @@ void PSOutputDev::doImageL3(Object *ref, GfxState *state, maskUseCompressed = gFalse; maskUseASCII = gFalse; } else { - s = maskStr->getPSFilter(3, " "); + s = maskStr->getPSFilter(3, " ", !inlineImg); if (!s) { if (globalParams->getPSLZW()) { maskUseLZW = gTrue; @@ -7018,7 +7032,7 @@ void PSOutputDev::doImageL3(Object *ref, GfxState *state, useCompressed = gFalse; useASCII = gFalse; } else { - s = str->getPSFilter(3, " "); + s = str->getPSFilter(3, " ", !inlineImg); if ((colorMap && level == psLevel3Gray) || inlineImg || !s) { if (globalParams->getPSLZW()) { useLZW = gTrue; @@ -7557,19 +7571,13 @@ GString *PSOutputDev::createDeviceNTintFunc(GfxDeviceNColorSpace *cs) { } obj1.free(); sepCSObj.arrayGet(3, &funcObj); - if (!(func = Function::parse(&funcObj))) { + if (!(func = Function::parse(&funcObj, 1, 4))) { funcObj.free(); sepCSObj.free(); colorants.free(); return NULL; } funcObj.free(); - if (func->getInputSize() != 1 || func->getOutputSize() != 4) { - delete func; - sepCSObj.free(); - colorants.free(); - return NULL; - } sepIn = 1; func->transform(&sepIn, cmyk[i]); delete func; diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/SplashOutputDev.cc b/Build/source/libs/xpdf/xpdf-src/xpdf/SplashOutputDev.cc index df2e2b289cc..187ef5657b5 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/SplashOutputDev.cc +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/SplashOutputDev.cc @@ -28,6 +28,7 @@ #include "BuiltinFont.h" #include "BuiltinFontTables.h" #include "FoFiTrueType.h" +#include "FoFiType1C.h" #include "JPXStream.h" #include "SplashBitmap.h" #include "SplashGlyphBitmap.h" @@ -498,6 +499,7 @@ public: 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 }; T3FontCache::T3FontCache(Ref *fontIDA, double m11A, double m12A, @@ -539,6 +541,7 @@ T3FontCache::T3FontCache(Ref *fontIDA, double m11A, double m12A, for (i = 0; i < cacheSets * cacheAssoc; ++i) { cacheTags[i].mru = (Gushort)(i & (cacheAssoc - 1)); } + inUse = gFalse; } T3FontCache::~T3FontCache() { @@ -615,8 +618,8 @@ SplashOutputDev::SplashOutputDev(SplashColorMode colorModeA, xref = NULL; bitmap = new SplashBitmap(1, 1, bitmapRowPad, colorMode, - colorMode != splashModeMono1, bitmapTopDown); - splash = new Splash(bitmap, vectorAntialias, &screenParams); + colorMode != splashModeMono1, bitmapTopDown, NULL); + splash = new Splash(bitmap, vectorAntialias, NULL, &screenParams); splash->setMinLineWidth(globalParams->getMinLineWidth()); splash->setStrokeAdjust( mapStrokeAdjustMode[globalParams->getStrokeAdjust()]); @@ -761,9 +764,10 @@ void SplashOutputDev::startPage(int pageNum, GfxState *state) { bitmap = NULL; } bitmap = new SplashBitmap(w, h, bitmapRowPad, colorMode, - colorMode != splashModeMono1, bitmapTopDown); + colorMode != splashModeMono1, bitmapTopDown, + NULL); } - splash = new Splash(bitmap, vectorAntialias, &screenParams); + splash = new Splash(bitmap, vectorAntialias, NULL, &screenParams); splash->setMinLineWidth(globalParams->getMinLineWidth()); splash->setEnablePathSimplification( globalParams->getEnablePathSimplification()); @@ -804,6 +808,7 @@ void SplashOutputDev::startPage(int pageNum, GfxState *state) { splash->setStrokeAdjust( mapStrokeAdjustMode[globalParams->getStrokeAdjust()]); splash->clear(paperColor, 0); + reverseVideoInvertImages = globalParams->getReverseVideoInvertImages(); if (startPageCbk) { (*startPageCbk)(startPageCbkData); } @@ -1149,6 +1154,7 @@ void SplashOutputDev::doUpdateFont(GfxState *state) { SplashFontFile *fontFile; int fontNum; FoFiTrueType *ff; + FoFiType1C *ffT1C; Ref embRef; Object refObj, strObj; #if LOAD_FONTS_FROM_MEM @@ -1166,9 +1172,9 @@ void SplashOutputDev::doUpdateFont(GfxState *state) { double fsx, fsy, w, fontScaleMin, fontScaleAvg, fontScale; Gushort ww; SplashCoord mat[4]; - char *name; + char *name, *start; Unicode uBuf[8]; - int substIdx, n, code, cmap, cmapPlatform, cmapEncoding, i; + int substIdx, n, code, cmap, cmapPlatform, cmapEncoding, length, i; needFontUpdate = gFalse; font = NULL; @@ -1306,6 +1312,17 @@ void SplashOutputDev::doUpdateFont(GfxState *state) { } break; case fontType1C: +#if LOAD_FONTS_FROM_MEM + if ((ffT1C = FoFiType1C::make(fontBuf->getCString(), + fontBuf->getLength()))) { +#else + if ((ffT1C = FoFiType1C::load(fileName->getCString()))) { +#endif + codeToGID = ((Gfx8BitFont *)gfxFont)->getCodeToGIDMap(ffT1C); + delete ffT1C; + } else { + codeToGID = NULL; + } if (!(fontFile = fontEngine->loadType1CFont( id, #if LOAD_FONTS_FROM_MEM @@ -1314,6 +1331,7 @@ void SplashOutputDev::doUpdateFont(GfxState *state) { fileName->getCString(), fileName == tmpFileName, #endif + codeToGID, (const char **)((Gfx8BitFont *)gfxFont)->getEncoding()))) { error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'", gfxFont->getName() ? gfxFont->getName()->getCString() @@ -1323,6 +1341,21 @@ void SplashOutputDev::doUpdateFont(GfxState *state) { } break; case fontType1COT: + codeToGID = NULL; +#if LOAD_FONTS_FROM_MEM + if ((ff = FoFiTrueType::make(fontBuf->getCString(), fontBuf->getLength(), + fontNum, gTrue))) { +#else + if ((ff = FoFiTrueType::load(fileName->getCString(), + fontNum, gTrue))) { +#endif + if (ff->getCFFBlock(&start, &length) && + (ffT1C = FoFiType1C::make(start, length))) { + codeToGID = ((Gfx8BitFont *)gfxFont)->getCodeToGIDMap(ffT1C); + delete ffT1C; + } + delete ff; + } if (!(fontFile = fontEngine->loadOpenTypeT1CFont( id, #if LOAD_FONTS_FROM_MEM @@ -1331,6 +1364,7 @@ void SplashOutputDev::doUpdateFont(GfxState *state) { fileName->getCString(), fileName == tmpFileName, #endif + codeToGID, (const char **)((Gfx8BitFont *)gfxFont)->getEncoding()))) { error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'", gfxFont->getName() ? gfxFont->getName()->getCString() @@ -1559,6 +1593,7 @@ void SplashOutputDev::doUpdateFont(GfxState *state) { break; default: // this shouldn't happen + delete fontLoc; goto err2; } @@ -1593,8 +1628,8 @@ void SplashOutputDev::doUpdateFont(GfxState *state) { (name[0] >= 'a' && name[0] <= 'z') || (name[0] >= '0' && name[0] <= '9'))) { w = ((Gfx8BitFont *)gfxFont)->getWidth((Guchar)code); - builtinFontSubst[substIdx]->widths->getWidth(name, &ww); - if (w > 0.01 && ww > 10) { + if (builtinFontSubst[substIdx]->widths->getWidth(name, &ww) && + w > 0.01 && ww > 10) { w /= ww * 0.001; if (w < fontScaleMin) { fontScaleMin = w; @@ -1780,7 +1815,10 @@ void SplashOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx, // check for an excessively large tile size tileSize = tileW * tileH; - if (tileSize > 1000000 || tileSize < 0) { + if (tileXMax - tileXMin + 0.5 > (double)INT_MAX || + tileYMax - tileYMin + 0.5 > (double)INT_MAX || + tileW > INT_MAX / tileH || + tileSize > 1000000) { mat1[0] = mat[0]; mat1[1] = mat[1]; mat1[2] = mat[2]; @@ -1932,8 +1970,10 @@ void SplashOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx, origBitmap = bitmap; origSplash = splash; bitmap = tileBitmap = new SplashBitmap(tileW, tileH, bitmapRowPad, - colorMode, gTrue, bitmapTopDown); - splash = new Splash(bitmap, vectorAntialias, origSplash->getScreen()); + colorMode, gTrue, bitmapTopDown, + origBitmap); + splash = new Splash(bitmap, vectorAntialias, + origSplash->getImageCache(), origSplash->getScreen()); for (i = 0; i < splashMaxColorComps; ++i) { color[i] = 0; } @@ -2085,7 +2125,7 @@ GBool SplashOutputDev::axialShadedFill(GfxState *state, bitmapWidth = ixMax - ixMin; bitmapHeight = iyMax - iyMin; tBitmap = new SplashBitmap(bitmapWidth, bitmapHeight, 1, - srcMode, gTrue, gTrue); + srcMode, gTrue, gTrue, bitmap); memset(tBitmap->getAlphaPtr(), 0, (size_t)bitmapWidth * bitmapHeight); nComps = splashColorModeNComps[srcMode]; @@ -2403,7 +2443,7 @@ GBool SplashOutputDev::radialShadedFill(GfxState *state, bitmapWidth = ixMax - ixMin; bitmapHeight = iyMax - iyMin; tBitmap = new SplashBitmap(bitmapWidth, bitmapHeight, 1, - srcMode, gTrue, gTrue); + srcMode, gTrue, gTrue, bitmap); memset(tBitmap->getAlphaPtr(), 0, tBitmap->getAlphaRowSize() * bitmapHeight); nComps = splashColorModeNComps[srcMode]; @@ -2908,12 +2948,25 @@ GBool SplashOutputDev::beginType3Char(GfxState *state, double x, double y, if (i >= nT3Fonts) { // create new entry in the font cache - if (nT3Fonts == splashOutT3FontCacheSize) { - delete t3FontCache[nT3Fonts - 1]; + if (nT3Fonts < splashOutT3FontCacheSize) { + for (j = nT3Fonts; j > 0; --j) { + t3FontCache[j] = t3FontCache[j - 1]; + } + } else { + for (j = nT3Fonts - 1; j >= 0; --j) { + if (!t3FontCache[j]->inUse) { + break; + } + } + if (j < 0) { + error(errSyntaxError, -1, "Type 3 fonts nested too deeply"); + return gTrue; + } + delete t3FontCache[j]; --nT3Fonts; - } - for (j = nT3Fonts; j > 0; --j) { - t3FontCache[j] = t3FontCache[j - 1]; + for (; j > 0; --j) { + t3FontCache[j] = t3FontCache[j - 1]; + } } ++nT3Fonts; bbox = gfxFont->getFontBBox(); @@ -2985,6 +3038,8 @@ GBool SplashOutputDev::beginType3Char(GfxState *state, double x, double y, } } + t3Font->inUse = gTrue; + // push a new Type 3 glyph record t3gs = new T3GlyphStack(); t3gs->next = t3GlyphStack; @@ -3021,6 +3076,7 @@ void SplashOutputDev::endType3Char(GfxState *state) { } t3gs = t3GlyphStack; t3GlyphStack = t3gs->next; + t3gs->cache->inUse = gFalse; delete t3gs; } @@ -3131,16 +3187,19 @@ void SplashOutputDev::type3D1(GfxState *state, double wx, double wy, if (colorMode == splashModeMono1) { colorMode = splashModeMono1; bitmap = new SplashBitmap(t3Font->glyphW, t3Font->glyphH, 1, - splashModeMono1, gFalse); - splash = new Splash(bitmap, gFalse, t3GlyphStack->origSplash->getScreen()); + splashModeMono1, gFalse, gTrue, bitmap); + splash = new Splash(bitmap, gFalse, + t3GlyphStack->origSplash->getImageCache(), + t3GlyphStack->origSplash->getScreen()); color[0] = 0; splash->clear(color); color[0] = 0xff; } else { colorMode = splashModeMono8; bitmap = new SplashBitmap(t3Font->glyphW, t3Font->glyphH, 1, - splashModeMono8, gFalse); + splashModeMono8, gFalse, gTrue, bitmap); splash = new Splash(bitmap, vectorAntialias, + t3GlyphStack->origSplash->getImageCache(), t3GlyphStack->origSplash->getScreen()); color[0] = 0x00; splash->clear(color); @@ -3214,6 +3273,7 @@ void SplashOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, double *ctm; SplashCoord mat[6]; SplashOutImageMaskData imgMaskData; + GString *imgTag; if (state->getFillColorSpace()->isNonMarking()) { return; @@ -3239,8 +3299,11 @@ void SplashOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, imgMaskData.height = height; imgMaskData.y = 0; - splash->fillImageMask(&imageMaskSrc, &imgMaskData, width, height, mat, + imgTag = makeImageTag(ref); + splash->fillImageMask(imgTag, + &imageMaskSrc, &imgMaskData, width, height, mat, t3GlyphStack != NULL, interpolate); + if (inlineImg) { while (imgMaskData.y < height) { imgMaskData.imgStr->getLine(); @@ -3248,6 +3311,7 @@ void SplashOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, } } + delete imgTag; delete imgMaskData.imgStr; str->close(); } @@ -3264,6 +3328,7 @@ void SplashOutputDev::setSoftMaskFromImageMask(GfxState *state, SplashBitmap *maskBitmap; Splash *maskSplash; SplashColor maskColor; + GString *imgTag; ctm = state->getCTM(); mat[0] = ctm[0]; @@ -3280,8 +3345,8 @@ void SplashOutputDev::setSoftMaskFromImageMask(GfxState *state, imgMaskData.height = height; imgMaskData.y = 0; maskBitmap = new SplashBitmap(bitmap->getWidth(), bitmap->getHeight(), - 1, splashModeMono8, gFalse); - maskSplash = new Splash(maskBitmap, gTrue); + 1, splashModeMono8, gFalse, gTrue, bitmap); + maskSplash = new Splash(maskBitmap, gTrue, splash->getImageCache()); maskSplash->setStrokeAdjust( mapStrokeAdjustMode[globalParams->getStrokeAdjust()]); maskSplash->setEnablePathSimplification( @@ -3289,8 +3354,10 @@ void SplashOutputDev::setSoftMaskFromImageMask(GfxState *state, clearMaskRegion(state, maskSplash, 0, 0, 1, 1); maskColor[0] = 0xff; maskSplash->setFillPattern(new SplashSolidColor(maskColor)); - maskSplash->fillImageMask(&imageMaskSrc, &imgMaskData, + imgTag = makeImageTag(ref); + maskSplash->fillImageMask(imgTag, &imageMaskSrc, &imgMaskData, width, height, mat, gFalse, interpolate); + delete imgTag; delete imgMaskData.imgStr; str->close(); delete maskSplash; @@ -3304,6 +3371,7 @@ struct SplashOutImageData { SplashColorPtr lookup; int *maskColors; SplashColorMode colorMode; + GBool invert; int width, height, y; }; @@ -3312,7 +3380,7 @@ GBool SplashOutputDev::imageSrc(void *data, SplashColorPtr colorLine, SplashOutImageData *imgData = (SplashOutImageData *)data; Guchar *p; SplashColorPtr q, col; - int x; + int n, x; if (imgData->y == imgData->height || !(p = imgData->imgStr->getLine())) { @@ -3371,6 +3439,13 @@ GBool SplashOutputDev::imageSrc(void *data, SplashColorPtr colorLine, } } + if (imgData->invert) { + n = imgData->width * splashColorModeNComps[imgData->colorMode]; + for (x = 0, p = colorLine; x < n; ++x, ++p) { + *p ^= 0xff; + } + } + ++imgData->y; return gTrue; } @@ -3381,7 +3456,7 @@ GBool SplashOutputDev::alphaImageSrc(void *data, SplashColorPtr colorLine, Guchar *p0, *p, *aq; SplashColorPtr q, col; Guchar alpha; - int nComps, x, i; + int nComps, x, n, i; if (imgData->y == imgData->height || !(p0 = imgData->imgStr->getLine())) { @@ -3455,6 +3530,13 @@ GBool SplashOutputDev::alphaImageSrc(void *data, SplashColorPtr colorLine, *aq++ = alpha; } + if (imgData->invert) { + n = imgData->width * splashColorModeNComps[imgData->colorMode]; + for (x = 0, p = colorLine; x < n; ++x, ++p) { + *p ^= 0xff; + } + } + ++imgData->y; return gTrue; } @@ -3470,6 +3552,7 @@ void SplashOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, SplashOutImageData imgData; SplashColorMode srcMode; SplashImageSource src; + GString *imgTag; GfxGray gray; GfxRGB rgb; #if SPLASH_CMYK @@ -3500,6 +3583,7 @@ void SplashOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, imgData.ri = state->getRenderingIntent(); imgData.maskColors = maskColors; imgData.colorMode = colorMode; + imgData.invert = reverseVideo && reverseVideoInvertImages; imgData.width = width; imgData.height = height; imgData.y = 0; @@ -3559,7 +3643,9 @@ void SplashOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, srcMode = colorMode; } src = maskColors ? &alphaImageSrc : &imageSrc; - splash->drawImage(src, &imgData, srcMode, maskColors ? gTrue : gFalse, + imgTag = makeImageTag(ref); + splash->drawImage(imgTag, + src, &imgData, srcMode, maskColors ? gTrue : gFalse, width, height, mat, interpolate); if (inlineImg) { while (imgData.y < height) { @@ -3568,6 +3654,7 @@ void SplashOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, } } + delete imgTag; gfree(imgData.lookup); delete imgData.imgStr; str->close(); @@ -3580,6 +3667,7 @@ struct SplashOutMaskedImageData { SplashBitmap *mask; SplashColorPtr lookup; SplashColorMode colorMode; + GBool invert; int width, height, y; }; @@ -3591,7 +3679,7 @@ GBool SplashOutputDev::maskedImageSrc(void *data, SplashColorPtr colorLine, static Guchar bitToByte[2] = {0x00, 0xff}; Guchar *maskPtr; int maskShift; - int x; + int n, x; if (imgData->y == imgData->height || !(p = imgData->imgStr->getLine())) { @@ -3672,6 +3760,13 @@ GBool SplashOutputDev::maskedImageSrc(void *data, SplashColorPtr colorLine, } } + if (imgData->invert) { + n = imgData->width * splashColorModeNComps[imgData->colorMode]; + for (x = 0, p = colorLine; x < n; ++x, ++p) { + *p ^= 0xff; + } + } + ++imgData->y; return gTrue; } @@ -3692,6 +3787,7 @@ void SplashOutputDev::drawMaskedImage(GfxState *state, Object *ref, SplashColorMode srcMode; SplashBitmap *maskBitmap; Splash *maskSplash; + GString *imgTag; SplashColor maskColor; GfxGray gray; GfxRGB rgb; @@ -3741,8 +3837,9 @@ void SplashOutputDev::drawMaskedImage(GfxState *state, Object *ref, imgMaskData.width = maskWidth; imgMaskData.height = maskHeight; imgMaskData.y = 0; - maskBitmap = new SplashBitmap(width, height, 1, splashModeMono1, gFalse); - maskSplash = new Splash(maskBitmap, gFalse); + maskBitmap = new SplashBitmap(width, height, 1, splashModeMono1, + gFalse, gTrue, bitmap); + maskSplash = new Splash(maskBitmap, gFalse, splash->getImageCache()); maskSplash->setStrokeAdjust( mapStrokeAdjustMode[globalParams->getStrokeAdjust()]); maskSplash->setEnablePathSimplification( @@ -3752,7 +3849,7 @@ void SplashOutputDev::drawMaskedImage(GfxState *state, Object *ref, maskColor[0] = 0xff; maskSplash->setFillPattern(new SplashSolidColor(maskColor)); // use "glyph mode" here to get the correct scaled size - maskSplash->fillImageMask(&imageMaskSrc, &imgMaskData, + maskSplash->fillImageMask(NULL, &imageMaskSrc, &imgMaskData, maskWidth, maskHeight, mat, gTrue, interpolate); delete imgMaskData.imgStr; maskStr->close(); @@ -3775,6 +3872,7 @@ void SplashOutputDev::drawMaskedImage(GfxState *state, Object *ref, imgData.ri = state->getRenderingIntent(); imgData.mask = maskBitmap; imgData.colorMode = colorMode; + imgData.invert = reverseVideo && reverseVideoInvertImages; imgData.width = width; imgData.height = height; imgData.y = 0; @@ -3833,9 +3931,12 @@ void SplashOutputDev::drawMaskedImage(GfxState *state, Object *ref, } else { srcMode = colorMode; } - splash->drawImage(&maskedImageSrc, &imgData, srcMode, gTrue, + imgTag = makeImageTag(ref); + splash->drawImage(imgTag, + &maskedImageSrc, &imgData, srcMode, gTrue, width, height, mat, interpolate); + delete imgTag; delete maskBitmap; gfree(imgData.lookup); delete imgData.imgStr; @@ -3850,6 +3951,7 @@ struct SplashOutSoftMaskMatteImageData { GfxRenderingIntent ri; Guchar matte[gfxColorMaxComps]; SplashColorMode colorMode; + GBool invert; int width, height, y; }; @@ -3866,7 +3968,7 @@ GBool SplashOutputDev::softMaskMatteImageSrc(void *data, GfxCMYK cmyk; #endif Guchar alpha; - int nComps, x; + int nComps, n, x; if (imgData->y == imgData->height || !(p = imgData->imgStr->getLine()) || @@ -3938,6 +4040,13 @@ GBool SplashOutputDev::softMaskMatteImageSrc(void *data, *aq++ = alpha; } + if (imgData->invert) { + n = imgData->width * splashColorModeNComps[imgData->colorMode]; + for (x = 0, p = colorLine; x < n; ++x, ++p) { + *p ^= 0xff; + } + } + ++imgData->y; return gTrue; } @@ -3955,6 +4064,7 @@ void SplashOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, SplashOutImageData imgData; SplashOutImageData imgMaskData; SplashOutSoftMaskMatteImageData matteImgData; + GString *imgTag; SplashColorMode srcMode; SplashBitmap *maskBitmap; Splash *maskSplash; @@ -4044,11 +4154,14 @@ void SplashOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, n = 1 << 8; } matteImgData.colorMode = colorMode; + matteImgData.invert = reverseVideo && reverseVideoInvertImages; matteImgData.width = width; matteImgData.height = height; matteImgData.y = 0; - splash->drawImage(&softMaskMatteImageSrc, &matteImgData, + imgTag = makeImageTag(ref); + splash->drawImage(imgTag, &softMaskMatteImageSrc, &matteImgData, srcMode, gTrue, width, height, mat, interpolate); + delete imgTag; delete matteImgData.maskStr; delete matteImgData.imgStr; maskStr->close(); @@ -4069,6 +4182,7 @@ void SplashOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, imgMaskData.ri = state->getRenderingIntent(); imgMaskData.maskColors = NULL; imgMaskData.colorMode = splashModeMono8; + imgMaskData.invert = gFalse; imgMaskData.width = maskWidth; imgMaskData.height = maskHeight; imgMaskData.y = 0; @@ -4080,14 +4194,16 @@ void SplashOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, imgMaskData.lookup[i] = colToByte(gray); } maskBitmap = new SplashBitmap(bitmap->getWidth(), bitmap->getHeight(), - 1, splashModeMono8, gFalse); - maskSplash = new Splash(maskBitmap, vectorAntialias); + 1, splashModeMono8, gFalse, gTrue, bitmap); + maskSplash = new Splash(maskBitmap, vectorAntialias, + splash->getImageCache()); maskSplash->setStrokeAdjust( mapStrokeAdjustMode[globalParams->getStrokeAdjust()]); maskSplash->setEnablePathSimplification( globalParams->getEnablePathSimplification()); clearMaskRegion(state, maskSplash, 0, 0, 1, 1); - maskSplash->drawImage(&imageSrc, &imgMaskData, splashModeMono8, gFalse, + maskSplash->drawImage(NULL, + &imageSrc, &imgMaskData, splashModeMono8, gFalse, maskWidth, maskHeight, mat, interpolate); delete imgMaskData.imgStr; maskStr->close(); @@ -4105,6 +4221,7 @@ void SplashOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, imgData.ri = state->getRenderingIntent(); imgData.maskColors = NULL; imgData.colorMode = colorMode; + imgData.invert = reverseVideo && reverseVideoInvertImages; imgData.width = width; imgData.height = height; imgData.y = 0; @@ -4156,10 +4273,13 @@ void SplashOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, } } - splash->drawImage(&imageSrc, &imgData, srcMode, gFalse, width, height, mat, + imgTag = makeImageTag(ref); + splash->drawImage(imgTag, + &imageSrc, &imgData, srcMode, gFalse, width, height, mat, interpolate); splash->setSoftMask(NULL); + delete imgTag; gfree(imgData.lookup); delete imgData.imgStr; @@ -4168,12 +4288,21 @@ void SplashOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, } } +GString *SplashOutputDev::makeImageTag(Object *ref) { + if (!ref || !ref->isRef()) { + return NULL; + } + return GString::format("{0:d}_{1:d}", ref->getRefNum(), ref->getRefGen()); +} + void SplashOutputDev::reduceImageResolution(Stream *str, double *ctm, int *width, int *height) { double sw, sh; int reduction; if (str->getKind() == strJPX && + *width >= 256 && + *height >= 256 && *width * *height > 10000000) { sw = (double)*width / (fabs(ctm[0]) + fabs(ctm[1])); sh = (double)*height / (fabs(ctm[2]) + fabs(ctm[3])); @@ -4396,8 +4525,9 @@ void SplashOutputDev::beginTransparencyGroup(GfxState *state, double *bbox, // create the temporary bitmap bitmap = new SplashBitmap(w, h, bitmapRowPad, colorMode, gTrue, - bitmapTopDown); + bitmapTopDown, transpGroup->origBitmap); splash = new Splash(bitmap, vectorAntialias, + transpGroup->origSplash->getImageCache(), transpGroup->origSplash->getScreen()); splash->setMinLineWidth(globalParams->getMinLineWidth()); splash->setStrokeAdjust( @@ -4415,11 +4545,12 @@ void SplashOutputDev::beginTransparencyGroup(GfxState *state, double *bbox, } if (!isolated && transpGroup->origBitmap->getAlphaPtr() && - transpGroup->origSplash->getInNonIsolatedGroup()) { + transpGroup->origSplash->getInNonIsolatedGroup() && + colorMode != splashModeMono1) { // when drawing a non-isolated group into another non-isolated group, // compute a backdrop bitmap with corrected alpha values backdropBitmap = new SplashBitmap(w, h, bitmapRowPad, colorMode, gTrue, - bitmapTopDown); + bitmapTopDown, transpGroup->origBitmap); transpGroup->origSplash->blitCorrectedAlpha(backdropBitmap, tx, ty, 0, 0, w, h); transpGroup->backdropBitmap = backdropBitmap; @@ -4521,6 +4652,7 @@ void SplashOutputDev::setSoftMask(GfxState *state, double *bbox, //~ space is given if (transpGroupStack->blendingColorSpace) { tSplash = new Splash(tBitmap, vectorAntialias, + transpGroupStack->origSplash->getImageCache(), transpGroupStack->origSplash->getScreen()); tSplash->setStrokeAdjust( mapStrokeAdjustMode[globalParams->getStrokeAdjust()]); @@ -4578,7 +4710,7 @@ void SplashOutputDev::setSoftMask(GfxState *state, double *bbox, } softMask = new SplashBitmap(bitmap->getWidth(), bitmap->getHeight(), - 1, splashModeMono8, gFalse); + 1, splashModeMono8, gFalse, gTrue, bitmap); memset(softMask->getDataPtr(), (int)(backdrop2 * 255.0 + 0.5), softMask->getRowSize() * softMask->getHeight()); if (tx < softMask->getWidth() && ty < softMask->getHeight()) { @@ -4660,7 +4792,7 @@ SplashBitmap *SplashOutputDev::takeBitmap() { ret = bitmap; bitmap = new SplashBitmap(1, 1, bitmapRowPad, colorMode, - colorMode != splashModeMono1, bitmapTopDown); + colorMode != splashModeMono1, bitmapTopDown, NULL); return ret; } diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/SplashOutputDev.h b/Build/source/libs/xpdf/xpdf-src/xpdf/SplashOutputDev.h index 12e8831a905..2215f883d32 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/SplashOutputDev.h +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/SplashOutputDev.h @@ -279,6 +279,7 @@ private: static GBool softMaskMatteImageSrc(void *data, SplashColorPtr colorLine, Guchar *alphaLine); + GString *makeImageTag(Object *ref); void reduceImageResolution(Stream *str, double *mat, int *width, int *height); void clearMaskRegion(GfxState *state, @@ -295,6 +296,7 @@ private: GBool allowAntialias; GBool vectorAntialias; GBool reverseVideo; // reverse video mode + GBool reverseVideoInvertImages; SplashColor paperColor; // paper color SplashScreenParams screenParams; GBool skipHorizText; diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/Stream.cc b/Build/source/libs/xpdf/xpdf-src/xpdf/Stream.cc index 4e9a2dc2ff4..a7c13c9eab3 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/Stream.cc +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/Stream.cc @@ -121,7 +121,8 @@ Guint Stream::discardChars(Guint n) { return count; } -GString *Stream::getPSFilter(int psLevel, const char *indent) { +GString *Stream::getPSFilter(int psLevel, const char *indent, + GBool okToReadStream) { return new GString(); } @@ -132,15 +133,15 @@ Stream *Stream::addFilters(Object *dict, int recursion) { int i; str = this; - dict->dictLookup("Filter", &obj); + dict->dictLookup("Filter", &obj, recursion); if (obj.isNull()) { obj.free(); - dict->dictLookup("F", &obj); + dict->dictLookup("F", &obj, recursion); } - dict->dictLookup("DecodeParms", ¶ms); + dict->dictLookup("DecodeParms", ¶ms, recursion); if (params.isNull()) { params.free(); - dict->dictLookup("DP", ¶ms); + dict->dictLookup("DP", ¶ms, recursion); } if (obj.isName()) { str = makeFilter(obj.getName(), str, ¶ms, recursion); @@ -1096,13 +1097,14 @@ int ASCIIHexStream::lookChar() { return buf; } -GString *ASCIIHexStream::getPSFilter(int psLevel, const char *indent) { +GString *ASCIIHexStream::getPSFilter(int psLevel, const char *indent, + GBool okToReadStream) { GString *s; if (psLevel < 2) { return NULL; } - if (!(s = str->getPSFilter(psLevel, indent))) { + if (!(s = str->getPSFilter(psLevel, indent, okToReadStream))) { return NULL; } s->append(indent)->append("/ASCIIHexDecode filter\n"); @@ -1181,13 +1183,14 @@ int ASCII85Stream::lookChar() { return b[index]; } -GString *ASCII85Stream::getPSFilter(int psLevel, const char *indent) { +GString *ASCII85Stream::getPSFilter(int psLevel, const char *indent, + GBool okToReadStream) { GString *s; if (psLevel < 2) { return NULL; } - if (!(s = str->getPSFilter(psLevel, indent))) { + if (!(s = str->getPSFilter(psLevel, indent, okToReadStream))) { return NULL; } s->append(indent)->append("/ASCII85Decode filter\n"); @@ -1408,13 +1411,14 @@ int LZWStream::getCode() { return code; } -GString *LZWStream::getPSFilter(int psLevel, const char *indent) { +GString *LZWStream::getPSFilter(int psLevel, const char *indent, + GBool okToReadStream) { GString *s; if (psLevel < 2 || pred) { return NULL; } - if (!(s = str->getPSFilter(psLevel, indent))) { + if (!(s = str->getPSFilter(psLevel, indent, okToReadStream))) { return NULL; } s->append(indent)->append("<< "); @@ -1474,13 +1478,14 @@ int RunLengthStream::getBlock(char *blk, int size) { return n; } -GString *RunLengthStream::getPSFilter(int psLevel, const char *indent) { +GString *RunLengthStream::getPSFilter(int psLevel, const char *indent, + GBool okToReadStream) { GString *s; if (psLevel < 2) { return NULL; } - if (!(s = str->getPSFilter(psLevel, indent))) { + if (!(s = str->getPSFilter(psLevel, indent, okToReadStream))) { return NULL; } s->append(indent)->append("/RunLengthDecode filter\n"); @@ -2012,7 +2017,7 @@ GBool CCITTFaxStream::readRow() { lookBits(1); eatBits(1); } - if (encoding >= 0) { + if (encoding > 0) { for (i = 0; i < 4; ++i) { code1 = lookBits(12); if (code1 != 0x001) { @@ -2260,14 +2265,15 @@ short CCITTFaxStream::lookBits(int n) { return (short)((inputBuf >> (inputBits - n)) & (0xffffffff >> (32 - n))); } -GString *CCITTFaxStream::getPSFilter(int psLevel, const char *indent) { +GString *CCITTFaxStream::getPSFilter(int psLevel, const char *indent, + GBool okToReadStream) { GString *s; char s1[50]; if (psLevel < 2) { return NULL; } - if (!(s = str->getPSFilter(psLevel, indent))) { + if (!(s = str->getPSFilter(psLevel, indent, okToReadStream))) { return NULL; } s->append(indent)->append("<< "); @@ -2384,6 +2390,11 @@ void DCTStream::reset() { jpeg_start_decompress(&decomp); } +GBool DCTStream::checkSequentialInterleaved() { + //~ this is unimplemented + return gTrue; +} + void DCTStream::close() { // we don't call jpeg_finish_decompress() here because it will report // an error if the full image wasn't read @@ -2754,6 +2765,28 @@ void DCTStream::reset() { } } +GBool DCTStream::checkSequentialInterleaved() { + GBool headerOk; + + str->reset(); + + progressive = interleaved = gFalse; + width = height = 0; + numComps = 0; + numQuantTables = 0; + numDCHuffTables = 0; + numACHuffTables = 0; + gotJFIFMarker = gFalse; + gotAdobeMarker = gFalse; + restartInterval = 0; + + headerOk = readHeader(gTrue); + + FilterStream::close(); + + return headerOk && !progressive && interleaved; +} + void DCTStream::close() { int i; @@ -3755,7 +3788,7 @@ int DCTStream::readBit() { GBool DCTStream::readHeader(GBool frame) { GBool doScan; - int n; + int n, i; int c = 0; // read headers @@ -3850,6 +3883,13 @@ GBool DCTStream::readHeader(GBool frame) { } } + for (i = 0; i < numComps; ++i) { + if (compInfo[i].quantTable >= numQuantTables) { + error(errSyntaxError, getPos(), "Invalid DCT quant table selector"); + return gFalse; + } + } + return gTrue; } @@ -3878,8 +3918,14 @@ GBool DCTStream::readBaselineSOF() { compInfo[i].hSample = (c >> 4) & 0x0f; compInfo[i].vSample = c & 0x0f; compInfo[i].quantTable = str->getChar(); - if (compInfo[i].hSample < 1 || compInfo[i].hSample > 4 || - compInfo[i].vSample < 1 || compInfo[i].vSample > 4) { + // a sampling factor of 3 is allowed by the spec, but requires + // messy upsampling, and appears not to be used in practice + if (!(compInfo[i].hSample == 1 || + compInfo[i].hSample == 2 || + compInfo[i].hSample == 4) || + !(compInfo[i].vSample == 1 || + compInfo[i].vSample == 2 || + compInfo[i].vSample == 4)) { error(errSyntaxError, getPos(), "Bad DCT sampling factor"); return gFalse; } @@ -3917,8 +3963,14 @@ GBool DCTStream::readProgressiveSOF() { compInfo[i].hSample = (c >> 4) & 0x0f; compInfo[i].vSample = c & 0x0f; compInfo[i].quantTable = str->getChar(); - if (compInfo[i].hSample < 1 || compInfo[i].hSample > 4 || - compInfo[i].vSample < 1 || compInfo[i].vSample > 4) { + // a sampling factor of 3 is allowed by the spec, but requires + // messy upsampling, and appears not to be used in practice + if (!(compInfo[i].hSample == 1 || + compInfo[i].hSample == 2 || + compInfo[i].hSample == 4) || + !(compInfo[i].vSample == 1 || + compInfo[i].vSample == 2 || + compInfo[i].vSample == 4)) { error(errSyntaxError, getPos(), "Bad DCT sampling factor"); return gFalse; } @@ -4182,13 +4234,19 @@ int DCTStream::read16() { #endif // HAVE_JPEGLIB -GString *DCTStream::getPSFilter(int psLevel, const char *indent) { +GString *DCTStream::getPSFilter(int psLevel, const char *indent, + GBool okToReadStream) { GString *s; if (psLevel < 2) { return NULL; } - if (!(s = str->getPSFilter(psLevel, indent))) { + if (!(s = str->getPSFilter(psLevel, indent, okToReadStream))) { + return NULL; + } + if (okToReadStream && !checkSequentialInterleaved()) { + // PostScript does not allow progressive or interleaved JPEG + delete s; return NULL; } s->append(indent)->append("<< >> /DCTDecode filter\n"); @@ -4982,13 +5040,14 @@ int FlateStream::getBlock(char *blk, int size) { return n; } -GString *FlateStream::getPSFilter(int psLevel, const char *indent) { +GString *FlateStream::getPSFilter(int psLevel, const char *indent, + GBool okToReadStream) { GString *s; if (psLevel < 3 || pred) { return NULL; } - if (!(s = str->getPSFilter(psLevel, indent))) { + if (!(s = str->getPSFilter(psLevel, indent, okToReadStream))) { return NULL; } s->append(indent)->append("<< >> /FlateDecode filter\n"); diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/Stream.h b/Build/source/libs/xpdf/xpdf-src/xpdf/Stream.h index c25d46b2cd7..38a8dd3497c 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/Stream.h +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/Stream.h @@ -117,7 +117,8 @@ public: virtual void setPos(GFileOffset pos, int dir = 0) = 0; // Get PostScript command for the filter(s). - virtual GString *getPSFilter(int psLevel, const char *indent); + virtual GString *getPSFilter(int psLevel, const char *indent, + GBool okToReadStream); // Does this stream type potentially contain non-printable chars? virtual GBool isBinary(GBool last = gTrue) = 0; @@ -422,7 +423,8 @@ public: virtual int getChar() { int c = lookChar(); buf = EOF; return c; } virtual int lookChar(); - virtual GString *getPSFilter(int psLevel, const char *indent); + virtual GString *getPSFilter(int psLevel, const char *indent, + GBool okToReadStream); virtual GBool isBinary(GBool last = gTrue); private: @@ -446,7 +448,8 @@ public: virtual int getChar() { int ch = lookChar(); ++index; return ch; } virtual int lookChar(); - virtual GString *getPSFilter(int psLevel, const char *indent); + virtual GString *getPSFilter(int psLevel, const char *indent, + GBool okToReadStream); virtual GBool isBinary(GBool last = gTrue); private: @@ -474,7 +477,8 @@ public: virtual int lookChar(); virtual int getRawChar(); virtual int getBlock(char *blk, int size); - virtual GString *getPSFilter(int psLevel, const char *indent); + virtual GString *getPSFilter(int psLevel, const char *indent, + GBool okToReadStream); virtual GBool isBinary(GBool last = gTrue); private: @@ -520,7 +524,8 @@ public: virtual int lookChar() { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } virtual int getBlock(char *blk, int size); - virtual GString *getPSFilter(int psLevel, const char *indent); + virtual GString *getPSFilter(int psLevel, const char *indent, + GBool okToReadStream); virtual GBool isBinary(GBool last = gTrue); private: @@ -552,7 +557,8 @@ public: virtual int getChar(); virtual int lookChar(); virtual int getBlock(char *blk, int size); - virtual GString *getPSFilter(int psLevel, const char *indent); + virtual GString *getPSFilter(int psLevel, const char *indent, + GBool okToReadStream); virtual GBool isBinary(GBool last = gTrue); private: @@ -650,12 +656,15 @@ public: virtual int getChar(); virtual int lookChar(); virtual int getBlock(char *blk, int size); - virtual GString *getPSFilter(int psLevel, const char *indent); + virtual GString *getPSFilter(int psLevel, const char *indent, + GBool okToReadStream); virtual GBool isBinary(GBool last = gTrue); Stream *getRawStream() { return str; } private: + GBool checkSequentialInterleaved(); + #if HAVE_JPEGLIB int colorXform; // color transform: -1 = unspecified @@ -785,7 +794,8 @@ public: virtual int lookChar(); virtual int getRawChar(); virtual int getBlock(char *blk, int size); - virtual GString *getPSFilter(int psLevel, const char *indent); + virtual GString *getPSFilter(int psLevel, const char *indent, + GBool okToReadStream); virtual GBool isBinary(GBool last = gTrue); private: @@ -840,7 +850,8 @@ public: virtual int getChar() { return EOF; } virtual int lookChar() { return EOF; } virtual int getBlock(char *blk, int size) { return 0; } - virtual GString *getPSFilter(int psLevel, const char *indent) + virtual GString *getPSFilter(int psLevel, const char *indent, + GBool okToReadStream) { return NULL; } virtual GBool isBinary(GBool last = gTrue) { return gFalse; } }; @@ -859,7 +870,8 @@ public: virtual void reset(); virtual int getChar(); virtual int lookChar(); - virtual GString *getPSFilter(int psLevel, const char *indent) + virtual GString *getPSFilter(int psLevel, const char *indent, + GBool okToReadStream) { return NULL; } virtual GBool isBinary(GBool last = gTrue); @@ -885,7 +897,8 @@ public: virtual void reset(); virtual int getChar(); virtual int lookChar(); - virtual GString *getPSFilter(int psLevel, const char *indent) + virtual GString *getPSFilter(int psLevel, const char *indent, + GBool okToReadStream) { return NULL; } virtual GBool isBinary(GBool last = gTrue); virtual GBool isEncoder() { return gTrue; } @@ -912,7 +925,8 @@ public: { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } virtual int lookChar() { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } - virtual GString *getPSFilter(int psLevel, const char *indent) + virtual GString *getPSFilter(int psLevel, const char *indent, + GBool okToReadStream) { return NULL; } virtual GBool isBinary(GBool last = gTrue) { return gFalse; } virtual GBool isEncoder() { return gTrue; } @@ -944,7 +958,8 @@ public: { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } virtual int lookChar() { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } - virtual GString *getPSFilter(int psLevel, const char *indent) + virtual GString *getPSFilter(int psLevel, const char *indent, + GBool okToReadStream) { return NULL; } virtual GBool isBinary(GBool last = gTrue) { return gFalse; } virtual GBool isEncoder() { return gTrue; } @@ -976,7 +991,8 @@ public: { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } virtual int lookChar() { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } - virtual GString *getPSFilter(int psLevel, const char *indent) + virtual GString *getPSFilter(int psLevel, const char *indent, + GBool okToReadStream) { return NULL; } virtual GBool isBinary(GBool last = gTrue) { return gTrue; } virtual GBool isEncoder() { return gTrue; } @@ -1012,7 +1028,8 @@ public: virtual void reset(); virtual int getChar(); virtual int lookChar(); - virtual GString *getPSFilter(int psLevel, const char *indent) + virtual GString *getPSFilter(int psLevel, const char *indent, + GBool okToReadStream) { return NULL; } virtual GBool isBinary(GBool last = gTrue) { return gTrue; } virtual GBool isEncoder() { return gTrue; } diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/TextOutputDev.cc b/Build/source/libs/xpdf/xpdf-src/xpdf/TextOutputDev.cc index 9c226af3f31..4f594384915 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/TextOutputDev.cc +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/TextOutputDev.cc @@ -16,6 +16,7 @@ #include <stdlib.h> #include <stddef.h> #include <math.h> +#include <limits.h> #include <ctype.h> #ifdef _WIN32 #include <fcntl.h> // for O_BINARY @@ -111,7 +112,7 @@ // In simple layout mode, lines are broken at gaps larger than this // value multiplied by font size. -#define simpleLayoutGapThreshold 0.4 +#define simpleLayoutGapThreshold 0.7 // Table cells (TextColumns) are allowed to overlap by this much // in table layout mode (as a fraction of cell width or height). @@ -407,19 +408,52 @@ void TextBlock::updateBounds(int childIdx) { } //------------------------------------------------------------------------ -// TextGap +// TextGaps //------------------------------------------------------------------------ -class TextGap { +struct TextGap { + double x; // center of gap: x for vertical gaps, + // y for horizontal gaps + double w; // width/height of gap +}; + +class TextGaps { public: - TextGap(double aXY, double aW): xy(aXY), w(aW) {} + TextGaps(); + ~TextGaps(); + void addGap(double x, double w); + int getLength() { return length; } + double getX(int idx) { return gaps[idx].x; } + double getW(int idx) { return gaps[idx].w; } - double xy; // center of gap: x for vertical gaps, - // y for horizontal gaps - double w; // width of gap +private: + + int length; + int size; + TextGap *gaps; }; +TextGaps::TextGaps() { + length = 0; + size = 16; + gaps = (TextGap *)gmallocn(size, sizeof(TextGap)); +} + +TextGaps::~TextGaps() { + gfree(gaps); +} + +void TextGaps::addGap(double x, double w) { + if (length == size) { + size *= 2; + gaps = (TextGap *)greallocn(gaps, size, sizeof(TextGap)); + } + gaps[length].x = x; + gaps[length].w = w; + ++length; +} + //------------------------------------------------------------------------ // TextSuperLine //------------------------------------------------------------------------ @@ -508,6 +542,10 @@ TextOutputControl::TextOutputControl() { discardInvisibleText = gFalse; discardClippedText = gFalse; insertBOM = gFalse; + marginLeft = 0; + marginRight = 0; + marginTop = 0; + marginBottom = 0; } @@ -1136,9 +1174,11 @@ void TextPage::updateFont(GfxState *state) { if (name && name[0] == 'm' && name[1] == '\0') { mCode = code; } - if (letterCode < 0 && name && name[1] == '\0' && + if (letterCode < 0 && + name && ((name[0] >= 'A' && name[0] <= 'Z') || - (name[0] >= 'a' && name[0] <= 'z'))) { + (name[0] >= 'a' && name[0] <= 'z')) && + name[1] == '\0') { letterCode = code; } if (anyCode < 0 && name && @@ -1239,9 +1279,12 @@ void TextPage::addChar(GfxState *state, double x, double y, // throw away chars that aren't inside the page bounds // (and also do a sanity check on the character size) state->transform(x, y, &x1, &y1); - if (x1 + w1 < 0 || x1 > pageWidth || - y1 + h1 < 0 || y1 > pageHeight || - w1 > pageWidth || h1 > pageHeight) { + if (x1 + w1 < control.marginLeft || + x1 > pageWidth - control.marginRight || + y1 + h1 < control.marginTop || + y1 > pageHeight - control.marginBottom || + w1 > pageWidth || + h1 > pageHeight) { charPos += nBytes; return; } @@ -1876,8 +1919,9 @@ void TextPage::writeRaw(void *outputStream, if (fabs(ch2->yMin - ch->yMin) > rawModeLineDelta * ch->fontSize || ch2->xMin - ch->xMax < -rawModeCharOverlap * ch->fontSize) { s->append(eol, eolLen); - } else if (ch2->xMin - ch->xMax > - rawModeWordSpacing * ch->fontSize) { + } else if (ch->spaceAfter || + ch2->xMin - ch->xMax > + rawModeWordSpacing * ch->fontSize) { s->append(space, spaceLen); } break; @@ -1885,8 +1929,9 @@ void TextPage::writeRaw(void *outputStream, if (fabs(ch->xMax - ch2->xMax) > rawModeLineDelta * ch->fontSize || ch2->yMin - ch->yMax < -rawModeCharOverlap * ch->fontSize) { s->append(eol, eolLen); - } else if (ch2->yMin - ch->yMax > - rawModeWordSpacing * ch->fontSize) { + } else if (ch->spaceAfter || + ch2->yMin - ch->yMax > + rawModeWordSpacing * ch->fontSize) { s->append(space, spaceLen); } break; @@ -1894,8 +1939,9 @@ void TextPage::writeRaw(void *outputStream, if (fabs(ch->yMax - ch2->yMax) > rawModeLineDelta * ch->fontSize || ch->xMin - ch2->xMax < -rawModeCharOverlap * ch->fontSize) { s->append(eol, eolLen); - } else if (ch->xMin - ch2->xMax > - rawModeWordSpacing * ch->fontSize) { + } else if (ch->spaceAfter || + ch->xMin - ch2->xMax > + rawModeWordSpacing * ch->fontSize) { s->append(space, spaceLen); } break; @@ -1903,8 +1949,9 @@ void TextPage::writeRaw(void *outputStream, if (fabs(ch2->xMin - ch->xMin) > rawModeLineDelta * ch->fontSize || ch->yMin - ch2->yMax < -rawModeCharOverlap * ch->fontSize) { s->append(eol, eolLen); - } else if (ch->yMin - ch2->yMax > - rawModeWordSpacing * ch->fontSize) { + } else if (ch->spaceAfter || + ch->yMin - ch2->yMax > + rawModeWordSpacing * ch->fontSize) { s->append(space, spaceLen); } break; @@ -2693,12 +2740,11 @@ TextBlock *TextPage::splitChars(GList *charsA) { TextBlock *TextPage::split(GList *charsA, int rot) { TextBlock *blk; GList *chars2, *chars3; - GList *horizGaps, *vertGaps; - TextGap *gap; + TextGaps *horizGaps, *vertGaps; TextChar *ch; double xMin, yMin, xMax, yMax, avgFontSize; double horizGapSize, vertGapSize, minHorizChunkWidth, minVertChunkWidth; - double nLines, vertGapThreshold, minChunk; + double gap, nLines, vertGapThreshold, minChunk; double largeCharSize; double x0, x1, y0, y1; int nHorizGaps, nVertGaps, nLargeChars; @@ -2707,8 +2753,8 @@ TextBlock *TextPage::split(GList *charsA, int rot) { //----- find all horizontal and vertical gaps - horizGaps = new GList(); - vertGaps = new GList(); + horizGaps = new TextGaps(); + vertGaps = new TextGaps(); findGaps(charsA, rot, &xMin, &yMin, &xMax, &yMax, &avgFontSize, horizGaps, vertGaps); @@ -2716,16 +2762,16 @@ TextBlock *TextPage::split(GList *charsA, int rot) { horizGapSize = 0; for (i = 0; i < horizGaps->getLength(); ++i) { - gap = (TextGap *)horizGaps->get(i); - if (gap->w > horizGapSize) { - horizGapSize = gap->w; + gap = horizGaps->getW(i); + if (gap > horizGapSize) { + horizGapSize = gap; } } vertGapSize = 0; for (i = 0; i < vertGaps->getLength(); ++i) { - gap = (TextGap *)vertGaps->get(i); - if (gap->w > vertGapSize) { - vertGapSize = gap->w; + gap = vertGaps->getW(i); + if (gap > vertGapSize) { + vertGapSize = gap; } } @@ -2736,14 +2782,14 @@ TextBlock *TextPage::split(GList *charsA, int rot) { if (horizGaps->getLength() > 0) { y0 = yMin; for (i = 0; i < horizGaps->getLength(); ++i) { - gap = (TextGap *)horizGaps->get(i); - if (gap->w > horizGapSize - splitGapSlack * avgFontSize) { + gap = horizGaps->getW(i); + if (gap > horizGapSize - splitGapSlack * avgFontSize) { ++nHorizGaps; - y1 = gap->xy - 0.5 * gap->w; + y1 = horizGaps->getX(i) - 0.5 * gap; if (y1 - y0 < minHorizChunkWidth) { minHorizChunkWidth = y1 - y0; } - y0 = y1 + gap->w; + y0 = y1 + gap; } } y1 = yMax; @@ -2756,14 +2802,14 @@ TextBlock *TextPage::split(GList *charsA, int rot) { if (vertGaps->getLength() > 0) { x0 = xMin; for (i = 0; i < vertGaps->getLength(); ++i) { - gap = (TextGap *)vertGaps->get(i); - if (gap->w > vertGapSize - splitGapSlack * avgFontSize) { + gap = vertGaps->getW(i); + if (gap > vertGapSize - splitGapSlack * avgFontSize) { ++nVertGaps; - x1 = gap->xy - 0.5 * gap->w; + x1 = vertGaps->getX(i) - 0.5 * gap; if (x1 - x0 < minVertChunkWidth) { minVertChunkWidth = x1 - x0; } - x0 = x1 + gap->w; + x0 = x1 + gap; } } x1 = xMax; @@ -2881,9 +2927,8 @@ TextBlock *TextPage::split(GList *charsA, int rot) { printf("vert split xMin=%g yMin=%g xMax=%g yMax=%g small=%d\n", xMin, pageHeight - yMax, xMax, pageHeight - yMin, smallSplit); for (i = 0; i < vertGaps->getLength(); ++i) { - gap = (TextGap *)vertGaps->get(i); - if (gap->w > vertGapSize - splitGapSlack * avgFontSize) { - printf(" x=%g\n", gap->xy); + if (vertGaps->getW(i) > vertGapSize - splitGapSlack * avgFontSize) { + printf(" x=%g\n", vertGaps->getX(i)); } } #endif @@ -2891,9 +2936,8 @@ TextBlock *TextPage::split(GList *charsA, int rot) { blk->smallSplit = smallSplit; x0 = xMin - 1; for (i = 0; i < vertGaps->getLength(); ++i) { - gap = (TextGap *)vertGaps->get(i); - if (gap->w > vertGapSize - splitGapSlack * avgFontSize) { - x1 = gap->xy; + if (vertGaps->getW(i) > vertGapSize - splitGapSlack * avgFontSize) { + x1 = vertGaps->getX(i); chars2 = getChars(charsA, x0, yMin - 1, x1, yMax + 1); blk->addChild(split(chars2, rot)); delete chars2; @@ -2910,9 +2954,8 @@ TextBlock *TextPage::split(GList *charsA, int rot) { printf("horiz split xMin=%g yMin=%g xMax=%g yMax=%g small=%d\n", xMin, pageHeight - yMax, xMax, pageHeight - yMin, smallSplit); for (i = 0; i < horizGaps->getLength(); ++i) { - gap = (TextGap *)horizGaps->get(i); - if (gap->w > horizGapSize - splitGapSlack * avgFontSize) { - printf(" y=%g\n", pageHeight - gap->xy); + if (horizGaps->getW(i) > horizGapSize - splitGapSlack * avgFontSize) { + printf(" y=%g\n", pageHeight - horizGaps->getX(i)); } } #endif @@ -2920,9 +2963,8 @@ TextBlock *TextPage::split(GList *charsA, int rot) { blk->smallSplit = smallSplit; y0 = yMin - 1; for (i = 0; i < horizGaps->getLength(); ++i) { - gap = (TextGap *)horizGaps->get(i); - if (gap->w > horizGapSize - splitGapSlack * avgFontSize) { - y1 = gap->xy; + if (horizGaps->getW(i) > horizGapSize - splitGapSlack * avgFontSize) { + y1 = horizGaps->getX(i); chars2 = getChars(charsA, xMin - 1, y0, xMax + 1, y1); blk->addChild(split(chars2, rot)); delete chars2; @@ -2966,8 +3008,8 @@ TextBlock *TextPage::split(GList *charsA, int rot) { } } - deleteGList(horizGaps, TextGap); - deleteGList(vertGaps, TextGap); + delete horizGaps; + delete vertGaps; tagBlock(blk); @@ -3001,11 +3043,12 @@ void TextPage::findGaps(GList *charsA, int rot, double *xMinOut, double *yMinOut, double *xMaxOut, double *yMaxOut, double *avgFontSizeOut, - GList *horizGaps, GList *vertGaps) { + TextGaps *horizGaps, TextGaps *vertGaps) { TextChar *ch; - int *horizProfile, *vertProfile; + char *horizProfile, *vertProfile; double xMin, yMin, xMax, yMax, w; - double minFontSize, avgFontSize, splitPrecision, ascentAdjust, descentAdjust; + double minFontSize, avgFontSize, splitPrecision, invSplitPrecision; + double ascentAdjust, descentAdjust; int xMinI, yMinI, xMaxI, yMaxI, xMinI2, yMinI2, xMaxI2, yMaxI2; int start, x, y, i; @@ -3037,6 +3080,7 @@ void TextPage::findGaps(GList *charsA, int rot, if (splitPrecision < minSplitPrecision) { splitPrecision = minSplitPrecision; } + invSplitPrecision = 1 / splitPrecision; *xMinOut = xMin; *yMinOut = yMin; *xMaxOut = xMax; @@ -3045,59 +3089,65 @@ void TextPage::findGaps(GList *charsA, int rot, //----- compute the horizontal and vertical profiles + 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) { + return; + } // add some slack to the array bounds to avoid floating point // precision problems - xMinI = (int)floor(xMin / splitPrecision) - 1; - yMinI = (int)floor(yMin / splitPrecision) - 1; - xMaxI = (int)floor(xMax / splitPrecision) + 1; - yMaxI = (int)floor(yMax / splitPrecision) + 1; - horizProfile = (int *)gmallocn(yMaxI - yMinI + 1, sizeof(int)); - vertProfile = (int *)gmallocn(xMaxI - xMinI + 1, sizeof(int)); - memset(horizProfile, 0, (yMaxI - yMinI + 1) * sizeof(int)); - memset(vertProfile, 0, (xMaxI - xMinI + 1) * sizeof(int)); + xMinI = (int)floor(xMin * invSplitPrecision) - 1; + yMinI = (int)floor(yMin * invSplitPrecision) - 1; + xMaxI = (int)floor(xMax * invSplitPrecision) + 1; + yMaxI = (int)floor(yMax * invSplitPrecision) + 1; + horizProfile = (char *)gmalloc(yMaxI - yMinI + 1); + vertProfile = (char *)gmalloc(xMaxI - xMinI + 1); + memset(horizProfile, 0, yMaxI - yMinI + 1); + memset(vertProfile, 0, xMaxI - xMinI + 1); for (i = 0; i < charsA->getLength(); ++i) { ch = (TextChar *)charsA->get(i); // yMinI2 and yMaxI2 are adjusted to allow for slightly overlapping lines switch (rot) { case 0: default: - xMinI2 = (int)floor(ch->xMin / splitPrecision); - xMaxI2 = (int)floor(ch->xMax / splitPrecision); + xMinI2 = (int)floor(ch->xMin * invSplitPrecision); + xMaxI2 = (int)floor(ch->xMax * invSplitPrecision); ascentAdjust = ascentAdjustFactor * (ch->yMax - ch->yMin); - yMinI2 = (int)floor((ch->yMin + ascentAdjust) / splitPrecision); + yMinI2 = (int)floor((ch->yMin + ascentAdjust) * invSplitPrecision); descentAdjust = descentAdjustFactor * (ch->yMax - ch->yMin); - yMaxI2 = (int)floor((ch->yMax - descentAdjust) / splitPrecision); + yMaxI2 = (int)floor((ch->yMax - descentAdjust) * invSplitPrecision); break; case 1: descentAdjust = descentAdjustFactor * (ch->xMax - ch->xMin); - xMinI2 = (int)floor((ch->xMin + descentAdjust) / splitPrecision); + xMinI2 = (int)floor((ch->xMin + descentAdjust) * invSplitPrecision); ascentAdjust = ascentAdjustFactor * (ch->xMax - ch->xMin); - xMaxI2 = (int)floor((ch->xMax - ascentAdjust) / splitPrecision); - yMinI2 = (int)floor(ch->yMin / splitPrecision); - yMaxI2 = (int)floor(ch->yMax / splitPrecision); + xMaxI2 = (int)floor((ch->xMax - ascentAdjust) * invSplitPrecision); + yMinI2 = (int)floor(ch->yMin * invSplitPrecision); + yMaxI2 = (int)floor(ch->yMax * invSplitPrecision); break; case 2: - xMinI2 = (int)floor(ch->xMin / splitPrecision); - xMaxI2 = (int)floor(ch->xMax / splitPrecision); + xMinI2 = (int)floor(ch->xMin * invSplitPrecision); + xMaxI2 = (int)floor(ch->xMax * invSplitPrecision); descentAdjust = descentAdjustFactor * (ch->yMax - ch->yMin); - yMinI2 = (int)floor((ch->yMin + descentAdjust) / splitPrecision); + yMinI2 = (int)floor((ch->yMin + descentAdjust) * invSplitPrecision); ascentAdjust = ascentAdjustFactor * (ch->yMax - ch->yMin); - yMaxI2 = (int)floor((ch->yMax - ascentAdjust) / splitPrecision); + yMaxI2 = (int)floor((ch->yMax - ascentAdjust) * invSplitPrecision); break; case 3: ascentAdjust = ascentAdjustFactor * (ch->xMax - ch->xMin); - xMinI2 = (int)floor((ch->xMin + ascentAdjust) / splitPrecision); + xMinI2 = (int)floor((ch->xMin + ascentAdjust) * invSplitPrecision); descentAdjust = descentAdjustFactor * (ch->xMax - ch->xMin); - xMaxI2 = (int)floor((ch->xMax - descentAdjust) / splitPrecision); - yMinI2 = (int)floor(ch->yMin / splitPrecision); - yMaxI2 = (int)floor(ch->yMax / splitPrecision); + xMaxI2 = (int)floor((ch->xMax - descentAdjust) * invSplitPrecision); + yMinI2 = (int)floor(ch->yMin * invSplitPrecision); + yMaxI2 = (int)floor(ch->yMax * invSplitPrecision); break; } for (y = yMinI2; y <= yMaxI2; ++y) { - ++horizProfile[y - yMinI]; + horizProfile[y - yMinI] = 1; } for (x = xMinI2; x <= xMaxI2; ++x) { - ++vertProfile[x - xMinI]; + vertProfile[x - xMinI] = 1; } } @@ -3112,8 +3162,7 @@ void TextPage::findGaps(GList *charsA, int rot, } else { if (horizProfile[y + 1 - yMinI]) { w = (y - start) * splitPrecision; - horizGaps->append(new TextGap((start + 1) * splitPrecision + 0.5 * w, - w)); + horizGaps->addGap((start + 1) * splitPrecision + 0.5 * w, w); } } } @@ -3129,8 +3178,7 @@ void TextPage::findGaps(GList *charsA, int rot, } else { if (vertProfile[x + 1 - xMinI]) { w = (x - start) * splitPrecision; - vertGaps->append(new TextGap((start + 1) * splitPrecision + 0.5 * w, - w)); + vertGaps->addGap((start + 1) * splitPrecision + 0.5 * w, w); } } } @@ -3818,18 +3866,27 @@ double TextPage::computeWordSpacingThreshold(GList *charsA, int rot) { minGap = 0; } - // if spacing is nearly uniform (minGap is close to maxGap), use the - // SpGap/AdjGap values if available, 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 spacing is nearly uniform (minGap is close to maxGap), there + // are three cases: + // (1) if the SpGap and AdjGap values are both available and + // sensible, use them + // (2) if only the SpGap values are available, meaning that every + // character in the line had a space after it, split after every + // character + // (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 (minAdjGap <= maxAdjGap && - minSpGap <= maxSpGap && - minSpGap - maxAdjGap > 0.01) { - return 0.5 * (maxAdjGap + minSpGap); - } else { - return maxGap + 1; + if (minSpGap <= maxSpGap) { + if (minAdjGap <= maxAdjGap && + minSpGap - maxAdjGap > 0.01) { + return 0.5 * (maxAdjGap + minSpGap); + } else if (minAdjGap > maxAdjGap && + maxSpGap - minSpGap < uniformSpacing * avgFontSize) { + return minSpGap - 1; + } } + return maxGap + 1; // if there is some variation in spacing, but it's small, assume // there are some inter-word spaces @@ -4033,8 +4090,8 @@ void TextPage::assignSimpleLayoutPositions(GList *superLines, UnicodeMap *uMap) { GList *lines; TextLine *line0, *line1; - double xMin; - int px, sp, i, j; + double xMin, xMax; + int px, px2, sp, i, j; // build a list of lines and sort by x lines = new GList(); @@ -4048,21 +4105,25 @@ void TextPage::assignSimpleLayoutPositions(GList *superLines, for (i = 0; i < lines->getLength(); ++i) { line0 = (TextLine *)lines->get(i); computeLinePhysWidth(line0, uMap); - line0->px = (int)((line0->xMin - xMin) / (0.5 * line0->fontSize)); + px = 0; + xMax = xMin; for (j = 0; j < i; ++j) { line1 = (TextLine *)lines->get(j); if (line0->xMin > line1->xMax) { - sp = (int)((line0->xMin - line1->xMax) / - (0.5 * line0->fontSize) + 0.5); - if (sp < 1) { - sp = 1; + if (line1->xMax > xMax) { + xMax = line1->xMax; } - px = line1->px + line1->pw + sp; - if (px > line0->px) { - line0->px = px; + px2 = line1->px + line1->pw; + if (px2 > px) { + px = px2; } } } + sp = (int)((line0->xMin - xMax) / (0.5 * line0->fontSize) + 0.5); + if (sp < 1 && xMax > xMin) { + sp = 1; + } + line0->px = px + sp; } delete lines; diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/TextOutputDev.h b/Build/source/libs/xpdf/xpdf-src/xpdf/TextOutputDev.h index 0884ace6b6b..0f00cf5ae7b 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/TextOutputDev.h +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/TextOutputDev.h @@ -26,6 +26,7 @@ class UnicodeRemapping; class TextBlock; class TextChar; +class TextGaps; class TextLink; class TextPage; @@ -69,6 +70,10 @@ public: GBool discardClippedText; // discard all clipped characters GBool insertBOM; // insert a Unicode BOM at the start of // the text output + double marginLeft, // characters outside the margins are + marginRight, // discarded + marginTop, + marginBottom; }; //------------------------------------------------------------------------ @@ -502,7 +507,7 @@ private: double *xMinOut, double *yMinOut, double *xMaxOut, double *yMaxOut, double *avgFontSizeOut, - GList *horizGaps, GList *vertGaps); + TextGaps *horizGaps, TextGaps *vertGaps); void tagBlock(TextBlock *blk); void insertLargeChars(GList *largeChars, TextBlock *blk); void insertLargeCharsInFirstLeaf(GList *largeChars, TextBlock *blk); diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/TileCompositor.cc b/Build/source/libs/xpdf/xpdf-src/xpdf/TileCompositor.cc index 431c639a020..70128a4a47f 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/TileCompositor.cc +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/TileCompositor.cc @@ -67,7 +67,7 @@ SplashBitmap *TileCompositor::getBitmap(GBool *finished) { } bitmap = new SplashBitmap(state->getWinW(), state->getWinH(), state->getBitmapRowPad(), state->getColorMode(), - gFalse); + gFalse, gTrue, NULL); } clearBitmap(); diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/TileMap.cc b/Build/source/libs/xpdf/xpdf-src/xpdf/TileMap.cc index 6db67738d70..d1a5aea2963 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/TileMap.cc +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/TileMap.cc @@ -592,6 +592,11 @@ GBool TileMap::cvtWindowToDev(int xw, int yw, offsetY = 0; } *pg = findContinuousPage(yw - offsetY + state->getScrollY()); + if (*pg < 1 || *pg > state->getDoc()->getNumPages()) { + *pg = 0; + *xd = *yd = 0; + return gFalse; + } pageW1 = pageW[*pg - 1]; pageH1 = pageH[*pg - 1]; if (maxW < state->getWinW()) { @@ -655,6 +660,11 @@ GBool TileMap::cvtWindowToDev(int xw, int yw, offsetY = 0; } *pg = findSideBySideContinuousPage(yw - offsetY + state->getScrollY()); + if (*pg < 1 || *pg > state->getDoc()->getNumPages()) { + *pg = 0; + *xd = *yd = 0; + return gFalse; + } pageW1 = pageW[*pg - 1]; pageH1 = pageH[*pg - 1]; if (*pg + 1 <= state->getDoc()->getNumPages()) { @@ -693,6 +703,11 @@ GBool TileMap::cvtWindowToDev(int xw, int yw, offsetX = 0; } *pg = findHorizContinuousPage(xw - offsetX + state->getScrollX()); + if (*pg < 1 || *pg > state->getDoc()->getNumPages()) { + *pg = 0; + *xd = *yd = 0; + return gFalse; + } pageW1 = pageW[*pg - 1]; pageH1 = pageH[*pg - 1]; if (maxH < state->getWinH()) { diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/UTF8.cc b/Build/source/libs/xpdf/xpdf-src/xpdf/UTF8.cc index 637d36b6d58..9ee01425094 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/UTF8.cc +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/UTF8.cc @@ -6,6 +6,7 @@ // //======================================================================== +#include <aconf.h> #include "UTF8.h" int mapUTF8(Unicode u, char *buf, int bufSize) { diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/WebFont.cc b/Build/source/libs/xpdf/xpdf-src/xpdf/WebFont.cc new file mode 100644 index 00000000000..95f0e983a31 --- /dev/null +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/WebFont.cc @@ -0,0 +1,384 @@ +//======================================================================== +// +// WebFont.cc +// +// Copyright 2019 Glyph & Cog, LLC +// +//======================================================================== + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include "gmem.h" +#include "gmempp.h" +#include "GHash.h" +#include "FoFiTrueType.h" +#include "FoFiType1C.h" +#include "CharCodeToUnicode.h" +#include "WebFont.h" + +WebFont::WebFont(GfxFont *gfxFontA, XRef *xref) { + GfxFontType type; + + gfxFont = gfxFontA; + fontBuf = NULL; + ffTrueType = NULL; + 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); + } + } 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; + } + } +} + +WebFont::~WebFont() { + delete ffTrueType; + delete ffType1C; + gfree(fontBuf); +} + +GBool WebFont::canWriteTTF() { + return ffTrueType != NULL; +} + +GBool WebFont::canWriteOTF() { + return ffType1C || isOpenType; +} + +static void writeToFile(void *stream, const char *data, int len) { + fwrite(data, 1, len, (FILE *)stream); +} + +GBool WebFont::writeTTF(const char *fontFilePath) { + FILE *out; + int *codeToGID; + Guchar *cmapTable; + GBool freeCodeToGID; + int nCodes, cmapTableLength; + + if (!ffTrueType) { + return gFalse; + } + if (gfxFont->isCIDFont()) { + codeToGID = ((GfxCIDFont *)gfxFont)->getCIDToGID(); + nCodes = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen(); + if (!codeToGID) { + nCodes = ffTrueType->getNumGlyphs(); + } + freeCodeToGID = gFalse; + } else { + codeToGID = ((Gfx8BitFont *)gfxFont)->getCodeToGIDMap(ffTrueType); + nCodes = 256; + freeCodeToGID = gTrue; + } + cmapTable = makeUnicodeCmapTable(codeToGID, nCodes, &cmapTableLength); + if (freeCodeToGID) { + gfree(codeToGID); + } + if (!cmapTable) { + return gFalse; + } + if (!(out = fopen(fontFilePath, "wb"))) { + gfree(cmapTable); + return gFalse; + } + ffTrueType->writeTTF(writeToFile, out, NULL, NULL, + cmapTable, cmapTableLength); + fclose(out); + gfree(cmapTable); + return gTrue; +} + +GBool WebFont::writeOTF(const char *fontFilePath) { + int *codeToGID; + Gushort *widths; + Guchar *cmapTable; + FILE *out; + int nCodes, nWidths, cmapTableLength; + + if (ffType1C) { + if (gfxFont->getType() == fontType1C) { + codeToGID = ((Gfx8BitFont *)gfxFont)->getCodeToGIDMap(ffType1C); + if (!(cmapTable = makeUnicodeCmapTable(codeToGID, 256, + &cmapTableLength))) { + gfree(codeToGID); + return gFalse; + } + widths = makeType1CWidths(codeToGID, 256, &nWidths); + gfree(codeToGID); + } else { // fontCIDType0C + codeToGID = ffType1C->getCIDToGIDMap(&nCodes); + if (!(cmapTable = makeUnicodeCmapTable(codeToGID, nCodes, + &cmapTableLength))) { + gfree(codeToGID); + return gFalse; + } + widths = makeCIDType0CWidths(codeToGID, nCodes, &nWidths); + gfree(codeToGID); + } + if (!(out = fopen(fontFilePath, "wb"))) { + gfree(cmapTable); + gfree(widths); + return gFalse; + } + ffType1C->convertToOpenType(writeToFile, out, + nWidths, widths, + cmapTable, cmapTableLength); + fclose(out); + gfree(cmapTable); + gfree(widths); + + } else if (isOpenType) { + if (!(out = fopen(fontFilePath, "wb"))) { + return gFalse; + } + if (fwrite(fontBuf, 1, fontLength, out) != (Guint)fontLength) { + fclose(out); + return gFalse; + } + fclose(out); + + } else { + return gFalse; + } + + return gTrue; +} + +Gushort *WebFont::makeType1CWidths(int *codeToGID, int nCodes, + int *nWidths) { + Gushort *widths; + Gushort width; + int widthsLen, gid, i; + + widthsLen = ffType1C->getNumGlyphs(); + widths = (Gushort *)gmallocn(widthsLen, sizeof(Gushort)); + for (i = 0; i < widthsLen; ++i) { + widths[i] = 0; + } + for (i = 0; i < nCodes; ++i) { + gid = codeToGID[i]; + if (gid < 0 || gid >= widthsLen) { + continue; + } + width = (Gushort)(((Gfx8BitFont *)gfxFont)->getWidth((Guchar)i) + * 1000 + 0.5); + if (width == 0) { + continue; + } + widths[gid] = width; + } + *nWidths = widthsLen; + return widths; +} + +Gushort *WebFont::makeCIDType0CWidths(int *codeToGID, int nCodes, + int *nWidths) { + Gushort *widths; + Gushort width; + int widthsLen, gid, i; + + widthsLen = ffType1C->getNumGlyphs(); + widths = (Gushort *)gmallocn(widthsLen, sizeof(Gushort)); + for (i = 0 ; i < widthsLen; ++i) { + widths[i] = 0; + } + for (i = 0; i < nCodes; ++i) { + gid = codeToGID[i]; + if (gid < 0 || gid >= widthsLen) { + continue; + } + width = (Gushort)(((GfxCIDFont *)gfxFont)->getWidth((CID)i) + * 1000 + 0.5); + if (width == 0) { + continue; + } + widths[gid] = width; + } + *nWidths = widthsLen; + return widths; +} + +Guchar *WebFont::makeUnicodeCmapTable(int *codeToGID, int nCodes, + int *unicodeCmapLength) { + int *unicodeToGID; + Guchar *cmapTable; + int unicodeToGIDLength, nMappings, len; + int nSegs, searchRange, entrySelector, rangeShift; + int glyphIdOffset, idRangeOffset; + int start, end, c, i; + + if (!(unicodeToGID = makeUnicodeToGID(codeToGID, nCodes, + &unicodeToGIDLength))) { + return NULL; + } + + // count the valid code-to-glyph mappings, and the sequences of + // consecutive valid mappings + // (note: char code 65535 is used to mark the end of table) + nMappings = 0; + nSegs = 1; // count the last segment, mapping 65535 + for (c = 0; c < unicodeToGIDLength && c <= 65534; ++c) { + if (unicodeToGID[c]) { + ++nMappings; + if (c == 0 || !unicodeToGID[c-1]) { + ++nSegs; + } + } + } + + i = 1; + entrySelector = 0; + while (2 * i <= nSegs) { + i *= 2; + ++entrySelector; + } + searchRange = 1 << (entrySelector + 1); + rangeShift = 2 * nSegs - searchRange; + + len = 28 + nSegs * 8 + nMappings * 2; + cmapTable = (Guchar *)gmalloc(len); + + // header + cmapTable[ 0] = 0x00; // table version + cmapTable[ 1] = 0x00; + cmapTable[ 2] = 0x00; // number of cmaps + cmapTable[ 3] = 0x01; + cmapTable[ 4] = 0x00; // platform[0] + cmapTable[ 5] = 0x03; + cmapTable[ 6] = 0x00; // encoding[0] + cmapTable[ 7] = 0x01; + cmapTable[ 8] = 0x00; // offset[0] + cmapTable[ 9] = 0x00; + cmapTable[10] = 0x00; + cmapTable[11] = 0x0c; + + // table info + cmapTable[12] = 0x00; // cmap format + cmapTable[13] = 0x04; + cmapTable[14] = (Guchar)((len - 12) >> 8); // cmap length + cmapTable[15] = (Guchar)(len - 12); + cmapTable[16] = 0x00; // cmap version + cmapTable[17] = 0x00; + cmapTable[18] = (Guchar)(nSegs >> 7); // segCountX2 + cmapTable[19] = (Guchar)(nSegs << 1); + cmapTable[20] = (Guchar)(searchRange >> 8); // searchRange + cmapTable[21] = (Guchar)searchRange; + cmapTable[22] = (Guchar)(entrySelector >> 8); // entrySelector + cmapTable[23] = (Guchar)entrySelector; + cmapTable[24] = (Guchar)(rangeShift >> 8); // rangeShift + cmapTable[25] = (Guchar)rangeShift; + cmapTable[26 + nSegs*2 ] = 0; // reservedPad + cmapTable[26 + nSegs*2 + 1] = 0; + + i = 0; + glyphIdOffset = 28 + nSegs*8; + for (c = 0; c < unicodeToGIDLength && c <= 65534; ++c) { + if (unicodeToGID[c]) { + if (c == 0 || !unicodeToGID[c-1]) { + start = c; + cmapTable[28 + nSegs*2 + i*2 ] = (Guchar)(start >> 8); + cmapTable[28 + nSegs*2 + i*2 + 1] = (Guchar)start; + cmapTable[28 + nSegs*4 + i*2 ] = (Guchar)0; // idDelta + cmapTable[28 + nSegs*4 + i*2 + 1] = (Guchar)0; + idRangeOffset = glyphIdOffset - (28 + nSegs*6 + i*2); + cmapTable[28 + nSegs*6 + i*2 ] = (Guchar)(idRangeOffset >> 8); + cmapTable[28 + nSegs*6 + i*2 + 1] = (Guchar)idRangeOffset; + } + if (c == 65534 || !unicodeToGID[c+1]) { + end = c; + cmapTable[26 + i*2 ] = (Guchar)(end >> 8); + cmapTable[26 + i*2 + 1] = (Guchar)end; + ++i; + } + cmapTable[glyphIdOffset++] = (Guchar)(unicodeToGID[c] >> 8); + cmapTable[glyphIdOffset++] = (Guchar)unicodeToGID[c]; + } + } + + // last segment maps code 65535 to GID 0 + cmapTable[26 + i*2 ] = (Guchar)0xff; // end + cmapTable[26 + i*2 + 1] = (Guchar)0xff; + cmapTable[28 + nSegs*2 + i*2 ] = (Guchar)0xff; // start + cmapTable[28 + nSegs*2 + i*2 + 1] = (Guchar)0xff; + cmapTable[28 + nSegs*4 + i*2 ] = (Guchar)0; // idDelta + cmapTable[28 + nSegs*4 + i*2 + 1] = (Guchar)1; + cmapTable[28 + nSegs*6 + i*2 ] = (Guchar)0; // idRangeOffset + cmapTable[28 + nSegs*6 + i*2 + 1] = (Guchar)0; + + gfree(unicodeToGID); + + *unicodeCmapLength = len; + return cmapTable; +} + +int *WebFont::makeUnicodeToGID(int *codeToGID, int nCodes, + int *unicodeToGIDLength) { + int *unicodeToGID; + CharCodeToUnicode *ctu; + Unicode u[2]; + int len, size, newSize, uLen, c, gid; + + if (gfxFont->isCIDFont()) { + if (!(ctu = ((GfxCIDFont *)gfxFont)->getToUnicode())) { + return NULL; + } + } else { + ctu = ((Gfx8BitFont *)gfxFont)->getToUnicode(); + } + + len = 0; + size = 256; + unicodeToGID = (int *)gmallocn(size, sizeof(int)); + memset(unicodeToGID, 0, size * sizeof(int)); + for (c = 0; c < nCodes; ++c) { + gid = codeToGID ? codeToGID[c] : c; + if (gid < 0 || gid >= 65536) { + continue; + } + uLen = ctu->mapToUnicode(c, u, 2); + if (uLen != 1) { + continue; + } + if (u[0] >= 65536) { // sanity check + continue; + } + if ((int)u[0] >= size) { + newSize = 2 * size; + while ((int)u[0] >= newSize) { + newSize *= 2; + } + unicodeToGID = (int *)greallocn(unicodeToGID, newSize, sizeof(int)); + memset(unicodeToGID + size, 0, (newSize - size) * sizeof(int)); + size = newSize; + } + unicodeToGID[u[0]] = gid; + if ((int)u[0] >= len) { + len = u[0] + 1; + } + } + + ctu->decRefCnt(); + + *unicodeToGIDLength = len; + return unicodeToGID; +} diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/WebFont.h b/Build/source/libs/xpdf/xpdf-src/xpdf/WebFont.h new file mode 100644 index 00000000000..a967e2e490a --- /dev/null +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/WebFont.h @@ -0,0 +1,69 @@ +//======================================================================== +// +// WebFont.h +// +// Modify/convert embedded PDF fonts to a form usable by web browsers. +// +// Copyright 2019 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef WEBFONT_H +#define WEBFONT_H + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "GfxFont.h" + +class FoFiTrueType; +class FoFiType1C; +class XRef; + +//------------------------------------------------------------------------ + +class WebFont { +public: + + WebFont(GfxFont *gfxFontA, XRef *xref); + + ~WebFont(); + + // Returns true if the font is, or can be converted to, a TrueType + // font. + GBool canWriteTTF(); + + // Returns true if the font is, or can be converted to, an OpenType + // font. + GBool canWriteOTF(); + + // Write a TrueType (.ttf) file to [fontFilePath]. This can only be + // called if canWriteTTF() returns true. Returns true on success. + GBool writeTTF(const char *fontFilePath); + + // Write an OpenType (.otf) file to [fontFilePath]. This can only + // be called if canWriteOTF() returns true. Returns true on + // success. + GBool writeOTF(const char *fontFilePath); + +private: + + Gushort *makeType1CWidths(int *codeToGID, int nCodes, int *nWidths); + Gushort *makeCIDType0CWidths(int *codeToGID, int nCodes, int *nWidths); + Guchar *makeUnicodeCmapTable(int *codeToGID, int nCodes, + int *unicodeCmapLength); + int *makeUnicodeToGID(int *codeToGID, int nCodes, int *unicodeToGIDLength); + + GfxFont *gfxFont; + char *fontBuf; + int fontLength; + FoFiTrueType *ffTrueType; + FoFiType1C *ffType1C; + GBool isOpenType; +}; + +#endif diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/XFAForm.cc b/Build/source/libs/xpdf/xpdf-src/xpdf/XFAForm.cc index 18534401946..3b88270c798 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/XFAForm.cc +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/XFAForm.cc @@ -25,6 +25,7 @@ #include "GfxFont.h" #include "Zoox.h" #include "PDF417Barcode.h" +#include "UTF8.h" #include "XFAForm.h" #ifdef _WIN32 @@ -446,7 +447,7 @@ XFAForm *XFAForm::load(PDFDoc *docA, Catalog *catalog, fullNameIdx = new GHash(); xfaForm->scanNode(tmpl, name, fullName, gFalse, NULL, nameCount, nameIdx, fullNameCount, fullNameIdx, - catalog); + NULL, catalog); delete nameCount; delete nameIdx; delete fullNameCount; @@ -504,11 +505,6 @@ XFAForm::~XFAForm() { gfree(pageOffsetY); } -//~ need to handle exclGroup -//~ - fields in an exclGroup may/must(?) not have names -//~ - each field has an items element with the the value when that -//~ field is selected - // 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, @@ -516,7 +512,7 @@ void XFAForm::scanNode(ZxElement *elem, GBool inPageSet, XFATableInfo *tableInfo, GHash *nameCount, GHash *nameIdx, GHash *fullNameCount, GHash *fullNameIdx, - Catalog *catalog) { + GString *exclGroupName, Catalog *catalog) { ZxAttr *attr; GString *name, *fullName, *namePart, *fullNamePart; GHash *childNameCount, *childNameIdx, *childFullNameCount, *childFullNameIdx; @@ -575,7 +571,8 @@ void XFAForm::scanNode(ZxElement *elem, } if (elem->isElement("field")) { - scanField(elem, name, fullName, inPageSet, tableInfo, colSpan, catalog); + scanField(elem, name, fullName, exclGroupName, + inPageSet, tableInfo, colSpan, catalog); } else { scanNonField(elem, name, fullName, inPageSet, tableInfo, colSpan, childNameCount, childNameIdx, @@ -652,7 +649,7 @@ void XFAForm::scanFullNames(ZxElement *elem, GHash *fullNameCount) { } void XFAForm::scanField(ZxElement *elem, GString *name, GString *fullName, - GBool inPageSet, + GString *exclGroupName, GBool inPageSet, XFATableInfo *tableInfo, int colSpan, Catalog *catalog) { double xSubOffset, ySubOffset, columnWidth, rowHeight; @@ -679,6 +676,8 @@ void XFAForm::scanField(ZxElement *elem, GString *name, GString *fullName, } fields->append(new XFAFormField(this, elem, name->copy(), fullName->copy(), + exclGroupName ? exclGroupName->copy() + : (GString *)NULL, curPageNum, curXOffset, curYOffset, columnWidth, rowHeight)); @@ -699,6 +698,7 @@ void XFAForm::scanNonField(ZxElement *elem, GString *name, GString *fullName, ZxNode *child; ZxAttr *attr; PDFRectangle *box; + GString *exclGroupName; double xSubOffset, ySubOffset; int savedPageNum; @@ -744,7 +744,8 @@ void XFAForm::scanNonField(ZxElement *elem, GString *name, GString *fullName, curXOffset += xSubOffset; curYOffset += ySubOffset; - } else if (elem->isElement("area")) { + } else if (elem->isElement("area") || + elem->isElement("exclGroup")) { xSubOffset = XFAFormField::getMeasurement(elem->findAttr("x"), 0); ySubOffset = XFAFormField::getMeasurement(elem->findAttr("y"), 0); curXOffset += xSubOffset; @@ -780,11 +781,17 @@ void XFAForm::scanNonField(ZxElement *elem, GString *name, GString *fullName, } } + 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, - catalog); + exclGroupName, catalog); } } @@ -871,12 +878,14 @@ FormField *XFAForm::getField(int idx) { 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; @@ -887,6 +896,9 @@ XFAFormField::XFAFormField(XFAForm *xfaFormA, ZxElement *xmlA, XFAFormField::~XFAFormField() { delete name; delete fullName; + if (exclGroupName) { + delete exclGroupName; + } } int XFAFormField::getPageNum() { @@ -943,7 +955,9 @@ Unicode *XFAFormField::getValue(int *length) { s = getFieldValue("text"); break; } else if (node->isElement("checkButton")) { - s = getFieldValue("integer"); + if (!(s = getFieldValue("integer"))) { + s = getFieldValue("text"); + } break; } else if (node->isElement("barcode")) { s = getFieldValue("text"); @@ -1921,6 +1935,22 @@ GString *XFAFormField::getFieldValue(const char *valueChildType) { } } } + 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(); @@ -1955,7 +1985,9 @@ GString *XFAFormField::getFieldValue(const char *valueChildType) { ZxElement *XFAFormField::findFieldInDatasets(ZxElement *elem, char *partName) { ZxNode *node; + ZxElement *result; GString *nodeName; + char *next; int curIdx, idx, n; curIdx = 0; @@ -1976,11 +2008,21 @@ ZxElement *XFAFormField::findFieldInDatasets(ZxElement *elem, char *partName) { if (!partName[n]) { return (ZxElement *)node; } else if (partName[n] == '.') { - return findFieldInDatasets((ZxElement *)node, partName + n + 1); + 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; } @@ -2054,14 +2096,26 @@ void XFAFormField::drawText(GString *text, GBool multiLine, int combCells, 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; - //~ deal with Unicode text (is it UTF-8?) + // 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))) { @@ -2093,8 +2147,8 @@ void XFAFormField::drawText(GString *text, GBool multiLine, int combCells, if (vAlign == xfaVAlignBottom || vAlign == xfaVAlignMiddle) { nLines = 0; i = 0; - while (i < text->getLength()) { - getNextLine(text, i, font, fontSize, w, &j, &tw, &k); + while (i < text2->getLength()) { + getNextLine(text2, i, font, fontSize, w, &j, &tw, &k); ++nLines; i = k; } @@ -2114,9 +2168,9 @@ void XFAFormField::drawText(GString *text, GBool multiLine, int combCells, // write a series of lines of text line = 0; i = 0; - while (i < text->getLength()) { + while (i < text2->getLength()) { - getNextLine(text, i, font, fontSize, w, &j, &tw, &k); + getNextLine(text2, i, font, fontSize, w, &j, &tw, &k); if (tw > rectW) { rectW = tw; } @@ -2140,7 +2194,7 @@ void XFAFormField::drawText(GString *text, GBool multiLine, int combCells, appearBuf->appendf("1 0 0 1 {0:.4f} {1:.4f} Tm\n", xx, yy); appearBuf->append('('); for (; i < j; ++i) { - c = text->getChar(i) & 0xff; + c = text2->getChar(i) & 0xff; if (c == '(' || c == ')' || c == '\\') { appearBuf->append('\\'); appearBuf->append((char)c); @@ -2172,13 +2226,13 @@ void XFAFormField::drawText(GString *text, GBool multiLine, int combCells, xx = x; break; case xfaHAlignCenter: - xx = x + (int)(0.5 * (combCells - text->getLength())) * tw; + xx = x + (int)(0.5 * (combCells - text2->getLength())) * tw; break; case xfaHAlignRight: - xx = x + w - text->getLength() * tw; + xx = x + w - text2->getLength() * tw; break; } - rectW = text->getLength() * tw; + rectW = text2->getLength() * tw; switch (vAlign) { case xfaVAlignTop: default: @@ -2195,8 +2249,8 @@ void XFAFormField::drawText(GString *text, GBool multiLine, int combCells, rectH = ascent - descent; // write the text string - for (i = 0; i < text->getLength(); ++i) { - c = text->getChar(i) & 0xff; + 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", @@ -2223,12 +2277,12 @@ void XFAFormField::drawText(GString *text, GBool multiLine, int combCells, // compute string width if (font && !font->isCIDFont()) { tw = 0; - for (i = 0; i < text->getLength(); ++i) { - tw += ((Gfx8BitFont *)font)->getWidth(text->getChar(i)); + for (i = 0; i < text2->getLength(); ++i) { + tw += ((Gfx8BitFont *)font)->getWidth(text2->getChar(i)); } } else { // otherwise, make a crude estimate - tw = text->getLength() * 0.5; + tw = text2->getLength() * 0.5; } tw *= fontSize; rectW = tw; @@ -2264,8 +2318,8 @@ void XFAFormField::drawText(GString *text, GBool multiLine, int combCells, // write the text string appearBuf->append('('); - for (i = 0; i < text->getLength(); ++i) { - c = text->getChar(i) & 0xff; + for (i = 0; i < text2->getLength(); ++i) { + c = text2->getChar(i) & 0xff; if (c == '(' || c == ')' || c == '\\') { appearBuf->append('\\'); appearBuf->append((char)c); @@ -2304,6 +2358,8 @@ void XFAFormField::drawText(GString *text, GBool multiLine, int combCells, appearBuf->insert(rectI, s); delete s; } + + delete text2; } // Searches <fontDict> for a font matching(<fontName>, <bold>, @@ -2734,7 +2790,7 @@ GString *XFAFormField::pictureFormatDateTime(GString *value, GString *picture) { u <<= 4; if (c >= '0' && c <= '9') { u += c - '0'; - } else if (c >= 'a' && c <= 'F') { + } else if (c >= 'a' && c <= 'f') { u += c - 'a' + 10; } else if (c >= 'A' && c <= 'F') { u += c - 'A' + 10; diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/XFAForm.h b/Build/source/libs/xpdf/xpdf-src/xpdf/XFAForm.h index 8e0b363386a..2f56e728a98 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/XFAForm.h +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/XFAForm.h @@ -63,11 +63,11 @@ private: GBool inPageSet, XFATableInfo *tableInfo, GHash *nameCount, GHash *nameIdx, GHash *fullNameCount, GHash *fullNameIdx, - Catalog *catalog); + GString *exclGroupName, Catalog *catalog); void scanNames(ZxElement *elem, GHash *nameCount); void scanFullNames(ZxElement *elem, GHash *fullNameCount); void scanField(ZxElement *elem, GString *name, GString *fullName, - GBool inPageSet, + GString *exclGroupName, GBool inPageSet, XFATableInfo *tableInfo, int colSpan, Catalog *catalog); void scanNonField(ZxElement *elem, GString *name, GString *fullName, @@ -102,7 +102,7 @@ class XFAFormField: public FormField { public: XFAFormField(XFAForm *xfaFormA, ZxElement *xmlA, - GString *nameA, GString *fullNameA, + GString *nameA, GString *fullNameA, GString *exclGroupNameA, int pageNumA, double xOffsetA, double yOffsetA, double columnWidthA, double rowHeightA); @@ -166,6 +166,7 @@ private: ZxElement *xml; GString *name; GString *fullName; + GString *exclGroupName; int pageNum; double xOffset, yOffset; double columnWidth; // column width, if this field is in a diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/config.h b/Build/source/libs/xpdf/xpdf-src/xpdf/config.h index f5c566e9696..3dbed2ae93c 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/config.h +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/config.h @@ -14,14 +14,14 @@ //------------------------------------------------------------------------ // xpdf version -#define xpdfVersion "4.01.01" -#define xpdfVersionNum 4.01 +#define xpdfVersion "4.02" +#define xpdfVersionNum 4.02 #define xpdfMajorVersion 4 -#define xpdfMinorVersion 1 -#define xpdfUpdateVersion 1 +#define xpdfMinorVersion 2 +#define xpdfUpdateVersion 0 #define xpdfMajorVersionStr "4" -#define xpdfMinorVersionStr "1" -#define xpdfUpdateVersionStr "1" +#define xpdfMinorVersionStr "2" +#define xpdfUpdateVersionStr "0" // supported PDF version #define supportedPDFVersionStr "2.0" @@ -31,7 +31,7 @@ #define xpdfCopyright "Copyright 1996-2019 Glyph & Cog, LLC" // Windows resource file stuff -#define winxpdfVersion "WinXpdf 4.01.01" +#define winxpdfVersion "WinXpdf 4.02" #define xpdfCopyrightAmp "Copyright 1996-2019 Glyph && Cog, LLC" //------------------------------------------------------------------------ diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/pdffonts.cc b/Build/source/libs/xpdf/xpdf-src/xpdf/pdffonts.cc index 7df38cc11d7..22298b138c5 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/pdffonts.cc +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/pdffonts.cc @@ -159,11 +159,11 @@ int main(int argc, char *argv[]) { // scan the fonts if (showFontLoc || showFontLocPS) { - printf("name type emb sub uni prob object ID location\n"); - printf("------------------------------------ ----------------- --- --- --- ---- --------- --------\n"); + printf("name type emb sub uni prob object ID location\n"); + printf("---------------------------------------------- ----------------- --- --- --- ---- --------- --------\n"); } else { - printf("name type emb sub uni prob object ID\n"); - printf("------------------------------------ ----------------- --- --- --- ---- ---------\n"); + printf("name type emb sub uni prob object ID\n"); + printf("---------------------------------------------- ----------------- --- --- --- ---- ---------\n"); } fonts = NULL; fontsLen = fontsSize = 0; @@ -302,7 +302,7 @@ static void scanFonts(Dict *resDict, PDFDoc *doc) { resDict->lookupNF("ExtGState", &gsDict1); if (checkObject(&gsDict1, &gsDict2) && gsDict2.isDict()) { for (i = 0; i < gsDict2.dictGetLength(); ++i) { - gsDict1.dictGetValNF(i, &gs1); + gsDict2.dictGetValNF(i, &gs1); if (checkObject(&gs1, &gs2) && gs2.isDict()) { gs2.dictLookupNF("SMask", &smask1); if (checkObject(&smask1, &smask2) && smask2.isDict()) { @@ -375,7 +375,7 @@ static void scanFont(GfxFont *font, PDFDoc *doc) { } // print the font info - printf("%-36s %-17s %-3s %-3s %-3s %-4s", + printf("%-46s %-17s %-3s %-3s %-3s %-4s", name ? name->getCString() : "[none]", fontTypeNames[font->getType()], emb ? "yes" : "no", diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/pdftohtml.cc b/Build/source/libs/xpdf/xpdf-src/xpdf/pdftohtml.cc index b458202effb..29095509bed 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/pdftohtml.cc +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/pdftohtml.cc @@ -171,6 +171,7 @@ int main(int argc, char *argv[]) { htmlGen->setZoom(zoom); htmlGen->setDrawInvisibleText(!skipInvisible); htmlGen->setAllTextInvisible(allInvisible); + htmlGen->setExtractFontFiles(gTrue); htmlGen->startDoc(doc); // convert the pages @@ -191,7 +192,7 @@ int main(int argc, char *argv[]) { goto err2; } pngURL = GString::format("page{0:d}.png", pg); - err = htmlGen->convertPage(pg, pngURL->getCString(), + err = htmlGen->convertPage(pg, pngURL->getCString(), htmlDir, &writeToFile, htmlFile, &writeToFile, pngFile); delete pngURL; diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/pdftopng.cc b/Build/source/libs/xpdf/xpdf-src/xpdf/pdftopng.cc index 720066d32a8..64a0087c7d3 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/pdftopng.cc +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/pdftopng.cc @@ -352,6 +352,7 @@ static void writePNGData(png_structp png, SplashBitmap *bitmap) { + static void finishPNG(png_structp *png, png_infop *pngInfo) { if (setjmp(png_jmpbuf(*png))) { exit(2); diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/pdftotext.cc b/Build/source/libs/xpdf/xpdf-src/xpdf/pdftotext.cc index 0496c6442ff..aa74fb68612 100644 --- a/Build/source/libs/xpdf/xpdf-src/xpdf/pdftotext.cc +++ b/Build/source/libs/xpdf/xpdf-src/xpdf/pdftotext.cc @@ -50,6 +50,10 @@ static char textEncName[128] = ""; static char textEOL[16] = ""; static GBool noPageBreaks = gFalse; static GBool insertBOM = gFalse; +static double marginLeft = 0; +static double marginRight = 0; +static double marginTop = 0; +static double marginBottom = 0; static char ownerPassword[33] = "\001"; static char userPassword[33] = "\001"; static GBool quiet = gFalse; @@ -88,6 +92,14 @@ static ArgDesc argDesc[] = { "don't insert page breaks between pages"}, {"-bom", argFlag, &insertBOM, 0, "insert a Unicode BOM at the start of the text file"}, + {"-marginl", argFP, &marginLeft, 0, + "left page margin"}, + {"-marginr", argFP, &marginRight, 0, + "right page margin"}, + {"-margint", argFP, &marginTop, 0, + "top page margin"}, + {"-marginb", argFP, &marginBottom, 0, + "bottom page margin"}, {"-opw", argString, ownerPassword, sizeof(ownerPassword), "owner password (for encrypted files)"}, {"-upw", argString, userPassword, sizeof(userPassword), @@ -247,6 +259,10 @@ int main(int argc, char *argv[]) { textOutControl.clipText = clipText; textOutControl.discardDiagonalText = discardDiag; textOutControl.insertBOM = insertBOM; + textOutControl.marginLeft = marginLeft; + textOutControl.marginRight = marginRight; + textOutControl.marginTop = marginTop; + textOutControl.marginBottom = marginBottom; textOut = new TextOutputDev(textFileName->getCString(), &textOutControl, gFalse); if (textOut->isOk()) { |