diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e89e75..137015d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,3 +23,6 @@ # Version 0.1.6 (09-jun-2023) - Implement pdftopng functionality + +# Version 0.1.7 (18-apr-2026) + - Update to xpdf-4.04 sources \ No newline at end of file diff --git a/MANIFEST.in b/MANIFEST.in old mode 100644 new mode 100755 index 63b1167..7dc74b3 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -6,7 +6,7 @@ include src/freetype/include/freetype/config/*.h include src/freetype/include/freetype/internal/*.h include src/freetype/include/freetype/internal/*/*.h include src/xpydf/* -include src/xpdf-4.04/** -include src/xpdf-4.04/**/*.cc -include src/xpdf-4.04/**/*.h +include src/xpdf-4.06/** +include src/xpdf-4.06/**/*.cc +include src/xpdf-4.06/**/*.h include src/xpydf/*.pyi diff --git a/Makefile b/Makefile old mode 100644 new mode 100755 index c28dc5c..e3099d4 --- a/Makefile +++ b/Makefile @@ -1,16 +1,16 @@ PROGNAME = a.out OBJDIR = obj/ +XDIR = src/xpdf-4.06/ CC = g++ -std=c++17 C = gcc -pedantic -std=c99 WARNFLAGS = -Wall # -Wno-deprecated-declarations -Wno-writable-strings -CCFLAGS = -O3 $(WARNFLAGS) -MD -Isrc/xpdf-4.04 -Isrc/xpdf-4.04/goo -Isrc/xpdf-4.04/splash -Isrc/xpdf-4.04/xpdf -Isrc/xpdf-4.04/fofi -I/usr/local/include -Isrc/freetype/include -Isrc/freetype/include/freetype +CCFLAGS = -O3 $(WARNFLAGS) -MD -I$(XDIR) -I$(XDIR)/goo -I$(XDIR)/splash -I$(XDIR)/xpdf -I$(XDIR)/fofi -I/usr/local/include -Isrc/freetype/include -Isrc/freetype/include/freetype CFLAGS = -O3 $(WARNFLAGS) -MD -pthread -DFT_CONFIG_CONFIG_H="" -DFT_CONFIG_MODULES_H="" -DFT_CONFIG_OPTIONS_H="" -DFT2_BUILD_LIBRARY -Isrc/freetype/include -Isrc/freetype/include/freetype -Isrc/freetype/include/freetype/config -Isrc/freetype/include/freetype/internal PYDIR = src/xpydf/ -XDIR = src/xpdf-4.04/ SPLASH_DIR = $(XDIR)splash/ FOFI_DIR = $(XDIR)fofi/ GOO_DIR = $(XDIR)goo/ @@ -163,8 +163,10 @@ clean: cleanft: rm -fv $(PROGNAME) $(FREE_OBJ) +install: + pip install . + test: - $(info $(FREE_DIRS)) - $(info $(SKIP_DIRS)) + python -m unittest -v -include $(OBJFILES:.o=.d) diff --git a/pyproject.toml b/pyproject.toml index 472a2d6..b31af06 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "xpydf" -version = "0.1.6" +version = "0.1.7" authors = [ { name = "Matthijs Wesseling", email = "matthijs.wesseling@bigdatarepublic.nl" }, ] diff --git a/setup.py b/setup.py old mode 100644 new mode 100755 index aa6e687..44f1815 --- a/setup.py +++ b/setup.py @@ -6,11 +6,13 @@ from setuptools.command.build_ext import build_ext from setuptools import Extension, setup +xpdf_src_dir = "src/xpdf-4.06" + python_dir = Path("src/xpydf") -xpdf_dir = Path("src/xpdf-4.04/xpdf") -splash_dir = Path("src/xpdf-4.04/splash") -fofi_dir = Path("src/xpdf-4.04/fofi") -goo_dir = Path("src/xpdf-4.04/goo") +xpdf_dir = Path(f"{xpdf_src_dir}/xpdf") +splash_dir = Path(f"{xpdf_src_dir}/splash") +fofi_dir = Path(f"{xpdf_src_dir}/fofi") +goo_dir = Path(f"{xpdf_src_dir}/goo") python_src = glob(str(python_dir / "*.cc")) splash_src = glob(str(splash_dir / "*.cc")) @@ -137,7 +139,7 @@ "cXpdfPython", sources = python_src + xpdf_src + splash_src + goo_src + fofi_src + freetype_sources, include_dirs = [ - "src/xpdf-4.04", + str(xpdf_src_dir), str(xpdf_dir), str(fofi_dir), str(splash_dir), diff --git a/src/xpdf-4.04/ANNOUNCE b/src/xpdf-4.04/ANNOUNCE deleted file mode 100644 index c20dcaf..0000000 --- a/src/xpdf-4.04/ANNOUNCE +++ /dev/null @@ -1,37 +0,0 @@ -Subject: ANNOUNCE: Xpdf 4.04 - 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. - -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.04 is primarily a bug fix release. There are some new features: - -* XpdfReader improvements: - - Implemented selection extension via shift-click, and word/line - selection via double/triple click. - - Added default bindings for ctrl-mousewheel-up/down to zoom in/out. - - Added a help menu item that shows all of the key bindings. - -* Various new command line options for pdftotext, pdftohtml, pdftoppm, - pdftopng, and xpdf. - -See the `CHANGES' file for a complete list of changes. - -Source (C++ and C) is available, and it should be fairly easy to -compile for Linux and Windows. - -More information, source code, and precompiled binaries are on the -xpdf web page: - - http://www.xpdfreader.com/ - -For information on commercial licensing and consulting, please see the -Glyph & Cog web site: - - http://www.glyphandcog.com/ diff --git a/src/xpdf-4.04/aconf2.h b/src/xpdf-4.04/aconf2.h deleted file mode 100644 index 05d785c..0000000 --- a/src/xpdf-4.04/aconf2.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * aconf2.h - * - * This gets included by aconf.h, and contains miscellaneous global - * settings not directly controlled by autoconf. This is a separate - * file because otherwise the configure script will munge any - * #define/#undef constructs. - * - * Copyright 2002-2003 Glyph & Cog, LLC - */ - -#ifndef ACONF2_H -#define ACONF2_H - -/* - * This controls the use of the interface/implementation pragmas. - */ -#if defined(__GNUC__) && !defined(__clang__) -#define USE_GCC_PRAGMAS -#endif -/* There is a bug in the version of gcc which ships with MacOS X 10.2 */ -#if defined(__APPLE__) && defined(__MACH__) -# include -#endif -#ifdef MAC_OS_X_VERSION_MAX_ALLOWED -# if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_2 -# undef USE_GCC_PRAGMAS -# 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/src/xpdf-4.06/ANNOUNCE b/src/xpdf-4.06/ANNOUNCE new file mode 100755 index 0000000..c14a473 --- /dev/null +++ b/src/xpdf-4.06/ANNOUNCE @@ -0,0 +1,53 @@ +Subject: ANNOUNCE: Xpdf 4.06 - 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. + +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.06 is primarily a bug fix release. There are some new features: + +* New command line options/features: + - Added the '-listonly' flag to pdfimages. + - Added the '-u' option to pdfimages. + - Added the '-J' option to pdfimages to dump JPEG 2000 images. + - Modified pdftohtml to generate a nicer index page; add the + '-noframe' option to generate the previous-style index page. + +* New configuration options: + - Added the 'initialMaximized' xpdfrc setting. + - Added the 'discardCoveredText' xpdfrc setting. + - Added the 'preferXFAFieldValues' xpdfrc setting. + +* XpdfReader improvements: + - Added the reverseVideoMode, normalVideoMode, and toggleVideoMode + commands; added the view -> reverse video menu item. + - Added a '%t' escape to include the currently selected text in the + argument to xpdf's 'run' command. + - Use the XDG config and state file directories on Linux. + - Added a file:close menu item to Xpdf. + +* Misc changes: + - Changed the default from Level 2 to Level 3 PostScript. + - Added support to pdftohtml for internal links (i.e., links to + pages in the same document). + +See the `CHANGES' file for a complete list of changes. + +Source (C++ and C) is available, and it should be fairly easy to +compile for Linux and Windows. + +More information, source code, and precompiled binaries are on the +xpdf web page: + + http://www.xpdfreader.com/ + +For information on commercial licensing and consulting, please see the +Glyph & Cog web site: + + http://www.glyphandcog.com/ diff --git a/src/xpdf-4.04/CHANGES b/src/xpdf-4.06/CHANGES old mode 100644 new mode 100755 similarity index 92% rename from src/xpdf-4.04/CHANGES rename to src/xpdf-4.06/CHANGES index 564aff3..2ecce38 --- a/src/xpdf-4.04/CHANGES +++ b/src/xpdf-4.06/CHANGES @@ -2810,3 +2810,208 @@ Added an integer overflow check in JPXStream. (JPXStream issue) The DCT (JPEG) decoder was allowing the 'interleaved' flag to be changed after the first scan of the image. (CVE-2022-24106) [Thanks to Shin Ando @ Ricera Security for the bug report.] + +4.05 (2024-feb-08) +------------------ +Added the '-overwrite' option to pdftohtml. +Added the 'ignoreWrongSizeToUnicode' xpdfrc setting. +Added the loadSession and saveSession commands, and the 'Load last + session' menu item. +Added code to automatically save and restore the xpdf session under + control of a session manager. This has not been thoroughly tested + yet. +Added the zoomScaleFactor xpdfrc setting. +Added the zoomValues xpdfrc setting. +Added a 'smart case' option for search in xpdf. +Added the '-custom' flag to pdfinfo. +Added a color/gray/mono switch to the 'save image' dialog. +Added the separateRotatedText xpdfrc setting. +Added the '-meta' flag to pdftohtml. +Added the allowLinksToChangeZoom xpdfrc setting. +Added the 'uses JavaScript' output to pdfinfo. +Implemented pattern stroking of text. Also fixed the various + combinations of filling/stroking with color/pattern + clipping, some + of which weren't being handled correctly. +Pdftops now (re)compresses any uncompressed or RLE-compressed images. +On an out-of-memory error, the command line tools now exit with an + "out of memory" message, rather than an exception message. +Add code to pdfimages to extract images from tiling patterns. +Pdftops can now embed external 8-bit OpenType CFF fonts. +Fixed a corner case in the text extractor related to characters drawn + at extremely large coordinates. [Thanks to elvadisas for the bug + report.] +Fixed an integer overflow in the transparency group code. [Thanks to + elvadisas for the bug report.] +Modify Annots::Annots() to skip annotations that have been turned into + AcroFormFields -- invalid Widget-type annots will now be rendered as + annots. +Added a missing integer overflow check in the JBIG2 decoder. [Thanks + to sangjun for the bug report.] +Added some sanity checks to the JBIG2 decoder. [Thanks to sangjun and + ycdxsb for the bug reports.] +Tiling patterns that use non-Normal blend modes can't be cached. +Fixed a bitmap size sanity check in the JBIG2 decoder. [Thanks to Han + Zheng (NCNIPC of China, Hexhive), for the bug report.] +Fixed a missing bounds check in FoFiType1C::convertToOpenType (used in + pdftohtml). [Thanks to cyth for the bug report.] +Fixed a use-after-free bug in pdftohtml. [Thanks to FeRDNYC for the + bug report.] +Merged aconf2.h into aconf.h; corrected the cmake config settings for + paths; added the BASE14_FONT_DIR config option. [Thanks to FeRDNYC + for the suggestions.] +Fixed a missing check for a zero-length index in the CFF (Type1C) font + parser. [Thanks to Yuhang Huang (NCNIPC of China), Han Zheng + (NCNIPC of China, Hexhive), Wanying Cao, Jiayu Zhao (NCNIPC of + China) for the bug report.] +Add an object loop check to Catalog::countPageTree(). +The DCT decoder wasn't checking for an SOF before the first SOS. + [Thanks to cyth for the bug report.] +The inline image decoder was skipping to end-of-stream in the wrong + stream object. [Thanks to cyth for the bug report.] +Fixed a bug in the JPEG 2000 decoder when nLayers > 1 and the + 'termination on each coding pass' flag is set. +Removed the #pragma interface/implementation stuff (which is outdated + and useless at this point). +Fixed a bug in the ICCBased color space parser that was allowing the + number of components to be zero. (CVE-2023-2662) [Thanks to + huckleberry for the bug report.] +Added checks for PDF object loops in AcroForm::scanField() + (CVE-2018-7453, CVE-2018-16369, CVE-2022-36561, CVE-2022-41844), + Catalog::readPageLabelTree2() (CVE-2023-2663), and + Catalog::readEmbeddedFileTree() (CVE-2023-2664). +The zero-width character problem can also happen if the page size is + very large -- that needs to be limited too, the same way as + character position coordinates. (CVE-2023-3044) [Thanks to jlinliu + for the bug report.] +Add some missing bounds check code in DCTStream. [Thanks to Jiahao + Liu for the bug report.] +Fix a deadlock when an object stream's length field is contained in + another object stream. (CVE-2023-3436) [Thanks to Jiahao Liu for + the bug report.] +Correctly handle tiling patterns with negative step values. +Ignore overprint in soft masks (to match Adobe's behavior). + +4.06 (2025-nov-14) +------------------ +Added the reverseVideoMode, normalVideoMode, and toggleVideoMode + commands; added the view -> reverse video menu item. +Added a '%t' escape to include the currently selected text in the + argument to xpdf's 'run' command. +Added the '-listonly' flag to pdfimages. +Changed the default from Level 2 to Level 3 PostScript. +Use the XDG config and state file directories on Linux. This means + that ~/.config/xpdf/xpdfrc will be checked first, but ~/.xpdfrc will + still be checked. The session and pages file will *only* be used if + they are in ~/.local/state/xpdf/session and + ~/.local/state/xpdf/pages. (XDG support can be disabled at compile + time with 'cmake -DUSE_XDG=OFF'.) +Added the '-u' option to pdfimages. +Added the 'initialMaximized' xpdfrc setting. +Added the 'discardCoveredText' xpdfrc setting. +Added a file:close menu item to Xpdf. +Added the 'preferXFAFieldValues' xpdfrc setting. +Added the '-J' option to pdfimages to dump JPEG 2000 images. +Modified pdftohtml to generate a nicer index page; add the '-noframe' + option to generate the previous-style index page. +Added support to pdftohtml for internal links (i.e., links to pages in + the same document). +Tweaked the antialiasing code to make the output look a little + lighter, and hopefully nicer. +The command line tools should print version info ('pdftotext -v' etc) + to stdout, not stderr. +Added support for AIS (alpha is shape) for soft masked images drawn in + knockout transparency groups. +Tweaked the code that determines a font's ascent metric, trying (yet + again) to make it a little more robust to bogus values in the + FontDescriptor. +On Linux systems (and anything else that uses fontconfig) look for the + Base-14 fonts under the newer Nimbus names via fontconfig (in + addition to checking for the older gs font names in 'standard' + directories). +Pdftohtml now treats text drawn before a full-page fill as invisible. +Added Thai.unicodeRemap to the Thai language support packge: it maps + old Microsoft private use area Thai diacritics to correct Unicode + values. +Tweak the way invisible (OCR) text is handled in the output from + pdftohtml. +Tweaked the appearance of the tab pane in the sidebar. +Fixed a missing bounds check (not exploitable) in + GfxFont::readFontDescriptor(). [Thanks to Sangbin Kim for the bug + report.] +Don't allow negative object or generation numbers in indirect + references. (CVE-2024-2971) [Thanks to Song Jiaxuan (Huazhong + University of Science and Technology) for the bug report.] +Extended the XRef/Parser object loop detector to catch loops that + involve object streams. (CVE-2024-3247) [Thanks to Zhijie Zhang, + from Institute of Information Engineering, Chinese Academy of + Sciences for the bug report.] +Extended the Catalog::readFileAttachmentAnnots object loop detector to + handle another case. (CVE-2024-3248) [Thanks to Wang Dawei and Zhou + Geng, from Zhongguancun Laboratory for the bug report.] +Added a missing zero check to the size argument in + UnicodeRemapping::map(). (CVE-2024-3900) [Thanks to Sangbin Kim, + from Korea University Sejong campus for the bug report.] +Fixed a bounds check in FoFiType1::parse() that was being optimized + away by modern compilers. (CVE-2024-4141) [Thanks to Wu JieCong for + the bug report.] +If the XRefStm link in the trailer is invalid, just ignore it rather + than triggering the repair code. +Extended the resource object loop detector in PSOutputDev to handle + another case. (CVE-2024-4568) [Thanks to Ximing Fan, from School of + Cyber Science and Engineering, Sichuan University, China for the bug + report.] +Fixed a missing object type check that could lead to an out-of-bounds + array write in Annots::loadFormFieldRefs(). (CVE-2024-4976) [Thanks + to Vladislav Shevchenko (HSE university, Moscow) for the bug + report.] +Increased the size of the inter-packet data buffer for the arithmetic + decoder used by the JPX decoder. +Added another object loop check for patterns. (CVE-2024-7866) [Thanks + to xiaobaozidi for the bug report.] +Check for unreasoanbly large page box coordinates, to avoid integer + overflows. (CVE-2024-7867) [Thanks to xiaobaozidi for the bug + report.] +DCTStream::getBlock() was missing a check for the case where + DCTStream::prepare() failed due to invalid headers. (CVE-2024-7868) + [Thanks to KMFL for the bug report.] +Added a check for the case where a stream has a large number of + invalid filters, which was causing a stack overflow. [Thanks to + Michael Lynch of mtlynch.io for the bug report.] +Fixed a bug in WebFont.cc that caused a read of one element past the + end of an array. [Thanks to Mohammad Hussam Alzeyyat / mhzcyber for + the bug report.] +Added a missing mutex to protect the Annots object when using + multithreaded rendering in Xpdf. +Fixed incorrect integer overflow checking in + PostScriptFunction::exec(), which led to an out-of-bounds array + write. (CVE-2025-2574) [Thanks to Erik Viken for the bug report.] +Fixed the object loop check in AcroForm::scanField(). [Thanks to Erik + Viken for the bug report.] +Fixed the object loop check in Catalog::readPageLabelTree2(). [Thanks + to Erik Viken for the bug report.] +Added a missing bounds check in JBIG2Stream::readHalftoneRegionSeg(). + [Thanks to Erik Viken for the bug report.] +Added a missing parsed value check in + GfxGouraudTriangleShading::parse(). (CVE-2025-3154) [Thanks to Erik + Viken for the bug report.] +Added a cache for the tiling pattern tile, to handle the case where + the same tiling pattern is used multiple times in different fill + operations. +Ignore a bogus encoding for non-embedded Symbol and ZapfDingbats + fonts. +Fixed an signed/unsigned conversion problem in Splash::fillChar(). + [Thanks to Erik Viken for the bug report.] +Fixed the object loop check in Catalog::countPageTree(). [Thanks to + Gipoco for the bug report.] +Added some checking for the annotation matrix in Gfx::drawAnnot(). + [Thanks to Sofia Aberegg for the bug report.] +Removed Qt4 support from the cmake scripts. Xpdf has required Qt5/6 + for a while, but the cmake scripts weren't properly updated. +Added an object loop check for CMaps. (CVE-2025-11896) [Thanks + to landw (GitHub: Landw-hub) for the bug report.] +Fixed two uninitialized fields in StandardSecurityHandler - this is + not an exploitable bug. [Thanks to Aldo Ristori (GitHub: Kaldreic) + for the bug report.] +Fixed an unitialized value bug in JBIG2Stream::readSymbolDictSeg - + this is not an exploitable bug. [Thanks to Aldo Ristori (GitHub: + Kaldreic) for the bug report.] diff --git a/src/xpdf-4.04/CMakeLists.txt b/src/xpdf-4.06/CMakeLists.txt old mode 100644 new mode 100755 similarity index 96% rename from src/xpdf-4.04/CMakeLists.txt rename to src/xpdf-4.06/CMakeLists.txt index 90cefe3..3227d42 --- a/src/xpdf-4.04/CMakeLists.txt +++ b/src/xpdf-4.06/CMakeLists.txt @@ -8,7 +8,7 @@ # #======================================================================== -cmake_minimum_required(VERSION 2.8.12) +cmake_minimum_required(VERSION 3.10) project(xpdf) diff --git a/src/xpdf-4.04/COPYING b/src/xpdf-4.06/COPYING old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/COPYING rename to src/xpdf-4.06/COPYING diff --git a/src/xpdf-4.04/COPYING3 b/src/xpdf-4.06/COPYING3 old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/COPYING3 rename to src/xpdf-4.06/COPYING3 diff --git a/src/xpdf-4.04/INSTALL b/src/xpdf-4.06/INSTALL old mode 100644 new mode 100755 similarity index 84% rename from src/xpdf-4.04/INSTALL rename to src/xpdf-4.06/INSTALL index 57ff61f..b192527 --- a/src/xpdf-4.04/INSTALL +++ b/src/xpdf-4.06/INSTALL @@ -1,11 +1,11 @@ Xpdf ==== -version 4.04 -2022-apr-18 +version 4.06 +2025-nov-14 The Xpdf software and documentation are -copyright 1996-2022 Glyph & Cog, LLC. +copyright 1996-2025 Glyph & Cog, LLC. Email: xpdf@xpdfreader.com WWW: http://www.xpdfreader.com/ @@ -34,8 +34,8 @@ different systems. - CMake 2.8.8 or newer - FreeType 2.0.5 or newer - Qt 5.x or 6.x (for xpdf only) - - libpng (for pdftoppm and pdftohtml) - - zlib (for pdftoppm and pdftohtml) + - libpng (for pdftopng and pdftohtml) + - zlib (for pdftopng and pdftohtml) If Qt isn't found, the GUI viewer (xpdf) won't be built, but the command line tools will still be built. @@ -112,6 +112,10 @@ different systems. -DXPDFWIDGET_PRINTING=OFF Disable printing support. + -DUSE_XDG=ON + Enables use of the XDG directories for config and state files. + This defaults to ON for Linux, and OFF for everything else. + -DSYSTEM_XPDFRC="/etc/xpdfrc" Look for a system-wide xpdfrc config file in this directory. @@ -119,9 +123,15 @@ different systems. The ${DATADIR} variable in xpdfrc config files will expand to this string. - -DCMAKE_DISABLE_FIND_PACKAGE_Qt4=1 + -DBASE14_FONT_DIR="/usr/share/fonts/type1" + By default, Xpdf will look for the URW Type 1 fonts in several + quasi-standard directories on Linux/Mac systems. This option + adds another directory to that search path. On Windows, this + does the same thing, except for the system TrueType fonts. + -DCMAKE_DISABLE_FIND_PACKAGE_Qt5Widgets=1 - Do not search for the Qt4/Qt5 libraries. This will disable + -DCMAKE_DISABLE_FIND_PACKAGE_Qt6Widgets=1 + Do not search for the Qt5/Qt6 libraries. This will disable building the GUI viewer (xpdf). Cmake will look for a "qmake" binary -- make sure the first qmake binary on your executable search path matches the desired version of Qt. @@ -141,6 +151,11 @@ different systems. Set the man directory, relative to CMAKE_INSTALL_PREFIX (typically "man" or "share/man"). + -DCMAKE_CXX_FLAGS="... -DDISABLE_SESSION_MANAGEMENT" + Disable the session manager interface, i.e., do not + automatically save and restore sessions under control of the + session manager. + * Build: make diff --git a/src/xpdf-4.04/README b/src/xpdf-4.06/README old mode 100644 new mode 100755 similarity index 99% rename from src/xpdf-4.04/README rename to src/xpdf-4.06/README index 026460d..ad39741 --- a/src/xpdf-4.04/README +++ b/src/xpdf-4.06/README @@ -1,11 +1,11 @@ Xpdf ==== -version 4.04 -2022-apr-18 +version 4.06 +2025-nov-14 The Xpdf software and documentation are -copyright 1996-2022 Glyph & Cog, LLC. +copyright 1996-2025 Glyph & Cog, LLC. Email: xpdf@xpdfreader.com WWW: http://www.xpdfreader.com/ diff --git a/src/xpdf-4.04/aconf.h b/src/xpdf-4.06/aconf.h old mode 100644 new mode 100755 similarity index 81% rename from src/xpdf-4.04/aconf.h rename to src/xpdf-4.06/aconf.h index 659efed..d7851fb --- a/src/xpdf-4.04/aconf.h +++ b/src/xpdf-4.06/aconf.h @@ -3,13 +3,21 @@ * * This file is modified by cmake. * - * Copyright 2002-2015 Glyph & Cog, LLC + * Copyright 2002-2022 Glyph & Cog, LLC */ #ifndef ACONF_H #define ACONF_H -#include +/* + * Speed up Windows compilation. This will only work for the command + * line tools. + */ +/* + *#ifdef _WIN32 + *# define WIN32_LEAN_AND_MEAN + *#endif + */ /* * Use A4 paper size instead of Letter for PostScript output. @@ -29,7 +37,7 @@ /* * Enable multithreading support. */ -#define MULTITHREADED 0 +#define MULTITHREADED 1 /* * Enable C++ exceptions. @@ -56,6 +64,11 @@ */ /* #undef HIGHLIGHTED_REGIONS */ +/* + * Enable support for XDG config/state file paths. + */ +#define USE_XDG 0 + /* * Full path for the system-wide xpdfrc file. */ @@ -67,6 +80,12 @@ */ /* #undef XPDFRC_DATADIR */ +/* + * Directory where the Base14 fonts are installed -- URW Type 1 fonts + * on Linux, system TrueType fonts on Windows + */ +/* #undef BASE14_FONT_DIR */ + /* * Various include files and functions. */ @@ -74,7 +93,6 @@ #define HAVE_MKSTEMPS 1 #define HAVE_POPEN #define HAVE_STD_SORT 1 - #if defined(_WIN32) || defined(_WIN64) #define HAVE_FSEEKO 0 #define HAVE_FSEEK64 0 @@ -84,7 +102,6 @@ #define HAVE_FSEEK64 0 #define HAVE_FSEEKI64 0 #endif - #define _FILE_OFFSET_BITS 64 #define _LARGE_FILES 1 #define _LARGEFILE_SOURCE 1 diff --git a/src/xpdf-4.04/aconf.h.in b/src/xpdf-4.06/aconf.h.in old mode 100644 new mode 100755 similarity index 77% rename from src/xpdf-4.04/aconf.h.in rename to src/xpdf-4.06/aconf.h.in index 99eb78b..8754db6 --- a/src/xpdf-4.04/aconf.h.in +++ b/src/xpdf-4.06/aconf.h.in @@ -3,13 +3,21 @@ * * This file is modified by cmake. * - * Copyright 2002-2015 Glyph & Cog, LLC + * Copyright 2002-2022 Glyph & Cog, LLC */ #ifndef ACONF_H #define ACONF_H -#include +/* + * Speed up Windows compilation. This will only work for the command + * line tools. + */ +/* + *#ifdef _WIN32 + *# define WIN32_LEAN_AND_MEAN + *#endif + */ /* * Use A4 paper size instead of Letter for PostScript output. @@ -56,16 +64,27 @@ */ #cmakedefine HIGHLIGHTED_REGIONS +/* + * Enable support for XDG config/state file paths. + */ +#cmakedefine01 USE_XDG + /* * Full path for the system-wide xpdfrc file. */ -@SYSTEM_XPDFRC_DEFINE@ +#cmakedefine SYSTEM_XPDFRC "@SYSTEM_XPDFRC@" /* * Directory to use for the ${DATADIR} variable in the xpdfrc config * file. */ -@XPDFRC_DATADIR_DEFINE@ +#cmakedefine XPDFRC_DATADIR "@XPDFRC_DATADIR@" + +/* + * Directory where the Base14 fonts are installed -- URW Type 1 fonts + * on Linux, system TrueType fonts on Windows + */ +#cmakedefine BASE14_FONT_DIR "@BASE14_FONT_DIR@" /* * Various include files and functions. diff --git a/src/xpdf-4.04/cmake-config.txt b/src/xpdf-4.06/cmake-config.txt old mode 100644 new mode 100755 similarity index 86% rename from src/xpdf-4.04/cmake-config.txt rename to src/xpdf-4.06/cmake-config.txt index f9339b9..189e988 --- a/src/xpdf-4.04/cmake-config.txt +++ b/src/xpdf-4.06/cmake-config.txt @@ -13,9 +13,6 @@ if (POLICY CMP0074) endif () if (APPLE) - if (POLICY CMP0042) - cmake_policy(SET CMP0042 NEW) - endif () set(CMAKE_MACOSX_RPATH 1) endif () @@ -24,6 +21,7 @@ include(CheckCXXSourceCompiles) include(GNUInstallDirs) enable_language(CXX) +set(CMAKE_CXX_STANDARD 11) #--- add a 'Profiling' build mode if (CMAKE_GENERATOR STREQUAL "Unix Makefiles") @@ -92,23 +90,21 @@ 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}\"") -else () - set(SYSTEM_XPDFRC_DEFINE "/* #undef SYSTEM_XPDFRC */") -endif () -option(XPDFRC_DATADIR "directory to use for the DATADIR xpdfrc variable" "") -if (XPDFRC_DATADIR) - set(XPDFRC_DATADIR_DEFINE "#define XPDFRC_DATADIR \"${XPDFRC_DATADIR}\"") -else () - set(XPDFRC_DATADIR_DEFINE "/* #undef XPDFRC_DATADIR */") -endif () if (WIN32) option(XPDFWIDGET_PRINTING "include printing support in XpdfWidget" OFF) else () option(XPDFWIDGET_PRINTING "include printing support in XpdfWidget" ON) endif () +if (CMAKE_SYSTEM_NAME MATCHES "Linux") + option(USE_XDG "use XDG paths for config and state files" ON) +else () + option(USE_XDG "use XDG paths for config and state files" OFF) +endif () + +#--- paths +set(SYSTEM_XPDFRC "${SYSTEM_XPDFRC}" CACHE FILEPATH "full path for system-wide xpdfrc file") +set(XPDFRC_DATADIR "${XPDFRC_DATADIR}" CACHE PATH "directory to use for the DATADIR xpdfrc variable") +set(BASE14_FONT_DIR "${BASE14_FONT_DIR}" CACHE PATH "directory where the Base14 fonts are installed") #--- check for various library functions check_function_exists(mkstemp HAVE_MKSTEMP) @@ -208,25 +204,25 @@ find_package(PNG) find_package(Qt6Widgets QUIET) if (Qt6Widgets_FOUND) find_package(Qt6Network) + find_package(Qt6Concurrent) find_package(Qt6PrintSupport) else () find_package(Qt5Widgets QUIET) if (Qt5Widgets_FOUND) find_package(Qt5Network) + find_package(Qt5Concurrent) find_package(Qt5PrintSupport) - else () - find_package(Qt4 COMPONENTS QtCore QtGui QtNetwork) endif () 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}") + set(QT_INCLUDES "${Qt5Widgets_INCLUDE_DIRS} ${Qt5Network_INCLUDE_DIRS} ${Qt5Concurrent_INCLUDE_DIRS} ${Qt5PrintSupport_INCLUDE_DIRS}") + set(QT_DEFINITIONS "${Qt5Widgets_DEFINITIONS} ${Qt5Network_DEFINITIONS} ${Qt5Concurrent_DEFINITIONS} ${Qt5PrintSupport_DEFINITIONS}") 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}") + set(QT_INCLUDES "${Qt5Widgets_INCLUDE_DIRS} ${Qt5Network_INCLUDE_DIRS} ${Qt5Concurrent_INCLUDE_DIRS}") + set(QT_DEFINITIONS "${Qt5Widgets_DEFINITIONS} ${Qt5Network_DEFINITIONS} ${Qt5Concurrent_DEFINITIONS}") set(QT_LIBRARIES Qt5::Widgets Qt5::Network) endif () if (XPDFWIDGET_PRINTING) @@ -248,13 +244,13 @@ if (Qt5Widgets_FOUND) elseif (Qt6Widgets_FOUND) message(STATUS "Qt6 found") if (XPDFWIDGET_PRINTING) - set(QT_INCLUDES "${Qt6Widgets_INCLUDE_DIRS} ${Qt6Network_INCLUDE_DIRS} ${Qt6PrintSupport_INCLUDE_DIRS}") - set(QT_DEFINITIONS "${Qt6Widgets_DEFINITIONS} ${Qt6Network_DEFINITIONS} ${Qt6PrintSupport_DEFINITIONS}") - set(QT_LIBRARIES Qt6::Widgets Qt6::Network Qt6::PrintSupport) + set(QT_INCLUDES ${Qt6Widgets_INCLUDE_DIRS} ${Qt6Network_INCLUDE_DIRS} ${Qt6Concurrent_INCLUDE_DIRS} ${Qt6PrintSupport_INCLUDE_DIRS}) + set(QT_DEFINITIONS "${Qt6Widgets_DEFINITIONS} ${Qt6Network_DEFINITIONS} ${Qt6Concurrent_DEFINITIONS} ${Qt6PrintSupport_DEFINITIONS}") + set(QT_LIBRARIES Qt6::Widgets Qt6::Network Qt6::Concurrent Qt6::PrintSupport) else () - set(QT_INCLUDES "${Qt6Widgets_INCLUDE_DIRS} ${Qt6Network_INCLUDE_DIRS}") - set(QT_DEFINITIONS "${Qt6Widgets_DEFINITIONS} ${Qt6Network_DEFINITIONS}") - set(QT_LIBRARIES Qt6::Widgets Qt6::Network) + set(QT_INCLUDES ${Qt6Widgets_INCLUDE_DIRS} ${Qt6Network_INCLUDE_DIRS} ${Qt6Concurrent_INCLUDE_DIRS}) + set(QT_DEFINITIONS "${Qt6Widgets_DEFINITIONS} ${Qt6Network_DEFINITIONS} ${Qt6Concurrent_DEFINITIONS}") + set(QT_LIBRARIES Qt6::Widgets Qt6::Network Qt6::Concurrent) endif () if (XPDFWIDGET_PRINTING) if (APPLE) @@ -272,22 +268,6 @@ elseif (Qt6Widgets_FOUND) endif () # remove "-fPIE" here because we added "-fPIC" above string(REPLACE "-fPIE" "" QT_CFLAGS "${Qt6Widgets_EXECUTABLE_COMPILE_FLAGS}") -elseif (QT4_FOUND) - message(STATUS "Qt4 found") - if (XPDFWIDGET_PRINTING) - if (APPLE) - set(EXTRA_QT_LIBRARIES "-framework ApplicationServices") - elseif (UNIX) - find_package(Cups) - if (CUPS_FOUND) - set(EXTRA_QT_LIBRARIES ${CUPS_LIBRARIES}) - else () - set (XPDFWIDGET_PRINTING OFF) - endif () - else () - set(EXTRA_QT_LIBRARIES "") - endif () - endif () else () message(STATUS "No Qt library found") endif () diff --git a/src/xpdf-4.04/doc/pdfdetach.1 b/src/xpdf-4.06/doc/pdfdetach.1 old mode 100644 new mode 100755 similarity index 93% rename from src/xpdf-4.04/doc/pdfdetach.1 rename to src/xpdf-4.06/doc/pdfdetach.1 index 4d00f37..3133060 --- a/src/xpdf-4.04/doc/pdfdetach.1 +++ b/src/xpdf-4.06/doc/pdfdetach.1 @@ -1,8 +1,8 @@ -.\" Copyright 2013-2022 Glyph & Cog, LLC -.TH pdfdetach 1 "18 Apr 2022" +.\" Copyright 2013-2025 Glyph & Cog, LLC +.TH pdfdetach 1 "14 Nov 2025" .SH NAME pdfdetach \- Portable Document Format (PDF) document embedded file -extractor (version 4.04) +extractor (version 4.06) .SH SYNOPSIS .B pdfdetach [options] @@ -86,10 +86,13 @@ Error opening an output file. 3 Error related to PDF permissions. .TP +98 +Out of memory. +.TP 99 Other error. .SH AUTHOR -The pdfinfo software and documentation are copyright 1996-2022 Glyph & +The pdfinfo software and documentation are copyright 1996-2025 Glyph & Cog, LLC. .SH "SEE ALSO" .BR xpdf (1), diff --git a/src/xpdf-4.04/doc/pdfdetach.cat b/src/xpdf-4.06/doc/pdfdetach.cat old mode 100644 new mode 100755 similarity index 93% rename from src/xpdf-4.04/doc/pdfdetach.cat rename to src/xpdf-4.06/doc/pdfdetach.cat index 220bb75..773106e --- a/src/xpdf-4.04/doc/pdfdetach.cat +++ b/src/xpdf-4.06/doc/pdfdetach.cat @@ -3,8 +3,8 @@ pdfdetach(1) General Commands Manual pdfdetach(1) NAME - pdfdetach - Portable Document Format (PDF) document embedded file - extractor (version 4.04) + pdfdetach - Portable Document Format (PDF) document embedded file ex- + tractor (version 4.06) SYNOPSIS pdfdetach [options] [PDF-file] @@ -76,10 +76,12 @@ EXIT CODES 3 Error related to PDF permissions. + 98 Out of memory. + 99 Other error. AUTHOR - The pdfinfo software and documentation are copyright 1996-2022 Glyph & + The pdfinfo software and documentation are copyright 1996-2025 Glyph & Cog, LLC. SEE ALSO @@ -89,4 +91,4 @@ SEE ALSO - 18 Apr 2022 pdfdetach(1) + 14 Nov 2025 pdfdetach(1) diff --git a/src/xpdf-4.04/doc/pdffonts.1 b/src/xpdf-4.06/doc/pdffonts.1 old mode 100644 new mode 100755 similarity index 95% rename from src/xpdf-4.04/doc/pdffonts.1 rename to src/xpdf-4.06/doc/pdffonts.1 index 6ee0226..902e8e7 --- a/src/xpdf-4.04/doc/pdffonts.1 +++ b/src/xpdf-4.06/doc/pdffonts.1 @@ -1,8 +1,8 @@ -.\" Copyright 1999-2022 Glyph & Cog, LLC -.TH pdffonts 1 "18 Apr 2022" +.\" Copyright 1999-2025 Glyph & Cog, LLC +.TH pdffonts 1 "14 Nov 2025" .SH NAME pdffonts \- Portable Document Format (PDF) font analyzer (version -4.04) +4.06) .SH SYNOPSIS .B pdffonts [options] @@ -143,10 +143,13 @@ Error opening an output file. 3 Error related to PDF permissions. .TP +98 +Out of memory. +.TP 99 Other error. .SH AUTHOR -The pdffonts software and documentation are copyright 1996-2022 Glyph +The pdffonts software and documentation are copyright 1996-2025 Glyph & Cog, LLC. .SH "SEE ALSO" .BR xpdf (1), diff --git a/src/xpdf-4.04/doc/pdffonts.cat b/src/xpdf-4.06/doc/pdffonts.cat old mode 100644 new mode 100755 similarity index 94% rename from src/xpdf-4.04/doc/pdffonts.cat rename to src/xpdf-4.06/doc/pdffonts.cat index 77fef55..2ff55dd --- a/src/xpdf-4.04/doc/pdffonts.cat +++ b/src/xpdf-4.06/doc/pdffonts.cat @@ -3,7 +3,7 @@ pdffonts(1) General Commands Manual pdffonts(1) NAME - pdffonts - Portable Document Format (PDF) font analyzer (version 4.04) + pdffonts - Portable Document Format (PDF) font analyzer (version 4.06) SYNOPSIS pdffonts [options] [PDF-file] @@ -14,8 +14,8 @@ DESCRIPTION The following information is listed for each font: - name the font name, exactly as given in the PDF file (potentially - including a subset prefix) + name the font name, exactly as given in the PDF file (potentially in- + cluding a subset prefix) type the font type -- see below for details @@ -102,10 +102,12 @@ EXIT CODES 3 Error related to PDF permissions. + 98 Out of memory. + 99 Other error. AUTHOR - The pdffonts software and documentation are copyright 1996-2022 Glyph & + The pdffonts software and documentation are copyright 1996-2025 Glyph & Cog, LLC. SEE ALSO @@ -115,4 +117,4 @@ SEE ALSO - 18 Apr 2022 pdffonts(1) + 14 Nov 2025 pdffonts(1) diff --git a/src/xpdf-4.04/doc/pdfimages.1 b/src/xpdf-4.06/doc/pdfimages.1 old mode 100644 new mode 100755 similarity index 77% rename from src/xpdf-4.04/doc/pdfimages.1 rename to src/xpdf-4.06/doc/pdfimages.1 index 06a9c1f..3a9a13e --- a/src/xpdf-4.04/doc/pdfimages.1 +++ b/src/xpdf-4.06/doc/pdfimages.1 @@ -1,8 +1,8 @@ -.\" Copyright 1998-2022 Glyph & Cog, LLC -.TH pdfimages 1 "18 Apr 2022" +.\" Copyright 1998-2025 Glyph & Cog, LLC +.TH pdfimages 1 "14 Nov 2025" .SH NAME pdfimages \- Portable Document Format (PDF) image extractor -(version 4.04) +(version 4.06) .SH SYNOPSIS .B pdfimages [options] @@ -51,18 +51,34 @@ option, images in DCT format are saved as JPEG files. All non-DCT images are saved in PBM/PGM/PPM format as usual. (Inline images are always saved in PBM/PGM/PPM format.) .TP +.B \-J +Write JPX / JPEG 2000 images as JPEG 2000 files (similar to "-j", but +for JPEG 2000). +.TP .B \-raw Write all images in PDF-native formats. Most of the formats are not standard image formats, so this option is primarily useful as input to a tool that generates PDF files. (Inline images are always saved in PBM/PGM/PPM format.) .TP +.B \-u +Write only one copy of each unique image. If the same image is used +multiple times, possibly across multiple pages, pdfimages will only +write one image file. "Uniqueness" is determined by looking for reuse +of image objects withiin the PDF file; if multiiple copies of an image +are embedded, pdfimages will treat them as separate, unique images. +.TP .B \-list Write a one-line summary to stdout for each image. The summary provides the image file name, the page number, the image width and height, the horizontal and vertical resolution (DPI) as drawn, the color space type, and the number of bits per component (BPC). .TP +.B \-listonly +Write a one-line summary to stdout for each image (similar to +"-list"), but do not generate any image files. If this option is used, +the "image-root" argument must not be provided. +.TP .BI \-opw " password" Specify the owner password for the PDF file. Providing this will bypass all security restrictions. @@ -78,6 +94,11 @@ Print a status message (to stdout) before processing each page. Don't print any messages or errors. .RB "[config file: " errQuiet ] .TP +.BI \-cfg " config-file" +Read +.I config-file +in place of ~/.xpdfrc or the system-wide config file. +.TP .B \-v Print copyright and version information. .TP @@ -102,10 +123,13 @@ Error opening an output file. 3 Error related to PDF permissions. .TP +98 +Out of memory. +.TP 99 Other error. .SH AUTHOR -The pdfimages software and documentation are copyright 1998-2022 Glyph +The pdfimages software and documentation are copyright 1998-2025 Glyph & Cog, LLC. .SH "SEE ALSO" .BR xpdf (1), diff --git a/src/xpdf-4.04/doc/pdfimages.cat b/src/xpdf-4.06/doc/pdfimages.cat old mode 100644 new mode 100755 similarity index 73% rename from src/xpdf-4.04/doc/pdfimages.cat rename to src/xpdf-4.06/doc/pdfimages.cat index 7361a3b..4815b45 --- a/src/xpdf-4.04/doc/pdfimages.cat +++ b/src/xpdf-4.06/doc/pdfimages.cat @@ -4,7 +4,7 @@ pdfimages(1) General Commands Manual pdfimages(1) NAME pdfimages - Portable Document Format (PDF) image extractor (version - 4.04) + 4.06) SYNOPSIS pdfimages [options] PDF-file image-root @@ -47,17 +47,32 @@ OPTIONS All non-DCT images are saved in PBM/PGM/PPM format as usual. (Inline images are always saved in PBM/PGM/PPM format.) + -J Write JPX / JPEG 2000 images as JPEG 2000 files (similar to + "-j", but for JPEG 2000). + -raw Write all images in PDF-native formats. Most of the formats are - not standard image formats, so this option is primarily useful + not standard image formats, so this option is primarily useful as input to a tool that generates PDF files. (Inline images are always saved in PBM/PGM/PPM format.) + -u Write only one copy of each unique image. If the same image is + used multiple times, possibly across multiple pages, pdfimages + will only write one image file. "Uniqueness" is determined by + looking for reuse of image objects withiin the PDF file; if mul- + tiiple copies of an image are embedded, pdfimages will treat + them as separate, unique images. + -list Write a one-line summary to stdout for each image. The summary provides the image file name, the page number, the image width and height, the horizontal and vertical resolution (DPI) as drawn, the color space type, and the number of bits per compo- nent (BPC). + -listonly + Write a one-line summary to stdout for each image (similar to + "-list"), but do not generate any image files. If this option is + used, the "image-root" argument must not be provided. + -opw password Specify the owner password for the PDF file. Providing this will bypass all security restrictions. @@ -71,6 +86,10 @@ OPTIONS -q Don't print any messages or errors. [config file: errQuiet] + -cfg config-file + Read config-file in place of ~/.xpdfrc or the system-wide config + file. + -v Print copyright and version information. -h Print usage information. (-help and --help are equivalent.) @@ -86,17 +105,19 @@ EXIT CODES 3 Error related to PDF permissions. + 98 Out of memory. + 99 Other error. AUTHOR - The pdfimages software and documentation are copyright 1998-2022 Glyph + The pdfimages software and documentation are copyright 1998-2025 Glyph & Cog, LLC. SEE ALSO - xpdf(1), pdftops(1), pdftotext(1), pdftohtml(1), pdfinfo(1), pdf- + xpdf(1), pdftops(1), pdftotext(1), pdftohtml(1), pdfinfo(1), pdf- fonts(1), pdfdetach(1), pdftoppm(1), pdftopng(1), xpdfrc(5) http://www.xpdfreader.com/ - 18 Apr 2022 pdfimages(1) + 14 Nov 2025 pdfimages(1) diff --git a/src/xpdf-4.04/doc/pdfinfo.1 b/src/xpdf-4.06/doc/pdfinfo.1 old mode 100644 new mode 100755 similarity index 90% rename from src/xpdf-4.04/doc/pdfinfo.1 rename to src/xpdf-4.06/doc/pdfinfo.1 index 66f3e70..807c2e7 --- a/src/xpdf-4.04/doc/pdfinfo.1 +++ b/src/xpdf-4.06/doc/pdfinfo.1 @@ -1,8 +1,8 @@ -.\" Copyright 1999-2022 Glyph & Cog, LLC -.TH pdfinfo 1 "18 Apr 2022" +.\" Copyright 1999-2025 Glyph & Cog, LLC +.TH pdfinfo 1 "14 Nov 2025" .SH NAME pdfinfo \- Portable Document Format (PDF) document information -extractor (version 4.04) +extractor (version 4.06) .SH SYNOPSIS .B pdfinfo [options] @@ -63,7 +63,10 @@ page size and rotation file size .RE .RS -linearized (yes/no) +optimized (aka linearized) (yes/no) +.RE +.RS +uses JavaScript (yes/no) .RE .RS PDF version @@ -103,6 +106,9 @@ the PDF file's Catalog object.) .B \-rawdates Prints the raw (undecoded) date strings, directly from the PDF file. .TP +.B \-custom +Prints any custom (non-standard) entries in the \'Info' dictionary. +.TP .BI \-enc " encoding-name" Sets the encoding to use for text output. The .I encoding\-name @@ -147,10 +153,13 @@ Error opening an output file. 3 Error related to PDF permissions. .TP +98 +Out of memory. +.TP 99 Other error. .SH AUTHOR -The pdfinfo software and documentation are copyright 1996-2022 Glyph & +The pdfinfo software and documentation are copyright 1996-2025 Glyph & Cog, LLC. .SH "SEE ALSO" .BR xpdf (1), diff --git a/src/xpdf-4.04/doc/pdfinfo.cat b/src/xpdf-4.06/doc/pdfinfo.cat old mode 100644 new mode 100755 similarity index 74% rename from src/xpdf-4.04/doc/pdfinfo.cat rename to src/xpdf-4.06/doc/pdfinfo.cat index 05dbc38..b51c83d --- a/src/xpdf-4.04/doc/pdfinfo.cat +++ b/src/xpdf-4.06/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.04) + (version 4.06) SYNOPSIS pdfinfo [options] [PDF-file] @@ -33,7 +33,8 @@ DESCRIPTION print and copy permissions (if encrypted) page size and rotation file size - linearized (yes/no) + optimized (aka linearized) (yes/no) + uses JavaScript (yes/no) PDF version metadata (only if requested) @@ -50,10 +51,10 @@ OPTIONS corresponding command line option. -f number - Specifies the first page to examine. If multiple pages are - requested using the "-f" and "-l" options, the size of each - requested page (and, optionally, the bounding boxes for each - requested page) are printed. Otherwise, only page one is exam- + Specifies the first page to examine. If multiple pages are re- + quested using the "-f" and "-l" options, the size of each re- + quested page (and, optionally, the bounding boxes for each re- + quested page) are printed. Otherwise, only page one is exam- ined. -l number @@ -69,14 +70,18 @@ OPTIONS Prints the raw (undecoded) date strings, directly from the PDF file. + -custom + Prints any custom (non-standard) entries in the 'Info' dictio- + nary. + -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] -opw password - Specify the owner password for the PDF file. Providing this + Specify the owner password for the PDF file. Providing this will bypass all security restrictions. -upw password @@ -101,17 +106,19 @@ EXIT CODES 3 Error related to PDF permissions. + 98 Out of memory. + 99 Other error. AUTHOR - The pdfinfo software and documentation are copyright 1996-2022 Glyph & + The pdfinfo software and documentation are copyright 1996-2025 Glyph & Cog, LLC. SEE ALSO - xpdf(1), pdftops(1), pdftotext(1), pdftohtml(1), pdffonts(1), pdfde- + xpdf(1), pdftops(1), pdftotext(1), pdftohtml(1), pdffonts(1), pdfde- tach(1), pdftoppm(1), pdftopng(1), pdfimages(1), xpdfrc(5) http://www.xpdfreader.com/ - 18 Apr 2022 pdfinfo(1) + 14 Nov 2025 pdfinfo(1) diff --git a/src/xpdf-4.04/doc/pdftohtml.1 b/src/xpdf-4.06/doc/pdftohtml.1 old mode 100644 new mode 100755 similarity index 85% rename from src/xpdf-4.04/doc/pdftohtml.1 rename to src/xpdf-4.06/doc/pdftohtml.1 index 5129f0d..2ac8726 --- a/src/xpdf-4.04/doc/pdftohtml.1 +++ b/src/xpdf-4.06/doc/pdftohtml.1 @@ -1,8 +1,8 @@ -.\" Copyright 1997-2022 Glyph & Cog, LLC -.TH pdftohtml 1 "18 Apr 2022" +.\" Copyright 1997-2025 Glyph & Cog, LLC +.TH pdftohtml 1 "14 Nov 2025" .SH NAME pdftohtml \- Portable Document Format (PDF) to HTML converter -(version 4.04) +(version 4.06) .SH SYNOPSIS .B pdftohtml [options] @@ -49,6 +49,13 @@ zoom level is controlled by the \'-z' option. Specifying a larger \'-r' value will allow the viewer to zoom in farther without upscaling artifacts in the background. .TP +.B \-noframe +The default is to generate an \'index.html\' page with a sidebar +listing all of the pages and a viewing area containing the current +page in an HTML iframe. This option switches back to the older +(pre-4.06) behavior of generating a very simple index page that just +has links to the pages. +.TP .BI \-vstretch " number" Specifies a vertical stretch factor. Setting this to a value greater than 1.0 will stretch each page vertically, spreading out the lines. @@ -84,12 +91,21 @@ Convert AcroForm text and checkbox fields to HTML input elements. This also removes text (e.g., underscore characters) and erases background image content (e.g., lines or boxes) in the field areas. .TP +.B \-meta +Include PDF document metadata as 'meta' elements in the HTML header. +.TP .B \-table Use table mode when performing the underlying text extraction. This will generally produce better output when the PDF content is a full-page table. NB: This does not generate HTML tables; it just changes the way text is split up. .TP +.B \-overwrite +By default pdftohtml will not overwrite the specified output +directory. If the directory already exists, pdftohtml will exit with +an error. This option tells pdftohtml to instead overwrite the +existing directory. +.TP .BI \-opw " password" Specify the owner password for the PDF file. Providing this will bypass all security restrictions. @@ -138,10 +154,13 @@ Error opening an output file. 3 Error related to PDF permissions. .TP +98 +Out of memory. +.TP 99 Other error. .SH AUTHOR -The pdftohtml software and documentation are copyright 1996-2022 Glyph +The pdftohtml software and documentation are copyright 1996-2025 Glyph & Cog, LLC. .SH "SEE ALSO" .BR xpdf (1), diff --git a/src/xpdf-4.04/doc/pdftohtml.cat b/src/xpdf-4.06/doc/pdftohtml.cat old mode 100644 new mode 100755 similarity index 78% rename from src/xpdf-4.04/doc/pdftohtml.cat rename to src/xpdf-4.06/doc/pdftohtml.cat index 5ddbfa0..da9eb1f --- a/src/xpdf-4.04/doc/pdftohtml.cat +++ b/src/xpdf-4.06/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.04) + 4.06) SYNOPSIS pdftohtml [options] PDF-file HTML-dir @@ -48,6 +48,13 @@ OPTIONS larger '-r' value will allow the viewer to zoom in farther with- out upscaling artifacts in the background. + -noframe + The default is to generate an 'index.html' page with a sidebar + listing all of the pages and a viewing area containing the cur- + rent page in an HTML iframe. This option switches back to the + older (pre-4.06) behavior of generating a very simple index page + that just has links to the pages. + -vstretch number Specifies a vertical stretch factor. Setting this to a value greater than 1.0 will stretch each page vertically, spreading @@ -59,8 +66,8 @@ OPTIONS the HTML file, rather than storing it as a separate file. -nofonts - Disable extraction of embedded fonts. By default, pdftohtml - extracts TrueType and OpenType fonts. Disabling extraction can + Disable extraction of embedded fonts. By default, pdftohtml ex- + tracts TrueType and OpenType fonts. Disabling extraction can work around problems with buggy fonts. -embedfonts @@ -70,8 +77,8 @@ OPTIONS -skipinvisible Don't draw invisible text. By default, invisible text (commonly used in OCR'ed PDF files) is drawn as transparent (alpha=0) HTML - text. This option tells pdftohtml to discard invisible text - entirely. + text. This option tells pdftohtml to discard invisible text en- + tirely. -allinvisible Treat all text as invisible. By default, regular (non-invisi- @@ -86,11 +93,20 @@ OPTIONS erases background image content (e.g., lines or boxes) in the field areas. - -table Use table mode when performing the underlying text extraction. - This will generally produce better output when the PDF content - is a full-page table. NB: This does not generate HTML tables; + -meta Include PDF document metadata as 'meta' elements in the HTML + header. + + -table Use table mode when performing the underlying text extraction. + This will generally produce better output when the PDF content + is a full-page table. NB: This does not generate HTML tables; it just changes the way text is split up. + -overwrite + By default pdftohtml will not overwrite the specified output di- + rectory. If the directory already exists, pdftohtml will exit + with an error. This option tells pdftohtml to instead overwrite + the existing directory. + -opw password Specify the owner password for the PDF file. Providing this will bypass all security restrictions. @@ -128,10 +144,12 @@ EXIT CODES 3 Error related to PDF permissions. + 98 Out of memory. + 99 Other error. AUTHOR - The pdftohtml software and documentation are copyright 1996-2022 Glyph + The pdftohtml software and documentation are copyright 1996-2025 Glyph & Cog, LLC. SEE ALSO @@ -141,4 +159,4 @@ SEE ALSO - 18 Apr 2022 pdftohtml(1) + 14 Nov 2025 pdftohtml(1) diff --git a/src/xpdf-4.04/doc/pdftopng.1 b/src/xpdf-4.06/doc/pdftopng.1 old mode 100644 new mode 100755 similarity index 91% rename from src/xpdf-4.04/doc/pdftopng.1 rename to src/xpdf-4.06/doc/pdftopng.1 index 1193120..8b64734 --- a/src/xpdf-4.04/doc/pdftopng.1 +++ b/src/xpdf-4.06/doc/pdftopng.1 @@ -1,8 +1,8 @@ -.\" Copyright 2017-2022 Glyph & Cog, LLC -.TH pdftopng 1 "18 Apr 2022" +.\" Copyright 2017-2025 Glyph & Cog, LLC +.TH pdftopng 1 "14 Nov 2025" .SH NAME pdftopng \- Portable Document Format (PDF) to Portable Network Graphics -(PNG) converter (version 4.04) +(PNG) converter (version 4.06) .SH SYNOPSIS .B pdftopng [options] @@ -86,6 +86,11 @@ Print a status message (to stdout) before processing each page. Don't print any messages or errors. .RB "[config file: " errQuiet ] .TP +.BI \-cfg " config-file" +Read +.I config-file +in place of ~/.xpdfrc or the system-wide config file. +.TP .B \-v Print copyright and version information. .TP @@ -110,10 +115,13 @@ Error opening an output file. 3 Error related to PDF permissions. .TP +98 +Out of memory. +.TP 99 Other error. .SH AUTHOR -The pdftopng software and documentation are copyright 1996-2022 Glyph +The pdftopng software and documentation are copyright 1996-2025 Glyph & Cog, LLC. .SH "SEE ALSO" .BR xpdf (1), diff --git a/src/xpdf-4.04/doc/pdftopng.cat b/src/xpdf-4.06/doc/pdftopng.cat old mode 100644 new mode 100755 similarity index 90% rename from src/xpdf-4.04/doc/pdftopng.cat rename to src/xpdf-4.06/doc/pdftopng.cat index 10a4408..12a48cf --- a/src/xpdf-4.04/doc/pdftopng.cat +++ b/src/xpdf-4.06/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.04) + (PNG) converter (version 4.06) SYNOPSIS pdftopng [options] PDF-file PNG-root @@ -76,6 +76,10 @@ OPTIONS -q Don't print any messages or errors. [config file: errQuiet] + -cfg config-file + Read config-file in place of ~/.xpdfrc or the system-wide config + file. + -v Print copyright and version information. -h Print usage information. (-help and --help are equivalent.) @@ -91,17 +95,19 @@ EXIT CODES 3 Error related to PDF permissions. + 98 Out of memory. + 99 Other error. AUTHOR - The pdftopng software and documentation are copyright 1996-2022 Glyph & + The pdftopng software and documentation are copyright 1996-2025 Glyph & Cog, LLC. SEE ALSO - xpdf(1), pdftops(1), pdftotext(1), pdftohtml(1), pdfinfo(1), pdf- + xpdf(1), pdftops(1), pdftotext(1), pdftohtml(1), pdfinfo(1), pdf- fonts(1), pdfdetach(1), pdftoppm(1), pdfimages(1), xpdfrc(5) http://www.xpdfreader.com/ - 18 Apr 2022 pdftopng(1) + 14 Nov 2025 pdftopng(1) diff --git a/src/xpdf-4.04/doc/pdftoppm.1 b/src/xpdf-4.06/doc/pdftoppm.1 old mode 100644 new mode 100755 similarity index 91% rename from src/xpdf-4.04/doc/pdftoppm.1 rename to src/xpdf-4.06/doc/pdftoppm.1 index d485b2b..8ed0875 --- a/src/xpdf-4.04/doc/pdftoppm.1 +++ b/src/xpdf-4.06/doc/pdftoppm.1 @@ -1,8 +1,8 @@ -.\" Copyright 2005-2022 Glyph & Cog, LLC -.TH pdftoppm 1 "18 Apr 2022" +.\" Copyright 2005-2025 Glyph & Cog, LLC +.TH pdftoppm 1 "14 Nov 2025" .SH NAME pdftoppm \- Portable Document Format (PDF) to Portable Pixmap (PPM) -converter (version 4.04) +converter (version 4.06) .SH SYNOPSIS .B pdftoppm [options] @@ -86,6 +86,11 @@ Print a status message (to stdout) before processing each page. Don't print any messages or errors. .RB "[config file: " errQuiet ] .TP +.BI \-cfg " config-file" +Read +.I config-file +in place of ~/.xpdfrc or the system-wide config file. +.TP .B \-v Print copyright and version information. .TP @@ -110,10 +115,13 @@ Error opening an output file. 3 Error related to PDF permissions. .TP +98 +Out of memory. +.TP 99 Other error. .SH AUTHOR -The pdftoppm software and documentation are copyright 1996-2022 Glyph +The pdftoppm software and documentation are copyright 1996-2025 Glyph & Cog, LLC. .SH "SEE ALSO" .BR xpdf (1), diff --git a/src/xpdf-4.04/doc/pdftoppm.cat b/src/xpdf-4.06/doc/pdftoppm.cat old mode 100644 new mode 100755 similarity index 90% rename from src/xpdf-4.04/doc/pdftoppm.cat rename to src/xpdf-4.06/doc/pdftoppm.cat index 30d012d..0381a64 --- a/src/xpdf-4.04/doc/pdftoppm.cat +++ b/src/xpdf-4.06/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.04) + verter (version 4.06) SYNOPSIS pdftoppm [options] PDF-file PPM-root @@ -75,6 +75,10 @@ OPTIONS -q Don't print any messages or errors. [config file: errQuiet] + -cfg config-file + Read config-file in place of ~/.xpdfrc or the system-wide config + file. + -v Print copyright and version information. -h Print usage information. (-help and --help are equivalent.) @@ -90,17 +94,19 @@ EXIT CODES 3 Error related to PDF permissions. + 98 Out of memory. + 99 Other error. AUTHOR - The pdftoppm software and documentation are copyright 1996-2022 Glyph & + The pdftoppm software and documentation are copyright 1996-2025 Glyph & Cog, LLC. SEE ALSO - xpdf(1), pdftops(1), pdftotext(1), pdftohtml(1), pdfinfo(1), pdf- + xpdf(1), pdftops(1), pdftotext(1), pdftohtml(1), pdfinfo(1), pdf- fonts(1), pdfdetach(1), pdftopng(1), pdfimages(1), xpdfrc(5) http://www.xpdfreader.com/ - 18 Apr 2022 pdftoppm(1) + 14 Nov 2025 pdftoppm(1) diff --git a/src/xpdf-4.04/doc/pdftops.1 b/src/xpdf-4.06/doc/pdftops.1 old mode 100644 new mode 100755 similarity index 97% rename from src/xpdf-4.04/doc/pdftops.1 rename to src/xpdf-4.06/doc/pdftops.1 index 028e983..cb9b43a --- a/src/xpdf-4.04/doc/pdftops.1 +++ b/src/xpdf-4.06/doc/pdftops.1 @@ -1,8 +1,8 @@ -.\" Copyright 1996-2022 Glyph & Cog, LLC -.TH pdftops 1 "18 Apr 2022" +.\" Copyright 1996-2025 Glyph & Cog, LLC +.TH pdftops 1 "14 Nov 2025" .SH NAME pdftops \- Portable Document Format (PDF) to PostScript converter -(version 4.04) +(version 4.06) .SH SYNOPSIS .B pdftops [options] @@ -237,10 +237,13 @@ Error opening an output file. 3 Error related to PDF permissions. .TP +98 +Out of memory. +.TP 99 Other error. .SH AUTHOR -The pdftops software and documentation are copyright 1996-2022 Glyph & +The pdftops software and documentation are copyright 1996-2025 Glyph & Cog, LLC. .SH "SEE ALSO" .BR xpdf (1), diff --git a/src/xpdf-4.04/doc/pdftops.cat b/src/xpdf-4.06/doc/pdftops.cat old mode 100644 new mode 100755 similarity index 93% rename from src/xpdf-4.04/doc/pdftops.cat rename to src/xpdf-4.06/doc/pdftops.cat index ed1c8b7..8513012 --- a/src/xpdf-4.04/doc/pdftops.cat +++ b/src/xpdf-4.06/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.04) + sion 4.06) SYNOPSIS pdftops [options] [PDF-file [PS-file]] @@ -40,8 +40,8 @@ OPTIONS Generate Level 1 PostScript. The resulting PostScript files will be significantly larger (if they contain images), but will print on Level 1 printers. This also converts all images to - black and white. No more than one of the PostScript level - options (-level1, -level1sep, -level2, -level2sep, -level3, + black and white. No more than one of the PostScript level op- + tions (-level1, -level1sep, -level2, -level2sep, -level3, -level3sep) may be given. [config file: psLevel] -level1sep @@ -147,8 +147,8 @@ OPTIONS maller] -noshrink - Don't scale PDF pages which are larger than the paper. By - default, pages larger than the paper are shrunk to fit. [config + Don't scale PDF pages which are larger than the paper. By de- + fault, pages larger than the paper are shrunk to fit. [config file: psShrinkLarger] -nocenter @@ -162,8 +162,8 @@ OPTIONS Box is used as the page size. [config file: psUseCropBoxAsPage] -userunit - Honor the UserUnit settings on PDF pages when computing - page/paper size. By default, pdftops ignores UserUnit. + Honor the UserUnit settings on PDF pages when computing page/pa- + per size. By default, pdftops ignores UserUnit. -duplex Set the Duplex pagedevice entry in the PostScript file. This @@ -202,10 +202,12 @@ EXIT CODES 3 Error related to PDF permissions. + 98 Out of memory. + 99 Other error. AUTHOR - The pdftops software and documentation are copyright 1996-2022 Glyph & + The pdftops software and documentation are copyright 1996-2025 Glyph & Cog, LLC. SEE ALSO @@ -215,4 +217,4 @@ SEE ALSO - 18 Apr 2022 pdftops(1) + 14 Nov 2025 pdftops(1) diff --git a/src/xpdf-4.04/doc/pdftotext.1 b/src/xpdf-4.06/doc/pdftotext.1 old mode 100644 new mode 100755 similarity index 97% rename from src/xpdf-4.04/doc/pdftotext.1 rename to src/xpdf-4.06/doc/pdftotext.1 index e5e7d65..f4ad050 --- a/src/xpdf-4.04/doc/pdftotext.1 +++ b/src/xpdf-4.06/doc/pdftotext.1 @@ -1,8 +1,8 @@ -.\" Copyright 1997-2022 Glyph & Cog, LLC -.TH pdftotext 1 "18 Apr 2022" +.\" Copyright 1997-2025 Glyph & Cog, LLC +.TH pdftotext 1 "14 Nov 2025" .SH NAME pdftotext \- Portable Document Format (PDF) to text converter -(version 4.04) +(version 4.06) .SH SYNOPSIS .B pdftotext [options] @@ -202,10 +202,13 @@ Error opening an output file. 3 Error related to PDF permissions. .TP +98 +Out of memory. +.TP 99 Other error. .SH AUTHOR -The pdftotext software and documentation are copyright 1996-2022 Glyph +The pdftotext software and documentation are copyright 1996-2025 Glyph & Cog, LLC. .SH "SEE ALSO" .BR xpdf (1), diff --git a/src/xpdf-4.04/doc/pdftotext.cat b/src/xpdf-4.06/doc/pdftotext.cat old mode 100644 new mode 100755 similarity index 96% rename from src/xpdf-4.04/doc/pdftotext.cat rename to src/xpdf-4.06/doc/pdftotext.cat index face257..8e2e996 --- a/src/xpdf-4.04/doc/pdftotext.cat +++ b/src/xpdf-4.06/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.04) + 4.06) SYNOPSIS pdftotext [options] [PDF-file [text-file]] @@ -55,8 +55,8 @@ OPTIONS -table Table mode is similar to physical layout mode, but optimized for tabular data, with the goal of keeping rows and columns aligned (at the expense of inserting extra whitespace). If the -fixed - option is given, character spacing within each line will be - determined by the specified character pitch. + option is given, character spacing within each line will be de- + termined by the specified character pitch. -lineprinter Line printer mode uses a strict fixed-character-pitch and @@ -168,10 +168,12 @@ EXIT CODES 3 Error related to PDF permissions. + 98 Out of memory. + 99 Other error. AUTHOR - The pdftotext software and documentation are copyright 1996-2022 Glyph + The pdftotext software and documentation are copyright 1996-2025 Glyph & Cog, LLC. SEE ALSO @@ -181,4 +183,4 @@ SEE ALSO - 18 Apr 2022 pdftotext(1) + 14 Nov 2025 pdftotext(1) diff --git a/src/xpdf-4.04/doc/sample-xpdfrc b/src/xpdf-4.06/doc/sample-xpdfrc old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/doc/sample-xpdfrc rename to src/xpdf-4.06/doc/sample-xpdfrc diff --git a/src/xpdf-4.04/doc/xpdf.1 b/src/xpdf-4.06/doc/xpdf.1 old mode 100644 new mode 100755 similarity index 95% rename from src/xpdf-4.04/doc/xpdf.1 rename to src/xpdf-4.06/doc/xpdf.1 index 2eaa95a..97b9cc4 --- a/src/xpdf-4.04/doc/xpdf.1 +++ b/src/xpdf-4.06/doc/xpdf.1 @@ -1,7 +1,7 @@ -.\" Copyright 1996-2022 Glyph & Cog, LLC -.TH xpdf 1 "18 Apr 2022" +.\" Copyright 1996-2025 Glyph & Cog, LLC +.TH xpdf 1 "14 Nov 2025" .SH NAME -xpdf \- Portable Document Format (PDF) file viewer (version 4.04) +xpdf \- Portable Document Format (PDF) file viewer (version 4.06) .SH SYNOPSIS .B xpdf [options] @@ -146,7 +146,7 @@ password. Open xpdf in full-screen mode, useful for presentations. .TP .BI \-remote " remote-name" -Start Xpdf in remote server mode. See the REMOVE SERVER MODE section. +Start Xpdf in remote server mode. See the REMOTE SERVER MODE section. .TP .BI \-display " display" Set the X display (only available with X11). @@ -221,8 +221,9 @@ Find the next occurrence of the search string. Find the previous occurrence of the search string. .TP .B "find settings button" -Display the current find settings: case sensitive (on/off), find whole -words (on/off). +Display the current find settings: case insensitive, case sensitive, +smart case (case sensitive only if the search string contains +uppercase characters), find whole words. .PP .SS Menu bar The menu bar is above the toolbar. The menu items should be @@ -564,6 +565,10 @@ Switch to horizontal continuous view mode. Set linear selection mode. In this mode, the selection follows text. Non-text regions cannot be selected. .TP +.B loadSession +Load the session from the session save file. The path for the session file is specified with the sessionFile setting (see +.BR xpdfrc (5)). +.TP .BI loadTabState Load the tab state file (which was written via the saveTabState command), and restore the tabs listed in that file. The path for the @@ -585,6 +590,9 @@ Go to the next page, with the current relative scroll position. .B nextTab Switch to the next tab. .TP +.B normalVideoMode +Switch to normal video mode (the opposite of reverse video mode). +.TP .B open Open a PDF file in the current tab, using the open dialog. .TP @@ -678,6 +686,9 @@ Bring the xpdf window to the front. .B reload Reload the current PDF file. .TP +.B reverseVideoMode +Switch to reverse video mode. +.TP .B rotateCCW Rotate the page 90 degrees counterclockwise. .TP @@ -706,6 +717,7 @@ command string: (or 0 if there is no selection) %Y => selection lower-right y coordinate (or 0 if there is no selection) + %t => selected text (limited to 500 characters) %i => page containing the mouse pointer %j => x coordinate of the mouse pointer %k => y coordinate of the mouse pointer @@ -730,6 +742,13 @@ Save PDF via a file requester. .B saveImage Open the \'save image' dialog. .TP +.B saveSession +Save the current session, consisting of all open windows and tabs, to +the session save file. This file can be loaded later with the +loadSession command. The path for the session file is specified with +the sessionFile setting (see +.BR xpdfrc (5)). +.TP .BI saveTabState Save a list of all tabs open in this window to the tab state file. For each tab, this writes the PDF file name and page number (on @@ -866,6 +885,9 @@ Toggle between full-screen and window modes. .B toggleMenuBar Toggle the menu bar between shown and hidden. .TP +.B toggleReverseVideoMode +Toggle between reverse and normal video modes. +.TP .B toggleSelectMode Toggle between block and linear selection mode. .TP @@ -928,6 +950,10 @@ For example: # has closed xpdf in the meantime, this will restart it and reopen # the file. xpdf -remote foo 'checkOpenFileAtPage(something.pdf, 7)' + + # Pass two commands to the remote instance: (1) open something.pdf + # and then (2) raise the xpdf window. + xpdf -remote foo 'openFile(something.pdf)' raise .RE .PP .SH EXIT CODES @@ -948,7 +974,7 @@ Error related to PDF permissions. 99 Other error. .SH AUTHOR -The xpdf software and documentation are copyright 1996-2022 Glyph & +The xpdf software and documentation are copyright 1996-2025 Glyph & Cog, LLC. .SH "SEE ALSO" .BR pdftops (1), diff --git a/src/xpdf-4.04/doc/xpdf.cat b/src/xpdf-4.06/doc/xpdf.cat old mode 100644 new mode 100755 similarity index 78% rename from src/xpdf-4.04/doc/xpdf.cat rename to src/xpdf-4.06/doc/xpdf.cat index ba20911..9c83292 --- a/src/xpdf-4.04/doc/xpdf.cat +++ b/src/xpdf-4.06/doc/xpdf.cat @@ -3,7 +3,7 @@ xpdf(1) General Commands Manual xpdf(1) NAME - xpdf - Portable Document Format (PDF) file viewer (version 4.04) + xpdf - Portable Document Format (PDF) file viewer (version 4.06) SYNOPSIS xpdf [options] [PDF-file [:page | +dest]] ... @@ -45,12 +45,12 @@ CONFIGURATION FILE Xpdf reads a configuration file at startup. It first tries to find the user's private config file, ~/.xpdfrc. If that doesn't exist, it looks for a system-wide config file, typically /etc/xpdfrc (but this location - can be changed when xpdf is built). See the xpdfrc(5) man page for - details. + can be changed when xpdf is built). See the xpdfrc(5) man page for de- + tails. OPTIONS - The following command line options are available. All command line - options must come before any PDF files to be opened. + The following command line options are available. All command line op- + tions must come before any PDF files to be opened. Many of the options can be set with configuration file commands. These are listed in square brackets with the description of the corresponding @@ -124,7 +124,7 @@ OPTIONS 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 REMOTE SERVER MODE section. -display display @@ -194,53 +194,54 @@ CONTROLS Find the previous occurrence of the search string. find settings button - Display the current find settings: case sensitive (on/off), find - whole words (on/off). + Display the current find settings: case insensitive, case sensi- + tive, smart case (case sensitive only if the search string con- + tains uppercase characters), find whole words. Menu bar - The menu bar is above the toolbar. The menu items should be self- - explanatory. + The menu bar is above the toolbar. The menu items should be self-ex- + planatory. Tab list 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 - In block selection mode, dragging the mouse with the left button held + In block selection mode, dragging the mouse with the left button held down will highlight an arbitrary rectangle. Shift-clicking will extend the selection. - In linear selection mode, dragging with the left button will highlight - text in reading order. Double-clicking or triple-clicking will select - a word or a line, respectively. Shift-clicking will extend the selec- + In linear selection mode, dragging with the left button will highlight + text in reading order. Double-clicking or triple-clicking will select + a word or a line, respectively. Shift-clicking will extend the selec- tion. - Selected text can be copied to the clipboard (with the edit/copy menu + Selected text can be copied to the clipboard (with the edit/copy menu item). On X11, selected text will be available in the X selection buf- fer. Links - When the mouse is over a hyperlink, the link target will be shown in a + When the mouse is over a hyperlink, the link target will be shown in a popup near the bottom of the window. Clicking on a hyperlink will jump to the link's destination. A link to - another PDF document will make xpdf load that document. A 'launch' - link to an executable program will display a dialog, and if you click - 'ok', execute the program. URL links are opened in a system-dependent + another PDF document will make xpdf load that document. A 'launch' + link to an executable program will display a dialog, and if you click + 'ok', execute the program. URL links are opened in a system-dependent way. (On UNIX, Qt uses the $BROWSER environment variable.) Mouse bindings @@ -250,19 +251,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 @@ -296,8 +297,8 @@ 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 @@ -332,11 +333,11 @@ CONTROLS Go to the last page. or - 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- or control- - Go to the next page. If is active, this maintains + Go to the next page. If is active, this maintains the relative position on the page. @@ -344,7 +345,7 @@ CONTROLS ous page. control- or control- - Go to the previous page. If is active, this main- + Go to the previous page. If is active, this main- tains the relative position on the page. Exit full-screen mode. @@ -358,26 +359,26 @@ 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 key binding, or + Full-screen mode can be exited via the default key binding, or via a binding to the windowMode or toggleFullScreenModecommand. COMMANDS Xpdf's key and mouse bindings are user-configurable, using the bind and - unbind commands in the config file (see xpdfrc(5)). The bind command - allows you to bind a key or mouse button to a sequence of one or more + unbind commands in the config file (see xpdfrc(5)). The bind command + allows you to bind a key or mouse button to a sequence of one or more commands. - In commands that take arguments (inside parentheses), special charac- - ters (namely '(', ')', ',', and '\x01') can be escaped by preceding - them with a '\x01' character. This is mostly useful in things like - scripts that need to be able to open arbitrary PDF files, using the + In commands that take arguments (inside parentheses), special charac- + ters (namely '(', ')', ',', and '\x01') can be escaped by preceding + them with a '\x01' character. This is mostly useful in things like + scripts that need to be able to open arbitrary PDF files, using the 'openFile' command. The following commands are supported: @@ -393,11 +394,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 @@ -425,7 +426,7 @@ COMMANDS copy Copy selected text to the clipboard. copyLinkTarget - Copy the target of the link under the mouse cursor to the clip- + Copy the target of the link under the mouse cursor to the clip- board. endPan End a pan operation. @@ -455,30 +456,30 @@ COMMANDS Set keyboard focus to the page number text box. followLink - Follow a hyperlink (does nothing if the mouse is not over a + Follow a hyperlink (does nothing if the mouse is not over a link). followLinkInNewTab Follow a hyperlink, opening PDF files in a new tab (does nothing - if the mouse is not over a link). For links to non-PDF files, + if the mouse is not over a link). For links to non-PDF files, this command is identical to followLink. followLinkInNewTabNoSel - Same as followLinkInNewTab, but does nothing if there is a non- + Same as followLinkInNewTab, but does nothing if there is a non- empty selection. (This is useful as a mouse button binding.) followLinkInNewWin - Follow a hyperlink, opening PDF files in a new window (does - nothing if the mouse is not over a link). For links to non-PDF + Follow a hyperlink, opening PDF files in a new window (does + nothing if the mouse is not over a link). For links to non-PDF files, this command is identical to followLink. followLinkInNewWinNoSel - Same as followLinkInNewWin, but does nothing if there is a non- + Same as followLinkInNewWin, but does nothing if there is a non- empty selection. (This is useful as a mouse button binding.) followLinkNoSel - Same as followLink, but does nothing if there is a non-empty - selection. (This is useful as a mouse button binding.) + Same as followLink, but does nothing if there is a non-empty se- + lection. (This is useful as a mouse button binding.) fullScreenMode Go to full-screen mode. @@ -510,13 +511,18 @@ COMMANDS Switch to horizontal continuous view mode. linearSelectMode - Set linear selection mode. In this mode, the selection follows + Set linear selection mode. In this mode, the selection follows text. Non-text regions cannot be selected. + loadSession + Load the session from the session save file. The path for the + session file is specified with the sessionFile setting (see + xpdfrc(5)). + loadTabState - Load the tab state file (which was written via the saveTabState - command), and restore the tabs listed in that file. The path - for the tab state file is specified with the tabStateFile set- + Load the tab state file (which was written via the saveTabState + command), and restore the tabs listed in that file. The path + for the tab state file is specified with the tabStateFile set- ting (see xpdfrc(5)). newTab Open an empty new tab. @@ -533,6 +539,10 @@ COMMANDS nextTab Switch to the next tab. + normalVideoMode + Switch to normal video mode (the opposite of reverse video + mode). + open Open a PDF file in the current tab, using the open dialog. openErrorWindow @@ -558,8 +568,8 @@ COMMANDS 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. + Open the specified file at the specified named destination. Lo- + cation 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 @@ -615,6 +625,9 @@ COMMANDS reload Reload the current PDF file. + reverseVideoMode + Switch to reverse video mode. + rotateCCW Rotate the page 90 degrees counterclockwise. @@ -642,6 +655,7 @@ COMMANDS (or 0 if there is no selection) %Y => selection lower-right y coordinate (or 0 if there is no selection) + %t => selected text (limited to 500 characters) %i => page containing the mouse pointer %j => x coordinate of the mouse pointer %k => y coordinate of the mouse pointer @@ -662,8 +676,14 @@ COMMANDS saveImage Open the 'save image' dialog. + saveSession + Save the current session, consisting of all open windows and + tabs, to the session save file. This file can be loaded later + with the loadSession command. The path for the session file is + specified with the sessionFile setting (see xpdfrc(5)). + saveTabState - Save a list of all tabs open in this window to the tab state + Save a list of all tabs open in this window to the tab state file. For each tab, this writes the PDF file name and page num- ber (on separate lines). This file can be loaded later with the loadTabState command. The path for the tab state file is speci- @@ -688,18 +708,18 @@ COMMANDS Scroll right by n pixels. scrollToBottomEdge - Scroll to the bottom edge of the last displayed page, with no + Scroll to the bottom edge of the last displayed page, with no horizontal movement. scrollToBottomRight Scroll to the bottom-right corner of the last displayed page. scrollToLeftEdge - Scroll to the left edge of the current page, with no vertical + Scroll to the left edge of the current page, with no vertical movement. scrollToRightEdge - Scroll to the right edge of the current page, with no vertical + Scroll to the right edge of the current page, with no vertical movement. scrollToTopEdge @@ -713,7 +733,7 @@ COMMANDS Scroll up by n pixels. scrollUpPrevPage(n) - Scroll up by n pixels, moving to the previous page if appropri- + Scroll up by n pixels, moving to the previous page if appropri- ate. selectLine @@ -723,7 +743,7 @@ COMMANDS Set the selection to the word at the current mouse position. setSelection(pg,ulx,uly,lrx,lry) - Set the selection to the specified coordinates on the specified + Set the selection to the specified coordinates on the specified page. showAttachmentsPane @@ -765,11 +785,11 @@ COMMANDS extending as the mouse moves. startPan - Start a pan operation at the current mouse position, which will + Start a pan operation at the current mouse position, which will scroll the document as the mouse moves. startSelection - Start a selection at the current mouse position, which will be + Start a selection at the current mouse position, which will be extended as the mouse moves. toggleContinuousMode @@ -781,6 +801,9 @@ COMMANDS toggleMenuBar Toggle the menu bar between shown and hidden. + toggleReverseVideoMode + Toggle between reverse and normal video modes. + toggleSelectMode Toggle between block and linear selection mode. @@ -788,19 +811,19 @@ 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 + Show page labels (if the PDF file has them), rather than page numbers. viewPageNumbers @@ -827,23 +850,28 @@ COMMANDS Zoom to the current selection. REMOTE SERVER MODE - Starting xpdf with the "-remote" switch puts it into remote server - mode. All remaining command line options are commands (see the COM- + Starting xpdf with the "-remote" switch puts it into remote server + mode. All remaining command line options are commands (see the COM- MANDS section). Subsequent invocations of "xpdf -remote" with the same - remote server name will send commands to the already-running instance - of xpdf. The "checkOpenFile" commands are useful here for things like + remote server name will send commands to the already-running instance + of xpdf. The "checkOpenFile" commands are useful here for things like changing pages. For example: # Start up xpdf, and open something.pdf. xpdf -remote foo 'openFile(something.pdf)' - # Switch to page 7 in the already-open something.pdf. If + # Switch to page 7 in the already-open something.pdf. If the user - # has closed xpdf in the meantime, this will restart it and + # has closed xpdf in the meantime, this will restart it and reopen # the file. xpdf -remote foo 'checkOpenFileAtPage(something.pdf, 7)' + # Pass two commands to the remote instance: (1) open some- + thing.pdf + # and then (2) raise the xpdf window. + xpdf -remote foo 'openFile(something.pdf)' raise + EXIT CODES The Xpdf tools use the following exit codes: @@ -858,7 +886,7 @@ EXIT CODES 99 Other error. AUTHOR - The xpdf software and documentation are copyright 1996-2022 Glyph & + The xpdf software and documentation are copyright 1996-2025 Glyph & Cog, LLC. SEE ALSO @@ -868,4 +896,4 @@ SEE ALSO - 18 Apr 2022 xpdf(1) + 14 Nov 2025 xpdf(1) diff --git a/src/xpdf-4.04/doc/xpdfrc.5 b/src/xpdf-4.06/doc/xpdfrc.5 old mode 100644 new mode 100755 similarity index 91% rename from src/xpdf-4.04/doc/xpdfrc.5 rename to src/xpdf-4.06/doc/xpdfrc.5 index 1c47e2e..015ecc2 --- a/src/xpdf-4.04/doc/xpdfrc.5 +++ b/src/xpdf-4.06/doc/xpdfrc.5 @@ -1,7 +1,7 @@ -.\" Copyright 2002-2022 Glyph & Cog, LLC -.TH xpdfrc 5 "18 Apr 202" +.\" Copyright 2002-2025 Glyph & Cog, LLC +.TH xpdfrc 5 "14 Nov 2025" .SH NAME -xpdfrc \- configuration file for Xpdf tools (version 4.04) +xpdfrc \- configuration file for Xpdf tools (version 4.06) .SH DESCRIPTION All of the Xpdf tools read a single configuration file. .PP @@ -448,6 +448,12 @@ information in TrueType fonts (16-bit only), if avaiable, to override the PDF ToUnicode maps. Otherwise, the ToUnicode maps are always used when present. This defaults to "no". .TP +.BI ignoreWrongSizeToUnicode " yes | no" +If set to "yes", Xpdf will ignore any ToUnicode CMaps that don't match +the font type (8-bit vs 16-bit). The PDF spec requires ToUnicode +CMaps match, and Adobe appears to ignore CMaps that don't match. This +defaults to "no" (for backward compatibility). +.TP .BI dropFont " font-name" Drop all text drawn in the specified font. To drop text drawn in unnamed fonts, use: @@ -457,6 +463,18 @@ unnamed fonts, use: .fi There can be any number of dropFont commands. +.TP +.BI separateRotatedText " yes | no" +If set to "no", pdftotext will attempt to place rotated text into the +"correct" location in the output. If set to "yes", when using reading +order mode, pdftotext will append rotated text to the end, after +unrotated text. This defaults to "no". +.TP +.BI discardCoveredText " yes | no" +If set to "yes", the xpdf tools will discard all text drawn before +("under") a full-page fill. If set to "no", such text will be marked +as invisible (only relevant for pdftohtml), but not discarded. This +defaults to "no". .SH RASTERIZER SETTINGS .TP .BR enableFreeType " yes | no" @@ -569,6 +587,17 @@ 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 +.BI zoomScaleFactor " \fIratio\fR | actual" +Zoom percentages will be scaled by this factor. By default, 100% zoom +corresponds to 72 dpi. Setting zoomScaleFactor to 1.5 will make 100% +zoom 1.5x larger, i.e., 108dpi. If this is set to \'actual', the zoom +scale factor will be computed based on the screen resolution. The +default value is 1.0. +.TP +.BI zoomValues " zoom1 zoom2 zoom3 ..." +Sets the list of zoom values (percentages) displayed in the zoom combo box. +The default list is: 25 50 75 100 110 125 150 175 200 300 400 600 800. +.TP .BR initialDisplayMode " single | continuous | sideBySideSingle | sideBySideContinuous | horizontalContinuous" Sets the initial display mode. The default setting is "continuous". .TP @@ -589,6 +618,9 @@ xpdf to use an internal default size. .BR initialSelectMode " block | linear" Sets the initial selection mode. The default setting is "linear". .TP +.BI initialMaximized " yes | no" +If set to "yes", xpdf windows open maximized. The default is "no". +.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 @@ -638,6 +670,12 @@ pages. This defaults to 10. Set the number of worker threads to be used by xpdf when rasterizing pages. This defaults to 1. .TP +.BI allowLinksToChangeZoom " yes | no" +PDF links, including outline items, can include a new zoom level. If +this setting is "yes", Xpdf changes the zoom when links are clicked; +if "no", Xpdf moves to the destination but does not change the zoom. +This defaults to "yes". +.TP .BI launchCommand " command" Sets the command executed when you click on a "launch"-type link. The intent is for the command to be a program/script which determines the @@ -740,7 +778,20 @@ want to create new key bindings for multiple contexts). Sets the file used by the loadTabState and saveTabState commands (see the .BR xpdf (1) -man page for more information). +man page for more information). The default path is ~/.xpdf.tabstate. +.TP +.BI sessionFile " path" +Sets the file used by the saveSession and loadSession commands (see +the +.BR xpdf (1) +man page for more information). The default path is ~/.xpdf.session. +When xpdf automatically saves the session via a session manager, it +appends ".managed" to the path. +.TP +.BI saveSessionOnQuit " yes | no" +If set to "yes", xpdf will automatically save the current session +(equivalent to the saveSession command) when quitting (via the menu or +a key binding). The default value is "yes". .SH MISCELLANEOUS SETTINGS .TP .BI drawAnnotations " yes | no" @@ -757,6 +808,12 @@ parse the XFA form and use certain XFA information to override AcroForm information. If set to "no", the XFA form will not be read. The default value is "yes". .TP +.BI preferXFAFieldValues " yes | no" +If set to "yes", Xpdf will use the XFA field value if present, and +fall back to the AcroForm value otherwise. If set to "no", Xpdf will +use the AcroForm value, and completely ignore the XFA value. The +default value is "yes". +.TP .BI savePageNumbers " yes | no" If set to "yes", xpdf will save the current page numbers of all open files in ~/.xpdf.pages when the files are closed (or when quitting @@ -837,7 +894,7 @@ Depending on build options, it may be placed elsewhere. This is the user's configuration file. If it exists, it will be read in place of the system-wide file. .SH AUTHOR -The Xpdf software and documentation are copyright 1996-2022 Glyph & +The Xpdf software and documentation are copyright 1996-2025 Glyph & Cog, LLC. .SH "SEE ALSO" .BR xpdf (1), diff --git a/src/xpdf-4.04/doc/xpdfrc.cat b/src/xpdf-4.06/doc/xpdfrc.cat old mode 100644 new mode 100755 similarity index 82% rename from src/xpdf-4.04/doc/xpdfrc.cat rename to src/xpdf-4.06/doc/xpdfrc.cat index c38791e..53c51c9 --- a/src/xpdf-4.04/doc/xpdfrc.cat +++ b/src/xpdf-4.06/doc/xpdfrc.cat @@ -3,7 +3,7 @@ xpdfrc(5) File Formats Manual xpdfrc(5) NAME - xpdfrc - configuration file for Xpdf tools (version 4.04) + xpdfrc - configuration file for Xpdf tools (version 4.06) DESCRIPTION All of the Xpdf tools read a single configuration file. @@ -18,8 +18,8 @@ DESCRIPTION (pdftotext.exe, xpdf.exe, etc.) The xpdfrc file consists of a series of configuration options, one per - line. Blank lines and lines starting with a '#' (comments) are - ignored. + line. Blank lines and lines starting with a '#' (comments) are ig- + nored. Arguments can be single-quoted or double-quoted, e.g., for file names that contain spaces ("aaa bbb", 'aaa bbb'). This quoting does not pro- @@ -49,8 +49,8 @@ INCLUDE FILES GENERAL FONT CONFIGURATION fontFile PDF-font-name font-file Maps a PDF font, PDF-font-name, to a font for display or Post- - Script output. The font file, font-file, can be any type - allowed in a PDF file. This command can be used for 8-bit or + Script output. The font file, font-file, can be any type al- + lowed in a PDF file. This command can be used for 8-bit or 16-bit (CID) fonts. fontDir dir @@ -80,8 +80,8 @@ POSTSCRIPT FONT CONFIGURATION When the 8-bit font PDF-font-name is used (without embedding) in a PDF file, it will be translated to the PostScript font PS-font-name, which is assumed to be resident in the printer. - Typically, PDF-font-name and PS-font-name are the same. By - default, only the Base-14 fonts are assumed to be resident. + Typically, PDF-font-name and PS-font-name are the same. By de- + fault, only the Base-14 fonts are assumed to be resident. psResidentFont16 PDF-font-name wMode PS-font-name encoding When the 16-bit (CID) font PDF-font-name with writing mode wMode @@ -140,8 +140,8 @@ POSTSCRIPT CONTROL gers are the coordinates of the lower-left and upper-right cor- ners of the imageable region, specified in points (with the ori- gin being the lower-left corner of the paper). This defaults to - the full paper size; the psPaperSize option will reset the - imageable area coordinates. + the full paper size; the psPaperSize option will reset the im- + ageable area coordinates. psCrop yes | no If set to "yes", PostScript output is cropped to the CropBox @@ -166,8 +166,8 @@ POSTSCRIPT CONTROL psCenter yes | no If set to yes, PDF pages smaller than the PostScript imageable area (after any scaling) are centered in the imageable area. - Otherwise, they are aligned at the lower-left corner of the - imageable area. This defaults to "yes". + Otherwise, they are aligned at the lower-left corner of the im- + ageable area. This defaults to "yes". psDuplex yes | no If set to "yes", the generated PostScript will set the "Duplex" @@ -187,9 +187,9 @@ POSTSCRIPT CONTROL of a long document. This defaults to "no". psOPI yes | no - If set to "yes", generates PostScript OPI comments for all - images and forms which have OPI information. This option is - only available if the Xpdf tools were compiled with OPI support. + If set to "yes", generates PostScript OPI comments for all im- + ages and forms which have OPI information. This option is only + available if the Xpdf tools were compiled with OPI support. This defaults to "no". psASCIIHex yes | no @@ -237,8 +237,8 @@ POSTSCRIPT CONTROL set to "yes", rasterization is disabled: pages will never be rasterized, even if they contain transparency. This will likely result in incorrect output for PDF files that use transparency, - and a warning message to that effect will be printed. This - defaults to "no". + and a warning message to that effect will be printed. This de- + faults to "no". fontDir dir See the description above, in the DISPLAY FONTS section. @@ -251,8 +251,8 @@ TEXT CONTROL AND CHARACTER MAPPING above). This defaults to "Latin1". textEOL unix | dos | mac - Sets the end-of-line convention to use for text output. The - options are: + Sets the end-of-line convention to use for text output. The op- + tions are: unix = LF dos = CR+LF @@ -269,8 +269,8 @@ TEXT CONTROL AND CHARACTER MAPPING textKeepTinyChars yes | no If set to "yes", text extraction will keep all characters. If set to "no", text extraction will discard tiny (smaller than 3 - point) characters after the first 50000 per page, avoiding - extremely slow run times for PDF files that use special fonts to + point) characters after the first 50000 per page, avoiding ex- + tremely slow run times for PDF files that use special fonts to do shading or cross-hatching. This defaults to "yes". nameToUnicode map-file @@ -312,9 +312,9 @@ TEXT CONTROL AND CHARACTER MAPPING in-hex out-hex1 out-hex2 ... The in-hex field is an input (incorrect) Unicode index, and the - rest of the fields are one or more output (correct) Unicode - indexes. Each occurrence of in-hex will be converted to the - specified output sequence. + rest of the fields are one or more output (correct) Unicode in- + dexes. Each occurrence of in-hex will be converted to the spec- + ified output sequence. unicodeRemapping remap-file Remap Unicode characters when doing text extraction. This spec- @@ -344,8 +344,8 @@ TEXT CONTROL AND CHARACTER MAPPING The in-start-hex and in-end-hex fields (or the single in-hex field) specify the Unicode range. The out-start-hex field (or the out-hex field) specifies the start of the output encoding - range. The length of the out-start-hex (or out-hex) string - determines the length of the output characters (e.g., UTF-8 uses + range. The length of the out-start-hex (or out-hex) string de- + termines the length of the output characters (e.g., UTF-8 uses different numbers of bytes to represent characters in different ranges). Entries must be given in increasing Unicode order. Only one file is allowed per encoding; the last specified file @@ -354,8 +354,8 @@ TEXT CONTROL AND CHARACTER MAPPING cMapDir registry-ordering dir Specifies a search directory, dir, for CMaps for the reg- - istry-ordering character collection. There can be multiple - directories for a particular collection. There are no default + istry-ordering character collection. There can be multiple di- + rectories for a particular collection. There are no default CMap directories. toUnicodeDir dir @@ -364,16 +364,16 @@ TEXT CONTROL AND CHARACTER MAPPING ToUnicode directories. mapNumericCharNames yes | no - If set to "yes", the Xpdf tools will attempt to map various - numeric character names sometimes used in font subsets. In some + If set to "yes", the Xpdf tools will attempt to map various nu- + meric character names sometimes used in font subsets. In some cases this leads to usable text, and in other cases it leads to gibberish -- there is no way for Xpdf to tell. This defaults to "yes". mapUnknownCharNames yes | no If set to "yes", and mapNumericCharNames is set to "no", the - Xpdf tools will apply a simple pass-through mapping (Unicode - index = character code) for all unrecognized glyph names. (For + Xpdf tools will apply a simple pass-through mapping (Unicode in- + dex = character code) for all unrecognized glyph names. (For CID fonts, setting mapNumericCharNames to "no" is unnecessary.) In some cases, this leads to usable text, and in other cases it leads to gibberish -- there is no way for Xpdf to tell. This @@ -395,6 +395,13 @@ TEXT CONTROL AND CHARACTER MAPPING override the PDF ToUnicode maps. Otherwise, the ToUnicode maps are always used when present. This defaults to "no". + ignoreWrongSizeToUnicode yes | no + If set to "yes", Xpdf will ignore any ToUnicode CMaps that don't + match the font type (8-bit vs 16-bit). The PDF spec requires + ToUnicode CMaps match, and Adobe appears to ignore CMaps that + don't match. This defaults to "no" (for backward compatibil- + ity). + dropFont font-name Drop all text drawn in the specified font. To drop text drawn in unnamed fonts, use: @@ -403,6 +410,18 @@ TEXT CONTROL AND CHARACTER MAPPING There can be any number of dropFont commands. + separateRotatedText yes | no + If set to "no", pdftotext will attempt to place rotated text + into the "correct" location in the output. If set to "yes", when + using reading order mode, pdftotext will append rotated text to + the end, after unrotated text. This defaults to "no". + + discardCoveredText yes | no + If set to "yes", the xpdf tools will discard all text drawn be- + fore ("under") a full-page fill. If set to "no", such text will + be marked as invisible (only relevant for pdftohtml), but not + discarded. This defaults to "no". + RASTERIZER SETTINGS enableFreeType yes | no Enables or disables use of FreeType (a TrueType / Type 1 font @@ -430,14 +449,14 @@ RASTERIZER SETTINGS "yes". antialiasPrinting yes | no - If this is "yes", bitmaps sent to the printer will be - antialiased (according to the "antialias" and "vectorAntialias" - settings). If this is "no", printed bitmaps will not be - antialiased. This defaults to "no". + If this is "yes", bitmaps sent to the printer will be an- + tialiased (according to the "antialias" and "vectorAntialias" + settings). If this is "no", printed bitmaps will not be an- + tialiased. This defaults to "no". strokeAdjust yes | no | cad - Sets the stroke adjustment mode. If set to "no", no stroke - adjustment will be done. If set to "yes", normal stroke adjust- + Sets the stroke adjustment mode. If set to "no", no stroke ad- + justment will be done. If set to "yes", normal stroke adjust- ment will be done: horizontal and vertical lines will be moved by up to half a pixel to make them look cleaner when vector anti-aliasing is enabled. If set to "cad", a slightly different @@ -520,6 +539,18 @@ VIEWER SETTINGS window at this zoom factor (which must be a percentage). The default value is based on the screen resolution. + zoomScaleFactor ratio | actual + Zoom percentages will be scaled by this factor. By default, + 100% zoom corresponds to 72 dpi. Setting zoomScaleFactor to 1.5 + will make 100% zoom 1.5x larger, i.e., 108dpi. If this is set + to 'actual', the zoom scale factor will be computed based on the + screen resolution. The default value is 1.0. + + zoomValues zoom1 zoom2 zoom3 ... + Sets the list of zoom values (percentages) displayed in the zoom + combo box. The default list is: 25 50 75 100 110 125 150 175 + 200 300 400 600 800. + initialDisplayMode single | continuous | sideBySideSingle | sideBySide- Continuous | horizontalContinuous Sets the initial display mode. The default setting is "continu- @@ -543,10 +574,14 @@ VIEWER SETTINGS Sets the initial selection mode. The default setting is "lin- ear". + initialMaximized yes | no + If set to "yes", xpdf windows open maximized. The default is + "no". + 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. matteColor color @@ -555,7 +590,7 @@ VIEWER SETTINGS a named color. fullScreenMatteColor color - Set the matte color for full-screen mode. The color can be + Set the matte color for full-screen mode. The color can be #RRGGBB (hexadecimal) or a named color. selectionColor color @@ -563,14 +598,14 @@ VIEWER SETTINGS 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". + If set to "no", xpdf's reverse-video mode inverts text and vec- + tor graphic content, but not images. If set to "yes", xpdf in- + verts images as well. The default is "no". popupMenuCmd title command ... - Add a command to the popup menu. Title is the text to be dis- - played in the menu. Command is an Xpdf command (see the COM- - MANDS section of the xpdf(1) man page for details). Multiple + Add a command to the popup menu. Title is the text to be dis- + played in the menu. Command is an Xpdf command (see the COM- + MANDS section of the xpdf(1) man page for details). Multiple commands are separated by whitespace. maxTileWidth pixels @@ -578,17 +613,23 @@ VIEWER SETTINGS ing pages. This defaults to 1500. maxTileHeight pixels - Set the maximum height of tiles to be used by xpdf when raster- + Set the maximum height of tiles to be used by xpdf when raster- izing pages. This defaults to 1500. tileCacheSize tiles - Set the maximum number of tiles to be cached by xpdf when ras- + Set the maximum number of tiles to be cached by xpdf when ras- terizing pages. This defaults to 10. workerThreads numThreads Set the number of worker threads to be used by xpdf when raster- izing pages. This defaults to 1. + allowLinksToChangeZoom yes | no + PDF links, including outline items, can include a new zoom + level. If this setting is "yes", Xpdf changes the zoom when + links are clicked; if "no", Xpdf moves to the destination but + does not change the zoom. This defaults to "yes". + launchCommand command Sets the command executed when you click on a "launch"-type link. The intent is for the command to be a program/script @@ -676,7 +717,19 @@ VIEWER SETTINGS tabStateFile path Sets the file used by the loadTabState and saveTabState commands - (see the xpdf(1) man page for more information). + (see the xpdf(1) man page for more information). The default + path is ~/.xpdf.tabstate. + + sessionFile path + Sets the file used by the saveSession and loadSession commands + (see the xpdf(1) man page for more information). The default + path is ~/.xpdf.session. When xpdf automatically saves the ses- + sion via a session manager, it appends ".managed" to the path. + + saveSessionOnQuit yes | no + If set to "yes", xpdf will automatically save the current ses- + sion (equivalent to the saveSession command) when quitting (via + the menu or a key binding). The default value is "yes". MISCELLANEOUS SETTINGS drawAnnotations yes | no @@ -693,22 +746,28 @@ MISCELLANEOUS SETTINGS ride AcroForm information. If set to "no", the XFA form will not be read. The default value is "yes". + preferXFAFieldValues yes | no + If set to "yes", Xpdf will use the XFA field value if present, + and fall back to the AcroForm value otherwise. If set to "no", + Xpdf will use the AcroForm value, and completely ignore the XFA + value. The default value is "yes". + savePageNumbers yes | no - If set to "yes", xpdf will save the current page numbers of all - open files in ~/.xpdf.pages when the files are closed (or when - quitting xpdf). Next time the file is opened, the last-viewed + If set to "yes", xpdf will save the current page numbers of all + open files in ~/.xpdf.pages when the files are closed (or when + quitting xpdf). Next time the file is opened, the last-viewed page number will be restored. The default value is "yes". printCommands yes | no - If set to "yes", drawing commands are printed as they're exe- + If set to "yes", drawing commands are printed as they're exe- cuted (useful for debugging). This defaults to "no". printStatusInfo - If set to "yes", print a status message (to stdout) before each + If set to "yes", print a status message (to stdout) before each page is processed. This defaults to "no". errQuiet yes | no - If set to "yes", this suppresses all error and warning messages + If set to "yes", this suppresses all error and warning messages from all of the Xpdf tools. This defaults to "no". EXAMPLES @@ -765,7 +824,7 @@ EXAMPLES FILES /etc/xpdfrc - This is the default location for the system-wide configuration + This is the default location for the system-wide configuration file. Depending on build options, it may be placed elsewhere. $HOME/.xpdfrc @@ -773,14 +832,14 @@ FILES read in place of the system-wide file. AUTHOR - The Xpdf software and documentation are copyright 1996-2022 Glyph & + The Xpdf software and documentation are copyright 1996-2025 Glyph & Cog, LLC. SEE ALSO - xpdf(1), pdftops(1), pdftotext(1), pdftohtml(1), pdfinfo(1), pdf- + xpdf(1), pdftops(1), pdftotext(1), pdftohtml(1), pdfinfo(1), pdf- fonts(1), pdfdetach(1), pdftoppm(1), pdftopng(1), pdfimages(1) http://www.xpdfreader.com/ - 18 Apr 202 xpdfrc(5) + 14 Nov 2025 xpdfrc(5) diff --git a/src/xpdf-4.04/fofi/CMakeLists.txt b/src/xpdf-4.06/fofi/CMakeLists.txt old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/fofi/CMakeLists.txt rename to src/xpdf-4.06/fofi/CMakeLists.txt diff --git a/src/xpdf-4.04/fofi/FoFiBase.cc b/src/xpdf-4.06/fofi/FoFiBase.cc old mode 100644 new mode 100755 similarity index 98% rename from src/xpdf-4.04/fofi/FoFiBase.cc rename to src/xpdf-4.06/fofi/FoFiBase.cc index e1951b0..73cf2f5 --- a/src/xpdf-4.04/fofi/FoFiBase.cc +++ b/src/xpdf-4.06/fofi/FoFiBase.cc @@ -8,10 +8,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include #include #include "gmem.h" diff --git a/src/xpdf-4.04/fofi/FoFiBase.h b/src/xpdf-4.06/fofi/FoFiBase.h old mode 100644 new mode 100755 similarity index 96% rename from src/xpdf-4.04/fofi/FoFiBase.h rename to src/xpdf-4.06/fofi/FoFiBase.h index c9f93eb..ffa14cf --- a/src/xpdf-4.04/fofi/FoFiBase.h +++ b/src/xpdf-4.06/fofi/FoFiBase.h @@ -11,10 +11,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #include "gtypes.h" //------------------------------------------------------------------------ diff --git a/src/xpdf-4.04/fofi/FoFiEncodings.cc b/src/xpdf-4.06/fofi/FoFiEncodings.cc old mode 100644 new mode 100755 similarity index 99% rename from src/xpdf-4.04/fofi/FoFiEncodings.cc rename to src/xpdf-4.06/fofi/FoFiEncodings.cc index 6b3debb..01ae5ac --- a/src/xpdf-4.04/fofi/FoFiEncodings.cc +++ b/src/xpdf-4.06/fofi/FoFiEncodings.cc @@ -8,10 +8,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include #include "gmempp.h" #include "FoFiEncodings.h" diff --git a/src/xpdf-4.04/fofi/FoFiEncodings.h b/src/xpdf-4.06/fofi/FoFiEncodings.h old mode 100644 new mode 100755 similarity index 95% rename from src/xpdf-4.04/fofi/FoFiEncodings.h rename to src/xpdf-4.06/fofi/FoFiEncodings.h index dd85458..6094387 --- a/src/xpdf-4.04/fofi/FoFiEncodings.h +++ b/src/xpdf-4.06/fofi/FoFiEncodings.h @@ -11,10 +11,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #include "gtypes.h" //------------------------------------------------------------------------ diff --git a/src/xpdf-4.04/fofi/FoFiIdentifier.cc b/src/xpdf-4.06/fofi/FoFiIdentifier.cc old mode 100644 new mode 100755 similarity index 99% rename from src/xpdf-4.04/fofi/FoFiIdentifier.cc rename to src/xpdf-4.06/fofi/FoFiIdentifier.cc index 4c6797b..fff1e26 --- a/src/xpdf-4.04/fofi/FoFiIdentifier.cc +++ b/src/xpdf-4.06/fofi/FoFiIdentifier.cc @@ -8,10 +8,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include #include #include @@ -843,6 +839,8 @@ static GList *getDfontFontList(FILE *f) { resNameListOffset >= resMapLength) { goto err2; } + nFonts = 0; + refListOffset = 0; for (i = 0; i < nTypes; ++i) { offset = resTypeListOffset + 2 + 8 * i; if (resMap[offset] == 0x73 && // 'sfnt' diff --git a/src/xpdf-4.04/fofi/FoFiIdentifier.h b/src/xpdf-4.06/fofi/FoFiIdentifier.h old mode 100644 new mode 100755 similarity index 97% rename from src/xpdf-4.04/fofi/FoFiIdentifier.h rename to src/xpdf-4.06/fofi/FoFiIdentifier.h index b0307a0..497be44 --- a/src/xpdf-4.04/fofi/FoFiIdentifier.h +++ b/src/xpdf-4.06/fofi/FoFiIdentifier.h @@ -11,10 +11,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - class GList; //------------------------------------------------------------------------ diff --git a/src/xpdf-4.04/fofi/FoFiTrueType.cc b/src/xpdf-4.06/fofi/FoFiTrueType.cc old mode 100644 new mode 100755 similarity index 97% rename from src/xpdf-4.04/fofi/FoFiTrueType.cc rename to src/xpdf-4.06/fofi/FoFiTrueType.cc index 57b12b1..a97b9fa --- a/src/xpdf-4.04/fofi/FoFiTrueType.cc +++ b/src/xpdf-4.06/fofi/FoFiTrueType.cc @@ -8,10 +8,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include #include #if HAVE_STD_SORT @@ -405,7 +401,7 @@ int FoFiTrueType::mapCodeToGID(int i, int c) { // to be 0xffff return 0; } - // invariant: seg[a].end < code <= seg[b].end + // invariant: seg[a].end < c <= seg[b].end while (b - a > 1 && ok) { m = (a + b) / 2; segEnd = getU16BE(pos + 14 + 2*m, &ok); @@ -439,6 +435,31 @@ int FoFiTrueType::mapCodeToGID(int i, int c) { } gid = getU16BE(pos + 10 + 2 * (c - cmapFirst), &ok); break; + case 12: + segCnt = getU32BE(pos + 12, &ok); + a = -1; + b = segCnt - 1; + segEnd = getU32BE(pos + 16 + 12*b + 4, &ok); + if (c > segEnd) { + return 0; + } + // invariant: seg[a].end < c <= seg[b].end + while (b - a > 1 && ok) { + m = (a + b) / 2; + segEnd = getU32BE(pos + 16 + 12*m + 4, &ok); + if (segEnd < c) { + a = m; + } else { + b = m; + } + } + segStart = getU32BE(pos + 16 + 12*b, &ok); + if (c < segStart) { + return 0; + } + segOffset = getU32BE(pos + 16 + 12*b + 8, &ok); + gid = segOffset + (c - segStart); + break; default: return 0; } @@ -1065,7 +1086,7 @@ GBool FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, 0, 0, 0, 0 // ulCodePageRange2 }; GBool missingCmap, missingName, missingPost, missingOS2; - GBool unsortedLoca, emptyCmap, badCmapLen, abbrevHMTX; + GBool unsortedLoca, bogusLastLoca, emptyCmap, badCmapLen, abbrevHMTX; int nZeroLengthTables, nBogusTables; int nHMetrics, advWidth, lsb; TrueTypeLoca *locaTable; @@ -1098,6 +1119,7 @@ GBool FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, // read the loca table, check to see if it's sorted locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca)); unsortedLoca = gFalse; + bogusLastLoca = gFalse; i = seekTable("loca"); pos = tables[i].offset; glyfLen = tables[seekTable("glyf")].len; @@ -1114,7 +1136,11 @@ GBool FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, unsortedLoca = gTrue; } if (i > 0 && locaTable[i].origOffset < locaTable[i-1].origOffset) { - unsortedLoca = gTrue; + if (i < nGlyphs) { + unsortedLoca = gTrue; + } else { + bogusLastLoca = gTrue; + } } // glyph descriptions must be at least 12 bytes long (nContours, // xMin, yMin, xMax, yMax, instructionLength - two bytes each); @@ -1131,6 +1157,9 @@ GBool FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, } locaTable[i].idx = i; } + if (unsortedLoca) { + bogusLastLoca = gFalse; + } // check for zero-length tables and bogus tags nZeroLengthTables = nBogusTables = 0; @@ -1188,7 +1217,8 @@ GBool FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, // if nothing is broken, just write the TTF file as is if (!missingCmap && !missingName && !missingPost && !missingOS2 && - !unsortedLoca && !emptyCmap && !badCmapLen && !abbrevHMTX && + !unsortedLoca && !bogusLastLoca && + !emptyCmap && !badCmapLen && !abbrevHMTX && nZeroLengthTables == 0 && nBogusTables == 0 && !name && !codeToGID && !replacementCmapTable && !isDfont && !isTTC) { (*outputFunc)(outputStream, (char *)file, len); @@ -1236,9 +1266,21 @@ GBool FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, glyfLen = pos; } + // if only the last loca entry is bogus (less than the one before + // it), just replace it with the glyf table size -- the last entry + // is just the end of the previous glyph, i.e., not the start of a + // valid glyph + if (bogusLastLoca) { + for (i = 0; i < nGlyphs; ++i) { + locaTable[i].newOffset = locaTable[i].origOffset; + } + i = seekTable("glyf"); + locaTable[nGlyphs].newOffset = tables[i].len; + } + // compute checksums for the loca and glyf tables locaChecksum = glyfChecksum = 0; - if (unsortedLoca) { + if (unsortedLoca || bogusLastLoca) { if (locaFmt) { for (j = 0; j <= nGlyphs; ++j) { locaChecksum += locaTable[j].newOffset; @@ -1251,6 +1293,8 @@ GBool FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, } } } + } + if (unsortedLoca) { pos = tables[seekTable("glyf")].offset; for (j = 0; j < nGlyphs; ++j) { n = locaTable[j].len; @@ -1455,7 +1499,8 @@ GBool FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, newTables[j].len = sizeof(cmapTab); } else if (newTables[j].tag == cmapTag && badCmapLen) { newTables[j].len = cmapLen; - } else if (newTables[j].tag == locaTag && unsortedLoca) { + } else if (newTables[j].tag == locaTag && + (unsortedLoca || bogusLastLoca)) { newTables[j].len = (nGlyphs + 1) * (locaFmt ? 4 : 2); newTables[j].checksum = locaChecksum; } else if (newTables[j].tag == glyfTag && unsortedLoca) { @@ -1620,7 +1665,8 @@ GBool FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, (*outputFunc)(outputStream, newHHEATab, newTables[i].len); } else if (newTables[i].tag == hmtxTag && abbrevHMTX) { (*outputFunc)(outputStream, newHMTXTab, newTables[i].len); - } else if (newTables[i].tag == locaTag && unsortedLoca) { + } else if (newTables[i].tag == locaTag && + (unsortedLoca || bogusLastLoca)) { for (j = 0; j <= nGlyphs; ++j) { if (locaFmt) { locaBuf[0] = (char)(locaTable[j].newOffset >> 24); diff --git a/src/xpdf-4.04/fofi/FoFiTrueType.h b/src/xpdf-4.06/fofi/FoFiTrueType.h old mode 100644 new mode 100755 similarity index 99% rename from src/xpdf-4.04/fofi/FoFiTrueType.h rename to src/xpdf-4.06/fofi/FoFiTrueType.h index 619e1bd..568ee84 --- a/src/xpdf-4.04/fofi/FoFiTrueType.h +++ b/src/xpdf-4.06/fofi/FoFiTrueType.h @@ -11,10 +11,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #include "gtypes.h" #include "FoFiBase.h" diff --git a/src/xpdf-4.04/fofi/FoFiType1.cc b/src/xpdf-4.06/fofi/FoFiType1.cc old mode 100644 new mode 100755 similarity index 98% rename from src/xpdf-4.04/fofi/FoFiType1.cc rename to src/xpdf-4.06/fofi/FoFiType1.cc index 83ec53e..66b1932 --- a/src/xpdf-4.04/fofi/FoFiType1.cc +++ b/src/xpdf-4.06/fofi/FoFiType1.cc @@ -8,10 +8,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include #include #include "gmem.h" @@ -197,7 +193,8 @@ void FoFiType1::parse() { char *line, *line1, *p, *p2; char buf[256]; char c; - int n, code, base, i, j; + unsigned int code; + int n, base, i, j; GBool gotMatrix, startsWithDup, endsWithDup; gotMatrix = gFalse; @@ -266,7 +263,7 @@ void FoFiType1::parse() { } ++p; for (p2 = p; *p2 && *p2 != ' ' && *p2 != '\t'; ++p2) ; - if (code >= 0 && code < 256) { + if (code < 256) { c = *p2; *p2 = '\0'; gfree(encoding[code]); diff --git a/src/xpdf-4.04/fofi/FoFiType1.h b/src/xpdf-4.06/fofi/FoFiType1.h old mode 100644 new mode 100755 similarity index 96% rename from src/xpdf-4.04/fofi/FoFiType1.h rename to src/xpdf-4.06/fofi/FoFiType1.h index 4a64f24..3576391 --- a/src/xpdf-4.04/fofi/FoFiType1.h +++ b/src/xpdf-4.06/fofi/FoFiType1.h @@ -11,10 +11,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #include "gtypes.h" #include "FoFiBase.h" diff --git a/src/xpdf-4.04/fofi/FoFiType1C.cc b/src/xpdf-4.06/fofi/FoFiType1C.cc old mode 100644 new mode 100755 similarity index 96% rename from src/xpdf-4.04/fofi/FoFiType1C.cc rename to src/xpdf-4.06/fofi/FoFiType1C.cc index b6a1339..64d676b --- a/src/xpdf-4.04/fofi/FoFiType1C.cc +++ b/src/xpdf-4.06/fofi/FoFiType1C.cc @@ -8,10 +8,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include #include #include @@ -181,16 +177,16 @@ GString *FoFiType1C::getGlyphName(int gid) { GHash *FoFiType1C::getNameToGIDMap() { GHash *map; - char name[256]; + char glyphName[256]; GBool ok; int gid; map = new GHash(gTrue); for (gid = 0; gid < nGlyphs; ++gid) { ok = gTrue; - getString(charset[gid], name, &ok); + getString(charset[gid], glyphName, &ok); if (ok) { - map->add(new GString(name), gid); + map->add(new GString(glyphName), gid); } } return map; @@ -1527,7 +1523,7 @@ void FoFiType1C::cvtGlyph(int offset, int nBytes, GString *charBuf, if (nOps < 6 || nOps % 6 != 0) { //~ error(-1, "Wrong number of args (%d) to Type 2 rrcurveto", nOps); } - for (k = 0; k < nOps; k += 6) { + for (k = 0; k+5 < nOps; k += 6) { cvtNum(ops[k], charBuf); cvtNum(ops[k+1], charBuf); cvtNum(ops[k+2], charBuf); @@ -1696,9 +1692,11 @@ void FoFiType1C::cvtGlyph(int offset, int nBytes, GString *charBuf, cvtNum(ops[k+5], charBuf); charBuf->append((char)8); } - cvtNum(ops[k], charBuf); - cvtNum(ops[k+1], charBuf); - charBuf->append((char)5); + if (k+1 < nOps) { + cvtNum(ops[k], charBuf); + cvtNum(ops[k+1], charBuf); + charBuf->append((char)5); + } nOps = 0; openPath = gTrue; break; @@ -1711,13 +1709,15 @@ void FoFiType1C::cvtGlyph(int offset, int nBytes, GString *charBuf, cvtNum(ops[k+1], charBuf); charBuf->append((char)5); } - cvtNum(ops[k], charBuf); - cvtNum(ops[k+1], charBuf); - cvtNum(ops[k+2], charBuf); - cvtNum(ops[k+3], charBuf); - cvtNum(ops[k+4], charBuf); - cvtNum(ops[k+5], charBuf); - charBuf->append((char)8); + if (k+5 < nOps) { + cvtNum(ops[k], charBuf); + cvtNum(ops[k+1], charBuf); + cvtNum(ops[k+2], charBuf); + cvtNum(ops[k+3], charBuf); + cvtNum(ops[k+4], charBuf); + cvtNum(ops[k+5], charBuf); + charBuf->append((char)8); + } nOps = 0; openPath = gTrue; break; @@ -2251,43 +2251,7 @@ 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 os2Table[96], headTable[54], hheaTable[36], maxpTable[6]; Guchar nameTable[26], postTable[32]; Guchar *hmtxTable; static const char *tableTag[9] = { @@ -2307,15 +2271,118 @@ void FoFiType1C::convertToOpenType(FoFiOutputFunc outputFunc, double mat[6]; Gushort maxWidth; Guint checksum, fileChecksum; - int unitsPerEm, xMin, yMin, xMax, yMax, offset, i; + int unitsPerEm, xMin, yMin, xMax, yMax, ascent, descent, offset, i; + + 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); + ascent = yMax; + descent = -yMin; //--- CFF_ table tableData[0] = file; tableLength[0] = len; //--- OS/2 table - tableData[1] = os2Tab; - tableLength[1] = 86; + os2Table[ 0] = 0; // version + os2Table[ 1] = 4; + os2Table[ 2] = 0; // xAvgCharWidth + os2Table[ 3] = 1; + os2Table[ 4] = 0x01; // usWeightClass + os2Table[ 5] = 0x90; + os2Table[ 6] = 0; // usWidthClass + os2Table[ 7] = 5; + os2Table[ 8] = 0; // fsType + os2Table[ 9] = 0; + os2Table[10] = 0; // ySubscriptXSize + os2Table[11] = 0; + os2Table[12] = 0; // ySubscriptYSize + os2Table[13] = 0; + os2Table[14] = 0; // ySubscriptXOffset + os2Table[15] = 0; + os2Table[16] = 0; // ySubscriptYOffset + os2Table[17] = 0; + os2Table[18] = 0; // ySuperscriptXSize + os2Table[19] = 0; + os2Table[20] = 0; // ySuperscriptYSize + os2Table[21] = 0; + os2Table[22] = 0; // ySuperscriptXOffset + os2Table[23] = 0; + os2Table[24] = 0; // ySuperscriptYOffset + os2Table[25] = 0; + os2Table[26] = 0; // yStrikeoutSize + os2Table[27] = 0; + os2Table[28] = 0; // yStrikeoutPosition + os2Table[29] = 0; + os2Table[30] = 0; // sFamilyClass + os2Table[31] = 0; + os2Table[32] = 0; // panose + os2Table[33] = 0; + os2Table[34] = 0; + os2Table[35] = 0; + os2Table[36] = 0; + os2Table[37] = 0; + os2Table[38] = 0; + os2Table[39] = 0; + os2Table[40] = 0; + os2Table[41] = 0; + os2Table[42] = 0; // ulUnicodeRange1 + os2Table[43] = 0; + os2Table[44] = 0; + os2Table[45] = 0; + os2Table[46] = 0; // ulUnicodeRange2 + os2Table[47] = 0; + os2Table[48] = 0; + os2Table[49] = 0; + os2Table[50] = 0; // ulUnicodeRange3 + os2Table[51] = 0; + os2Table[52] = 0; + os2Table[53] = 0; + os2Table[54] = 0; // ulUnicodeRange4 + os2Table[55] = 0; + os2Table[56] = 0; + os2Table[57] = 0; + os2Table[58] = 0; // achVendID + os2Table[59] = 0; + os2Table[60] = 0; + os2Table[61] = 0; + os2Table[62] = 0; // fsSelection + os2Table[63] = 0; + os2Table[64] = 0; // usFirstCharIndex + os2Table[65] = 0; + os2Table[66] = 0; // usLastCharIndex + os2Table[67] = 0; + os2Table[68] = 0; // sTypoAscender + os2Table[69] = 0; + os2Table[70] = 0; // sTypoDescender + os2Table[71] = 0; + os2Table[72] = 0; // sTypoLineGap + os2Table[73] = 0; + os2Table[74] = (Guchar)(ascent >> 8); // usWinAscent + os2Table[75] = (Guchar)ascent; + os2Table[76] = (Guchar)(descent >> 8); // usWinDescent + os2Table[77] = (Guchar)descent; + os2Table[78] = 0; // ulCodePageRange1 + os2Table[79] = 0; + os2Table[80] = 0; + os2Table[81] = 1; + os2Table[82] = 0; // ulCodePageRange2 + os2Table[83] = 0; + os2Table[84] = 0; + os2Table[85] = 0; + os2Table[86] = 0; // sxHeight + os2Table[87] = 0; + os2Table[88] = 0; // sCapHeight + os2Table[89] = 0; + os2Table[90] = 0; // usDefaultChar + os2Table[91] = 0; + os2Table[92] = 0; // usBreakChar + os2Table[93] = 0; + os2Table[94] = 0; // usMaxContext + os2Table[95] = 0; + tableData[1] = os2Table; + tableLength[1] = 96; //--- cmap table tableData[2] = cmapTable; @@ -2328,18 +2395,14 @@ void FoFiType1C::convertToOpenType(FoFiOutputFunc outputFunc, } 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[ 5] = 0x01; // (needs to be non-zero) headTable[ 6] = 0x00; - headTable[ 7] = 0x00; + headTable[ 7] = 0x01; headTable[ 8] = 0x00; // checksumAdjustment headTable[ 9] = 0x00; // (set later) headTable[10] = 0x00; @@ -2390,8 +2453,8 @@ void FoFiType1C::convertToOpenType(FoFiOutputFunc outputFunc, tableLength[3] = 54; //--- hhea table - maxWidth = widths[0]; - for (i = 1; i < nWidths; ++i) { + maxWidth = 0; + for (i = 0; i < nWidths; ++i) { if (widths[i] > maxWidth) { maxWidth = widths[i]; } @@ -2659,6 +2722,10 @@ GBool FoFiType1C::parse() { return gFalse; } nFDs = fdIdx.len; + if (nFDs < 1) { + parsedOk = gFalse; + return gFalse; + } privateDicts = (Type1CPrivateDict *) gmallocn(nFDs, sizeof(Type1CPrivateDict)); for (i = 0; i < nFDs; ++i) { diff --git a/src/xpdf-4.04/fofi/FoFiType1C.h b/src/xpdf-4.06/fofi/FoFiType1C.h old mode 100644 new mode 100755 similarity index 99% rename from src/xpdf-4.04/fofi/FoFiType1C.h rename to src/xpdf-4.06/fofi/FoFiType1C.h index 15a823c..301f42d --- a/src/xpdf-4.04/fofi/FoFiType1C.h +++ b/src/xpdf-4.06/fofi/FoFiType1C.h @@ -11,10 +11,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #include "gtypes.h" #include "FoFiBase.h" diff --git a/src/xpdf-4.04/goo/CMakeLists.txt b/src/xpdf-4.06/goo/CMakeLists.txt old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/goo/CMakeLists.txt rename to src/xpdf-4.06/goo/CMakeLists.txt diff --git a/src/xpdf-4.04/goo/FixedPoint.cc b/src/xpdf-4.06/goo/FixedPoint.cc old mode 100644 new mode 100755 similarity index 98% rename from src/xpdf-4.04/goo/FixedPoint.cc rename to src/xpdf-4.06/goo/FixedPoint.cc index 503a06a..8c4c474 --- a/src/xpdf-4.04/goo/FixedPoint.cc +++ b/src/xpdf-4.06/goo/FixedPoint.cc @@ -12,10 +12,6 @@ #if USE_FIXEDPOINT -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include "gmempp.h" #include "FixedPoint.h" diff --git a/src/xpdf-4.04/goo/FixedPoint.h b/src/xpdf-4.06/goo/FixedPoint.h old mode 100644 new mode 100755 similarity index 99% rename from src/xpdf-4.04/goo/FixedPoint.h rename to src/xpdf-4.06/goo/FixedPoint.h index 9f0c324..31f2ca4 --- a/src/xpdf-4.04/goo/FixedPoint.h +++ b/src/xpdf-4.06/goo/FixedPoint.h @@ -15,10 +15,6 @@ #if USE_FIXEDPOINT -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #include #include #include "gtypes.h" diff --git a/src/xpdf-4.04/goo/GHash.cc b/src/xpdf-4.06/goo/GHash.cc old mode 100644 new mode 100755 similarity index 99% rename from src/xpdf-4.04/goo/GHash.cc rename to src/xpdf-4.06/goo/GHash.cc index e6b3244..c77a1b9 --- a/src/xpdf-4.04/goo/GHash.cc +++ b/src/xpdf-4.06/goo/GHash.cc @@ -8,10 +8,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include "gmem.h" #include "gmempp.h" #include "GString.h" diff --git a/src/xpdf-4.04/goo/GHash.h b/src/xpdf-4.06/goo/GHash.h old mode 100644 new mode 100755 similarity index 97% rename from src/xpdf-4.04/goo/GHash.h rename to src/xpdf-4.06/goo/GHash.h index 179753a..92ce226 --- a/src/xpdf-4.04/goo/GHash.h +++ b/src/xpdf-4.06/goo/GHash.h @@ -11,10 +11,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #include "gtypes.h" class GString; diff --git a/src/xpdf-4.04/goo/GList.cc b/src/xpdf-4.06/goo/GList.cc old mode 100644 new mode 100755 similarity index 94% rename from src/xpdf-4.04/goo/GList.cc rename to src/xpdf-4.06/goo/GList.cc index c194818..7aaa5d7 --- a/src/xpdf-4.04/goo/GList.cc +++ b/src/xpdf-4.06/goo/GList.cc @@ -8,10 +8,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include #include #include "gmem.h" @@ -100,6 +96,11 @@ void GList::sort(int (*cmp)(const void *obj1, const void *obj2)) { qsort(data, length, sizeof(void *), cmp); } +void GList::sort(int first, int n, + int (*cmp)(const void *ptr1, const void *ptr2)) { + qsort(data + first, n, sizeof(void *), cmp); +} + void GList::reverse() { void *t; int n, i; diff --git a/src/xpdf-4.04/goo/GList.h b/src/xpdf-4.06/goo/GList.h old mode 100644 new mode 100755 similarity index 95% rename from src/xpdf-4.04/goo/GList.h rename to src/xpdf-4.06/goo/GList.h index 0050437..ee12346 --- a/src/xpdf-4.04/goo/GList.h +++ b/src/xpdf-4.06/goo/GList.h @@ -11,10 +11,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #include "gtypes.h" //------------------------------------------------------------------------ @@ -70,6 +66,9 @@ class GList { // be double-dereferenced. void sort(int (*cmp)(const void *ptr1, const void *ptr2)); + // Sort items starting at . + void sort(int first, int n, int (*cmp)(const void *ptr1, const void *ptr2)); + // Reverse the list. void reverse(); diff --git a/src/xpdf-4.04/goo/GMutex.h b/src/xpdf-4.06/goo/GMutex.h old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/goo/GMutex.h rename to src/xpdf-4.06/goo/GMutex.h diff --git a/src/xpdf-4.04/goo/GString.cc b/src/xpdf-4.06/goo/GString.cc old mode 100644 new mode 100755 similarity index 99% rename from src/xpdf-4.04/goo/GString.cc rename to src/xpdf-4.06/goo/GString.cc index 54de35b..1e41bca --- a/src/xpdf-4.04/goo/GString.cc +++ b/src/xpdf-4.06/goo/GString.cc @@ -10,10 +10,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include #include #include @@ -416,6 +412,8 @@ GString *GString::appendfv(const char *fmt, va_list argList) { // format the argument arg = args[idx]; + str = NULL; + len = 0; switch (ft) { case fmtIntDecimal: formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 10, &str, &len); diff --git a/src/xpdf-4.04/goo/GString.h b/src/xpdf-4.06/goo/GString.h old mode 100644 new mode 100755 similarity index 98% rename from src/xpdf-4.04/goo/GString.h rename to src/xpdf-4.06/goo/GString.h index 6b342f8..2e67fd0 --- a/src/xpdf-4.04/goo/GString.h +++ b/src/xpdf-4.06/goo/GString.h @@ -13,10 +13,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #include // for LLONG_MAX and ULLONG_MAX #include #include "gtypes.h" diff --git a/src/xpdf-4.04/goo/Trace.cc b/src/xpdf-4.06/goo/Trace.cc old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/goo/Trace.cc rename to src/xpdf-4.06/goo/Trace.cc diff --git a/src/xpdf-4.04/goo/Trace.h b/src/xpdf-4.06/goo/Trace.h old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/goo/Trace.h rename to src/xpdf-4.06/goo/Trace.h diff --git a/src/xpdf-4.04/goo/gfile.cc b/src/xpdf-4.06/goo/gfile.cc old mode 100644 new mode 100755 similarity index 95% rename from src/xpdf-4.04/goo/gfile.cc rename to src/xpdf-4.06/goo/gfile.cc index 9ec8bae..69dce6e --- a/src/xpdf-4.04/goo/gfile.cc +++ b/src/xpdf-4.06/goo/gfile.cc @@ -415,6 +415,18 @@ GBool pathIsFile(const char *path) { #endif } +GBool pathIsDir(const char *path) { +#ifdef _WIN32 + wchar_t wPath[winMaxLongPath + 1]; + fileNameToUCS2(path, wPath, winMaxLongPath + 1); + DWORD attr = GetFileAttributesW(wPath); + return attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY); +#else + struct stat statBuf; + return stat(path, &statBuf) == 0 && S_ISDIR(statBuf.st_mode); +#endif +} + time_t getModTime(char *fileName) { #ifdef _WIN32 //~ should implement this, but it's (currently) only used in xpdf @@ -597,6 +609,17 @@ GString *fileNameToUTF8(wchar_t *path) { return s; } +GString *fileNameMultiByteToUTF8(char *path) { + wchar_t fileNameW[winMaxLongPath + 1]; + if (MultiByteToWideChar(CP_ACP, 0, path, -1, + fileNameW, sizeof(fileNameW) / sizeof(wchar_t))) { + return fileNameToUTF8(fileNameW); + } else { + // shouldn't happen, but just in case... + return new GString(path); + } +} + wchar_t *fileNameToUCS2(const char *path, wchar_t *out, size_t outSize) { const char *p; size_t i; @@ -671,7 +694,7 @@ void readWindowsShortcut(wchar_t *wPath, size_t wPathSize) { } hres = persistFile->Load(wPath, STGM_READ); if (FAILED(hres)) { - fprintf(stderr, "IPersistFile.Load failed: 0x%08x\n", hres); + fprintf(stderr, "IPersistFile.Load failed: 0x%08lx\n", hres); exit(1); } wchar_t target[winMaxLongPath + 1]; diff --git a/src/xpdf-4.04/goo/gfile.h b/src/xpdf-4.06/goo/gfile.h old mode 100644 new mode 100755 similarity index 95% rename from src/xpdf-4.04/goo/gfile.h rename to src/xpdf-4.06/goo/gfile.h index 202e6ee..a246b65 --- a/src/xpdf-4.04/goo/gfile.h +++ b/src/xpdf-4.06/goo/gfile.h @@ -64,6 +64,9 @@ extern GString *makePathAbsolute(GString *path); // Returns true if [path] exists and is a regular file. extern GBool pathIsFile(const char *path); +// Returns true if [path] exists and is a directory. +extern GBool pathIsDir(const char *path); + // Get the modification time for . Returns 0 if there is an // error. extern time_t getModTime(char *fileName); @@ -90,6 +93,9 @@ extern GString *fileNameToUTF8(char *path); // Convert a file name from UCS-2 to UTF-8. extern GString *fileNameToUTF8(wchar_t *path); +// Convert a file name from the OEM code page to UTF-8. +extern GString *fileNameMultiByteToUTF8(char *path); + // Convert a file name from UTF-8 to UCS-2. [out] has space for // [outSize] wchar_t elements (including the trailing zero). Returns // [out]. diff --git a/src/xpdf-4.04/goo/gmem.cc b/src/xpdf-4.06/goo/gmem.cc old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/goo/gmem.cc rename to src/xpdf-4.06/goo/gmem.cc index 7291f20..00fde9b --- a/src/xpdf-4.04/goo/gmem.cc +++ b/src/xpdf-4.06/goo/gmem.cc @@ -207,10 +207,10 @@ void *gmallocn(int nObjs, int objSize) GMEM_EXCEP { if (nObjs == 0) { return NULL; } - n = nObjs * objSize; if (objSize <= 0 || nObjs < 0 || nObjs >= INT_MAX / objSize) { gMemError("Bogus memory allocation size"); } + n = nObjs * objSize; return gmalloc(n); } @@ -281,10 +281,10 @@ void *gmallocn64(int nObjs, size_t objSize) GMEM_EXCEP { if (nObjs == 0) { return NULL; } - n = nObjs * objSize; if (nObjs < 0 || (size_t)nObjs >= SIZE_MAX / objSize) { gMemError("Bogus memory allocation size"); } + n = nObjs * objSize; return gmalloc64(n); } @@ -297,10 +297,10 @@ void *greallocn(void *p, int nObjs, int objSize) GMEM_EXCEP { } return NULL; } - n = nObjs * objSize; if (objSize <= 0 || nObjs < 0 || nObjs >= INT_MAX / objSize) { gMemError("Bogus memory allocation size"); } + n = nObjs * objSize; return grealloc(p, n); } diff --git a/src/xpdf-4.04/goo/gmem.h b/src/xpdf-4.06/goo/gmem.h old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/goo/gmem.h rename to src/xpdf-4.06/goo/gmem.h diff --git a/src/xpdf-4.04/goo/gmempp.cc b/src/xpdf-4.06/goo/gmempp.cc old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/goo/gmempp.cc rename to src/xpdf-4.06/goo/gmempp.cc diff --git a/src/xpdf-4.04/goo/gmempp.h b/src/xpdf-4.06/goo/gmempp.h old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/goo/gmempp.h rename to src/xpdf-4.06/goo/gmempp.h diff --git a/src/xpdf-4.04/goo/gtypes.h b/src/xpdf-4.06/goo/gtypes.h old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/goo/gtypes.h rename to src/xpdf-4.06/goo/gtypes.h diff --git a/src/xpdf-4.04/goo/parseargs.c b/src/xpdf-4.06/goo/parseargs.c old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/goo/parseargs.c rename to src/xpdf-4.06/goo/parseargs.c diff --git a/src/xpdf-4.04/goo/parseargs.h b/src/xpdf-4.06/goo/parseargs.h old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/goo/parseargs.h rename to src/xpdf-4.06/goo/parseargs.h diff --git a/src/xpdf-4.04/splash/CMakeLists.txt b/src/xpdf-4.06/splash/CMakeLists.txt old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/splash/CMakeLists.txt rename to src/xpdf-4.06/splash/CMakeLists.txt diff --git a/src/xpdf-4.04/splash/Splash.cc b/src/xpdf-4.06/splash/Splash.cc old mode 100644 new mode 100755 similarity index 84% rename from src/xpdf-4.04/splash/Splash.cc rename to src/xpdf-4.06/splash/Splash.cc index 4afe21b..1259b4f --- a/src/xpdf-4.04/splash/Splash.cc +++ b/src/xpdf-4.06/splash/Splash.cc @@ -8,10 +8,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include #include #include @@ -86,9 +82,12 @@ struct SplashPipe { //~ null pointers, since it's rarely used Guint *srcOverprintMaskPtr; + // alpha is shape + GBool alphaIsShape; + // special cases and result color GBool noTransparency; - GBool shapeOnly; + GBool alphaOnly; SplashPipeResultColorCtrl resultColorCtrl; // non-isolated group correction @@ -98,7 +97,8 @@ struct SplashPipe { // the "run" function void (Splash::*run)(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr); + Guchar *shapPetr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr); }; SplashPipeResultColorCtrl Splash::pipeResultColorNoAlphaBlend[] = { @@ -168,8 +168,9 @@ inline void Splash::updateModY(int y) { //------------------------------------------------------------------------ inline void Splash::pipeInit(SplashPipe *pipe, SplashPattern *pattern, - Guchar aInput, GBool usesShape, - GBool nonIsolatedGroup, GBool usesSrcOverprint) { + Guchar aInput, GBool usesShape, GBool usesAlpha, + GBool nonIsolatedGroup, GBool usesSrcOverprint, + GBool alphaIsShape) { SplashColorMode mode; mode = bitmap->mode; @@ -190,17 +191,22 @@ inline void Splash::pipeInit(SplashPipe *pipe, SplashPattern *pattern, // source overprint mask pipe->srcOverprintMaskPtr = NULL; + // alpha is shape + pipe->alphaIsShape = alphaIsShape; + // special cases pipe->noTransparency = aInput == 255 && !state->softMask && !usesShape && + !usesAlpha && !state->inNonIsolatedGroup && !state->inKnockoutGroup && !nonIsolatedGroup && state->overprintMask == 0xffffffff; - pipe->shapeOnly = aInput == 255 && + pipe->alphaOnly = aInput == 255 && !state->softMask && - usesShape && + !usesShape && + usesAlpha && !state->inNonIsolatedGroup && !state->inKnockoutGroup && !nonIsolatedGroup && @@ -221,7 +227,7 @@ inline void Splash::pipeInit(SplashPipe *pipe, SplashPattern *pattern, // select the 'run' function pipe->run = &Splash::pipeRun; - if (overprintMaskBitmap || usesSrcOverprint) { + if (shapeBitmap || overprintMaskBitmap || usesSrcOverprint) { // use Splash::pipeRun } else if (!pipe->pattern && pipe->noTransparency && !state->blendFunc) { if (mode == splashModeMono1 && !bitmap->alpha) { @@ -237,7 +243,7 @@ inline void Splash::pipeInit(SplashPipe *pipe, SplashPattern *pattern, pipe->run = &Splash::pipeRunSimpleCMYK8; #endif } - } else if (!pipe->pattern && pipe->shapeOnly && !state->blendFunc) { + } else if (!pipe->pattern && pipe->alphaOnly && !state->blendFunc) { if (mode == splashModeMono1 && !bitmap->alpha) { pipe->run = &Splash::pipeRunShapeMono1; } else if (mode == splashModeMono8 && bitmap->alpha) { @@ -255,8 +261,9 @@ inline void Splash::pipeInit(SplashPipe *pipe, SplashPattern *pattern, pipe->run = &Splash::pipeRunShapeNoAlphaMono8; } } else if (!pipe->pattern && !pipe->noTransparency && !state->softMask && - usesShape && - !(state->inNonIsolatedGroup && groupBackBitmap->alpha) && + usesAlpha && + !(state->inNonIsolatedGroup && (alpha0Bitmap || + parent->bitmap->alpha)) && !state->inKnockoutGroup && !state->blendFunc && !pipe->nonIsolatedGroup) { if (mode == splashModeMono1 && !bitmap->alpha) { @@ -275,7 +282,7 @@ inline void Splash::pipeInit(SplashPipe *pipe, SplashPattern *pattern, } else if (!pipe->pattern && aInput == 255 && state->softMask && - usesShape && + usesAlpha && !state->inNonIsolatedGroup && !state->inKnockoutGroup && !nonIsolatedGroup && @@ -293,8 +300,9 @@ inline void Splash::pipeInit(SplashPipe *pipe, SplashPattern *pattern, #endif } } else if (!pipe->pattern && !pipe->noTransparency && !state->softMask && - usesShape && - state->inNonIsolatedGroup && groupBackBitmap->alpha && + usesAlpha && + state->inNonIsolatedGroup && (alpha0Bitmap || + parent->bitmap->alpha) && !state->inKnockoutGroup && !state->blendFunc && !pipe->nonIsolatedGroup) { if (mode == splashModeMono8 && bitmap->alpha) { @@ -313,15 +321,18 @@ inline void Splash::pipeInit(SplashPipe *pipe, SplashPattern *pattern, // general case void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr) { - Guchar *shapePtr2; - Guchar shape, aSrc, aDest, alphaI, alphaIm1, alpha0, aResult; - SplashColor cSrc, cDest, cBlend; - Guchar shapeVal, cResult0, cResult1, cResult2, cResult3; - int cSrcStride, shapeStride, x, lastX, t; - SplashColorPtr destColorPtr; + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr) { + Guchar *shapePtr2, *alphaPtr2; + Guchar shape, alpha, fSrc, aSrc, fDest, aDest; + Guchar alphaI, alphaIm1, alpha0, fResult, aResult; + Guchar m1, m2, m3, m4; + SplashColor cSrc, cDest, c0, cBlend; + Guchar shapeVal, alphaVal, cResult0, cResult1, cResult2, cResult3; + int cSrcStride, shapeStride, alphaStride, x, lastX, t; + SplashColorPtr cBlendIn, destColorPtr; Guchar destColorMask; - Guchar *destAlphaPtr; + Guchar *destShapePtr, *destAlphaPtr; SplashColorPtr color0Ptr; Guchar color0Mask; Guchar *alpha0Ptr; @@ -330,8 +341,9 @@ void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y, Guint *overprintMaskPtr; #if SPLASH_CMYK Guchar aPrev; - SplashColor cSrc2, cDest2; + SplashColor cSrc2, cBlendIn2; #endif + int i; if (cSrcPtr && !pipe->pattern) { cSrcStride = bitmapComps; @@ -339,24 +351,46 @@ void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y, cSrcPtr = pipe->cSrcVal; cSrcStride = 0; } - if (shapePtr) { shapePtr2 = shapePtr; shapeStride = 1; + } else { + shapeVal = 0xff; + shapePtr2 = &shapeVal; + shapeStride = 0; + } + if (alphaPtr) { + alphaPtr2 = alphaPtr; + alphaStride = 1; + } else { + alphaVal = 0xff; + alphaPtr2 = &alphaVal; + alphaStride = 0; + } + + if (shapePtr) { for (; x0 <= x1; ++x0) { if (*shapePtr2) { break; } cSrcPtr += cSrcStride; ++shapePtr2; + ++alphaPtr2; + if (pipe->srcOverprintMaskPtr) { + ++pipe->srcOverprintMaskPtr; + } + } + } else if (alphaPtr) { + for (; x0 <= x1; ++x0) { + if (*alphaPtr2) { + break; + } + cSrcPtr += cSrcStride; + ++alphaPtr2; if (pipe->srcOverprintMaskPtr) { ++pipe->srcOverprintMaskPtr; } } - } else { - shapeVal = 0xff; - shapePtr2 = &shapeVal; - shapeStride = 0; } if (x0 > x1) { return; @@ -365,7 +399,7 @@ void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y, updateModY(y); lastX = x0; - useDestRow(y); + useBitmapRow(y); if (bitmap->mode == splashModeMono1) { destColorPtr = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)]; @@ -374,6 +408,11 @@ void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y, destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * bitmapComps]; destColorMask = 0; // make gcc happy } + if (shapeBitmap) { + destShapePtr = &shapeBitmap->alpha[y * shapeBitmap->alphaRowSize + x0]; + } else { + destShapePtr = NULL; + } if (bitmap->alpha) { destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; } else { @@ -387,24 +426,25 @@ void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y, if (state->inKnockoutGroup) { if (bitmap->mode == splashModeMono1) { color0Ptr = - &groupBackBitmap->data[(groupBackY + y) * groupBackBitmap->rowSize + - ((groupBackX + x0) >> 3)]; - color0Mask = (Guchar)(0x80 >> ((groupBackX + x0) & 7)); + &parent->bitmap->data[(parentOffsetY + y) * parent->bitmap->rowSize + + ((parentOffsetX + x0) >> 3)]; + color0Mask = (Guchar)(0x80 >> ((parentOffsetX + x0) & 7)); } else { color0Ptr = - &groupBackBitmap->data[(groupBackY + y) * groupBackBitmap->rowSize + - (groupBackX + x0) * bitmapComps]; + &parent->bitmap->data[(parentOffsetY + y) * parent->bitmap->rowSize + + (parentOffsetX + x0) * bitmapComps]; color0Mask = 0; // make gcc happy } } else { color0Ptr = NULL; color0Mask = 0; // make gcc happy } - if (state->inNonIsolatedGroup && groupBackBitmap->alpha) { - alpha0Ptr = - &groupBackBitmap->alpha[(groupBackY + y) - * groupBackBitmap->alphaRowSize + - (groupBackX + x0)]; + if (alpha0Bitmap) { + alpha0Ptr = &alpha0Bitmap->alpha[y * alpha0Bitmap->alphaRowSize + x0]; + } else if (state->inNonIsolatedGroup && parent->bitmap->alpha) { + alpha0Ptr = &parent->bitmap->alpha[ + (parentOffsetY + y) * parent->bitmap->alphaRowSize + + (parentOffsetX + x0)]; } else { alpha0Ptr = NULL; } @@ -414,18 +454,29 @@ void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y, overprintMaskPtr = NULL; } + // c0 is only used for non-iso knockout groups, but in some other + // cases we use m2 * c0[i], with m2=0 -- so initialize c0[i]=0 here + // to avoid valgrind warnings + for (i = 0; i < bitmapComps; ++i) { + c0[i] = 0; + } + for (x = x0; x <= x1; ++x) { - //----- shape + //----- shape and alpha shape = *shapePtr2; - if (!shape) { + alpha = *alphaPtr2; + if (!(shapePtr ? shape : alpha)) { if (bitmap->mode == splashModeMono1) { destColorPtr += destColorMask & 1; destColorMask = (Guchar)((destColorMask << 7) | (destColorMask >> 1)); } else { destColorPtr += bitmapComps; } + if (destShapePtr) { + ++destShapePtr; + } if (destAlphaPtr) { ++destAlphaPtr; } @@ -445,6 +496,7 @@ void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y, } cSrcPtr += cSrcStride; shapePtr2 += shapeStride; + alphaPtr2 += alphaStride; if (pipe->srcOverprintMaskPtr) { ++pipe->srcOverprintMaskPtr; } @@ -497,76 +549,86 @@ void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y, break; #endif } + fResult = 255; aResult = 255; } else { // if (noTransparency && !blendFunc) - //----- read destination pixel - // (or backdrop color, for knockout groups) + //----- read destination color - if (color0Ptr) { + switch (bitmap->mode) { + case splashModeMono1: + cDest[0] = (*destColorPtr & destColorMask) ? 0xff : 0x00; + break; + case splashModeMono8: + cDest[0] = *destColorPtr; + break; + case splashModeRGB8: + cDest[0] = destColorPtr[0]; + cDest[1] = destColorPtr[1]; + cDest[2] = destColorPtr[2]; + break; + case splashModeBGR8: + cDest[0] = destColorPtr[2]; + cDest[1] = destColorPtr[1]; + cDest[2] = destColorPtr[0]; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + cDest[0] = destColorPtr[0]; + cDest[1] = destColorPtr[1]; + cDest[2] = destColorPtr[2]; + cDest[3] = destColorPtr[3]; + break; +#endif + } + + //----- read backdrop color + // (only used for non-iso knockout groups) + if (color0Ptr && alpha0Ptr) { switch (bitmap->mode) { case splashModeMono1: - cDest[0] = (*color0Ptr & color0Mask) ? 0xff : 0x00; + c0[0] = (*color0Ptr & color0Mask) ? 0xff : 0x00; color0Ptr += color0Mask & 1; color0Mask = (Guchar)((color0Mask << 7) | (color0Mask >> 1)); break; case splashModeMono8: - cDest[0] = *color0Ptr++; + c0[0] = *color0Ptr++; break; case splashModeRGB8: - cDest[0] = color0Ptr[0]; - cDest[1] = color0Ptr[1]; - cDest[2] = color0Ptr[2]; + c0[0] = color0Ptr[0]; + c0[1] = color0Ptr[1]; + c0[2] = color0Ptr[2]; color0Ptr += 3; break; case splashModeBGR8: - cDest[2] = color0Ptr[0]; - cDest[1] = color0Ptr[1]; - cDest[0] = color0Ptr[2]; + c0[2] = color0Ptr[0]; + c0[1] = color0Ptr[1]; + c0[0] = color0Ptr[2]; color0Ptr += 3; break; #if SPLASH_CMYK case splashModeCMYK8: - cDest[0] = color0Ptr[0]; - cDest[1] = color0Ptr[1]; - cDest[2] = color0Ptr[2]; - cDest[3] = color0Ptr[3]; + c0[0] = color0Ptr[0]; + c0[1] = color0Ptr[1]; + c0[2] = color0Ptr[2]; + c0[3] = color0Ptr[3]; color0Ptr += 4; break; #endif } - + cBlendIn = c0; } else { + cBlendIn = cDest; + } - switch (bitmap->mode) { - case splashModeMono1: - cDest[0] = (*destColorPtr & destColorMask) ? 0xff : 0x00; - break; - case splashModeMono8: - cDest[0] = *destColorPtr; - break; - case splashModeRGB8: - cDest[0] = destColorPtr[0]; - cDest[1] = destColorPtr[1]; - cDest[2] = destColorPtr[2]; - break; - case splashModeBGR8: - cDest[0] = destColorPtr[2]; - cDest[1] = destColorPtr[1]; - cDest[2] = destColorPtr[0]; - break; -#if SPLASH_CMYK - case splashModeCMYK8: - cDest[0] = destColorPtr[0]; - cDest[1] = destColorPtr[1]; - cDest[2] = destColorPtr[2]; - cDest[3] = destColorPtr[3]; - break; -#endif - } + //----- read destination shape and alpha + if (destShapePtr) { + fDest = *destShapePtr; + } else { + fDest = 0xff; } if (destAlphaPtr) { @@ -636,26 +698,24 @@ void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y, #endif } - //----- source alpha + //----- source shape and alpha + fSrc = shape; + aSrc = div255(pipe->aInput * alpha); if (softMaskPtr) { - if (shapePtr) { - aSrc = div255(div255(pipe->aInput * *softMaskPtr++) * shape); - } else { - aSrc = div255(pipe->aInput * *softMaskPtr++); + if (pipe->alphaIsShape) { + fSrc = div255(fSrc * *softMaskPtr); } - } else if (shapePtr) { - aSrc = div255(pipe->aInput * shape); - } else { - aSrc = pipe->aInput; + aSrc = div255(aSrc * *softMaskPtr); + ++softMaskPtr; } //----- non-isolated group correction - if (pipe->nonIsolatedGroup) { + if (pipe->nonIsolatedGroup && alpha != 0) { // This path is only used when Splash::composite() is called to // composite a non-isolated group onto the backdrop. In this - // case, shape is the source (group) alpha. + // case, alpha is the source (group) alpha. // // In a nested non-isolated group, i.e., if the destination is // also a non-isolated group (state->inNonIsolatedGroup), we @@ -668,7 +728,7 @@ void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y, } else { t = aDest; } - t = (t * 255) / shape - t; + t = (t * 255) / alpha - t; switch (bitmap->mode) { #if SPLASH_CMYK case splashModeCMYK8: @@ -695,11 +755,11 @@ void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y, cSrc2[1] = (Guchar)(0xff - cSrc[1]); cSrc2[2] = (Guchar)(0xff - cSrc[2]); cSrc2[3] = (Guchar)(0xff - cSrc[3]); - cDest2[0] = (Guchar)(0xff - cDest[0]); - cDest2[1] = (Guchar)(0xff - cDest[1]); - cDest2[2] = (Guchar)(0xff - cDest[2]); - cDest2[3] = (Guchar)(0xff - cDest[3]); - (*state->blendFunc)(cSrc2, cDest2, cBlend, bitmap->mode); + cBlendIn2[0] = (Guchar)(0xff - cBlendIn[0]); + cBlendIn2[1] = (Guchar)(0xff - cBlendIn[1]); + cBlendIn2[2] = (Guchar)(0xff - cBlendIn[2]); + cBlendIn2[3] = (Guchar)(0xff - cBlendIn[3]); + (*state->blendFunc)(cSrc2, cBlendIn2, cBlend, bitmap->mode); // convert result back to subtractive cBlend[0] = (Guchar)(0xff - cBlend[0]); cBlend[1] = (Guchar)(0xff - cBlend[1]); @@ -707,41 +767,58 @@ void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y, cBlend[3] = (Guchar)(0xff - cBlend[3]); } else #endif - (*state->blendFunc)(cSrc, cDest, cBlend, bitmap->mode); + (*state->blendFunc)(cSrc, cBlendIn, cBlend, bitmap->mode); } - //----- result alpha and non-isolated group element correction + //----- result shape + + fResult = (Guchar)(fSrc + fDest - div255(fSrc * fDest)); + + //----- result alpha + // and setup for result color // alphaI = alpha_i // alphaIm1 = alpha_(i-1) if (pipe->noTransparency) { - alphaI = alphaIm1 = aResult = 255; - } else if (alpha0Ptr) { - if (color0Ptr) { - // non-isolated, knockout - aResult = aSrc; - alpha0 = *alpha0Ptr++; - alphaI = (Guchar)(aSrc + alpha0 - div255(aSrc * alpha0)); - alphaIm1 = alpha0; - } else { - // non-isolated, non-knockout + alphaI = aResult = 255; + m1 = m2 = m3 = m4 = 0; // make gcc happy + } else if (alpha0Ptr) { // non-isolated + alpha0 = *alpha0Ptr++; + if (color0Ptr) { // non-isolated, knockout + aResult = (Guchar)(div255((255 - fSrc) * aDest) + aSrc); + alphaI = (Guchar)(alpha0 + aResult - div255(alpha0 * aResult)); + alphaIm1 = (Guchar)(alpha0 + aDest - div255(alpha0 * aDest)); + m1 = div255((255 - fSrc) * alphaIm1); + m2 = div255((fSrc - aSrc) * alpha0); + m3 = div255(aSrc * (255 - alpha0)); + m4 = div255(aSrc * alpha0); + } else { // non-isolated, non-knockout aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest)); - alpha0 = *alpha0Ptr++; - alphaI = (Guchar)(aResult + alpha0 - div255(aResult * alpha0)); + alphaI = (Guchar)(alpha0 + aResult - div255(alpha0 * aResult)); alphaIm1 = (Guchar)(alpha0 + aDest - div255(alpha0 * aDest)); + m1 = alphaI - aSrc; + m2 = 0; + m3 = div255(aSrc * (255 - alphaIm1)); + m4 = div255(aSrc * alphaIm1); } } else { - if (color0Ptr) { - // isolated, knockout - aResult = aSrc; - alphaI = aSrc; - alphaIm1 = 0; - } else { - // isolated, non-knockout + if (color0Ptr) { // isolated, knockout + aResult = (Guchar)(div255((255 - fSrc) * aDest) + aSrc); + alphaI = aResult; + alphaIm1 = aDest; + m1 = div255((255 - fSrc) * alphaIm1); + m2 = 0; + m3 = aSrc; + m4 = 0; + } else { // isolated, non-knockout aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest)); alphaI = aResult; alphaIm1 = aDest; + m1 = alphaI - aSrc; + m2 = 0; + m3 = div255(aSrc * (255 - alphaIm1)); + m4 = div255(aSrc * alphaIm1); } } @@ -770,7 +847,7 @@ void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y, if (alphaI == 0) { cResult0 = 0; } else { - cResult0 = (Guchar)(((alphaI - aSrc) * cDest[0] + aSrc * cSrc[0]) + cResult0 = (Guchar)((m1 * cDest[0] + m2 * c0[0] + aSrc * cSrc[0]) / alphaI); } break; @@ -780,11 +857,11 @@ void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y, cResult1 = 0; cResult2 = 0; } else { - cResult0 = (Guchar)(((alphaI - aSrc) * cDest[0] + aSrc * cSrc[0]) + cResult0 = (Guchar)((m1 * cDest[0] + m2 * c0[0] + aSrc * cSrc[0]) / alphaI); - cResult1 = (Guchar)(((alphaI - aSrc) * cDest[1] + aSrc * cSrc[1]) + cResult1 = (Guchar)((m1 * cDest[1] + m2 * c0[1] + aSrc * cSrc[1]) / alphaI); - cResult2 = (Guchar)(((alphaI - aSrc) * cDest[2] + aSrc * cSrc[2]) + cResult2 = (Guchar)((m1 * cDest[2] + m2 * c0[2] + aSrc * cSrc[2]) / alphaI); } break; @@ -796,13 +873,13 @@ void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y, cResult2 = 0; cResult3 = 0; } else { - cResult0 = (Guchar)(((alphaI - aSrc) * cDest[0] + aSrc * cSrc[0]) + cResult0 = (Guchar)((m1 * cDest[0] + m2 * c0[0] + aSrc * cSrc[0]) / alphaI); - cResult1 = (Guchar)(((alphaI - aSrc) * cDest[1] + aSrc * cSrc[1]) + cResult1 = (Guchar)((m1 * cDest[1] + m2 * c0[1] + aSrc * cSrc[1]) / alphaI); - cResult2 = (Guchar)(((alphaI - aSrc) * cDest[2] + aSrc * cSrc[2]) + cResult2 = (Guchar)((m1 * cDest[2] + m2 * c0[2] + aSrc * cSrc[2]) / alphaI); - cResult3 = (Guchar)(((alphaI - aSrc) * cDest[3] + aSrc * cSrc[3]) + cResult3 = (Guchar)((m1 * cDest[3] + m2 * c0[2] + aSrc * cSrc[3]) / alphaI); } break; @@ -812,9 +889,8 @@ void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y, if (alphaI == 0) { cResult0 = 0; } else { - cResult0 = (Guchar)(((alphaI - aSrc) * cDest[0] + - aSrc * ((255 - alphaIm1) * cSrc[0] + - alphaIm1 * cBlend[0]) / 255) + cResult0 = (Guchar)((m1 * cDest[0] + m2 * c0[0] + + m3 * cSrc[0] + m4 * cBlend[0]) / alphaI); } break; @@ -824,17 +900,14 @@ void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y, cResult1 = 0; cResult2 = 0; } else { - cResult0 = (Guchar)(((alphaI - aSrc) * cDest[0] + - aSrc * ((255 - alphaIm1) * cSrc[0] + - alphaIm1 * cBlend[0]) / 255) + cResult0 = (Guchar)((m1 * cDest[0] + m2 * c0[0] + + m3 * cSrc[0] + m4 * cBlend[0]) / alphaI); - cResult1 = (Guchar)(((alphaI - aSrc) * cDest[1] + - aSrc * ((255 - alphaIm1) * cSrc[1] + - alphaIm1 * cBlend[1]) / 255) + cResult1 = (Guchar)((m1 * cDest[1] + m2 * c0[1] + + m3 * cSrc[1] + m4 * cBlend[1]) / alphaI); - cResult2 = (Guchar)(((alphaI - aSrc) * cDest[2] + - aSrc * ((255 - alphaIm1) * cSrc[2] + - alphaIm1 * cBlend[2]) / 255) + cResult2 = (Guchar)((m1 * cDest[2] + m2 * c0[2] + + m3 * cSrc[2] + m4 * cBlend[2]) / alphaI); } break; @@ -846,21 +919,17 @@ void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y, cResult2 = 0; cResult3 = 0; } else { - cResult0 = (Guchar)(((alphaI - aSrc) * cDest[0] + - aSrc * ((255 - alphaIm1) * cSrc[0] + - alphaIm1 * cBlend[0]) / 255) + cResult0 = (Guchar)((m1 * cDest[0] + m2 * c0[0] + + m3 * cSrc[0] + m4 * cBlend[0]) / alphaI); - cResult1 = (Guchar)(((alphaI - aSrc) * cDest[1] + - aSrc * ((255 - alphaIm1) * cSrc[1] + - alphaIm1 * cBlend[1]) / 255) + cResult1 = (Guchar)((m1 * cDest[1] + m2 * c0[1] + + m3 * cSrc[1] + m4 * cBlend[1]) / alphaI); - cResult2 = (Guchar)(((alphaI - aSrc) * cDest[2] + - aSrc * ((255 - alphaIm1) * cSrc[2] + - alphaIm1 * cBlend[2]) / 255) + cResult2 = (Guchar)((m1 * cDest[2] + m2 * c0[2] + + m3 * cSrc[2] + m4 * cBlend[2]) / alphaI); - cResult3 = (Guchar)(((alphaI - aSrc) * cDest[3] + - aSrc * ((255 - alphaIm1) * cSrc[3] + - alphaIm1 * cBlend[3]) / 255) + cResult3 = (Guchar)((m1 * cDest[3] + m2 * c0[3] + + m3 * cSrc[3] + m4 * cBlend[3]) / alphaI); } break; @@ -906,12 +975,16 @@ void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y, break; #endif } + if (destShapePtr) { + *destShapePtr++ = fResult; + } if (destAlphaPtr) { *destAlphaPtr++ = aResult; } cSrcPtr += cSrcStride; shapePtr2 += shapeStride; + alphaPtr2 += alphaStride; } // for (x ...) updateModX(lastX); @@ -921,7 +994,8 @@ void Splash::pipeRun(SplashPipe *pipe, int x0, int x1, int y, // !pipe->pattern && pipe->noTransparency && !state->blendFunc && // bitmap->mode == splashModeMono1 && !bitmap->alpha) { void Splash::pipeRunSimpleMono1(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr) { + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr) { Guchar cResult0; SplashColorPtr destColorPtr; Guchar destColorMask; @@ -941,7 +1015,7 @@ void Splash::pipeRunSimpleMono1(SplashPipe *pipe, int x0, int x1, int y, updateModX(x1); updateModY(y); - useDestRow(y); + useBitmapRow(y); destColorPtr = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)]; destColorMask = (Guchar)(0x80 >> (x0 & 7)); @@ -968,7 +1042,8 @@ void Splash::pipeRunSimpleMono1(SplashPipe *pipe, int x0, int x1, int y, // !pipe->pattern && pipe->noTransparency && !state->blendFunc && // bitmap->mode == splashModeMono8 && bitmap->alpha) { void Splash::pipeRunSimpleMono8(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr) { + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr) { SplashColorPtr destColorPtr; Guchar *destAlphaPtr; int cSrcStride, x; @@ -986,7 +1061,7 @@ void Splash::pipeRunSimpleMono8(SplashPipe *pipe, int x0, int x1, int y, updateModX(x1); updateModY(y); - useDestRow(y); + useBitmapRow(y); destColorPtr = &bitmap->data[y * bitmap->rowSize + x0]; destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; @@ -1005,7 +1080,8 @@ void Splash::pipeRunSimpleMono8(SplashPipe *pipe, int x0, int x1, int y, // !pipe->pattern && pipe->noTransparency && !state->blendFunc && // bitmap->mode == splashModeRGB8 && bitmap->alpha) { void Splash::pipeRunSimpleRGB8(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr) { + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr) { SplashColorPtr destColorPtr; Guchar *destAlphaPtr; int cSrcStride, x; @@ -1023,7 +1099,7 @@ void Splash::pipeRunSimpleRGB8(SplashPipe *pipe, int x0, int x1, int y, updateModX(x1); updateModY(y); - useDestRow(y); + useBitmapRow(y); destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0]; destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; @@ -1045,7 +1121,8 @@ void Splash::pipeRunSimpleRGB8(SplashPipe *pipe, int x0, int x1, int y, // !pipe->pattern && pipe->noTransparency && !state->blendFunc && // bitmap->mode == splashModeBGR8 && bitmap->alpha) { void Splash::pipeRunSimpleBGR8(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr) { + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr) { SplashColorPtr destColorPtr; Guchar *destAlphaPtr; int cSrcStride, x; @@ -1063,7 +1140,7 @@ void Splash::pipeRunSimpleBGR8(SplashPipe *pipe, int x0, int x1, int y, updateModX(x1); updateModY(y); - useDestRow(y); + useBitmapRow(y); destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0]; destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; @@ -1086,7 +1163,8 @@ void Splash::pipeRunSimpleBGR8(SplashPipe *pipe, int x0, int x1, int y, // !pipe->pattern && pipe->noTransparency && !state->blendFunc && // bitmap->mode == splashModeCMYK8 && bitmap->alpha) { void Splash::pipeRunSimpleCMYK8(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr) { + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr) { SplashColorPtr destColorPtr; Guchar *destAlphaPtr; int cSrcStride, x; @@ -1104,7 +1182,7 @@ void Splash::pipeRunSimpleCMYK8(SplashPipe *pipe, int x0, int x1, int y, updateModX(x1); updateModY(y); - useDestRow(y); + useBitmapRow(y); destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x0]; destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; @@ -1126,11 +1204,12 @@ void Splash::pipeRunSimpleCMYK8(SplashPipe *pipe, int x0, int x1, int y, // special case: -// !pipe->pattern && pipe->shapeOnly && !state->blendFunc && +// !pipe->pattern && pipe->alphaOnly && !state->blendFunc && // bitmap->mode == splashModeMono1 && !bitmap->alpha void Splash::pipeRunShapeMono1(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr) { - Guchar shape, aSrc, cSrc0, cDest0, cResult0; + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr) { + Guchar alpha, aSrc, cSrc0, cDest0, cResult0; SplashColorPtr destColorPtr; Guchar destColorMask; SplashScreenCursor screenCursor; @@ -1143,11 +1222,11 @@ void Splash::pipeRunShapeMono1(SplashPipe *pipe, int x0, int x1, int y, cSrcStride = 0; } for (; x0 <= x1; ++x0) { - if (*shapePtr) { + if (*alphaPtr) { break; } cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; } if (x0 > x1) { return; @@ -1156,7 +1235,7 @@ void Splash::pipeRunShapeMono1(SplashPipe *pipe, int x0, int x1, int y, updateModY(y); lastX = x0; - useDestRow(y); + useBitmapRow(y); destColorPtr = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)]; destColorMask = (Guchar)(0x80 >> (x0 & 7)); @@ -1165,13 +1244,13 @@ void Splash::pipeRunShapeMono1(SplashPipe *pipe, int x0, int x1, int y, for (x = x0; x <= x1; ++x) { - //----- shape - shape = *shapePtr; - if (!shape) { + //----- alpha + alpha = *alphaPtr; + if (!alpha) { destColorPtr += destColorMask & 1; destColorMask = (Guchar)((destColorMask << 7) | (destColorMask >> 1)); cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; continue; } lastX = x; @@ -1180,7 +1259,7 @@ void Splash::pipeRunShapeMono1(SplashPipe *pipe, int x0, int x1, int y, cSrc0 = state->grayTransfer[cSrcPtr[0]]; //----- source alpha - aSrc = shape; + aSrc = alpha; //----- special case for aSrc = 255 if (aSrc == 255) { @@ -1205,18 +1284,19 @@ void Splash::pipeRunShapeMono1(SplashPipe *pipe, int x0, int x1, int y, destColorMask = (Guchar)((destColorMask << 7) | (destColorMask >> 1)); cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; } updateModX(lastX); } // special case: -// !pipe->pattern && pipe->shapeOnly && !state->blendFunc && +// !pipe->pattern && pipe->alphaOnly && !state->blendFunc && // bitmap->mode == splashModeMono8 && bitmap->alpha void Splash::pipeRunShapeMono8(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr) { - Guchar shape, aSrc, aDest, alphaI, aResult, cSrc0, cDest0, cResult0; + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr) { + Guchar alpha, aSrc, aDest, alphaI, aResult, cSrc0, cDest0, cResult0; SplashColorPtr destColorPtr; Guchar *destAlphaPtr; int cSrcStride, x, lastX; @@ -1228,11 +1308,11 @@ void Splash::pipeRunShapeMono8(SplashPipe *pipe, int x0, int x1, int y, cSrcStride = 0; } for (; x0 <= x1; ++x0) { - if (*shapePtr) { + if (*alphaPtr) { break; } cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; } if (x0 > x1) { return; @@ -1241,20 +1321,20 @@ void Splash::pipeRunShapeMono8(SplashPipe *pipe, int x0, int x1, int y, updateModY(y); lastX = x0; - useDestRow(y); + useBitmapRow(y); destColorPtr = &bitmap->data[y * bitmap->rowSize + x0]; destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; for (x = x0; x <= x1; ++x) { - //----- shape - shape = *shapePtr; - if (!shape) { + //----- alpha + alpha = *alphaPtr; + if (!alpha) { ++destColorPtr; ++destAlphaPtr; cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; continue; } lastX = x; @@ -1263,7 +1343,7 @@ void Splash::pipeRunShapeMono8(SplashPipe *pipe, int x0, int x1, int y, cSrc0 = state->grayTransfer[cSrcPtr[0]]; //----- source alpha - aSrc = shape; + aSrc = alpha; //----- special case for aSrc = 255 if (aSrc == 255) { @@ -1297,18 +1377,19 @@ void Splash::pipeRunShapeMono8(SplashPipe *pipe, int x0, int x1, int y, *destAlphaPtr++ = aResult; cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; } updateModX(lastX); } // special case: -// !pipe->pattern && pipe->shapeOnly && !state->blendFunc && +// !pipe->pattern && pipe->alphaOnly && !state->blendFunc && // bitmap->mode == splashModeRGB8 && bitmap->alpha void Splash::pipeRunShapeRGB8(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr) { - Guchar shape, aSrc, aDest, alphaI, aResult; + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr) { + Guchar alpha, aSrc, aDest, alphaI, aResult; Guchar cSrc0, cSrc1, cSrc2; Guchar cDest0, cDest1, cDest2; Guchar cResult0, cResult1, cResult2; @@ -1323,11 +1404,11 @@ void Splash::pipeRunShapeRGB8(SplashPipe *pipe, int x0, int x1, int y, cSrcStride = 0; } for (; x0 <= x1; ++x0) { - if (*shapePtr) { + if (*alphaPtr) { break; } cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; } if (x0 > x1) { return; @@ -1336,20 +1417,20 @@ void Splash::pipeRunShapeRGB8(SplashPipe *pipe, int x0, int x1, int y, updateModY(y); lastX = x0; - useDestRow(y); + useBitmapRow(y); destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0]; destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; for (x = x0; x <= x1; ++x) { - //----- shape - shape = *shapePtr; - if (!shape) { + //----- alpha + alpha = *alphaPtr; + if (!alpha) { destColorPtr += 3; ++destAlphaPtr; cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; continue; } lastX = x; @@ -1360,7 +1441,7 @@ void Splash::pipeRunShapeRGB8(SplashPipe *pipe, int x0, int x1, int y, cSrc2 = state->rgbTransferB[cSrcPtr[2]]; //----- source alpha - aSrc = shape; + aSrc = alpha; //----- special case for aSrc = 255 if (aSrc == 255) { @@ -1405,18 +1486,19 @@ void Splash::pipeRunShapeRGB8(SplashPipe *pipe, int x0, int x1, int y, *destAlphaPtr++ = aResult; cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; } updateModX(lastX); } // special case: -// !pipe->pattern && pipe->shapeOnly && !state->blendFunc && +// !pipe->pattern && pipe->alphaOnly && !state->blendFunc && // bitmap->mode == splashModeBGR8 && bitmap->alpha void Splash::pipeRunShapeBGR8(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr) { - Guchar shape, aSrc, aDest, alphaI, aResult; + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr) { + Guchar alpha, aSrc, aDest, alphaI, aResult; Guchar cSrc0, cSrc1, cSrc2; Guchar cDest0, cDest1, cDest2; Guchar cResult0, cResult1, cResult2; @@ -1431,11 +1513,11 @@ void Splash::pipeRunShapeBGR8(SplashPipe *pipe, int x0, int x1, int y, cSrcStride = 0; } for (; x0 <= x1; ++x0) { - if (*shapePtr) { + if (*alphaPtr) { break; } cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; } if (x0 > x1) { return; @@ -1444,20 +1526,20 @@ void Splash::pipeRunShapeBGR8(SplashPipe *pipe, int x0, int x1, int y, updateModY(y); lastX = x0; - useDestRow(y); + useBitmapRow(y); destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0]; destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; for (x = x0; x <= x1; ++x) { - //----- shape - shape = *shapePtr; - if (!shape) { + //----- alpha + alpha = *alphaPtr; + if (!alpha) { destColorPtr += 3; ++destAlphaPtr; cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; continue; } lastX = x; @@ -1468,7 +1550,7 @@ void Splash::pipeRunShapeBGR8(SplashPipe *pipe, int x0, int x1, int y, cSrc2 = state->rgbTransferB[cSrcPtr[2]]; //----- source alpha - aSrc = shape; + aSrc = alpha; //----- special case for aSrc = 255 if (aSrc == 255) { @@ -1513,7 +1595,7 @@ void Splash::pipeRunShapeBGR8(SplashPipe *pipe, int x0, int x1, int y, *destAlphaPtr++ = aResult; cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; } updateModX(lastX); @@ -1521,11 +1603,12 @@ void Splash::pipeRunShapeBGR8(SplashPipe *pipe, int x0, int x1, int y, #if SPLASH_CMYK // special case: -// !pipe->pattern && pipe->shapeOnly && !state->blendFunc && +// !pipe->pattern && pipe->alphaOnly && !state->blendFunc && // bitmap->mode == splashModeCMYK8 && bitmap->alpha void Splash::pipeRunShapeCMYK8(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr) { - Guchar shape, aSrc, aDest, alphaI, aResult; + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr) { + Guchar alpha, aSrc, aDest, alphaI, aResult; Guchar cSrc0, cSrc1, cSrc2, cSrc3; Guchar cDest0, cDest1, cDest2, cDest3; Guchar cResult0, cResult1, cResult2, cResult3; @@ -1540,11 +1623,11 @@ void Splash::pipeRunShapeCMYK8(SplashPipe *pipe, int x0, int x1, int y, cSrcStride = 0; } for (; x0 <= x1; ++x0) { - if (*shapePtr) { + if (*alphaPtr) { break; } cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; } if (x0 > x1) { return; @@ -1553,20 +1636,20 @@ void Splash::pipeRunShapeCMYK8(SplashPipe *pipe, int x0, int x1, int y, updateModY(y); lastX = x0; - useDestRow(y); + useBitmapRow(y); destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x0]; destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; for (x = x0; x <= x1; ++x) { - //----- shape - shape = *shapePtr; - if (!shape) { + //----- alpha + alpha = *alphaPtr; + if (!alpha) { destColorPtr += 4; ++destAlphaPtr; cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; continue; } lastX = x; @@ -1585,7 +1668,7 @@ void Splash::pipeRunShapeCMYK8(SplashPipe *pipe, int x0, int x1, int y, cSrc3 = state->cmykTransferK[cSrcPtr[3]]; //----- source alpha - aSrc = shape; + aSrc = alpha; //----- special case for aSrc = 255 if (aSrc == 255) { @@ -1626,7 +1709,7 @@ void Splash::pipeRunShapeCMYK8(SplashPipe *pipe, int x0, int x1, int y, *destAlphaPtr++ = aResult; cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; } updateModX(lastX); @@ -1635,12 +1718,12 @@ void Splash::pipeRunShapeCMYK8(SplashPipe *pipe, int x0, int x1, int y, // special case: -// !pipe->pattern && pipe->shapeOnly && !state->blendFunc && +// !pipe->pattern && pipe->alphaOnly && !state->blendFunc && // bitmap->mode == splashModeMono8 && !bitmap->alpha void Splash::pipeRunShapeNoAlphaMono8(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, + Guchar *shapePtr, Guchar *alphaPtr, SplashColorPtr cSrcPtr) { - Guchar shape, aSrc, cSrc0, cDest0, cResult0; + Guchar alpha, aSrc, cSrc0, cDest0, cResult0; SplashColorPtr destColorPtr; int cSrcStride, x, lastX; @@ -1651,11 +1734,11 @@ void Splash::pipeRunShapeNoAlphaMono8(SplashPipe *pipe, int x0, int x1, int y, cSrcStride = 0; } for (; x0 <= x1; ++x0) { - if (*shapePtr) { + if (*alphaPtr) { break; } cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; } if (x0 > x1) { return; @@ -1664,18 +1747,18 @@ void Splash::pipeRunShapeNoAlphaMono8(SplashPipe *pipe, int x0, int x1, int y, updateModY(y); lastX = x0; - useDestRow(y); + useBitmapRow(y); destColorPtr = &bitmap->data[y * bitmap->rowSize + x0]; for (x = x0; x <= x1; ++x) { - //----- shape - shape = *shapePtr; - if (!shape) { + //----- alpha + alpha = *alphaPtr; + if (!alpha) { ++destColorPtr; cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; continue; } lastX = x; @@ -1684,7 +1767,7 @@ void Splash::pipeRunShapeNoAlphaMono8(SplashPipe *pipe, int x0, int x1, int y, cSrc0 = state->grayTransfer[cSrcPtr[0]]; //----- source alpha - aSrc = shape; + aSrc = alpha; //----- special case for aSrc = 255 if (aSrc == 255) { @@ -1702,7 +1785,7 @@ void Splash::pipeRunShapeNoAlphaMono8(SplashPipe *pipe, int x0, int x1, int y, *destColorPtr++ = cResult0; cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; } updateModX(lastX); @@ -1710,12 +1793,13 @@ void Splash::pipeRunShapeNoAlphaMono8(SplashPipe *pipe, int x0, int x1, int y, // special case: // !pipe->pattern && !pipe->noTransparency && !state->softMask && -// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc && +// usesAlpha && !pipe->alpha0Ptr && !state->blendFunc && // !pipe->nonIsolatedGroup && // bitmap->mode == splashModeMono1 && !bitmap->alpha void Splash::pipeRunAAMono1(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr) { - Guchar shape, aSrc, cSrc0, cDest0, cResult0; + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr) { + Guchar alpha, aSrc, cSrc0, cDest0, cResult0; SplashColorPtr destColorPtr; Guchar destColorMask; SplashScreenCursor screenCursor; @@ -1728,11 +1812,11 @@ void Splash::pipeRunAAMono1(SplashPipe *pipe, int x0, int x1, int y, cSrcStride = 0; } for (; x0 <= x1; ++x0) { - if (*shapePtr) { + if (*alphaPtr) { break; } cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; } if (x0 > x1) { return; @@ -1741,7 +1825,7 @@ void Splash::pipeRunAAMono1(SplashPipe *pipe, int x0, int x1, int y, updateModY(y); lastX = x0; - useDestRow(y); + useBitmapRow(y); destColorPtr = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)]; destColorMask = (Guchar)(0x80 >> (x0 & 7)); @@ -1750,13 +1834,13 @@ void Splash::pipeRunAAMono1(SplashPipe *pipe, int x0, int x1, int y, for (x = x0; x <= x1; ++x) { - //----- shape - shape = *shapePtr; - if (!shape) { + //----- alpha + alpha = *alphaPtr; + if (!alpha) { destColorPtr += destColorMask & 1; destColorMask = (Guchar)((destColorMask << 7) | (destColorMask >> 1)); cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; continue; } lastX = x; @@ -1768,7 +1852,7 @@ void Splash::pipeRunAAMono1(SplashPipe *pipe, int x0, int x1, int y, cSrc0 = state->grayTransfer[cSrcPtr[0]]; //----- source alpha - aSrc = div255(pipe->aInput * shape); + aSrc = div255(pipe->aInput * alpha); //----- result color // note: aDest = alphaI = aResult = 0xff @@ -1784,7 +1868,7 @@ void Splash::pipeRunAAMono1(SplashPipe *pipe, int x0, int x1, int y, destColorMask = (Guchar)((destColorMask << 7) | (destColorMask >> 1)); cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; } updateModX(lastX); @@ -1792,12 +1876,13 @@ void Splash::pipeRunAAMono1(SplashPipe *pipe, int x0, int x1, int y, // special case: // !pipe->pattern && !pipe->noTransparency && !state->softMask && -// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc && +// usesAlpha && !pipe->alpha0Ptr && !state->blendFunc && // !pipe->nonIsolatedGroup && // bitmap->mode == splashModeMono8 && bitmap->alpha void Splash::pipeRunAAMono8(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr) { - Guchar shape, aSrc, aDest, alphaI, aResult, cSrc0, cDest0, cResult0; + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr) { + Guchar alpha, aSrc, aDest, alphaI, aResult, cSrc0, cDest0, cResult0; SplashColorPtr destColorPtr; Guchar *destAlphaPtr; int cSrcStride, x, lastX; @@ -1809,11 +1894,11 @@ void Splash::pipeRunAAMono8(SplashPipe *pipe, int x0, int x1, int y, cSrcStride = 0; } for (; x0 <= x1; ++x0) { - if (*shapePtr) { + if (*alphaPtr) { break; } cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; } if (x0 > x1) { return; @@ -1822,20 +1907,20 @@ void Splash::pipeRunAAMono8(SplashPipe *pipe, int x0, int x1, int y, updateModY(y); lastX = x0; - useDestRow(y); + useBitmapRow(y); destColorPtr = &bitmap->data[y * bitmap->rowSize + x0]; destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; for (x = x0; x <= x1; ++x) { - //----- shape - shape = *shapePtr; - if (!shape) { + //----- alpha + alpha = *alphaPtr; + if (!alpha) { ++destColorPtr; ++destAlphaPtr; cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; continue; } lastX = x; @@ -1848,7 +1933,7 @@ void Splash::pipeRunAAMono8(SplashPipe *pipe, int x0, int x1, int y, cSrc0 = state->grayTransfer[cSrcPtr[0]]; //----- source alpha - aSrc = div255(pipe->aInput * shape); + aSrc = div255(pipe->aInput * alpha); //----- result alpha and non-isolated group element correction aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest)); @@ -1866,7 +1951,7 @@ void Splash::pipeRunAAMono8(SplashPipe *pipe, int x0, int x1, int y, *destAlphaPtr++ = aResult; cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; } updateModX(lastX); @@ -1874,12 +1959,13 @@ void Splash::pipeRunAAMono8(SplashPipe *pipe, int x0, int x1, int y, // special case: // !pipe->pattern && !pipe->noTransparency && !state->softMask && -// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc && +// usesAlpha && !pipe->alpha0Ptr && !state->blendFunc && // !pipe->nonIsolatedGroup && // bitmap->mode == splashModeRGB8 && bitmap->alpha void Splash::pipeRunAARGB8(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr) { - Guchar shape, aSrc, aDest, alphaI, aResult; + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr) { + Guchar alpha, aSrc, aDest, alphaI, aResult; Guchar cSrc0, cSrc1, cSrc2; Guchar cDest0, cDest1, cDest2; Guchar cResult0, cResult1, cResult2; @@ -1894,11 +1980,11 @@ void Splash::pipeRunAARGB8(SplashPipe *pipe, int x0, int x1, int y, cSrcStride = 0; } for (; x0 <= x1; ++x0) { - if (*shapePtr) { + if (*alphaPtr) { break; } cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; } if (x0 > x1) { return; @@ -1907,20 +1993,20 @@ void Splash::pipeRunAARGB8(SplashPipe *pipe, int x0, int x1, int y, updateModY(y); lastX = x0; - useDestRow(y); + useBitmapRow(y); destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0]; destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; for (x = x0; x <= x1; ++x) { - //----- shape - shape = *shapePtr; - if (!shape) { + //----- alpha + alpha = *alphaPtr; + if (!alpha) { destColorPtr += 3; ++destAlphaPtr; cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; continue; } lastX = x; @@ -1937,7 +2023,7 @@ void Splash::pipeRunAARGB8(SplashPipe *pipe, int x0, int x1, int y, cSrc2 = state->rgbTransferB[cSrcPtr[2]]; //----- source alpha - aSrc = div255(pipe->aInput * shape); + aSrc = div255(pipe->aInput * alpha); //----- result alpha and non-isolated group element correction aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest)); @@ -1962,7 +2048,7 @@ void Splash::pipeRunAARGB8(SplashPipe *pipe, int x0, int x1, int y, *destAlphaPtr++ = aResult; cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; } updateModX(lastX); @@ -1970,12 +2056,13 @@ void Splash::pipeRunAARGB8(SplashPipe *pipe, int x0, int x1, int y, // special case: // !pipe->pattern && !pipe->noTransparency && !state->softMask && -// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc && +// usesAlpha && !pipe->alpha0Ptr && !state->blendFunc && // !pipe->nonIsolatedGroup && // bitmap->mode == splashModeBGR8 && bitmap->alpha void Splash::pipeRunAABGR8(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr) { - Guchar shape, aSrc, aDest, alphaI, aResult; + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr) { + Guchar alpha, aSrc, aDest, alphaI, aResult; Guchar cSrc0, cSrc1, cSrc2; Guchar cDest0, cDest1, cDest2; Guchar cResult0, cResult1, cResult2; @@ -1990,11 +2077,11 @@ void Splash::pipeRunAABGR8(SplashPipe *pipe, int x0, int x1, int y, cSrcStride = 0; } for (; x0 <= x1; ++x0) { - if (*shapePtr) { + if (*alphaPtr) { break; } cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; } if (x0 > x1) { return; @@ -2003,20 +2090,20 @@ void Splash::pipeRunAABGR8(SplashPipe *pipe, int x0, int x1, int y, updateModY(y); lastX = x0; - useDestRow(y); + useBitmapRow(y); destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0]; destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; for (x = x0; x <= x1; ++x) { - //----- shape - shape = *shapePtr; - if (!shape) { + //----- alpha + alpha = *alphaPtr; + if (!alpha) { destColorPtr += 3; ++destAlphaPtr; cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; continue; } lastX = x; @@ -2033,7 +2120,7 @@ void Splash::pipeRunAABGR8(SplashPipe *pipe, int x0, int x1, int y, cSrc2 = state->rgbTransferB[cSrcPtr[2]]; //----- source alpha - aSrc = div255(pipe->aInput * shape); + aSrc = div255(pipe->aInput * alpha); //----- result alpha and non-isolated group element correction aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest)); @@ -2058,7 +2145,7 @@ void Splash::pipeRunAABGR8(SplashPipe *pipe, int x0, int x1, int y, *destAlphaPtr++ = aResult; cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; } updateModX(lastX); @@ -2067,12 +2154,13 @@ void Splash::pipeRunAABGR8(SplashPipe *pipe, int x0, int x1, int y, #if SPLASH_CMYK // special case: // !pipe->pattern && !pipe->noTransparency && !state->softMask && -// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc && +// usesAlpha && !pipe->alpha0Ptr && !state->blendFunc && // !pipe->nonIsolatedGroup && // bitmap->mode == splashModeCMYK8 && bitmap->alpha void Splash::pipeRunAACMYK8(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr) { - Guchar shape, aSrc, aDest, alphaI, aResult; + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr) { + Guchar alpha, aSrc, aDest, alphaI, aResult; Guchar cSrc0, cSrc1, cSrc2, cSrc3; Guchar cDest0, cDest1, cDest2, cDest3; Guchar cResult0, cResult1, cResult2, cResult3; @@ -2087,11 +2175,11 @@ void Splash::pipeRunAACMYK8(SplashPipe *pipe, int x0, int x1, int y, cSrcStride = 0; } for (; x0 <= x1; ++x0) { - if (*shapePtr) { + if (*alphaPtr) { break; } cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; } if (x0 > x1) { return; @@ -2100,20 +2188,20 @@ void Splash::pipeRunAACMYK8(SplashPipe *pipe, int x0, int x1, int y, updateModY(y); lastX = x0; - useDestRow(y); + useBitmapRow(y); destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x0]; destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; for (x = x0; x <= x1; ++x) { - //----- shape - shape = *shapePtr; - if (!shape) { + //----- alpha + alpha = *alphaPtr; + if (!alpha) { destColorPtr += 4; ++destAlphaPtr; cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; continue; } lastX = x; @@ -2148,7 +2236,7 @@ void Splash::pipeRunAACMYK8(SplashPipe *pipe, int x0, int x1, int y, } //----- source alpha - aSrc = div255(pipe->aInput * shape); + aSrc = div255(pipe->aInput * alpha); //----- result alpha and non-isolated group element correction aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest)); @@ -2176,7 +2264,7 @@ void Splash::pipeRunAACMYK8(SplashPipe *pipe, int x0, int x1, int y, *destAlphaPtr++ = aResult; cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; } updateModX(lastX); @@ -2185,14 +2273,15 @@ void Splash::pipeRunAACMYK8(SplashPipe *pipe, int x0, int x1, int y, // special case: -// !pipe->pattern && aInput == 255 && state->softMask && usesShape && +// !pipe->pattern && aInput == 255 && state->softMask && usesAlpha && // !state->inNonIsolatedGroup && !state->inKnockoutGroup && // !nonIsolatedGroup && state->overprintMask == 0xffffffff && // !state->blendFunc && // bitmap->mode == splashModeMono8 && bitmap->alpha void Splash::pipeRunSoftMaskMono8(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr) { - Guchar shape, aSrc, aDest, alphaI, aResult; + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr) { + Guchar alpha, aSrc, aDest, alphaI, aResult; Guchar cSrc0, cDest0, cResult0; SplashColorPtr destColorPtr; Guchar *destAlphaPtr; @@ -2206,11 +2295,11 @@ void Splash::pipeRunSoftMaskMono8(SplashPipe *pipe, int x0, int x1, int y, cSrcStride = 0; } for (; x0 <= x1; ++x0) { - if (*shapePtr) { + if (*alphaPtr) { break; } cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; } if (x0 > x1) { return; @@ -2219,7 +2308,7 @@ void Splash::pipeRunSoftMaskMono8(SplashPipe *pipe, int x0, int x1, int y, updateModY(y); lastX = x0; - useDestRow(y); + useBitmapRow(y); destColorPtr = &bitmap->data[y * bitmap->rowSize + x0]; destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; @@ -2227,14 +2316,14 @@ void Splash::pipeRunSoftMaskMono8(SplashPipe *pipe, int x0, int x1, int y, for (x = x0; x <= x1; ++x) { - //----- shape - shape = *shapePtr; - if (!shape) { + //----- alpha + alpha = *alphaPtr; + if (!alpha) { ++destColorPtr; ++destAlphaPtr; ++softMaskPtr; cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; continue; } lastX = x; @@ -2243,7 +2332,7 @@ void Splash::pipeRunSoftMaskMono8(SplashPipe *pipe, int x0, int x1, int y, cSrc0 = state->grayTransfer[cSrcPtr[0]]; //----- source alpha - aSrc = div255(*softMaskPtr++ * shape); + aSrc = div255(*softMaskPtr++ * alpha); //----- special case for aSrc = 255 if (aSrc == 255) { @@ -2278,21 +2367,22 @@ void Splash::pipeRunSoftMaskMono8(SplashPipe *pipe, int x0, int x1, int y, *destAlphaPtr++ = aResult; cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; } updateModX(lastX); } // special case: -// !pipe->pattern && aInput == 255 && state->softMask && usesShape && +// !pipe->pattern && aInput == 255 && state->softMask && usesAlpha && // !state->inNonIsolatedGroup && !state->inKnockoutGroup && // !nonIsolatedGroup && state->overprintMask == 0xffffffff && // !state->blendFunc && // bitmap->mode == splashModeRGB8 && bitmap->alpha void Splash::pipeRunSoftMaskRGB8(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr) { - Guchar shape, aSrc, aDest, alphaI, aResult; + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr) { + Guchar alpha, aSrc, aDest, alphaI, aResult; Guchar cSrc0, cSrc1, cSrc2; Guchar cDest0, cDest1, cDest2; Guchar cResult0, cResult1, cResult2; @@ -2308,11 +2398,11 @@ void Splash::pipeRunSoftMaskRGB8(SplashPipe *pipe, int x0, int x1, int y, cSrcStride = 0; } for (; x0 <= x1; ++x0) { - if (*shapePtr) { + if (*alphaPtr) { break; } cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; } if (x0 > x1) { return; @@ -2321,7 +2411,7 @@ void Splash::pipeRunSoftMaskRGB8(SplashPipe *pipe, int x0, int x1, int y, updateModY(y); lastX = x0; - useDestRow(y); + useBitmapRow(y); destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * 3]; destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; @@ -2329,14 +2419,14 @@ void Splash::pipeRunSoftMaskRGB8(SplashPipe *pipe, int x0, int x1, int y, for (x = x0; x <= x1; ++x) { - //----- shape - shape = *shapePtr; - if (!shape) { + //----- alpha + alpha = *alphaPtr; + if (!alpha) { destColorPtr += 3; ++destAlphaPtr; ++softMaskPtr; cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; continue; } lastX = x; @@ -2347,7 +2437,7 @@ void Splash::pipeRunSoftMaskRGB8(SplashPipe *pipe, int x0, int x1, int y, cSrc2 = state->rgbTransferB[cSrcPtr[2]]; //----- source alpha - aSrc = div255(*softMaskPtr++ * shape); + aSrc = div255(*softMaskPtr++ * alpha); //----- special case for aSrc = 255 if (aSrc == 255) { @@ -2392,21 +2482,22 @@ void Splash::pipeRunSoftMaskRGB8(SplashPipe *pipe, int x0, int x1, int y, *destAlphaPtr++ = aResult; cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; } updateModX(lastX); } // special case: -// !pipe->pattern && aInput == 255 && state->softMask && usesShape && +// !pipe->pattern && aInput == 255 && state->softMask && usesAlpha && // !state->inNonIsolatedGroup && !state->inKnockoutGroup && // !nonIsolatedGroup && state->overprintMask == 0xffffffff && // !state->blendFunc && // bitmap->mode == splashModeBGR8 && bitmap->alpha void Splash::pipeRunSoftMaskBGR8(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr) { - Guchar shape, aSrc, aDest, alphaI, aResult; + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr) { + Guchar alpha, aSrc, aDest, alphaI, aResult; Guchar cSrc0, cSrc1, cSrc2; Guchar cDest0, cDest1, cDest2; Guchar cResult0, cResult1, cResult2; @@ -2422,11 +2513,11 @@ void Splash::pipeRunSoftMaskBGR8(SplashPipe *pipe, int x0, int x1, int y, cSrcStride = 0; } for (; x0 <= x1; ++x0) { - if (*shapePtr) { + if (*alphaPtr) { break; } cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; } if (x0 > x1) { return; @@ -2435,7 +2526,7 @@ void Splash::pipeRunSoftMaskBGR8(SplashPipe *pipe, int x0, int x1, int y, updateModY(y); lastX = x0; - useDestRow(y); + useBitmapRow(y); destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * 3]; destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; @@ -2443,14 +2534,14 @@ void Splash::pipeRunSoftMaskBGR8(SplashPipe *pipe, int x0, int x1, int y, for (x = x0; x <= x1; ++x) { - //----- shape - shape = *shapePtr; - if (!shape) { + //----- alpha + alpha = *alphaPtr; + if (!alpha) { destColorPtr += 3; ++destAlphaPtr; ++softMaskPtr; cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; continue; } lastX = x; @@ -2461,7 +2552,7 @@ void Splash::pipeRunSoftMaskBGR8(SplashPipe *pipe, int x0, int x1, int y, cSrc2 = state->rgbTransferB[cSrcPtr[2]]; //----- source alpha - aSrc = div255(*softMaskPtr++ * shape); + aSrc = div255(*softMaskPtr++ * alpha); //----- special case for aSrc = 255 if (aSrc == 255) { @@ -2506,7 +2597,7 @@ void Splash::pipeRunSoftMaskBGR8(SplashPipe *pipe, int x0, int x1, int y, *destAlphaPtr++ = aResult; cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; } updateModX(lastX); @@ -2514,14 +2605,15 @@ void Splash::pipeRunSoftMaskBGR8(SplashPipe *pipe, int x0, int x1, int y, #if SPLASH_CMYK // special case: -// !pipe->pattern && aInput == 255 && state->softMask && usesShape && +// !pipe->pattern && aInput == 255 && state->softMask && usesAlpha && // !state->inNonIsolatedGroup && !state->inKnockoutGroup && // !nonIsolatedGroup && state->overprintMask == 0xffffffff && // !state->blendFunc && // bitmap->mode == splashModeCMYK8 && bitmap->alpha void Splash::pipeRunSoftMaskCMYK8(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr) { - Guchar shape, aSrc, aDest, alphaI, aResult; + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr) { + Guchar alpha, aSrc, aDest, alphaI, aResult; Guchar cSrc0, cSrc1, cSrc2, cSrc3; Guchar cDest0, cDest1, cDest2, cDest3; Guchar cResult0, cResult1, cResult2, cResult3; @@ -2537,11 +2629,11 @@ void Splash::pipeRunSoftMaskCMYK8(SplashPipe *pipe, int x0, int x1, int y, cSrcStride = 0; } for (; x0 <= x1; ++x0) { - if (*shapePtr) { + if (*alphaPtr) { break; } cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; } if (x0 > x1) { return; @@ -2550,7 +2642,7 @@ void Splash::pipeRunSoftMaskCMYK8(SplashPipe *pipe, int x0, int x1, int y, updateModY(y); lastX = x0; - useDestRow(y); + useBitmapRow(y); destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * 4]; destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; @@ -2558,14 +2650,14 @@ void Splash::pipeRunSoftMaskCMYK8(SplashPipe *pipe, int x0, int x1, int y, for (x = x0; x <= x1; ++x) { - //----- shape - shape = *shapePtr; - if (!shape) { + //----- alpha + alpha = *alphaPtr; + if (!alpha) { destColorPtr += 4; ++destAlphaPtr; ++softMaskPtr; cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; continue; } lastX = x; @@ -2586,7 +2678,7 @@ void Splash::pipeRunSoftMaskCMYK8(SplashPipe *pipe, int x0, int x1, int y, cSrc3 = state->cmykTransferK[cSrcPtr[3]]; //----- source alpha - aSrc = div255(*softMaskPtr++ * shape); + aSrc = div255(*softMaskPtr++ * alpha); //----- special case for aSrc = 255 if (aSrc == 255) { @@ -2627,7 +2719,7 @@ void Splash::pipeRunSoftMaskCMYK8(SplashPipe *pipe, int x0, int x1, int y, *destAlphaPtr++ = aResult; cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; } updateModX(lastX); @@ -2636,8 +2728,9 @@ void Splash::pipeRunSoftMaskCMYK8(SplashPipe *pipe, int x0, int x1, int y, void Splash::pipeRunNonIsoMono8(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr) { - Guchar shape, aSrc, aDest, alphaI, alpha0, aResult; + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr) { + Guchar alpha, aSrc, aDest, alphaI, alpha0, aResult; Guchar cSrc0, cDest0, cResult0; SplashColorPtr destColorPtr; Guchar *destAlphaPtr; @@ -2651,11 +2744,11 @@ void Splash::pipeRunNonIsoMono8(SplashPipe *pipe, int x0, int x1, int y, cSrcStride = 0; } for (; x0 <= x1; ++x0) { - if (*shapePtr) { + if (*alphaPtr) { break; } cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; } if (x0 > x1) { return; @@ -2664,24 +2757,28 @@ void Splash::pipeRunNonIsoMono8(SplashPipe *pipe, int x0, int x1, int y, updateModY(y); lastX = x0; - useDestRow(y); + useBitmapRow(y); destColorPtr = &bitmap->data[y * bitmap->rowSize + x0]; destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; - alpha0Ptr = &groupBackBitmap->alpha[(groupBackY + y) - * groupBackBitmap->alphaRowSize + - (groupBackX + x0)]; + if (alpha0Bitmap) { + alpha0Ptr = &alpha0Bitmap->alpha[y * alpha0Bitmap->alphaRowSize + x0]; + } else { + alpha0Ptr = &parent->bitmap->alpha[ + (parentOffsetY + y) * parent->bitmap->alphaRowSize + + (parentOffsetX + x0)]; + } for (x = x0; x <= x1; ++x) { - //----- shape - shape = *shapePtr; - if (!shape) { + //----- alpha + alpha = *alphaPtr; + if (!alpha) { destColorPtr += 1; ++destAlphaPtr; ++alpha0Ptr; cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; continue; } lastX = x; @@ -2694,7 +2791,7 @@ void Splash::pipeRunNonIsoMono8(SplashPipe *pipe, int x0, int x1, int y, cSrc0 = state->grayTransfer[cSrcPtr[0]]; //----- source alpha - aSrc = div255(pipe->aInput * shape); + aSrc = div255(pipe->aInput * alpha); //----- result alpha and non-isolated group element correction aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest)); @@ -2713,15 +2810,16 @@ void Splash::pipeRunNonIsoMono8(SplashPipe *pipe, int x0, int x1, int y, *destAlphaPtr++ = aResult; cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; } // 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 *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr) { + Guchar alpha, aSrc, aDest, alphaI, alpha0, aResult; Guchar cSrc0, cSrc1, cSrc2; Guchar cDest0, cDest1, cDest2; Guchar cResult0, cResult1, cResult2; @@ -2737,11 +2835,11 @@ void Splash::pipeRunNonIsoRGB8(SplashPipe *pipe, int x0, int x1, int y, cSrcStride = 0; } for (; x0 <= x1; ++x0) { - if (*shapePtr) { + if (*alphaPtr) { break; } cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; } if (x0 > x1) { return; @@ -2750,24 +2848,28 @@ void Splash::pipeRunNonIsoRGB8(SplashPipe *pipe, int x0, int x1, int y, updateModY(y); lastX = x0; - useDestRow(y); + useBitmapRow(y); destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * 3]; destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; - alpha0Ptr = &groupBackBitmap->alpha[(groupBackY + y) - * groupBackBitmap->alphaRowSize + - (groupBackX + x0)]; + if (alpha0Bitmap) { + alpha0Ptr = &alpha0Bitmap->alpha[y * alpha0Bitmap->alphaRowSize + x0]; + } else { + alpha0Ptr = &parent->bitmap->alpha[ + (parentOffsetY + y) * parent->bitmap->alphaRowSize + + (parentOffsetX + x0)]; + } for (x = x0; x <= x1; ++x) { - //----- shape - shape = *shapePtr; - if (!shape) { + //----- alpha + alpha = *alphaPtr; + if (!alpha) { destColorPtr += 3; ++destAlphaPtr; ++alpha0Ptr; cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; continue; } lastX = x; @@ -2784,7 +2886,7 @@ void Splash::pipeRunNonIsoRGB8(SplashPipe *pipe, int x0, int x1, int y, cSrc2 = state->rgbTransferB[cSrcPtr[2]]; //----- source alpha - aSrc = div255(pipe->aInput * shape); + aSrc = div255(pipe->aInput * alpha); //----- result alpha and non-isolated group element correction aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest)); @@ -2810,15 +2912,16 @@ void Splash::pipeRunNonIsoRGB8(SplashPipe *pipe, int x0, int x1, int y, *destAlphaPtr++ = aResult; cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; } // 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 *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr) { + Guchar alpha, aSrc, aDest, alphaI, alpha0, aResult; Guchar cSrc0, cSrc1, cSrc2; Guchar cDest0, cDest1, cDest2; Guchar cResult0, cResult1, cResult2; @@ -2834,11 +2937,11 @@ void Splash::pipeRunNonIsoBGR8(SplashPipe *pipe, int x0, int x1, int y, cSrcStride = 0; } for (; x0 <= x1; ++x0) { - if (*shapePtr) { + if (*alphaPtr) { break; } cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; } if (x0 > x1) { return; @@ -2847,24 +2950,28 @@ void Splash::pipeRunNonIsoBGR8(SplashPipe *pipe, int x0, int x1, int y, updateModY(y); lastX = x0; - useDestRow(y); + useBitmapRow(y); destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * 3]; destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; - alpha0Ptr = &groupBackBitmap->alpha[(groupBackY + y) - * groupBackBitmap->alphaRowSize + - (groupBackX + x0)]; + if (alpha0Bitmap) { + alpha0Ptr = &alpha0Bitmap->alpha[y * alpha0Bitmap->alphaRowSize + x0]; + } else { + alpha0Ptr = &parent->bitmap->alpha[ + (parentOffsetY + y) * parent->bitmap->alphaRowSize + + (parentOffsetX + x0)]; + } for (x = x0; x <= x1; ++x) { - //----- shape - shape = *shapePtr; - if (!shape) { + //----- alpha + alpha = *alphaPtr; + if (!alpha) { destColorPtr += 3; ++destAlphaPtr; ++alpha0Ptr; cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; continue; } lastX = x; @@ -2881,7 +2988,7 @@ void Splash::pipeRunNonIsoBGR8(SplashPipe *pipe, int x0, int x1, int y, cSrc2 = state->rgbTransferB[cSrcPtr[2]]; //----- source alpha - aSrc = div255(pipe->aInput * shape); + aSrc = div255(pipe->aInput * alpha); //----- result alpha and non-isolated group element correction aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest)); @@ -2907,7 +3014,7 @@ void Splash::pipeRunNonIsoBGR8(SplashPipe *pipe, int x0, int x1, int y, *destAlphaPtr++ = aResult; cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; } // for (x ...) updateModX(lastX); @@ -2915,8 +3022,9 @@ void Splash::pipeRunNonIsoBGR8(SplashPipe *pipe, int x0, int x1, int y, #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 *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr) { + Guchar alpha, aSrc, aDest, alphaI, alpha0, aResult, aPrev; Guchar cSrc0, cSrc1, cSrc2, cSrc3; Guchar cDest0, cDest1, cDest2, cDest3; Guchar cResult0, cResult1, cResult2, cResult3; @@ -2932,11 +3040,11 @@ void Splash::pipeRunNonIsoCMYK8(SplashPipe *pipe, int x0, int x1, int y, cSrcStride = 0; } for (; x0 <= x1; ++x0) { - if (*shapePtr) { + if (*alphaPtr) { break; } cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; } if (x0 > x1) { return; @@ -2945,24 +3053,28 @@ void Splash::pipeRunNonIsoCMYK8(SplashPipe *pipe, int x0, int x1, int y, updateModY(y); lastX = x0; - useDestRow(y); + useBitmapRow(y); destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * 4]; destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; - alpha0Ptr = &groupBackBitmap->alpha[(groupBackY + y) - * groupBackBitmap->alphaRowSize + - (groupBackX + x0)]; + if (alpha0Bitmap) { + alpha0Ptr = &alpha0Bitmap->alpha[y * alpha0Bitmap->alphaRowSize + x0]; + } else { + alpha0Ptr = &parent->bitmap->alpha[ + (parentOffsetY + y) * parent->bitmap->alphaRowSize + + (parentOffsetX + x0)]; + } for (x = x0; x <= x1; ++x) { - //----- shape - shape = *shapePtr; - if (!shape) { + //----- alpha + alpha = *alphaPtr; + if (!alpha) { destColorPtr += 4; ++destAlphaPtr; ++alpha0Ptr; cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; continue; } lastX = x; @@ -2998,7 +3110,7 @@ void Splash::pipeRunNonIsoCMYK8(SplashPipe *pipe, int x0, int x1, int y, } //----- source alpha - aSrc = div255(pipe->aInput * shape); + aSrc = div255(pipe->aInput * alpha); //----- result alpha and non-isolated group element correction aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest)); @@ -3027,7 +3139,7 @@ void Splash::pipeRunNonIsoCMYK8(SplashPipe *pipe, int x0, int x1, int y, *destAlphaPtr++ = aResult; cSrcPtr += cSrcStride; - ++shapePtr; + ++alphaPtr; } // for (x ...) updateModX(lastX); @@ -3035,58 +3147,61 @@ void Splash::pipeRunNonIsoCMYK8(SplashPipe *pipe, int x0, int x1, int y, #endif -void Splash::useDestRow(int y) { - int y0, y1, yy; - - if (groupDestInitMode == splashGroupDestPreInit) { +void Splash::useBitmapRow(int y) { + if (!deferredInit) { return; } - if (groupDestInitYMin > groupDestInitYMax) { + + int y0, y1; + if (deferredInitYMin > deferredInitYMax) { y0 = y1 = y; - groupDestInitYMin = groupDestInitYMax = y; - } else if (y < groupDestInitYMin) { + deferredInitYMin = deferredInitYMax = y; + } else if (y < deferredInitYMin) { y0 = y; - y1 = groupDestInitYMin - 1; - groupDestInitYMin = y; - } else if (y > groupDestInitYMax) { - y0 = groupDestInitYMax + 1; + y1 = deferredInitYMin - 1; + deferredInitYMin = y; + } else if (y > deferredInitYMax) { + y0 = deferredInitYMax + 1; y1 = y; - groupDestInitYMax = y; + deferredInitYMax = y; } else { return; } - for (yy = y0; yy <= y1; ++yy) { - if (groupDestInitMode == splashGroupDestInitZero) { - // same as clear(color=0, alpha=0) - memset(bitmap->data + bitmap->rowSize * yy, 0, - bitmap->rowSize < 0 ? -bitmap->rowSize : bitmap->rowSize); - if (bitmap->alpha) { - memset(bitmap->alpha + bitmap->alphaRowSize * yy, 0, - bitmap->alphaRowSize); - } - } else { // (groupDestInitMode == splashGroupDestInitCopy) - // same as blitTransparent - copyGroupBackdropRow(yy); + + parent->useBitmapRow(parentOffsetY + y); + if (state->inNonIsolatedGroup) { + for (int yy = y0; yy <= y1; ++yy) { + copyParentRowColor(yy); + } + } else { + for (int yy = y0; yy <= y1; ++yy) { + zeroRowColor(yy); + } + } + if (bitmap->alpha) { + for (int yy = y0; yy <= y1; ++yy) { + zeroRowAlpha(yy); + } + } + if (alpha0Bitmap) { + for (int yy = y0; yy <= y1; ++yy) { + computeAlpha0Row(yy); } } } -void Splash::copyGroupBackdropRow(int y) { - SplashColorPtr p, q; - Guchar mask, srcMask; - int x; - - if (groupBackBitmap->mode != bitmap->mode) { +void Splash::copyParentRowColor(int y) { + if (parent->bitmap->mode != bitmap->mode) { return; } - if (bitmap->mode == splashModeMono1) { - p = &bitmap->data[y * bitmap->rowSize]; - mask = (Guchar)0x80; - q = &groupBackBitmap->data[(groupBackY + y) * groupBackBitmap->rowSize - + (groupBackX >> 3)]; - srcMask = (Guchar)(0x80 >> (groupBackX & 7)); - for (x = 0; x < bitmap->width; ++x) { + SplashColorPtr p = &bitmap->data[y * bitmap->rowSize]; + Guchar mask = (Guchar)0x80; + SplashColorPtr q = + &parent->bitmap->data[(parentOffsetY + y) * parent->bitmap->rowSize + + (parentOffsetX >> 3)]; + Guchar srcMask = (Guchar)(0x80 >> (parentOffsetX & 7)); + for (int x = 0; x < bitmap->width; ++x) { if (*q & srcMask) { *p |= mask; } else { @@ -3102,14 +3217,44 @@ void Splash::copyGroupBackdropRow(int y) { } } } else { - p = &bitmap->data[y * bitmap->rowSize]; - q = &groupBackBitmap->data[(groupBackY + y) * groupBackBitmap->rowSize - + bitmapComps * groupBackX]; + SplashColorPtr p = &bitmap->data[y * bitmap->rowSize]; + SplashColorPtr q = + &parent->bitmap->data[(parentOffsetY + y) * parent->bitmap->rowSize + + bitmapComps * parentOffsetX]; memcpy(p, q, bitmapComps * bitmap->width); } +} - if (bitmap->alpha) { - memset(&bitmap->alpha[y * bitmap->alphaRowSize], 0, bitmap->width); +void Splash::zeroRowColor(int y) { + memset(&bitmap->data[y * bitmap->rowSize], 0, + bitmap->rowSize < 0 ? -bitmap->rowSize : bitmap->rowSize); +} + +void Splash::zeroRowAlpha(int y) { + memset(&bitmap->alpha[y * bitmap->alphaRowSize], 0, bitmap->width); +} + +void Splash::computeAlpha0Row(int y) { + Guchar *p = &alpha0Bitmap->alpha[y * alpha0Bitmap->alphaRowSize]; + Guchar *q0; + if (parent->alpha0Bitmap) { + q0 = &parent->alpha0Bitmap->alpha[ + (parentOffsetY + y) * parent->alpha0Bitmap->alphaRowSize + + parentOffsetX]; + } else { + q0 = &parent->parent->bitmap->alpha[ + (parentOffsetY + parent->parentOffsetY + y) + * parent->parent->bitmap->alphaRowSize + + parentOffsetX + parent->parentOffsetX]; + } + Guchar *q1 = &parent->bitmap->alpha[ + (parentOffsetY + y) * parent->bitmap->alphaRowSize + + parentOffsetX]; + int w = alpha0Bitmap->width; + for (int x = 0; x < w; ++x) { + Guchar a0 = *q0++; + Guchar a1 = *q1++; + *p++ = (Guchar)(a0 + a1 - div255(a0 * a1)); } } @@ -4492,7 +4637,6 @@ Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA, bitmap = bitmapA; bitmapComps = splashColorModeNComps[bitmap->mode]; vectorAntialias = vectorAntialiasA; - inShading = gFalse; state = new SplashState(bitmap->width, bitmap->height, vectorAntialias, screenParams); scanBuf = (Guchar *)gmalloc(bitmap->width); @@ -4501,8 +4645,10 @@ Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA, } else { scanBuf2 = NULL; } - groupBackBitmap = NULL; - groupDestInitMode = splashGroupDestPreInit; + parent = NULL; + deferredInit = gFalse; + alpha0Bitmap = NULL; + shapeBitmap = NULL; overprintMaskBitmap = NULL; minLineWidth = 0; clearModRegion(); @@ -4521,7 +4667,6 @@ Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA, bitmap = bitmapA; bitmapComps = splashColorModeNComps[bitmap->mode]; vectorAntialias = vectorAntialiasA; - inShading = gFalse; state = new SplashState(bitmap->width, bitmap->height, vectorAntialias, screenA); scanBuf = (Guchar *)gmalloc(bitmap->width); @@ -4530,8 +4675,10 @@ Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA, } else { scanBuf2 = NULL; } - groupBackBitmap = NULL; - groupDestInitMode = splashGroupDestPreInit; + parent = NULL; + deferredInit = gFalse; + alpha0Bitmap = NULL; + shapeBitmap = NULL; overprintMaskBitmap = NULL; minLineWidth = 0; clearModRegion(); @@ -4713,6 +4860,10 @@ void Splash::setStrokeAdjust(SplashStrokeAdjustMode strokeAdjust) { state->strokeAdjust = strokeAdjust; } +void Splash::setAlphaIsShape(GBool alphaIsShape) { + state->alphaIsShape = alphaIsShape; +} + void Splash::clipResetToRect(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1) { state->clipResetToRect(x0, y0, x1, y1); @@ -4731,23 +4882,26 @@ void Splash::setSoftMask(SplashBitmap *softMask, GBool deleteBitmap) { state->setSoftMask(softMask, deleteBitmap); } -void Splash::setInTransparencyGroup(SplashBitmap *groupBackBitmapA, - int groupBackXA, int groupBackYA, - SplashGroupDestInitMode groupDestInitModeA, +void Splash::setInTransparencyGroup(Splash *parentA, + int parentOffsetXA, int parentOffsetYA, + SplashAlphaBitmap *alpha0BitmapA, + SplashAlphaBitmap *shapeBitmapA, GBool nonIsolated, GBool knockout) { - groupBackBitmap = groupBackBitmapA; - groupBackX = groupBackXA; - groupBackY = groupBackYA; - groupDestInitMode = groupDestInitModeA; - groupDestInitYMin = 1; - groupDestInitYMax = 0; + parent = parentA; + parentOffsetX = parentOffsetXA; + parentOffsetY = parentOffsetYA; + deferredInit = gTrue; + deferredInitYMin = 1; + deferredInitYMax = 0; + alpha0Bitmap = alpha0BitmapA; + shapeBitmap = shapeBitmapA; state->inNonIsolatedGroup = nonIsolated; state->inKnockoutGroup = knockout; } void Splash::forceDeferredInit(int y, int h) { - useDestRow(y); - useDestRow(y + h - 1); + useBitmapRow(y); + useBitmapRow(y + h - 1); } // Check that alpha is 0 in the specified rectangle. @@ -4763,15 +4917,14 @@ GBool Splash::checkTransparentRect(int x, int y, int w, int h) { return gFalse; } int yy0, yy1; - if (groupDestInitMode == splashGroupDestPreInit) { + if (deferredInit) { + // all transparency groups initialize alpha to zero, so anything + // outside of groupDestInit[YMin,YMax] will have alpha=0 + yy0 = (y > deferredInitYMin) ? y : deferredInitYMin; + yy1 = (y + h - 1 < deferredInitYMax) ? y + h - 1 : deferredInitYMax; + } else { yy0 = y; yy1 = y + h - 1; - } else { - // both splashGroupDestInitZero and splashGroupDestInitCopy set - // alpha to zero, so anything outside of groupDestInit[YMin,YMax] - // will have alpha=0 - yy0 = (y > groupDestInitYMin) ? y : groupDestInitYMin; - yy1 = (y + h - 1 < groupDestInitYMax) ? y + h - 1 : groupDestInitYMax; } Guchar *alphaP = &bitmap->alpha[yy0 * bitmap->alphaRowSize + x]; for (int yy = yy0; yy <= yy1; ++yy) { @@ -4930,7 +5083,7 @@ void Splash::clear(SplashColorPtr color, Guchar alpha) { SplashError Splash::stroke(SplashPath *path) { SplashPath *path2, *dPath; - SplashCoord t0, t1, t2, t3, w, w2, lineDashMax, lineDashTotal; + SplashCoord w, w2, lineDashMax, lineDashTotal; int lineCap, lineJoin, i; if (debugMode) { @@ -4942,6 +5095,9 @@ SplashError Splash::stroke(SplashPath *path) { if (path->length == 0) { return splashErrEmptyPath; } + if (pathAllOutside(path, gTrue)) { + return splashOk; + } path2 = flattenPath(path, state->matrix, state->flatness); // Compute an approximation of the transformed line width. @@ -4953,15 +5109,13 @@ SplashError Splash::stroke(SplashPath *path) { // [0 +/-s] [+/-s 0] // well, and still does something reasonable for the uncommon // case transforms. - t0 = splashAbs(state->matrix[0]); - t1 = splashAbs(state->matrix[1]); - t2 = splashAbs(state->matrix[2]); - t3 = splashAbs(state->matrix[3]); - if (t0 * t3 >= t1 * t2) { - w = (t0 < t3) ? t0 : t3; - } else { - w = (t1 < t2) ? t1 : t2; - } + double t0 = splashAbs(state->matrix[0]); + double t1 = splashAbs(state->matrix[1]); + double t2 = splashAbs(state->matrix[2]); + double t3 = splashAbs(state->matrix[3]); + double t01 = t0 * t0 + t1 * t1; + double t23 = t2 * t2 + t3 * t3; + w = sqrt((t01 > t23) ? t01 : t23); w2 = w * state->lineWidth; // construct the dashed path @@ -4972,6 +5126,10 @@ SplashError Splash::stroke(SplashPath *path) { // pixel, don't apply the dash pattern; this avoids a huge // performance/memory hit with PDF files that use absurd dash // patterns like [0.0007 0.0003] + // + // we also skip the dash pattern for very long paths with short + // (but not necessarily sub-pixel) dash patterns -- Adobe appears + // to do something similar lineDashTotal = 0; lineDashMax = 0; for (i = 0; i < state->lineDashLength; ++i) { @@ -4985,8 +5143,8 @@ SplashError Splash::stroke(SplashPath *path) { delete path2; return splashOk; } - if (w * lineDashMax > 0.1) { - + if (w * lineDashMax > 0.1 && + w * lineDashMax > 0.0001 * path->length) { dPath = makeDashedPath(path2); delete path2; path2 = dPath; @@ -5056,11 +5214,11 @@ void Splash::strokeNarrow(SplashPath *path) { xPath = new SplashXPath(path, state->matrix, state->flatness, gFalse, state->enablePathSimplification, - state->strokeAdjust); + state->strokeAdjust, state->clip); pipeInit(&pipe, state->strokePattern, (Guchar)splashRound(state->strokeAlpha * 255), - gTrue, gFalse); + gFalse, gTrue, gFalse); for (i = 0, seg = xPath->segs; i < xPath->length; ++i, ++seg) { if (seg->y0 <= seg->y1) { @@ -5074,6 +5232,44 @@ void Splash::strokeNarrow(SplashPath *path) { x0 = splashFloor(seg->x1); x1 = splashFloor(seg->x0); } + + // With CAD-mode stroke adjustment, and a simple rectangular clip + // region, horizontal and vertical stroke-adjusted edges that fall + // slightly outside the clip region are adjusted back inside the + // clip region. This avoids problems with narrow lines in + // slightly mismatched clip rectangles, which appear to be + // generated somewhat commonly by buggy CAD software. This is + // similar to the code in SplashXPath::strokeAdjust() -- narrow + // strokes aren't stroke-adjusted, so this tweak has to be done + // here. + if (y0 == y1 && + seg->y0 == seg->y1 && + state->clip->getIsSimple() && + state->strokeAdjust == splashStrokeAdjustCAD) { + SplashCoord cy0 = state->clip->getYMin(); + SplashCoord cy1 = state->clip->getYMax(); + int cyi0 = state->clip->getYMinI(state->strokeAdjust); + int cyi1 = state->clip->getYMaxI(state->strokeAdjust); + if (y0 == cyi0 - 1 && cy0 - seg->y0 < 0.5) { + y0 = y1 = y0 + 1; + } else if (y0 == cyi1 + 1 && seg->y0 - cy1 < 0.5) { + y0 = y1 = y0 - 1; + } + } else if (x0 == x1 && + seg->x0 == seg->x1 && + state->clip->getIsSimple() && + state->strokeAdjust == splashStrokeAdjustCAD) { + SplashCoord cx0 = state->clip->getXMin(); + SplashCoord cx1 = state->clip->getXMax(); + int cxi0 = state->clip->getXMinI(state->strokeAdjust); + int cxi1 = state->clip->getXMaxI(state->strokeAdjust); + if (x0 == cxi0 - 1 && cx0 - seg->x0 < 0.5) { + x0 = x1 = x0 + 1; + } else if (x0 == cxi1 + 1 && seg->x0 - cx1 < 0.5) { + x0 = x1 = x0 - 1; + } + } + if ((clipRes = state->clip->testRect(x0 <= x1 ? x0 : x1, y0, x0 <= x1 ? x1 : x0, y1, state->strokeAdjust)) @@ -5084,6 +5280,18 @@ void Splash::strokeNarrow(SplashPath *path) { } else { drawStrokeSpan(&pipe, x1, x0, y0, clipRes == splashClipAllInside); } + } else if (x0 == x1) { + y = state->clip->getYMinI(state->strokeAdjust); + if (y0 < y) { + y0 = y; + } + y = state->clip->getYMaxI(state->strokeAdjust); + if (y1 > y) { + y1 = y; + } + for (y = y0; y <= y1; ++y) { + drawStrokeSpan(&pipe, x0, x0, y, clipRes == splashClipAllInside); + } } else { dxdy = seg->dxdy; y = state->clip->getYMinI(state->strokeAdjust); @@ -5094,7 +5302,7 @@ void Splash::strokeNarrow(SplashPath *path) { y = state->clip->getYMaxI(state->strokeAdjust); if (y1 > y) { y1 = y; - x1 = splashFloor(seg->x0 + ((SplashCoord)y1 - seg->y0) * dxdy); + x1 = splashFloor(seg->x0 + ((SplashCoord)y1 + 1 - seg->y0) * dxdy); } if (x0 <= x1) { xa = x0; @@ -5135,6 +5343,7 @@ void Splash::strokeNarrow(SplashPath *path) { } ++nClipRes[clipRes]; } + if (nClipRes[splashClipPartial] || (nClipRes[splashClipAllInside] && nClipRes[splashClipAllOutside])) { opClipRes = splashClipPartial; @@ -5170,7 +5379,7 @@ void Splash::drawStrokeSpan(SplashPipe *pipe, int x0, int x1, int y, return; } } - (this->*pipe->run)(pipe, x0, x1, y, scanBuf + x0, NULL); + (this->*pipe->run)(pipe, x0, x1, y, scanBuf + x0, scanBuf + x0, NULL); } void Splash::strokeWide(SplashPath *path, SplashCoord w, @@ -5326,16 +5535,14 @@ SplashPath *Splash::makeDashedPath(SplashPath *path) { return new SplashPath(); } lineDashStartPhase = state->lineDashPhase; - if (lineDashStartPhase > lineDashTotal * 2) { - i = splashFloor(lineDashStartPhase / (lineDashTotal * 2)); - lineDashStartPhase -= lineDashTotal * i * 2; - } else if (lineDashStartPhase < 0) { - i = splashCeil(-lineDashStartPhase / (lineDashTotal * 2)); - lineDashStartPhase += lineDashTotal * i * 2; - } - i = splashFloor(lineDashStartPhase / lineDashTotal); - lineDashStartPhase -= (SplashCoord)i * lineDashTotal; - lineDashStartOn = gTrue; + if (lineDashStartPhase > 0) { + i = splashFloor(lineDashStartPhase / lineDashTotal); + lineDashStartPhase -= lineDashTotal * i; + } else { + i = splashCeil(-lineDashStartPhase / lineDashTotal); + lineDashStartPhase += lineDashTotal * i; + } + lineDashStartOn = !((state->lineDashLength & 1) && (i & 1)); lineDashStartIdx = 0; if (lineDashStartPhase > 0) { while (lineDashStartPhase >= state->lineDash[lineDashStartIdx]) { @@ -5377,6 +5584,14 @@ SplashPath *Splash::makeDashedPath(SplashPath *path) { y1 = path->pts[k+1].y; segLen = splashDist(x0, y0, x1, y1); + // Special case for zero-length subpath: copy the zero-length + // segment into the dashed path so that the round line cap + // special case is handled. + if (j == i+1 && segLen == 0) { + dPath->moveTo(x0, y0); + dPath->lineTo(x0, y0); + } + // process the segment while (segLen > 0) { @@ -5477,6 +5692,13 @@ SplashError Splash::fill(SplashPath *path, GBool eo) { printf("fill [eo:%d]:\n", eo); dumpPath(path); } + if (path->length == 0) { + return splashErrEmptyPath; + } + if (pathAllOutside(path, gFalse)) { + opClipRes = splashClipAllOutside; + return splashOk; + } return fillWithPattern(path, eo, state->fillPattern, state->fillAlpha); } @@ -5490,19 +5712,11 @@ SplashError Splash::fillWithPattern(SplashPath *path, GBool eo, int xMin, yMin, xMax, xMin2, xMax2, yMax, y, t; SplashClipResult clipRes; - if (path->length == 0) { - return splashErrEmptyPath; - } - if (pathAllOutside(path)) { - opClipRes = splashClipAllOutside; - return splashOk; - } - path2 = tweakFillPath(path); xPath = new SplashXPath(path2, state->matrix, state->flatness, gTrue, state->enablePathSimplification, - state->strokeAdjust); + state->strokeAdjust, state->clip); if (path2 != path) { delete path2; } @@ -5540,10 +5754,10 @@ SplashError Splash::fillWithPattern(SplashPath *path, GBool eo, } pipeInit(&pipe, pattern, (Guchar)splashRound(alpha * 255), - gTrue, gFalse); + gFalse, gTrue, gFalse); // draw the spans - if (vectorAntialias && !inShading) { + if (vectorAntialias) { for (y = yMin; y <= yMax; ++y) { scanner->getSpan(scanBuf, y, xMin, xMax, &xMin2, &xMax2); if (xMin2 <= xMax2) { @@ -5551,7 +5765,8 @@ SplashError Splash::fillWithPattern(SplashPath *path, GBool eo, state->clip->clipSpan(scanBuf, y, xMin2, xMax2, state->strokeAdjust); } - (this->*pipe.run)(&pipe, xMin2, xMax2, y, scanBuf + xMin2, NULL); + (this->*pipe.run)(&pipe, xMin2, xMax2, y, + NULL, scanBuf + xMin2, NULL); } } } else { @@ -5562,7 +5777,8 @@ SplashError Splash::fillWithPattern(SplashPath *path, GBool eo, state->clip->clipSpanBinary(scanBuf, y, xMin2, xMax2, state->strokeAdjust); } - (this->*pipe.run)(&pipe, xMin2, xMax2, y, scanBuf + xMin2, NULL); + (this->*pipe.run)(&pipe, xMin2, xMax2, y, + NULL, scanBuf + xMin2, NULL); } } } @@ -5678,13 +5894,17 @@ SplashPath *Splash::tweakFillPath(SplashPath *path) { return path2; } -GBool Splash::pathAllOutside(SplashPath *path) { +// Returns true if [path] is entirely outside the current clipping +// path. The path coordinates have not been stroke adjusted, so we +// compare against the floating point clip rect. If [stroke] is true, +// allow for the stroke width and miter limit. +GBool Splash::pathAllOutside(SplashPath *path, GBool stroke) { SplashCoord xMin1, yMin1, xMax1, yMax1; SplashCoord xMin2, yMin2, xMax2, yMax2; SplashCoord x, y; - int xMinI, yMinI, xMaxI, yMaxI; int i; + //--- compute the path's bbox in user space xMin1 = xMax1 = path->pts[0].x; yMin1 = yMax1 = path->pts[0].y; for (i = 1; i < path->length; ++i) { @@ -5700,6 +5920,19 @@ GBool Splash::pathAllOutside(SplashPath *path) { } } + //--- allow for stroke width and miter limit + if (stroke && state->lineWidth > 0) { + SplashCoord w = state->lineWidth * 0.5; + if (state->lineJoin == splashLineJoinMiter) { + w *= state->miterLimit; + } + xMin1 -= w; + yMin1 -= w; + xMax1 += w; + yMax1 += w; + } + + //--- convert path bbox to device space transform(state->matrix, xMin1, yMin1, &x, &y); xMin2 = xMax2 = x; yMin2 = yMax2 = y; @@ -5736,29 +5969,31 @@ GBool Splash::pathAllOutside(SplashPath *path) { } else if (y > yMax2) { yMax2 = y; } - // sanity-check the coordinates - xMinI/yMinI/xMaxI/yMaxI are - // 32-bit integers, so coords need to be < 2^31 - SplashXPath::clampCoords(&xMin2, &yMin2); - SplashXPath::clampCoords(&xMax2, &yMax2); - xMinI = splashFloor(xMin2); - yMinI = splashFloor(yMin2); - xMaxI = splashFloor(xMax2); - yMaxI = splashFloor(yMax2); - return state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI, - state->strokeAdjust) == - splashClipAllOutside; + //--- handle zero-width strokes + if (stroke && state->lineWidth == 0) { + xMin1 -= 1; + yMin1 -= 1; + xMax1 += 1; + yMax1 += 1; + } + + //--- check against the clip rect + return xMin2 > state->clip->getXMax() || + xMax2 < state->clip->getXMin() || + yMin2 > state->clip->getYMax() || + yMax2 < state->clip->getYMin(); } SplashError Splash::fillChar(SplashCoord x, SplashCoord y, - int c, SplashFont *font) { + Guint c, SplashFont *font) { SplashGlyphBitmap glyph; SplashCoord xt, yt; int x0, y0, xFrac, yFrac; SplashError err; if (debugMode) { - printf("fillChar: x=%.2f y=%.2f c=%3d=0x%02x='%c'\n", + printf("fillChar: x=%.2f y=%.2f c=%3u=0x%02x='%c'\n", (double)x, (double)y, c, c, c); } transform(state->matrix, x, y, &xt, &yt); @@ -5806,13 +6041,15 @@ SplashError Splash::fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph) { != splashClipAllOutside) { pipeInit(&pipe, state->fillPattern, (Guchar)splashRound(state->fillAlpha * 255), - gTrue, gFalse); + gFalse, gTrue, gFalse); if (clipRes == splashClipAllInside) { if (glyph->aa) { p = glyph->data; for (y = yMin; y <= yMax; ++y) { (this->*pipe.run)(&pipe, xMin, xMax, y, - glyph->data + (y - yMin) * glyph->w, NULL); + NULL, + glyph->data + (y - yMin) * glyph->w, + NULL); } } else { p = glyph->data; @@ -5824,7 +6061,8 @@ SplashError Splash::fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph) { alpha = (Guchar)(alpha << 1); } } - (this->*pipe.run)(&pipe, xMin, xMax, y, scanBuf + xMin, NULL); + (this->*pipe.run)(&pipe, xMin, xMax, y, + NULL, scanBuf + xMin, NULL); } } } else { @@ -5847,7 +6085,8 @@ SplashError Splash::fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph) { memcpy(scanBuf + xMin, p, xMax - xMin + 1); state->clip->clipSpan(scanBuf, y, xMin, xMax, state->strokeAdjust); - (this->*pipe.run)(&pipe, xMin, xMax, y, scanBuf + xMin, NULL); + (this->*pipe.run)(&pipe, xMin, xMax, y, + NULL, scanBuf + xMin, NULL); } } else { for (y = yMin; y <= yMax; ++y) { @@ -5869,7 +6108,8 @@ SplashError Splash::fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph) { } state->clip->clipSpanBinary(scanBuf, y, xMin, xMax, state->strokeAdjust); - (this->*pipe.run)(&pipe, xMin, xMax, y, scanBuf + xMin, NULL); + (this->*pipe.run)(&pipe, xMin, xMax, y, + NULL, scanBuf + xMin, NULL); } } } @@ -6022,6 +6262,9 @@ SplashError Splash::fillImageMask(GString *imageTag, SplashClipResult clipRes = state->clip->testRect(xMin, yMin, xMax - 1, yMax - 1, state->strokeAdjust); + if (clipRes == splashClipAllOutside) { + return splashOk; + } // If the scaled mask is much wider and/or taller than the clip // region, we use the "arbitrary" scaling path, to avoid a // potentially very slow loop in the flips-only path (which scans @@ -6038,7 +6281,7 @@ SplashError Splash::fillImageMask(GString *imageTag, SplashDrawImageMaskRowData dd; pipeInit(&dd.pipe, state->fillPattern, (Guchar)splashRound(state->fillAlpha * 255), - gTrue, gFalse); + gFalse, gTrue, gFalse); //--- choose the drawRow function SplashDrawImageMaskRowFunc drawRowFunc; @@ -6054,93 +6297,89 @@ SplashError Splash::fillImageMask(GString *imageTag, //--- horizontal/vertical flips only if (flipsOnly && !veryLarge) { - if (clipRes != splashClipAllOutside) { - int scaledWidth = xMax - xMin; - int scaledHeight = yMax - yMin; - ImageMaskScaler scaler(src, srcData, w, h, - scaledWidth, scaledHeight, interpolate, antialias); - Guchar *tmpLine = NULL; - if (horizFlip) { - tmpLine = (Guchar *)gmalloc(scaledWidth); + int scaledWidth = xMax - xMin; + int scaledHeight = yMax - yMin; + ImageMaskScaler scaler(src, srcData, w, h, + scaledWidth, scaledHeight, interpolate, antialias); + Guchar *tmpLine = NULL; + if (horizFlip) { + tmpLine = (Guchar *)gmalloc(scaledWidth); + } + if (vertFlip) { + if (horizFlip) { // bottom-up, mirrored + for (int y = 0; y < scaledHeight; ++y) { + scaler.nextLine(); + mirrorImageMaskRow(scaler.data(), tmpLine, scaledWidth); + (this->*drawRowFunc)(&dd, tmpLine, + xMin, yMax - 1 - y, scaledWidth); + } + } else { // bottom-up + for (int y = 0; y < scaledHeight; ++y) { + scaler.nextLine(); + (this->*drawRowFunc)(&dd, scaler.data(), + xMin, yMax - 1 - y, scaledWidth); + } } - if (vertFlip) { - if (horizFlip) { // bottom-up, mirrored - for (int y = 0; y < scaledHeight; ++y) { - scaler.nextLine(); - mirrorImageMaskRow(scaler.data(), tmpLine, scaledWidth); - (this->*drawRowFunc)(&dd, tmpLine, - xMin, yMax - 1 - y, scaledWidth); - } - } else { // bottom-up - for (int y = 0; y < scaledHeight; ++y) { - scaler.nextLine(); - (this->*drawRowFunc)(&dd, scaler.data(), - xMin, yMax - 1 - y, scaledWidth); - } + } else { + if (horizFlip) { // top-down, mirrored + for (int y = 0; y < scaledHeight; ++y) { + scaler.nextLine(); + mirrorImageMaskRow(scaler.data(), tmpLine, scaledWidth); + (this->*drawRowFunc)(&dd, tmpLine, + xMin, yMin + y, scaledWidth); } - } else { - if (horizFlip) { // top-down, mirrored - for (int y = 0; y < scaledHeight; ++y) { - scaler.nextLine(); - mirrorImageMaskRow(scaler.data(), tmpLine, scaledWidth); - (this->*drawRowFunc)(&dd, tmpLine, - xMin, yMin + y, scaledWidth); - } - } else { // top-down - for (int y = 0; y < scaledHeight; ++y) { - scaler.nextLine(); - (this->*drawRowFunc)(&dd, scaler.data(), - xMin, yMin + y, scaledWidth); - } + } else { // top-down + for (int y = 0; y < scaledHeight; ++y) { + scaler.nextLine(); + (this->*drawRowFunc)(&dd, scaler.data(), + xMin, yMin + y, scaledWidth); } } - gfree(tmpLine); } + gfree(tmpLine); //--- 90/270 rotation } else if (rot90Only && !veryLarge) { - if (clipRes != splashClipAllOutside) { - // scale the mask - int scaledWidth = yMax - yMin; - int scaledHeight = xMax - xMin; - ImageMaskScaler scaler(src, srcData, w, h, - scaledWidth, scaledHeight, interpolate, antialias); - Guchar *scaledMask = (Guchar *)gmallocn(scaledHeight, scaledWidth); - Guchar *ptr = scaledMask; - for (int y = 0; y < scaledHeight; ++y) { - scaler.nextLine(); - memcpy(ptr, scaler.data(), scaledWidth); - ptr += scaledWidth; - } + // scale the mask + int scaledWidth = yMax - yMin; + int scaledHeight = xMax - xMin; + ImageMaskScaler scaler(src, srcData, w, h, + scaledWidth, scaledHeight, interpolate, antialias); + Guchar *scaledMask = (Guchar *)gmallocn64(scaledHeight, scaledWidth); + Guchar *ptr = scaledMask; + for (int y = 0; y < scaledHeight; ++y) { + scaler.nextLine(); + memcpy(ptr, scaler.data(), scaledWidth); + ptr += scaledWidth; + } - // draw it - Guchar *tmpLine = (Guchar *)gmalloc(scaledHeight); - for (int y = 0; y < scaledWidth; ++y) { - if (vertFlip) { - ptr = scaledMask + (scaledWidth - 1 - y); - } else { - ptr = scaledMask + y; + // draw it + Guchar *tmpLine = (Guchar *)gmalloc(scaledHeight); + for (int y = 0; y < scaledWidth; ++y) { + if (vertFlip) { + ptr = scaledMask + (scaledWidth - 1 - y); + } else { + ptr = scaledMask + y; + } + if (horizFlip) { + ptr += (scaledHeight - 1) * (SplashBitmapRowSize)scaledWidth; + for (int x = 0; x < scaledHeight; ++x) { + tmpLine[x] = *ptr; + ptr -= scaledWidth; } - if (horizFlip) { - ptr += (scaledHeight - 1) * scaledWidth; - for (int x = 0; x < scaledHeight; ++x) { - tmpLine[x] = *ptr; - ptr -= scaledWidth; - } - } else { - for (int x = 0; x < scaledHeight; ++x) { - tmpLine[x] = *ptr; - ptr += scaledWidth; - } + } else { + for (int x = 0; x < scaledHeight; ++x) { + tmpLine[x] = *ptr; + ptr += scaledWidth; } - (this->*drawRowFunc)(&dd, tmpLine, xMin, yMin + y, scaledHeight); } - - gfree(tmpLine); - gfree(scaledMask); + (this->*drawRowFunc)(&dd, tmpLine, xMin, yMin + y, scaledHeight); } + gfree(tmpLine); + gfree(scaledMask); + //--- arbitrary transform } else { // estimate of size of scaled image @@ -6155,7 +6394,7 @@ SplashError Splash::fillImageMask(GString *imageTag, scaledHeight = 1; } GBool downscaling = gTrue; - if (veryLarge || (scaledWidth >= w && scaledHeight >= h)) { + if (scaledWidth >= w && scaledHeight >= h) { downscaling = gFalse; scaledWidth = w; scaledHeight = h; @@ -6189,7 +6428,7 @@ SplashError Splash::fillImageMask(GString *imageTag, // if downscaling: store the downscaled image mask // if upscaling: store the unscaled image mask - Guchar *scaledMask = (Guchar *)gmallocn(scaledHeight, scaledWidth); + Guchar *scaledMask = (Guchar *)gmallocn64(scaledHeight, scaledWidth); if (downscaling) { ImageMaskScaler scaler(src, srcData, w, h, scaledWidth, scaledHeight, interpolate, antialias); @@ -6271,7 +6510,7 @@ void Splash::drawImageMaskArbitraryNoInterp( + (SplashCoord)y * invMat[3] + invMat[5]); if (xx >= 0 && xx < scaledWidth && yy >= 0 && yy < scaledHeight) { - Guchar *p = scaledMask + (yy * scaledWidth + xx); + Guchar *p = scaledMask + (yy * (SplashBitmapRowSize)scaledWidth + xx); Guchar *q = buf + (x - xMin); *q = *p; if (x < rowMin) { @@ -6349,10 +6588,10 @@ void Splash::drawImageMaskArbitraryInterp( if (y1 >= scaledHeight) { y1 = scaledHeight - 1; } - Guchar *p00 = scaledMask + (y0 * scaledWidth + x0); - Guchar *p10 = scaledMask + (y0 * scaledWidth + x1); - Guchar *p01 = scaledMask + (y1 * scaledWidth + x0); - Guchar *p11 = scaledMask + (y1 * scaledWidth + x1); + Guchar *p00 = scaledMask + (y0 * (SplashBitmapRowSize)scaledWidth + x0); + Guchar *p10 = scaledMask + (y0 * (SplashBitmapRowSize)scaledWidth + x1); + Guchar *p01 = scaledMask + (y1 * (SplashBitmapRowSize)scaledWidth + x0); + Guchar *p11 = scaledMask + (y1 * (SplashBitmapRowSize)scaledWidth + x1); Guchar *q = buf + (x - xMin); *q = (Guchar)(int)(sx0 * (sy0 * (int)*p00 + sy1 * (int)*p01) + sx1 * (sy0 * (int)*p10 + sy1 * (int)*p11)); @@ -6386,7 +6625,8 @@ void Splash::mirrorImageMaskRow(Guchar *maskIn, Guchar *maskOut, int width) { void Splash::drawImageMaskRowNoClip(SplashDrawImageMaskRowData *data, Guchar *maskData, int x, int y, int width) { - (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y, maskData, NULL); + (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y, + NULL, maskData, NULL); } void Splash::drawImageMaskRowClipNoAA(SplashDrawImageMaskRowData *data, @@ -6410,7 +6650,7 @@ void Splash::drawImageMaskRowClipNoAA(SplashDrawImageMaskRowData *data, state->clip->clipSpanBinary(scanBuf, y, x, x + width - 1, state->strokeAdjust); (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y, - scanBuf + x, NULL); + NULL, scanBuf + x, NULL); } void Splash::drawImageMaskRowClipAA(SplashDrawImageMaskRowData *data, @@ -6433,7 +6673,7 @@ void Splash::drawImageMaskRowClipAA(SplashDrawImageMaskRowData *data, memcpy(scanBuf + x, maskData, width); state->clip->clipSpan(scanBuf, y, x, x + width - 1, state->strokeAdjust); (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y, - scanBuf + x, NULL); + NULL, scanBuf + x, NULL); } struct SplashDrawImageRowData { @@ -6569,6 +6809,9 @@ SplashError Splash::drawImage(GString *imageTag, SplashClipResult clipRes = state->clip->testRect(xMin, yMin, xMax - 1, yMax - 1, state->strokeAdjust); + if (clipRes == splashClipAllOutside) { + return splashOk; + } // If the scaled image is much wider and/or taller than the clip // region, we use the arbitrary transform path, to avoid a // potentially very slow loop in the flips-only path (which scans @@ -6587,8 +6830,8 @@ SplashError Splash::drawImage(GString *imageTag, dd.srcAlpha = srcAlpha; pipeInit(&dd.pipe, NULL, (Guchar)splashRound(state->fillAlpha * 255), - clipRes != splashClipAllInside || srcAlpha, - gFalse); + gFalse, clipRes != splashClipAllInside || srcAlpha, + gFalse, gFalse, state->alphaIsShape); //--- choose the drawRow function SplashDrawImageRowFunc drawRowFunc; @@ -6616,136 +6859,133 @@ SplashError Splash::drawImage(GString *imageTag, //--- horizontal/vertical flips only if (flipsOnly && !veryLarge) { - if (clipRes != splashClipAllOutside) { - int scaledWidth = xMax - xMin; - int scaledHeight = yMax - yMin; - ImageScaler *scaler = getImageScaler(imageTag, src, srcData, - w, h, nComps, - scaledWidth, scaledHeight, - srcMode, srcAlpha, interpolate); - Guchar *tmpLine = NULL; - Guchar *tmpAlphaLine = NULL; - if (horizFlip) { - tmpLine = (Guchar *)gmallocn(scaledWidth, nComps); - if (srcAlpha) { - tmpAlphaLine = (Guchar *)gmalloc(scaledWidth); + int scaledWidth = xMax - xMin; + int scaledHeight = yMax - yMin; + ImageScaler *scaler = getImageScaler(imageTag, src, srcData, + w, h, nComps, + scaledWidth, scaledHeight, + srcMode, srcAlpha, interpolate); + Guchar *tmpLine = NULL; + Guchar *tmpAlphaLine = NULL; + if (horizFlip) { + tmpLine = (Guchar *)gmallocn(scaledWidth, nComps); + if (srcAlpha) { + tmpAlphaLine = (Guchar *)gmalloc(scaledWidth); + } + } + if (vertFlip) { + if (horizFlip) { // bottom-up, mirrored + for (int y = 0; y < scaledHeight; ++y) { + scaler->nextLine(); + mirrorImageRow(scaler->colorData(), scaler->alphaData(), + tmpLine, tmpAlphaLine, + scaledWidth, nComps, srcAlpha); + (this->*drawRowFunc)(&dd, tmpLine, tmpAlphaLine, + xMin, yMax - 1 - y, scaledWidth); + } + } else { // bottom-up + for (int y = 0; y < scaledHeight; ++y) { + scaler->nextLine(); + (this->*drawRowFunc)(&dd, scaler->colorData(), scaler->alphaData(), + xMin, yMax - 1 - y, scaledWidth); } } - if (vertFlip) { - if (horizFlip) { // bottom-up, mirrored - for (int y = 0; y < scaledHeight; ++y) { - scaler->nextLine(); - mirrorImageRow(scaler->colorData(), scaler->alphaData(), - tmpLine, tmpAlphaLine, - scaledWidth, nComps, srcAlpha); - (this->*drawRowFunc)(&dd, tmpLine, tmpAlphaLine, - xMin, yMax - 1 - y, scaledWidth); - } - } else { // bottom-up - for (int y = 0; y < scaledHeight; ++y) { - scaler->nextLine(); - (this->*drawRowFunc)(&dd, scaler->colorData(), scaler->alphaData(), - xMin, yMax - 1 - y, scaledWidth); - } + } else { + if (horizFlip) { // top-down, mirrored + for (int y = 0; y < scaledHeight; ++y) { + scaler->nextLine(); + mirrorImageRow(scaler->colorData(), scaler->alphaData(), + tmpLine, tmpAlphaLine, + scaledWidth, nComps, srcAlpha); + (this->*drawRowFunc)(&dd, tmpLine, tmpAlphaLine, + xMin, yMin + y, scaledWidth); } - } else { - if (horizFlip) { // top-down, mirrored - for (int y = 0; y < scaledHeight; ++y) { - scaler->nextLine(); - mirrorImageRow(scaler->colorData(), scaler->alphaData(), - tmpLine, tmpAlphaLine, - scaledWidth, nComps, srcAlpha); - (this->*drawRowFunc)(&dd, tmpLine, tmpAlphaLine, - xMin, yMin + y, scaledWidth); - } - } else { // top-down - for (int y = 0; y < scaledHeight; ++y) { - scaler->nextLine(); - (this->*drawRowFunc)(&dd, scaler->colorData(), scaler->alphaData(), - xMin, yMin + y, scaledWidth); - } + } else { // top-down + for (int y = 0; y < scaledHeight; ++y) { + scaler->nextLine(); + (this->*drawRowFunc)(&dd, scaler->colorData(), scaler->alphaData(), + xMin, yMin + y, scaledWidth); } } - gfree(tmpLine); - gfree(tmpAlphaLine); - delete scaler; } + gfree(tmpLine); + gfree(tmpAlphaLine); + delete scaler; //--- 90/270 rotation } else if (rot90Only && !veryLarge) { - if (clipRes != splashClipAllOutside) { - - // scale the image - int scaledWidth = yMax - yMin; - int scaledHeight = xMax - xMin; - Guchar *scaledColor, *scaledAlpha; - GBool freeScaledImage; - getScaledImage(imageTag, src, srcData, w, h, nComps, - scaledWidth, scaledHeight, srcMode, srcAlpha, interpolate, - &scaledColor, &scaledAlpha, &freeScaledImage); - - // draw it - Guchar *tmpLine = (Guchar *)gmallocn(scaledHeight, nComps); - Guchar *tmpAlphaLine = NULL; - if (srcAlpha) { - tmpAlphaLine = (Guchar *)gmalloc(scaledHeight); + + // scale the image + int scaledWidth = yMax - yMin; + int scaledHeight = xMax - xMin; + Guchar *scaledColor, *scaledAlpha; + GBool freeScaledImage; + getScaledImage(imageTag, src, srcData, w, h, nComps, + scaledWidth, scaledHeight, srcMode, srcAlpha, interpolate, + &scaledColor, &scaledAlpha, &freeScaledImage); + + // draw it + Guchar *tmpLine = (Guchar *)gmallocn(scaledHeight, nComps); + Guchar *tmpAlphaLine = NULL; + if (srcAlpha) { + tmpAlphaLine = (Guchar *)gmalloc(scaledHeight); + } + for (int y = 0; y < scaledWidth; ++y) { + Guchar *ptr = NULL; + Guchar *alphaPtr = NULL; + if (vertFlip) { + ptr = scaledColor + ((SplashBitmapRowSize)scaledWidth - 1 - y) * nComps; + if (srcAlpha) { + alphaPtr = scaledAlpha + (scaledWidth - 1 - y); + } + } else { + ptr = scaledColor + y * nComps; + if (srcAlpha) { + alphaPtr = scaledAlpha + y; + } } - for (int y = 0; y < scaledWidth; ++y) { - Guchar *ptr, *alphaPtr; - if (vertFlip) { - ptr = scaledColor + (scaledWidth - 1 - y) * nComps; - if (srcAlpha) { - alphaPtr = scaledAlpha + (scaledWidth - 1 - y); - } - } else { - ptr = scaledColor + y * nComps; - if (srcAlpha) { - alphaPtr = scaledAlpha + y; + if (horizFlip) { + ptr += (scaledHeight - 1) * (SplashBitmapRowSize)scaledWidth * nComps; + Guchar *q = tmpLine; + for (int x = 0; x < scaledHeight; ++x) { + for (int i = 0; i < nComps; ++i) { + *q++ = ptr[i]; } + ptr -= scaledWidth * nComps; } - if (horizFlip) { - ptr += (scaledHeight - 1) * scaledWidth * nComps; - Guchar *q = tmpLine; + if (srcAlpha) { + alphaPtr += (scaledHeight - 1) * (SplashBitmapRowSize)scaledWidth; + q = tmpAlphaLine; for (int x = 0; x < scaledHeight; ++x) { - for (int i = 0; i < nComps; ++i) { - *q++ = ptr[i]; - } - ptr -= scaledWidth * nComps; + *q++ = *alphaPtr; + alphaPtr -= scaledWidth; } - if (srcAlpha) { - alphaPtr += (scaledHeight - 1) * scaledWidth; - q = tmpAlphaLine; - for (int x = 0; x < scaledHeight; ++x) { - *q++ = *alphaPtr; - alphaPtr -= scaledWidth; - } + } + } else { + Guchar *q = tmpLine; + for (int x = 0; x < scaledHeight; ++x) { + for (int i = 0; i < nComps; ++i) { + *q++ = ptr[i]; } - } else { - Guchar *q = tmpLine; + ptr += scaledWidth * nComps; + } + if (srcAlpha) { + q = tmpAlphaLine; for (int x = 0; x < scaledHeight; ++x) { - for (int i = 0; i < nComps; ++i) { - *q++ = ptr[i]; - } - ptr += scaledWidth * nComps; - } - if (srcAlpha) { - q = tmpAlphaLine; - for (int x = 0; x < scaledHeight; ++x) { - *q++ = *alphaPtr; - alphaPtr += scaledWidth; - } + *q++ = *alphaPtr; + alphaPtr += scaledWidth; } } - (this->*drawRowFunc)(&dd, tmpLine, tmpAlphaLine, - xMin, yMin + y, scaledHeight); } + (this->*drawRowFunc)(&dd, tmpLine, tmpAlphaLine, + xMin, yMin + y, scaledHeight); + } - gfree(tmpLine); - gfree(tmpAlphaLine); - if (freeScaledImage) { - gfree(scaledColor); - gfree(scaledAlpha); - } + gfree(tmpLine); + gfree(tmpAlphaLine); + if (freeScaledImage) { + gfree(scaledColor); + gfree(scaledAlpha); } //--- arbitrary transform @@ -6761,7 +7001,7 @@ SplashError Splash::drawImage(GString *imageTag, if (scaledHeight < 1) { scaledHeight = 1; } - if (veryLarge || (scaledWidth >= w && scaledHeight >= h)) { + if (scaledWidth >= w && scaledHeight >= h) { scaledWidth = w; scaledHeight = h; } @@ -6851,9 +7091,9 @@ ImageScaler *Splash::getImageScaler(GString *imageTag, } else { lineSize = -1; } - imageCache->colorData = (Guchar *)gmallocn(scaledHeight, lineSize); + imageCache->colorData = (Guchar *)gmallocn64(scaledHeight, lineSize); if (srcAlpha) { - imageCache->alphaData = (Guchar *)gmallocn(scaledHeight, scaledWidth); + imageCache->alphaData = (Guchar *)gmallocn64(scaledHeight, scaledWidth); } return new SavingImageScaler(src, srcData, w, h, nComps, srcAlpha, @@ -6894,9 +7134,9 @@ void Splash::getScaledImage(GString *imageTag, } else { lineSize = -1; } - *scaledColor = (Guchar *)gmallocn(scaledHeight, lineSize); + *scaledColor = (Guchar *)gmallocn64(scaledHeight, lineSize); if (srcAlpha) { - *scaledAlpha = (Guchar *)gmallocn(scaledHeight, scaledWidth); + *scaledAlpha = (Guchar *)gmallocn64(scaledHeight, scaledWidth); } else { *scaledAlpha = NULL; } @@ -6938,9 +7178,9 @@ void Splash::getScaledImage(GString *imageTag, } else { lineSize = -1; } - imageCache->colorData = (Guchar *)gmallocn(scaledHeight, lineSize); + imageCache->colorData = (Guchar *)gmallocn64(scaledHeight, lineSize); if (srcAlpha) { - imageCache->alphaData = (Guchar *)gmallocn(scaledHeight, scaledWidth); + imageCache->alphaData = (Guchar *)gmallocn64(scaledHeight, scaledWidth); } if (scaledWidth == w && scaledHeight == h) { Guchar *colorPtr = imageCache->colorData; @@ -7021,13 +7261,15 @@ void Splash::drawImageArbitraryNoInterp(Guchar *scaledColor, + (SplashCoord)y * invMat[3] + invMat[5]); if (xx >= 0 && xx < scaledWidth && yy >= 0 && yy < scaledHeight) { - Guchar *p = scaledColor + (yy * scaledWidth + xx) * nComps; + Guchar *p = scaledColor + + (yy * (SplashBitmapRowSize)scaledWidth + xx) * nComps; Guchar *q = colorBuf + (x - xMin) * nComps; for (int i = 0; i < nComps; ++i) { *q++ = *p++; } if (srcAlpha) { - alphaBuf[x - xMin] = scaledAlpha[yy * scaledWidth + xx]; + alphaBuf[x - xMin] = + scaledAlpha[yy * (SplashBitmapRowSize)scaledWidth + xx]; } if (x < rowMin) { rowMin = x; @@ -7111,20 +7353,24 @@ void Splash::drawImageArbitraryInterp(Guchar *scaledColor, Guchar *scaledAlpha, if (y1 >= scaledHeight) { y1 = scaledHeight - 1; } - Guchar *p00 = scaledColor + (y0 * scaledWidth + x0) * nComps; - Guchar *p10 = scaledColor + (y0 * scaledWidth + x1) * nComps; - Guchar *p01 = scaledColor + (y1 * scaledWidth + x0) * nComps; - Guchar *p11 = scaledColor + (y1 * scaledWidth + x1) * nComps; + Guchar *p00 = scaledColor + + (y0 * (SplashBitmapRowSize)scaledWidth + x0) * nComps; + Guchar *p10 = scaledColor + + (y0 * (SplashBitmapRowSize)scaledWidth + x1) * nComps; + Guchar *p01 = scaledColor + + (y1 * (SplashBitmapRowSize)scaledWidth + x0) * nComps; + Guchar *p11 = scaledColor + + (y1 * (SplashBitmapRowSize)scaledWidth + x1) * nComps; Guchar *q = colorBuf + (x - xMin) * nComps; for (int i = 0; i < nComps; ++i) { *q++ = (Guchar)(int)(sx0 * (sy0 * (int)*p00++ + sy1 * (int)*p01++) + sx1 * (sy0 * (int)*p10++ + sy1 * (int)*p11++)); } if (srcAlpha) { - p00 = scaledAlpha + (y0 * scaledWidth + x0); - p10 = scaledAlpha + (y0 * scaledWidth + x1); - p01 = scaledAlpha + (y1 * scaledWidth + x0); - p11 = scaledAlpha + (y1 * scaledWidth + x1); + p00 = scaledAlpha + (y0 * (SplashBitmapRowSize)scaledWidth + x0); + p10 = scaledAlpha + (y0 * (SplashBitmapRowSize)scaledWidth + x1); + p01 = scaledAlpha + (y1 * (SplashBitmapRowSize)scaledWidth + x0); + p11 = scaledAlpha + (y1 * (SplashBitmapRowSize)scaledWidth + x1); q = alphaBuf + (x - xMin); *q = (Guchar)(int)(sx0 * (sy0 * (int)*p00 + sy1 * (int)*p01) + sx1 * (sy0 * (int)*p10 + sy1 * (int)*p11)); @@ -7176,14 +7422,15 @@ void Splash::mirrorImageRow(Guchar *colorIn, Guchar *alphaIn, void Splash::drawImageRowNoClipNoAlpha(SplashDrawImageRowData *data, Guchar *colorData, Guchar *alphaData, int x, int y, int width) { - (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y, NULL, colorData); + (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y, + NULL, NULL, colorData); } void Splash::drawImageRowNoClipAlpha(SplashDrawImageRowData *data, Guchar *colorData, Guchar *alphaData, int x, int y, int width) { (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y, - alphaData, colorData); + NULL, alphaData, colorData); } void Splash::drawImageRowClipNoAlphaNoAA(SplashDrawImageRowData *data, @@ -7208,7 +7455,7 @@ void Splash::drawImageRowClipNoAlphaNoAA(SplashDrawImageRowData *data, state->clip->clipSpanBinary(scanBuf, y, x, x + width - 1, state->strokeAdjust); (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y, - scanBuf + x, colorData); + NULL, scanBuf + x, colorData); } void Splash::drawImageRowClipNoAlphaAA(SplashDrawImageRowData *data, @@ -7232,7 +7479,7 @@ void Splash::drawImageRowClipNoAlphaAA(SplashDrawImageRowData *data, memset(scanBuf + x, 0xff, width); state->clip->clipSpan(scanBuf, y, x, x + width - 1, state->strokeAdjust); (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y, - scanBuf + x, colorData); + NULL, scanBuf + x, colorData); } void Splash::drawImageRowClipAlphaNoAA(SplashDrawImageRowData *data, @@ -7258,7 +7505,7 @@ void Splash::drawImageRowClipAlphaNoAA(SplashDrawImageRowData *data, state->clip->clipSpanBinary(scanBuf, y, x, x + width - 1, state->strokeAdjust); (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y, - scanBuf + x, colorData); + NULL, scanBuf + x, colorData); } void Splash::drawImageRowClipAlphaAA(SplashDrawImageRowData *data, @@ -7283,12 +7530,12 @@ void Splash::drawImageRowClipAlphaAA(SplashDrawImageRowData *data, memcpy(scanBuf + x, alphaData, width); state->clip->clipSpan(scanBuf, y, x, x + width - 1, state->strokeAdjust); (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y, - scanBuf + x, colorData); + NULL, scanBuf + x, colorData); } -SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc, - int xDest, int yDest, int w, int h, - GBool noClip, GBool nonIsolated) { +SplashError Splash::composite(SplashBitmap *src, SplashAlphaBitmap *srcShape, + int xSrc, int ySrc, int xDest, int yDest, + int w, int h, GBool noClip, GBool nonIsolated) { SplashPipe pipe; Guchar *mono1Ptr, *lineBuf, *linePtr; Guchar mono1Mask, b; @@ -7300,15 +7547,33 @@ SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc, return splashErrModeMismatch; } + GBool usesShape = srcShape && shapeBitmap && src->alpha; + GBool usesAlpha = !noClip || src->alpha; pipeInit(&pipe, NULL, (Guchar)splashRound(state->fillAlpha * 255), - !noClip || src->alpha != NULL, nonIsolated); + usesShape, usesAlpha, nonIsolated); if (src->mode == splashModeMono1) { // in mono1 mode, pipeRun expects the source to be in mono8 // format, so we need to extract the source color values into // scanBuf, expanding them from mono1 to mono8 if (noClip) { - if (src->alpha) { + if (usesShape) { + for (y = 0; y < h; ++y) { + mono1Ptr = src->data + (ySrc + y) * src->rowSize + (xSrc >> 3); + mono1Mask = (Guchar)(0x80 >> (xSrc & 7)); + for (x = 0; x < w; ++x) { + scanBuf[x] = (*mono1Ptr & mono1Mask) ? 0xff : 0x00; + mono1Ptr += mono1Mask & 1; + mono1Mask = (Guchar)((mono1Mask << 7) | (mono1Mask >> 1)); + } + (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y, + srcShape->alpha + + (ySrc + y) * srcShape->alphaRowSize + xSrc, + src->alpha + + (ySrc + y) * src->alphaRowSize + xSrc, + scanBuf); + } + } else if (usesAlpha) { for (y = 0; y < h; ++y) { mono1Ptr = src->data + (ySrc + y) * src->rowSize + (xSrc >> 3); mono1Mask = (Guchar)(0x80 >> (xSrc & 7)); @@ -7320,6 +7585,7 @@ SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc, // this uses shape instead of alpha, which isn't technically // correct, but works out the same (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y, + NULL, src->alpha + (ySrc + y) * src->alphaRowSize + xSrc, scanBuf); @@ -7334,8 +7600,7 @@ SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc, mono1Mask = (Guchar)((mono1Mask << 7) | (mono1Mask >> 1)); } (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y, - NULL, - scanBuf); + NULL, NULL, scanBuf); } } } else { @@ -7356,7 +7621,7 @@ SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc, y1 = t; } if (x0 < x1 && y0 < y1) { - if (src->alpha) { + if (usesShape) { for (y = y0; y < y1; ++y) { mono1Ptr = src->data + (ySrc + y - yDest) * src->rowSize @@ -7368,19 +7633,43 @@ SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc, mono1Mask = (Guchar)((mono1Mask << 7) | (mono1Mask >> 1)); } memcpy(scanBuf2 + x0, - src->alpha + (ySrc + y - yDest) * src->alphaRowSize + + srcShape->alpha + + (ySrc + y - yDest) * srcShape->alphaRowSize + (xSrc + x0 - xDest), x1 - x0); if (!state->clip->clipSpanBinary(scanBuf2, y, x0, x1 - 1, state->strokeAdjust)) { continue; } - // this uses shape instead of alpha, which isn't technically - // correct, but works out the same (this->*pipe.run)(&pipe, x0, x1 - 1, y, scanBuf2 + x0, + srcShape->alpha + + (ySrc + y - yDest) * srcShape->alphaRowSize + + (xSrc + x0 - xDest), scanBuf + x0); } + } else if (usesAlpha) { + for (y = y0; y < y1; ++y) { + mono1Ptr = src->data + + (ySrc + y - yDest) * src->rowSize + + ((xSrc + x0 - xDest) >> 3); + mono1Mask = (Guchar)(0x80 >> ((xSrc + x0 - xDest) & 7)); + for (x = x0; x < x1; ++x) { + scanBuf[x] = (*mono1Ptr & mono1Mask) ? 0xff : 0x00; + mono1Ptr += mono1Mask & 1; + mono1Mask = (Guchar)((mono1Mask << 7) | (mono1Mask >> 1)); + } + memcpy(scanBuf2 + x0, + src->alpha + (ySrc + y - yDest) * src->alphaRowSize + + (xSrc + x0 - xDest), + x1 - x0); + if (!state->clip->clipSpanBinary(scanBuf2, y, x0, x1 - 1, + state->strokeAdjust)) { + continue; + } + (this->*pipe.run)(&pipe, x0, x1 - 1, y, + NULL, scanBuf2 + x0, scanBuf + x0); + } } else { for (y = y0; y < y1; ++y) { mono1Ptr = src->data @@ -7398,8 +7687,7 @@ SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc, continue; } (this->*pipe.run)(&pipe, x0, x1 - 1, y, - scanBuf2 + x0, - scanBuf + x0); + NULL, scanBuf2 + x0, scanBuf + x0); } } } @@ -7410,7 +7698,24 @@ SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc, // so we need to swap bytes lineBuf = (Guchar *)gmallocn(w, 3); if (noClip) { - if (src->alpha) { + if (usesShape) { + for (y = 0; y < h; ++y) { + memcpy(lineBuf, + src->data + (ySrc + y) * src->rowSize + xSrc * 3, + w * 3); + for (x = 0, linePtr = lineBuf; x < w; ++x, linePtr += 3) { + b = linePtr[0]; + linePtr[0] = linePtr[2]; + linePtr[2] = b; + } + (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y, + srcShape->alpha + + (ySrc + y) * srcShape->alphaRowSize + xSrc, + src->alpha + + (ySrc + y) * src->alphaRowSize + xSrc, + lineBuf); + } + } else if (usesAlpha) { for (y = 0; y < h; ++y) { memcpy(lineBuf, src->data + (ySrc + y) * src->rowSize + xSrc * 3, @@ -7420,9 +7725,8 @@ SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc, linePtr[0] = linePtr[2]; linePtr[2] = b; } - // this uses shape instead of alpha, which isn't technically - // correct, but works out the same (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y, + NULL, src->alpha + (ySrc + y) * src->alphaRowSize + xSrc, lineBuf); @@ -7438,7 +7742,7 @@ SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc, linePtr[2] = b; } (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y, - NULL, lineBuf); + NULL, NULL, lineBuf); } } } else { @@ -7459,7 +7763,34 @@ SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc, y1 = t; } if (x0 < x1 && y0 < y1) { - if (src->alpha) { + if (usesShape) { + for (y = y0; y < y1; ++y) { + memcpy(scanBuf + x0, + srcShape->alpha + + (ySrc + y - yDest) * srcShape->alphaRowSize + + (xSrc + x0 - xDest), + x1 - x0); + state->clip->clipSpan(scanBuf, y, x0, x1 - 1, state->strokeAdjust); + memcpy(lineBuf, + src->data + + (ySrc + y - yDest) * src->rowSize + + (xSrc + x0 - xDest) * 3, + (x1 - x0) * 3); + for (x = 0, linePtr = lineBuf; x < x1 - x0; ++x, linePtr += 3) { + b = linePtr[0]; + linePtr[0] = linePtr[2]; + linePtr[2] = b; + } + // this uses shape instead of alpha, which isn't technically + // correct, but works out the same + (this->*pipe.run)(&pipe, x0, x1 - 1, y, + scanBuf + x0, + src->alpha + + (ySrc + y - yDest) * src->alphaRowSize + + (xSrc + x0 - xDest), + lineBuf); + } + } else if (usesAlpha) { for (y = y0; y < y1; ++y) { memcpy(scanBuf + x0, src->alpha + (ySrc + y - yDest) * src->alphaRowSize + @@ -7479,7 +7810,7 @@ SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc, // this uses shape instead of alpha, which isn't technically // correct, but works out the same (this->*pipe.run)(&pipe, x0, x1 - 1, y, - scanBuf + x0, lineBuf); + NULL, scanBuf + x0, lineBuf); } } else { for (y = y0; y < y1; ++y) { @@ -7496,6 +7827,7 @@ SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc, linePtr[2] = b; } (this->*pipe.run)(&pipe, x0, x1 - 1, yDest + y, + NULL, scanBuf + x0, src->data + (ySrc + y - yDest) * src->rowSize + @@ -7508,20 +7840,29 @@ SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc, } else { // src->mode not mono1 or BGR8 if (noClip) { - if (src->alpha) { + if (usesShape) { for (y = 0; y < h; ++y) { - // this uses shape instead of alpha, which isn't technically - // correct, but works out the same (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y, + srcShape->alpha + + (ySrc + y) * srcShape->alphaRowSize + xSrc, src->alpha + (ySrc + y) * src->alphaRowSize + xSrc, src->data + (ySrc + y) * src->rowSize + - xSrc * bitmapComps); + xSrc * bitmapComps); } - } else { + } else if (usesAlpha) { for (y = 0; y < h; ++y) { (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y, NULL, + src->alpha + + (ySrc + y) * src->alphaRowSize + xSrc, + src->data + (ySrc + y) * src->rowSize + + xSrc * bitmapComps); + } + } else { + for (y = 0; y < h; ++y) { + (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y, + NULL, NULL, src->data + (ySrc + y) * src->rowSize + xSrc * bitmapComps); } @@ -7544,16 +7885,32 @@ SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc, y1 = t; } if (x0 < x1 && y0 < y1) { - if (src->alpha) { + if (usesShape) { + for (y = y0; y < y1; ++y) { + memcpy(scanBuf + x0, + srcShape->alpha + + (ySrc + y - yDest) * srcShape->alphaRowSize + + (xSrc + x0 - xDest), + x1 - x0); + state->clip->clipSpan(scanBuf, y, x0, x1 - 1, state->strokeAdjust); + (this->*pipe.run)(&pipe, x0, x1 - 1, y, + scanBuf + x0, + src->alpha + + (ySrc + y - yDest) * src->alphaRowSize + + (xSrc + x0 - xDest), + src->data + + (ySrc + y - yDest) * src->rowSize + + (xSrc + x0 - xDest) * bitmapComps); + } + } else if (usesAlpha) { for (y = y0; y < y1; ++y) { memcpy(scanBuf + x0, src->alpha + (ySrc + y - yDest) * src->alphaRowSize + (xSrc + x0 - xDest), x1 - x0); state->clip->clipSpan(scanBuf, y, x0, x1 - 1, state->strokeAdjust); - // this uses shape instead of alpha, which isn't technically - // correct, but works out the same (this->*pipe.run)(&pipe, x0, x1 - 1, y, + NULL, scanBuf + x0, src->data + (ySrc + y - yDest) * src->rowSize + @@ -7564,6 +7921,7 @@ SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc, memset(scanBuf + x0, 0xff, x1 - x0); state->clip->clipSpan(scanBuf, y, x0, x1 - 1, state->strokeAdjust); (this->*pipe.run)(&pipe, x0, x1 - 1, yDest + y, + NULL, scanBuf + x0, src->data + (ySrc + y - yDest) * src->rowSize + @@ -7578,6 +7936,7 @@ SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc, } SplashError Splash::compositeWithOverprint(SplashBitmap *src, + SplashAlphaBitmap *srcShape, Guint *srcOverprintMaskBitmap, int xSrc, int ySrc, int xDest, int yDest, int w, int h, @@ -7591,27 +7950,39 @@ SplashError Splash::compositeWithOverprint(SplashBitmap *src, return splashErrModeMismatch; } + GBool usesShape = srcShape && shapeBitmap && src->alpha; + GBool usesAlpha = !noClip || src->alpha; pipeInit(&pipe, NULL, (Guchar)splashRound(state->fillAlpha * 255), - !noClip || src->alpha != NULL, nonIsolated, gTrue); + usesShape, usesAlpha, nonIsolated, gTrue); if (noClip) { - if (src->alpha) { + if (usesShape) { for (y = 0; y < h; ++y) { pipe.srcOverprintMaskPtr = srcOverprintMaskBitmap + y * w + xSrc; - // this uses shape instead of alpha, which isn't technically - // correct, but works out the same (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y, + srcShape->alpha + + (ySrc + y) * srcShape->alphaRowSize + xSrc, src->alpha + (ySrc + y) * src->alphaRowSize + xSrc, src->data + (ySrc + y) * src->rowSize + xSrc * bitmapComps); } - } else { + } else if (usesAlpha) { for (y = 0; y < h; ++y) { pipe.srcOverprintMaskPtr = srcOverprintMaskBitmap + y * w + xSrc; (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y, NULL, + src->alpha + + (ySrc + y) * src->alphaRowSize + xSrc, + src->data + (ySrc + y) * src->rowSize + + xSrc * bitmapComps); + } + } else { + for (y = 0; y < h; ++y) { + pipe.srcOverprintMaskPtr = srcOverprintMaskBitmap + y * w + xSrc; + (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y, + NULL, NULL, src->data + (ySrc + y) * src->rowSize + xSrc * bitmapComps); } @@ -7634,7 +8005,27 @@ SplashError Splash::compositeWithOverprint(SplashBitmap *src, y1 = t; } if (x0 < x1 && y0 < y1) { - if (src->alpha) { + if (usesShape) { + for (y = y0; y < y1; ++y) { + memcpy(scanBuf + x0, + srcShape->alpha + + (ySrc + y - yDest) * srcShape->alphaRowSize + + (xSrc + x0 - xDest), + x1 - x0); + state->clip->clipSpan(scanBuf, y, x0, x1 - 1, state->strokeAdjust); + pipe.srcOverprintMaskPtr = srcOverprintMaskBitmap + + (ySrc + y - yDest) * w + + (xSrc + x0 - xDest); + (this->*pipe.run)(&pipe, x0, x1 - 1, y, + scanBuf + x0, + src->alpha + + (ySrc + y - yDest) * src->alphaRowSize + + (xSrc + x0 - xDest), + src->data + + (ySrc + y - yDest) * src->rowSize + + (xSrc + x0 - xDest) * bitmapComps); + } + } else if (usesAlpha) { for (y = y0; y < y1; ++y) { memcpy(scanBuf + x0, src->alpha + (ySrc + y - yDest) * src->alphaRowSize + @@ -7644,9 +8035,8 @@ SplashError Splash::compositeWithOverprint(SplashBitmap *src, pipe.srcOverprintMaskPtr = srcOverprintMaskBitmap + (ySrc + y - yDest) * w + (xSrc + x0 - xDest); - // this uses shape instead of alpha, which isn't technically - // correct, but works out the same (this->*pipe.run)(&pipe, x0, x1 - 1, y, + NULL, scanBuf + x0, src->data + (ySrc + y - yDest) * src->rowSize + @@ -7660,6 +8050,7 @@ SplashError Splash::compositeWithOverprint(SplashBitmap *src, + (ySrc + y - yDest) * w + (xSrc + x0 - xDest); (this->*pipe.run)(&pipe, x0, x1 - 1, y, + NULL, scanBuf + x0, src->data + (ySrc + y - yDest) * src->rowSize + @@ -7786,156 +8177,6 @@ void Splash::compositeBackground(SplashColorPtr color) { memset(bitmap->alpha, 255, bitmap->alphaRowSize * bitmap->height); } -SplashError Splash::blitTransparent(SplashBitmap *src, int xSrc, int ySrc, - int xDest, int yDest, int w, int h) { - SplashColorPtr p, q; - Guchar mask, srcMask; - int x, y; - - if (src->mode != bitmap->mode) { - return splashErrModeMismatch; - } - - switch (bitmap->mode) { - case splashModeMono1: - for (y = 0; y < h; ++y) { - p = &bitmap->data[(yDest + y) * bitmap->rowSize + (xDest >> 3)]; - mask = (Guchar)(0x80 >> (xDest & 7)); - q = &src->data[(ySrc + y) * src->rowSize + (xSrc >> 3)]; - srcMask = (Guchar)(0x80 >> (xSrc & 7)); - for (x = 0; x < w; ++x) { - if (*q & srcMask) { - *p |= mask; - } else { - *p &= (Guchar)~mask; - } - if (!(mask = (Guchar)(mask >> 1))) { - mask = 0x80; - ++p; - } - if (!(srcMask = (Guchar)(srcMask >> 1))) { - srcMask = 0x80; - ++q; - } - } - } - break; - case splashModeMono8: - for (y = 0; y < h; ++y) { - p = &bitmap->data[(yDest + y) * bitmap->rowSize + xDest]; - q = &src->data[(ySrc + y) * src->rowSize + xSrc]; - memcpy(p, q, w); - } - break; - case splashModeRGB8: - case splashModeBGR8: - for (y = 0; y < h; ++y) { - p = &bitmap->data[(yDest + y) * bitmap->rowSize + 3 * xDest]; - q = &src->data[(ySrc + y) * src->rowSize + 3 * xSrc]; - memcpy(p, q, 3 * w); - } - break; -#if SPLASH_CMYK - case splashModeCMYK8: - for (y = 0; y < h; ++y) { - p = &bitmap->data[(yDest + y) * bitmap->rowSize + 4 * xDest]; - q = &src->data[(ySrc + y) * src->rowSize + 4 * xSrc]; - memcpy(p, q, 4 * w); - } - break; -#endif - } - - if (bitmap->alpha) { - for (y = 0; y < h; ++y) { - q = &bitmap->alpha[(yDest + y) * bitmap->alphaRowSize + xDest]; - memset(q, 0, w); - } - } - - return splashOk; -} - -SplashError Splash::blitCorrectedAlpha(SplashBitmap *dest, int xSrc, int ySrc, - int xDest, int yDest, int w, int h) { - SplashColorPtr p, q; - Guchar *alpha0Ptr; - Guchar alpha0, aSrc, mask, srcMask; - int x, y; - - if (bitmap->mode != dest->mode || - !bitmap->alpha || - !dest->alpha || - !groupBackBitmap) { - return splashErrModeMismatch; - } - - switch (bitmap->mode) { - case splashModeMono1: - for (y = 0; y < h; ++y) { - p = &dest->data[(yDest + y) * dest->rowSize + (xDest >> 3)]; - mask = (Guchar)(0x80 >> (xDest & 7)); - q = &bitmap->data[(ySrc + y) * bitmap->rowSize + (xSrc >> 3)]; - srcMask = (Guchar)(0x80 >> (xSrc & 7)); - for (x = 0; x < w; ++x) { - if (*q & srcMask) { - *p |= mask; - } else { - *p &= (Guchar)~mask; - } - if (!(mask = (Guchar)(mask >> 1))) { - mask = 0x80; - ++p; - } - if (!(srcMask = (Guchar)(srcMask >> 1))) { - srcMask = 0x80; - ++q; - } - } - } - break; - case splashModeMono8: - for (y = 0; y < h; ++y) { - p = &dest->data[(yDest + y) * dest->rowSize + xDest]; - q = &bitmap->data[(ySrc + y) * bitmap->rowSize + xSrc]; - memcpy(p, q, w); - } - break; - case splashModeRGB8: - case splashModeBGR8: - for (y = 0; y < h; ++y) { - p = &dest->data[(yDest + y) * dest->rowSize + 3 * xDest]; - q = &bitmap->data[(ySrc + y) * bitmap->rowSize + 3 * xSrc]; - memcpy(p, q, 3 * w); - } - break; -#if SPLASH_CMYK - case splashModeCMYK8: - for (y = 0; y < h; ++y) { - p = &dest->data[(yDest + y) * dest->rowSize + 4 * xDest]; - q = &bitmap->data[(ySrc + y) * bitmap->rowSize + 4 * xSrc]; - memcpy(p, q, 4 * w); - } - break; -#endif - } - - for (y = 0; y < h; ++y) { - p = &dest->alpha[(yDest + y) * dest->alphaRowSize + xDest]; - q = &bitmap->alpha[(ySrc + y) * bitmap->alphaRowSize + xSrc]; - alpha0Ptr = &groupBackBitmap->alpha[(groupBackY + ySrc + y) - * groupBackBitmap->alphaRowSize + - (groupBackX + xSrc)]; - for (x = 0; x < w; ++x) { - alpha0 = *alpha0Ptr++; - aSrc = *q++; - *p++ = (Guchar)(alpha0 + aSrc - div255(alpha0 * aSrc)); - } - } - - return splashOk; -} - SplashPath *Splash::makeStrokePath(SplashPath *path, SplashCoord w, int lineCap, int lineJoin, GBool flatten) { diff --git a/src/xpdf-4.04/splash/Splash.h b/src/xpdf-4.06/splash/Splash.h old mode 100644 new mode 100755 similarity index 84% rename from src/xpdf-4.04/splash/Splash.h rename to src/xpdf-4.06/splash/Splash.h index 9622b07..dcca49d --- a/src/xpdf-4.04/splash/Splash.h +++ b/src/xpdf-4.06/splash/Splash.h @@ -11,16 +11,13 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #include "SplashTypes.h" #include "SplashClip.h" class GString; class Splash; class SplashBitmap; +class SplashAlphaBitmap; struct SplashGlyphBitmap; class SplashState; class SplashPattern; @@ -174,6 +171,7 @@ class Splash { void setLineDash(SplashCoord *lineDash, int lineDashLength, SplashCoord lineDashPhase); void setStrokeAdjust(SplashStrokeAdjustMode strokeAdjust); + void setAlphaIsShape(GBool alphaIsShape); // NB: uses transformed coordinates. void clipResetToRect(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1); @@ -183,9 +181,10 @@ class Splash { // NB: uses untransformed coordinates. SplashError clipToPath(SplashPath *path, GBool eo); void setSoftMask(SplashBitmap *softMask, GBool deleteBitmap = gTrue); - void setInTransparencyGroup(SplashBitmap *groupBackBitmapA, - int groupBackXA, int groupBackYA, - SplashGroupDestInitMode groupDestInitModeA, + void setInTransparencyGroup(Splash *parentA, + int parentOffsetXA, int parentOffsetYA, + SplashAlphaBitmap *alpha0BitmapA, + SplashAlphaBitmap *shapeBitmapA, GBool nonIsolated, GBool knockout); void forceDeferredInit(int y, int h); GBool checkTransparentRect(int x, int y, int w, int h); @@ -210,7 +209,8 @@ class Splash { SplashError fill(SplashPath *path, GBool eo); // Draw a character, using the current fill pattern. - SplashError fillChar(SplashCoord x, SplashCoord y, int c, SplashFont *font); + SplashError fillChar(SplashCoord x, SplashCoord y, + Guint c, SplashFont *font); // Draw a glyph, using the current fill pattern. This function does // not free any data, i.e., it ignores glyph->freeData. @@ -261,14 +261,15 @@ class Splash { // Composite a rectangular region from onto this Splash // object. - SplashError composite(SplashBitmap *src, int xSrc, int ySrc, - int xDest, int yDest, int w, int h, - GBool noClip, GBool nonIsolated); + SplashError composite(SplashBitmap *src, SplashAlphaBitmap *srcShape, + int xSrc, int ySrc, int xDest, int yDest, + int w, int h, GBool noClip, GBool nonIsolated); // Composite a rectangular region from onto this Splash // object, using as the overprint mask per // pixel. This is only supported for CMYK and DeviceN bitmaps. SplashError compositeWithOverprint(SplashBitmap *src, + SplashAlphaBitmap *srcShape, Guint *srcOverprintMaskBitmap, int xSrc, int ySrc, int xDest, int yDest, int w, int h, @@ -278,18 +279,6 @@ class Splash { // background alpha is assumed to be 1. void compositeBackground(SplashColorPtr color); - // Copy a rectangular region from onto the bitmap belonging to - // this Splash object. The destination alpha values are all set to - // zero. - SplashError blitTransparent(SplashBitmap *src, int xSrc, int ySrc, - int xDest, int yDest, int w, int h); - - // Copy a rectangular region from the bitmap belonging to this - // Splash object to . The alpha values are corrected for a - // non-isolated group. - SplashError blitCorrectedAlpha(SplashBitmap *dest, int xSrc, int ySrc, - int xDest, int yDest, int w, int h); - //----- misc // Construct a path for a stroke, given the path to be stroked and @@ -333,78 +322,103 @@ class Splash { SplashImageCache *getImageCache() { return imageCache; } -#if 1 //~tmp: turn off anti-aliasing temporarily - void setInShading(GBool sh) { inShading = sh; } -#endif - private: void pipeInit(SplashPipe *pipe, SplashPattern *pattern, - Guchar aInput, GBool usesShape, - GBool nonIsolatedGroup, GBool usesSrcOverprint = gFalse); + Guchar aInput, GBool usesShape, GBool usesAlpha, + GBool nonIsolatedGroup, GBool usesSrcOverprint = gFalse, + GBool alphaIsShape = gFalse); void pipeRun(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr); + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr); void pipeRunSimpleMono1(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr); + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr); void pipeRunSimpleMono8(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr); + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr); void pipeRunSimpleRGB8(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr); + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr); void pipeRunSimpleBGR8(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr); + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr); #if SPLASH_CMYK void pipeRunSimpleCMYK8(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr); + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr); #endif void pipeRunShapeMono1(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr); + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr); void pipeRunShapeMono8(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr); + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr); void pipeRunShapeRGB8(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr); + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr); void pipeRunShapeBGR8(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr); + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr); #if SPLASH_CMYK void pipeRunShapeCMYK8(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr); + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr); #endif void pipeRunShapeNoAlphaMono8(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr); + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr); void pipeRunAAMono1(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr); + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr); void pipeRunAAMono8(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr); + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr); void pipeRunAARGB8(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr); + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr); void pipeRunAABGR8(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr); + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr); #if SPLASH_CMYK void pipeRunAACMYK8(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr); + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr); #endif void pipeRunSoftMaskMono8(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr); + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr); void pipeRunSoftMaskRGB8(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr); + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr); void pipeRunSoftMaskBGR8(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr); + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr); #if SPLASH_CMYK void pipeRunSoftMaskCMYK8(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr); + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr); #endif void pipeRunNonIsoMono8(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr); + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr); void pipeRunNonIsoRGB8(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr); + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr); void pipeRunNonIsoBGR8(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr); + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr); #if SPLASH_CMYK void pipeRunNonIsoCMYK8(SplashPipe *pipe, int x0, int x1, int y, - Guchar *shapePtr, SplashColorPtr cSrcPtr); + Guchar *shapePtr, Guchar *alphaPtr, + SplashColorPtr cSrcPtr); #endif - void useDestRow(int y); - void copyGroupBackdropRow(int y); + void useBitmapRow(int y); + void copyParentRowColor(int y); + void zeroRowColor(int y); + void zeroRowAlpha(int y); + void computeAlpha0Row(int y); void transform(SplashCoord *matrix, SplashCoord xi, SplashCoord yi, SplashCoord *xo, SplashCoord *yo); void updateModX(int x); @@ -425,7 +439,7 @@ class Splash { SplashError fillWithPattern(SplashPath *path, GBool eo, SplashPattern *pattern, SplashCoord alpha); SplashPath *tweakFillPath(SplashPath *path); - GBool pathAllOutside(SplashPath *path); + GBool pathAllOutside(SplashPath *path, GBool stroke); SplashError fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph); void getImageBounds(SplashCoord xyMin, SplashCoord xyMax, int *xyMinI, int *xyMaxI); @@ -518,17 +532,19 @@ class Splash { SplashState *state; Guchar *scanBuf; Guchar *scanBuf2; - SplashBitmap // for transparency groups, this is the bitmap - *groupBackBitmap; // containing the alpha0/color0 values - int groupBackX, groupBackY; // offset within groupBackBitmap - SplashGroupDestInitMode groupDestInitMode; - int groupDestInitYMin, groupDestInitYMax; + Splash *parent; // transparency group parent + int parentOffsetX, // offset within parent + parentOffsetY; + GBool deferredInit; // true if bitmap initialization is deferred + int deferredInitYMin, // range of rows that have been initialized + deferredInitYMax; + SplashAlphaBitmap *alpha0Bitmap; + SplashAlphaBitmap *shapeBitmap; Guint *overprintMaskBitmap; SplashCoord minLineWidth; int modXMin, modYMin, modXMax, modYMax; SplashClipResult opClipRes; GBool vectorAntialias; - GBool inShading; GBool debugMode; SplashImageCache *imageCache; diff --git a/src/xpdf-4.04/splash/SplashBitmap.cc b/src/xpdf-4.06/splash/SplashBitmap.cc old mode 100644 new mode 100755 similarity index 61% rename from src/xpdf-4.04/splash/SplashBitmap.cc rename to src/xpdf-4.06/splash/SplashBitmap.cc index db341d7..9ddce06 --- a/src/xpdf-4.04/splash/SplashBitmap.cc +++ b/src/xpdf-4.06/splash/SplashBitmap.cc @@ -8,10 +8,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include #include #include "gmem.h" @@ -21,19 +17,96 @@ #include "SplashErrorCodes.h" #include "SplashBitmap.h" +//------------------------------------------------------------------------ +// SplashBitmapMemCache +//------------------------------------------------------------------------ + +#define splashBitmapMemCacheThreshold 4000000 + +SplashBitmapMemCache::SplashBitmapMemCache() { + for (int i = 0; i < splashBitmapMemCacheSize; ++i) { + cache[i].data = NULL; + cache[i].height = 0; + cache[i].rowSize = 0; + } +} + +SplashBitmapMemCache::~SplashBitmapMemCache() { + for (int i = 0; i < splashBitmapMemCacheSize; ++i) { + if (cache[i].data) { + gfree(cache[i].data); + cache[i].data = NULL; + cache[i].height = 0; + cache[i].rowSize = 0; + } + } +} + +void *SplashBitmapMemCache::alloc(int height, SplashBitmapRowSize rowSize) { + // if the block is small, just allocate it + if (rowSize < splashBitmapMemCacheThreshold / height) { + return gmallocn64(height, rowSize); + } + + // if a match is found in the cache, return it + for (int i = splashBitmapMemCacheSize - 1; i >= 0; --i) { + if (cache[i].data && + cache[i].height == height && + cache[i].rowSize == rowSize) { + void *data = cache[i].data; + for (int j = i; j < splashBitmapMemCacheSize - 1; ++j) { + cache[j] = cache[j + 1]; + } + cache[splashBitmapMemCacheSize - 1].data = NULL; + cache[splashBitmapMemCacheSize - 1].height = 0; + cache[splashBitmapMemCacheSize - 1].rowSize = 0; + return data; + } + } + + // if no match was found, clear the cache and allcoate the block + for (int i = 0; i < splashBitmapMemCacheSize; ++i) { + if (cache[i].data) { + gfree(cache[i].data); + cache[i].data = NULL; + cache[i].height = 0; + cache[i].rowSize = 0; + } + } + return gmallocn64(height, rowSize); +} + +void SplashBitmapMemCache::free(void *data, int height, + SplashBitmapRowSize rowSize) { + if (rowSize < splashBitmapMemCacheThreshold / height) { + gfree(data); + return; + } + if (cache[0].data) { + gfree(cache[0].data); + } + for (int i = 0; i < splashBitmapMemCacheSize - 1; ++i) { + cache[i] = cache[i + 1]; + } + cache[splashBitmapMemCacheSize - 1].data = data; + cache[splashBitmapMemCacheSize - 1].height = height; + cache[splashBitmapMemCacheSize - 1].rowSize = rowSize; +} + //------------------------------------------------------------------------ // SplashBitmap //------------------------------------------------------------------------ SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPad, SplashColorMode modeA, GBool alphaA, - GBool topDown, SplashBitmap *parentA) { + GBool topDown, SplashBitmapMemCache *cacheA) { // NB: this code checks that rowSize fits in a signed 32-bit // integer, because some code (outside this class) makes that // assumption width = widthA; height = heightA; mode = modeA; + rowSize = 0; // make gcc happy switch (mode) { case splashModeMono1: if (width <= 0) { @@ -71,25 +144,11 @@ SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPad, alphaA ? "with alpha" : "without alpha", height * rowSize + (alphaA ? height * width : 0)); - 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; - traceMessage("reusing bitmap memory"); + cache = cacheA; + if (cache) { + data = (SplashColorPtr)cache->alloc(height, rowSize); } else { data = (SplashColorPtr)gmallocn64(height, rowSize); - traceMessage("not reusing bitmap memory" - " (parent=%p parent->oldData=%p same-size=%d)", - parent, parent ? parent->oldData : NULL, - parent ? (parent->oldRowSize == rowSize && - parent->oldHeight == height) : 0); } if (!topDown) { data += (height - 1) * rowSize; @@ -97,11 +156,8 @@ SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPad, } if (alphaA) { alphaRowSize = width; - if (parent && parent->oldAlpha && - parent->oldAlphaRowSize == alphaRowSize && - parent->oldHeight == height) { - alpha = parent->oldAlpha; - parent->oldAlpha = NULL; + if (cache) { + alpha = (Guchar *)cache->alloc(height, alphaRowSize); } else { alpha = (Guchar *)gmallocn64(height, alphaRowSize); } @@ -117,20 +173,15 @@ SplashBitmap::~SplashBitmap() { rowSize = -rowSize; data -= (height - 1) * rowSize; } - if (parent && rowSize > 4000000 / height) { - gfree(parent->oldData); - gfree(parent->oldAlpha); - parent->oldData = data; - parent->oldAlpha = alpha; - parent->oldRowSize = rowSize; - parent->oldAlphaRowSize = alphaRowSize; - parent->oldHeight = height; + if (cache) { + cache->free(data, height, rowSize); + if (alpha) { + cache->free(alpha, height, alphaRowSize); + } } else { gfree(data); gfree(alpha); } - gfree(oldData); - gfree(oldAlpha); } SplashError SplashBitmap::writePNMFile(char *fileName) { @@ -286,3 +337,37 @@ SplashColorPtr SplashBitmap::takeData() { return data2; } +void SplashBitmap::doNotCache() { + cache = NULL; +} + + +//------------------------------------------------------------------------ +// SplashAlphaBitmap +//------------------------------------------------------------------------ + +SplashAlphaBitmap::SplashAlphaBitmap(int widthA, int heightA, + SplashBitmapMemCache *cacheA) { + width = widthA; + height = heightA; + alphaRowSize = width; + + traceAlloc(this, "alloc alpha bitmap: %d x %d -> %lld bytes", + width, height, height * alphaRowSize); + + cache = cacheA; + if (cache) { + alpha = (Guchar *)cache->alloc(height, alphaRowSize); + } else { + alpha = (Guchar *)gmallocn64(height, alphaRowSize); + } +} + +SplashAlphaBitmap::~SplashAlphaBitmap() { + traceFree(this, "free alpha bitmap"); + if (cache) { + cache->free(alpha, height, alphaRowSize); + } else { + gfree(alpha); + } +} diff --git a/src/xpdf-4.04/splash/SplashBitmap.h b/src/xpdf-4.06/splash/SplashBitmap.h old mode 100644 new mode 100755 similarity index 59% rename from src/xpdf-4.04/splash/SplashBitmap.h rename to src/xpdf-4.06/splash/SplashBitmap.h index 54975a3..22c4ed2 --- a/src/xpdf-4.04/splash/SplashBitmap.h +++ b/src/xpdf-4.06/splash/SplashBitmap.h @@ -11,10 +11,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #include #include // older compilers won't define SIZE_MAX in stdint.h without this @@ -35,6 +31,39 @@ # define SplashBitmapRowSizeMax LLONG_MAX #endif +//------------------------------------------------------------------------ +// SplashBitmapMemCache +//------------------------------------------------------------------------ + +#define splashBitmapMemCacheSize 4 + +struct SplashBitmapMemCacheEntry { + void *data; + int height; + SplashBitmapRowSize rowSize; +}; + +// This holds onto a small number of freed bitmaps so they can be +// reused, avoiding system overhead for (re)allocating large chunks of +// memory. It's not thread-safe, so it needs to be owned by a single +// thread. +class SplashBitmapMemCache { +public: + + SplashBitmapMemCache(); + ~SplashBitmapMemCache(); + +private: + + void *alloc(int height, SplashBitmapRowSize rowSize); + void free(void *data, int height, SplashBitmapRowSize rowSize); + + SplashBitmapMemCacheEntry cache[splashBitmapMemCacheSize]; + + friend class SplashBitmap; + friend class SplashAlphaBitmap; +}; + //------------------------------------------------------------------------ // SplashBitmap //------------------------------------------------------------------------ @@ -48,7 +77,7 @@ class SplashBitmap { // upside-down, i.e., with the last row first in memory. SplashBitmap(int widthA, int heightA, int rowPad, SplashColorMode modeA, GBool alphaA, - GBool topDown, SplashBitmap *parentA); + GBool topDown, SplashBitmapMemCache *cacheA); ~SplashBitmap(); @@ -72,6 +101,8 @@ class SplashBitmap { // destructor. SplashColorPtr takeData(); + void doNotCache(); + private: int width, height; // size of bitmap @@ -83,16 +114,38 @@ class SplashBitmap { 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; + SplashBitmapMemCache *cache; friend class Splash; }; +//------------------------------------------------------------------------ +// SplashAlphaBitmap +//------------------------------------------------------------------------ + +class SplashAlphaBitmap { +public: + + // Create a new alpha bitmap with x pixels. + SplashAlphaBitmap(int widthA, int heightA, SplashBitmapMemCache *cacheA); + + ~SplashAlphaBitmap(); + + int getWidth() { return width; } + int getHeight() { return height; } + size_t getAlphaRowSize() { return alphaRowSize; } + Guchar *getAlphaPtr() { return alpha; } + +private: + + int width, height; // size of bitmap + size_t alphaRowSize; // size of one row, in bytes + Guchar *alpha; // pointer to the alpha data + + SplashBitmapMemCache *cache; + + friend class Splash; +}; + #endif diff --git a/src/xpdf-4.04/splash/SplashClip.cc b/src/xpdf-4.06/splash/SplashClip.cc old mode 100644 new mode 100755 similarity index 99% rename from src/xpdf-4.04/splash/SplashClip.cc rename to src/xpdf-4.06/splash/SplashClip.cc index bf7b802..4b491aa --- a/src/xpdf-4.04/splash/SplashClip.cc +++ b/src/xpdf-4.06/splash/SplashClip.cc @@ -8,10 +8,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include #include #include "gmem.h" @@ -210,7 +206,7 @@ SplashError SplashClip::clipToPath(SplashPath *path, SplashCoord *matrix, xPath = new SplashXPath(path, matrix, flatness, gTrue, enablePathSimplification, - strokeAdjust); + strokeAdjust, NULL); // check for an empty path if (xPath->length == 0) { diff --git a/src/xpdf-4.04/splash/SplashClip.h b/src/xpdf-4.06/splash/SplashClip.h old mode 100644 new mode 100755 similarity index 94% rename from src/xpdf-4.04/splash/SplashClip.h rename to src/xpdf-4.06/splash/SplashClip.h index fb86ed8..093c65c --- a/src/xpdf-4.04/splash/SplashClip.h +++ b/src/xpdf-4.06/splash/SplashClip.h @@ -11,10 +11,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #include "SplashTypes.h" #include "SplashMath.h" @@ -100,6 +96,9 @@ class SplashClip { // Get the number of arbitrary paths used by the clip region. int getNumPaths(); + // Return true if the clip path is a simple rectangle. + GBool getIsSimple() { return isSimple; } + private: SplashClip(SplashClip *clip); @@ -110,10 +109,11 @@ class SplashClip { hardXMax, hardYMax; // [hardXMin, hardXMax), [hardYMin, hardYMax) SplashCoord xMin, yMin, // current clip bounding rectangle - xMax, yMax; // (these coordinates may be adjusted if - // stroke adjustment is enabled) + xMax, yMax; - int xMinI, yMinI, xMaxI, yMaxI; + int xMinI, yMinI, // integer clip bounding rectangle + xMaxI, yMaxI; // (these coordinates are adjusted if + // stroke adjustment is enabled) GBool intBoundsValid; // true if xMinI, etc. are valid GBool intBoundsStrokeAdjust; // value of strokeAdjust used to compute // xMinI, etc. diff --git a/src/xpdf-4.04/splash/SplashErrorCodes.h b/src/xpdf-4.06/splash/SplashErrorCodes.h old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/splash/SplashErrorCodes.h rename to src/xpdf-4.06/splash/SplashErrorCodes.h diff --git a/src/xpdf-4.04/splash/SplashFTFont.cc b/src/xpdf-4.06/splash/SplashFTFont.cc old mode 100644 new mode 100755 similarity index 97% rename from src/xpdf-4.04/splash/SplashFTFont.cc rename to src/xpdf-4.06/splash/SplashFTFont.cc index 9148144..e40f057 --- a/src/xpdf-4.04/splash/SplashFTFont.cc +++ b/src/xpdf-4.06/splash/SplashFTFont.cc @@ -10,10 +10,6 @@ #if HAVE_FREETYPE_H -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include #include FT_OUTLINE_H #include FT_SIZES_H @@ -223,12 +219,12 @@ SplashFTFont::SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA, SplashFTFont::~SplashFTFont() { } -GBool SplashFTFont::getGlyph(int c, int xFrac, int yFrac, +GBool SplashFTFont::getGlyph(Guint c, int xFrac, int yFrac, SplashGlyphBitmap *bitmap) { return SplashFont::getGlyph(c, xFrac, 0, bitmap); } -GBool SplashFTFont::makeGlyph(int c, int xFrac, int yFrac, +GBool SplashFTFont::makeGlyph(Guint c, int xFrac, int yFrac, SplashGlyphBitmap *bitmap) { SplashFTFontFile *ff; FT_Vector offset; @@ -247,7 +243,7 @@ GBool SplashFTFont::makeGlyph(int c, int xFrac, int yFrac, FT_Set_Transform(ff->face, &matrix, &offset); slot = ff->face->glyph; - if (ff->codeToGID && c < ff->codeToGIDLen) { + if (ff->codeToGID && c < (Guint)ff->codeToGIDLen) { gid = ff->codeToGID[c]; } else { gid = c; @@ -325,7 +321,7 @@ struct SplashFTFontPath { GBool needClose; }; -SplashPath *SplashFTFont::getGlyphPath(int c) { +SplashPath *SplashFTFont::getGlyphPath(Guint c) { static FT_Outline_Funcs outlineFuncs = { #if FREETYPE_MINOR <= 1 (int (*)(FT_Vector *, void *))&glyphPathMoveTo, @@ -350,7 +346,7 @@ SplashPath *SplashFTFont::getGlyphPath(int c) { ff->face->size = sizeObj; FT_Set_Transform(ff->face, &textMatrix, NULL); slot = ff->face->glyph; - if (ff->codeToGID && c < ff->codeToGIDLen) { + if (ff->codeToGID && c < (Guint)ff->codeToGIDLen) { gid = ff->codeToGID[c]; } else { gid = c; diff --git a/src/xpdf-4.04/splash/SplashFTFont.h b/src/xpdf-4.06/splash/SplashFTFont.h old mode 100644 new mode 100755 similarity index 85% rename from src/xpdf-4.04/splash/SplashFTFont.h rename to src/xpdf-4.06/splash/SplashFTFont.h index ac08b00..d7ad39a --- a/src/xpdf-4.04/splash/SplashFTFont.h +++ b/src/xpdf-4.06/splash/SplashFTFont.h @@ -13,10 +13,6 @@ #if HAVE_FREETYPE_H -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #include #include FT_FREETYPE_H #include "SplashFont.h" @@ -36,16 +32,16 @@ class SplashFTFont: public SplashFont { virtual ~SplashFTFont(); // Munge xFrac and yFrac before calling SplashFont::getGlyph. - virtual GBool getGlyph(int c, int xFrac, int yFrac, + virtual GBool getGlyph(Guint c, int xFrac, int yFrac, SplashGlyphBitmap *bitmap); // Rasterize a glyph. The and values are the same // as described for getGlyph. - virtual GBool makeGlyph(int c, int xFrac, int yFrac, + virtual GBool makeGlyph(Guint c, int xFrac, int yFrac, SplashGlyphBitmap *bitmap); // Return the path for a glyph. - virtual SplashPath *getGlyphPath(int c); + virtual SplashPath *getGlyphPath(Guint c); private: diff --git a/src/xpdf-4.04/splash/SplashFTFontEngine.cc b/src/xpdf-4.06/splash/SplashFTFontEngine.cc old mode 100644 new mode 100755 similarity index 99% rename from src/xpdf-4.04/splash/SplashFTFontEngine.cc rename to src/xpdf-4.06/splash/SplashFTFontEngine.cc index 3393954..4b99586 --- a/src/xpdf-4.04/splash/SplashFTFontEngine.cc +++ b/src/xpdf-4.06/splash/SplashFTFontEngine.cc @@ -10,10 +10,6 @@ #if HAVE_FREETYPE_H -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include #ifndef _WIN32 # include diff --git a/src/xpdf-4.04/splash/SplashFTFontEngine.h b/src/xpdf-4.06/splash/SplashFTFontEngine.h old mode 100644 new mode 100755 similarity index 97% rename from src/xpdf-4.04/splash/SplashFTFontEngine.h rename to src/xpdf-4.06/splash/SplashFTFontEngine.h index 24db3c6..e6612e1 --- a/src/xpdf-4.04/splash/SplashFTFontEngine.h +++ b/src/xpdf-4.06/splash/SplashFTFontEngine.h @@ -13,10 +13,6 @@ #if HAVE_FREETYPE_H -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #include #include FT_FREETYPE_H #include "gtypes.h" diff --git a/src/xpdf-4.04/splash/SplashFTFontFile.cc b/src/xpdf-4.06/splash/SplashFTFontFile.cc old mode 100644 new mode 100755 similarity index 98% rename from src/xpdf-4.04/splash/SplashFTFontFile.cc rename to src/xpdf-4.06/splash/SplashFTFontFile.cc index b5fd02a..b76e543 --- a/src/xpdf-4.04/splash/SplashFTFontFile.cc +++ b/src/xpdf-4.06/splash/SplashFTFontFile.cc @@ -10,10 +10,6 @@ #if HAVE_FREETYPE_H -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include "gmem.h" #include "gmempp.h" #include "GString.h" diff --git a/src/xpdf-4.04/splash/SplashFTFontFile.h b/src/xpdf-4.06/splash/SplashFTFontFile.h old mode 100644 new mode 100755 similarity index 97% rename from src/xpdf-4.04/splash/SplashFTFontFile.h rename to src/xpdf-4.06/splash/SplashFTFontFile.h index 3a6b9b7..3720d05 --- a/src/xpdf-4.04/splash/SplashFTFontFile.h +++ b/src/xpdf-4.06/splash/SplashFTFontFile.h @@ -13,10 +13,6 @@ #if HAVE_FREETYPE_H -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #include #include FT_FREETYPE_H #include "SplashFontFile.h" diff --git a/src/xpdf-4.04/splash/SplashFont.cc b/src/xpdf-4.06/splash/SplashFont.cc old mode 100644 new mode 100755 similarity index 97% rename from src/xpdf-4.04/splash/SplashFont.cc rename to src/xpdf-4.06/splash/SplashFont.cc index 2fcd83d..0e147ab --- a/src/xpdf-4.04/splash/SplashFont.cc +++ b/src/xpdf-4.06/splash/SplashFont.cc @@ -8,10 +8,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include #include "gmem.h" #include "gmempp.h" @@ -30,7 +26,7 @@ //------------------------------------------------------------------------ struct SplashFontCacheTag { - int c; + Guint c; short xFrac, yFrac; // x and y fractions int mru; // valid bit (0x80000000) and MRU index int x, y, w, h; // offset and size of glyph @@ -107,7 +103,7 @@ SplashFont::~SplashFont() { } } -GBool SplashFont::getGlyph(int c, int xFrac, int yFrac, +GBool SplashFont::getGlyph(Guint c, int xFrac, int yFrac, SplashGlyphBitmap *bitmap) { SplashGlyphBitmap bitmap2; int size; diff --git a/src/xpdf-4.04/splash/SplashFont.h b/src/xpdf-4.06/splash/SplashFont.h old mode 100644 new mode 100755 similarity index 94% rename from src/xpdf-4.04/splash/SplashFont.h rename to src/xpdf-4.06/splash/SplashFont.h index 2bb9654..9ca0371 --- a/src/xpdf-4.04/splash/SplashFont.h +++ b/src/xpdf-4.06/splash/SplashFont.h @@ -11,10 +11,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #include "gtypes.h" #include "SplashTypes.h" #include "SplashMath.h" @@ -72,16 +68,16 @@ class SplashFont { // splashFontFraction = 1 << splashFontFractionBits. Subclasses // should override this to zero out xFrac and/or yFrac if they don't // support fractional coordinates. - virtual GBool getGlyph(int c, int xFrac, int yFrac, + virtual GBool getGlyph(Guint c, int xFrac, int yFrac, SplashGlyphBitmap *bitmap); // Rasterize a glyph. The and values are the same // as described for getGlyph. - virtual GBool makeGlyph(int c, int xFrac, int yFrac, + virtual GBool makeGlyph(Guint c, int xFrac, int yFrac, SplashGlyphBitmap *bitmap) = 0; // Return the path for a glyph. - virtual SplashPath *getGlyphPath(int c) = 0; + virtual SplashPath *getGlyphPath(Guint c) = 0; // Return the font transform matrix. SplashCoord *getMatrix() { return mat; } diff --git a/src/xpdf-4.04/splash/SplashFontEngine.cc b/src/xpdf-4.06/splash/SplashFontEngine.cc old mode 100644 new mode 100755 similarity index 99% rename from src/xpdf-4.04/splash/SplashFontEngine.cc rename to src/xpdf-4.06/splash/SplashFontEngine.cc index 81afe0c..70338a8 --- a/src/xpdf-4.04/splash/SplashFontEngine.cc +++ b/src/xpdf-4.06/splash/SplashFontEngine.cc @@ -8,10 +8,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include #include #ifndef _WIN32 diff --git a/src/xpdf-4.04/splash/SplashFontEngine.h b/src/xpdf-4.06/splash/SplashFontEngine.h old mode 100644 new mode 100755 similarity index 98% rename from src/xpdf-4.04/splash/SplashFontEngine.h rename to src/xpdf-4.06/splash/SplashFontEngine.h index 59adb95..99d7b1b --- a/src/xpdf-4.04/splash/SplashFontEngine.h +++ b/src/xpdf-4.06/splash/SplashFontEngine.h @@ -11,10 +11,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #include "gtypes.h" class GString; class GList; diff --git a/src/xpdf-4.04/splash/SplashFontFile.cc b/src/xpdf-4.06/splash/SplashFontFile.cc old mode 100644 new mode 100755 similarity index 96% rename from src/xpdf-4.04/splash/SplashFontFile.cc rename to src/xpdf-4.06/splash/SplashFontFile.cc index 2d260e3..8d846a9 --- a/src/xpdf-4.04/splash/SplashFontFile.cc +++ b/src/xpdf-4.06/splash/SplashFontFile.cc @@ -8,10 +8,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include #ifndef _WIN32 # include diff --git a/src/xpdf-4.04/splash/SplashFontFile.h b/src/xpdf-4.06/splash/SplashFontFile.h old mode 100644 new mode 100755 similarity index 97% rename from src/xpdf-4.04/splash/SplashFontFile.h rename to src/xpdf-4.06/splash/SplashFontFile.h index 133e6ab..72c51b8 --- a/src/xpdf-4.04/splash/SplashFontFile.h +++ b/src/xpdf-4.06/splash/SplashFontFile.h @@ -11,10 +11,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #include "gtypes.h" #include "SplashTypes.h" diff --git a/src/xpdf-4.04/splash/SplashFontFileID.cc b/src/xpdf-4.06/splash/SplashFontFileID.cc old mode 100644 new mode 100755 similarity index 91% rename from src/xpdf-4.04/splash/SplashFontFileID.cc rename to src/xpdf-4.06/splash/SplashFontFileID.cc index 27f5203..2c03cf1 --- a/src/xpdf-4.04/splash/SplashFontFileID.cc +++ b/src/xpdf-4.06/splash/SplashFontFileID.cc @@ -8,10 +8,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include "gmempp.h" #include "SplashFontFileID.h" diff --git a/src/xpdf-4.04/splash/SplashFontFileID.h b/src/xpdf-4.06/splash/SplashFontFileID.h old mode 100644 new mode 100755 similarity index 92% rename from src/xpdf-4.04/splash/SplashFontFileID.h rename to src/xpdf-4.06/splash/SplashFontFileID.h index 384018a..c4a0d7e --- a/src/xpdf-4.04/splash/SplashFontFileID.h +++ b/src/xpdf-4.06/splash/SplashFontFileID.h @@ -11,10 +11,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #include "gtypes.h" //------------------------------------------------------------------------ diff --git a/src/xpdf-4.04/splash/SplashGlyphBitmap.h b/src/xpdf-4.06/splash/SplashGlyphBitmap.h old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/splash/SplashGlyphBitmap.h rename to src/xpdf-4.06/splash/SplashGlyphBitmap.h diff --git a/src/xpdf-4.04/splash/SplashMath.h b/src/xpdf-4.06/splash/SplashMath.h old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/splash/SplashMath.h rename to src/xpdf-4.06/splash/SplashMath.h diff --git a/src/xpdf-4.04/splash/SplashPath.cc b/src/xpdf-4.06/splash/SplashPath.cc old mode 100644 new mode 100755 similarity index 98% rename from src/xpdf-4.04/splash/SplashPath.cc rename to src/xpdf-4.06/splash/SplashPath.cc index 7921667..ff993d5 --- a/src/xpdf-4.04/splash/SplashPath.cc +++ b/src/xpdf-4.06/splash/SplashPath.cc @@ -8,10 +8,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include #include "gmem.h" #include "gmempp.h" diff --git a/src/xpdf-4.04/splash/SplashPath.h b/src/xpdf-4.06/splash/SplashPath.h old mode 100644 new mode 100755 similarity index 98% rename from src/xpdf-4.04/splash/SplashPath.h rename to src/xpdf-4.06/splash/SplashPath.h index b5732b8..648b320 --- a/src/xpdf-4.04/splash/SplashPath.h +++ b/src/xpdf-4.06/splash/SplashPath.h @@ -11,10 +11,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #include "SplashTypes.h" //------------------------------------------------------------------------ diff --git a/src/xpdf-4.04/splash/SplashPattern.cc b/src/xpdf-4.06/splash/SplashPattern.cc old mode 100644 new mode 100755 similarity index 94% rename from src/xpdf-4.04/splash/SplashPattern.cc rename to src/xpdf-4.06/splash/SplashPattern.cc index 0c5b509..344a449 --- a/src/xpdf-4.04/splash/SplashPattern.cc +++ b/src/xpdf-4.06/splash/SplashPattern.cc @@ -8,10 +8,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include "gmempp.h" #include "SplashMath.h" #include "SplashScreen.h" diff --git a/src/xpdf-4.04/splash/SplashPattern.h b/src/xpdf-4.06/splash/SplashPattern.h old mode 100644 new mode 100755 similarity index 96% rename from src/xpdf-4.04/splash/SplashPattern.h rename to src/xpdf-4.06/splash/SplashPattern.h index fcbe21d..45a9dcd --- a/src/xpdf-4.04/splash/SplashPattern.h +++ b/src/xpdf-4.06/splash/SplashPattern.h @@ -11,10 +11,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #include "SplashTypes.h" class SplashScreen; diff --git a/src/xpdf-4.04/splash/SplashScreen.cc b/src/xpdf-4.06/splash/SplashScreen.cc old mode 100644 new mode 100755 similarity index 99% rename from src/xpdf-4.04/splash/SplashScreen.cc rename to src/xpdf-4.06/splash/SplashScreen.cc index 9993edc..0428683 --- a/src/xpdf-4.04/splash/SplashScreen.cc +++ b/src/xpdf-4.06/splash/SplashScreen.cc @@ -8,10 +8,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include #include #if HAVE_STD_SORT diff --git a/src/xpdf-4.04/splash/SplashScreen.h b/src/xpdf-4.06/splash/SplashScreen.h old mode 100644 new mode 100755 similarity index 97% rename from src/xpdf-4.04/splash/SplashScreen.h rename to src/xpdf-4.06/splash/SplashScreen.h index 560e275..9edf8e8 --- a/src/xpdf-4.04/splash/SplashScreen.h +++ b/src/xpdf-4.06/splash/SplashScreen.h @@ -11,10 +11,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #include "SplashTypes.h" //------------------------------------------------------------------------ diff --git a/src/xpdf-4.04/splash/SplashState.cc b/src/xpdf-4.06/splash/SplashState.cc old mode 100644 new mode 100755 similarity index 99% rename from src/xpdf-4.04/splash/SplashState.cc rename to src/xpdf-4.06/splash/SplashState.cc index 7fc5104..1bfc22a --- a/src/xpdf-4.04/splash/SplashState.cc +++ b/src/xpdf-4.06/splash/SplashState.cc @@ -8,10 +8,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include #include "gmem.h" #include "gmempp.h" @@ -57,6 +53,7 @@ SplashState::SplashState(int width, int height, GBool vectorAntialias, lineDashLength = 0; lineDashPhase = 0; strokeAdjust = splashStrokeAdjustOff; + alphaIsShape = gFalse; clip = new SplashClip(0, 0, width, height); clipIsShared = gFalse; softMask = NULL; @@ -120,6 +117,7 @@ SplashState::SplashState(int width, int height, GBool vectorAntialias, lineDashLength = 0; lineDashPhase = 0; strokeAdjust = splashStrokeAdjustOff; + alphaIsShape = gFalse; clip = new SplashClip(0, 0, width, height); clipIsShared = gFalse; softMask = NULL; @@ -182,6 +180,7 @@ SplashState::SplashState(SplashState *state) { } lineDashPhase = state->lineDashPhase; strokeAdjust = state->strokeAdjust; + alphaIsShape = state->alphaIsShape; clip = state->clip; clipIsShared = gTrue; softMask = state->softMask; diff --git a/src/xpdf-4.04/splash/SplashState.h b/src/xpdf-4.06/splash/SplashState.h old mode 100644 new mode 100755 similarity index 98% rename from src/xpdf-4.04/splash/SplashState.h rename to src/xpdf-4.06/splash/SplashState.h index be64b47..36c40bb --- a/src/xpdf-4.04/splash/SplashState.h +++ b/src/xpdf-4.06/splash/SplashState.h @@ -11,10 +11,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #include "SplashTypes.h" class SplashPattern; @@ -107,6 +103,7 @@ class SplashState { int lineDashLength; SplashCoord lineDashPhase; SplashStrokeAdjustMode strokeAdjust; + GBool alphaIsShape; SplashClip *clip; GBool clipIsShared; SplashBitmap *softMask; diff --git a/src/xpdf-4.04/splash/SplashTypes.h b/src/xpdf-4.06/splash/SplashTypes.h old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/splash/SplashTypes.h rename to src/xpdf-4.06/splash/SplashTypes.h diff --git a/src/xpdf-4.04/splash/SplashXPath.cc b/src/xpdf-4.06/splash/SplashXPath.cc old mode 100644 new mode 100755 similarity index 91% rename from src/xpdf-4.04/splash/SplashXPath.cc rename to src/xpdf-4.06/splash/SplashXPath.cc index 4c77765..e48c29a --- a/src/xpdf-4.04/splash/SplashXPath.cc +++ b/src/xpdf-4.06/splash/SplashXPath.cc @@ -8,10 +8,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include #include #if HAVE_STD_SORT @@ -21,6 +17,7 @@ #include "gmempp.h" #include "SplashMath.h" #include "SplashPath.h" +#include "SplashClip.h" #include "SplashXPath.h" //------------------------------------------------------------------------ @@ -83,10 +80,11 @@ void SplashXPath::clampCoords(SplashCoord *x, SplashCoord *y) { SplashXPath::SplashXPath(SplashPath *path, SplashCoord *matrix, SplashCoord flatness, GBool closeSubpaths, GBool simplify, - SplashStrokeAdjustMode strokeAdjMode) { + SplashStrokeAdjustMode strokeAdjMode, + SplashClip *clip) { SplashXPathPoint *pts; SplashCoord x0, y0, x1, y1, x2, y2, x3, y3, xsp, ysp, t; - int curSubpath, firstSegInSubpath, i; + int nSubpaths, curSubpath, firstSegInSubpath, i; GBool adjusted; //--- transform the points @@ -99,7 +97,7 @@ SplashXPath::SplashXPath(SplashPath *path, SplashCoord *matrix, //--- do stroke adjustment if (path->hints) { adjusted = strokeAdjust(pts, path->hints, path->hintsLength, - strokeAdjMode); + strokeAdjMode, clip); } else { adjusted = gFalse; } @@ -110,6 +108,7 @@ SplashXPath::SplashXPath(SplashPath *path, SplashCoord *matrix, length = size = 0; x0 = y0 = xsp = ysp = 0; // make gcc happy + nSubpaths = 0; curSubpath = 0; firstSegInSubpath = 0; i = 0; @@ -160,6 +159,7 @@ SplashXPath::SplashXPath(SplashPath *path, SplashCoord *matrix, // end a subpath if (path->flags[i-1] & splashPathLast) { + ++nSubpaths; if (closeSubpaths && (pts[i-1].x != pts[curSubpath].x || pts[i-1].y != pts[curSubpath].y)) { @@ -180,7 +180,7 @@ SplashXPath::SplashXPath(SplashPath *path, SplashCoord *matrix, //--- check for a rectangle isRect = gFalse; rectX0 = rectY0 = rectX1 = rectY1 = 0; - if (length == 4) { + if (nSubpaths == 1 && length == 4) { #if HAVE_STD_SORT std::sort(segs, segs + length, SplashXPathSeg::cmpY); #else @@ -227,7 +227,8 @@ SplashXPath::SplashXPath(SplashPath *path, SplashCoord *matrix, GBool SplashXPath::strokeAdjust(SplashXPathPoint *pts, SplashPathHint *hints, int nHints, - SplashStrokeAdjustMode strokeAdjMode) { + SplashStrokeAdjustMode strokeAdjMode, + SplashClip *clip) { SplashXPathAdjust *adjusts, *adjust; SplashPathHint *hint; SplashCoord x0, y0, x1, y1, x2, y2, x3, y3; @@ -238,6 +239,26 @@ GBool SplashXPath::strokeAdjust(SplashXPathPoint *pts, adjusted = gFalse; + // If there is a simple rectangular clip region, stroke-adjusted + // edges that fall slightly outside the clip region are adjusted + // back inside the clip region. This avoids problems with narrow + // lines in slightly mismatched clip rectangles, which appear to be + // generated somewhat commonly by buggy CAD software. (Note: [clip] + // is NULL when called to build a clip path.) + GBool clipTweak = clip && clip->getIsSimple(); + SplashCoord cx0 = 0, cx1 = 0, cy0 = 0, cy1 = 0; + int cxi0 = 0, cxi1 = 0, cyi0 = 0, cyi1 = 0; + if (clipTweak) { + cx0 = clip->getXMin(); + cx1 = clip->getXMax(); + cy0 = clip->getYMin(); + cy1 = clip->getYMax(); + cxi0 = clip->getXMinI(strokeAdjMode); + cxi1 = clip->getXMaxI(strokeAdjMode); + cyi0 = clip->getYMinI(strokeAdjMode); + cyi1 = clip->getYMaxI(strokeAdjMode); + } + // set up the stroke adjustment hints adjusts = (SplashXPathAdjust *)gmallocn(nHints, sizeof(SplashXPathAdjust)); for (i = 0; i < nHints; ++i) { @@ -282,6 +303,32 @@ GBool SplashXPath::strokeAdjust(SplashXPathPoint *pts, adjusts[i].x1a = adj1 - d; adjusts[i].x1b = adj1 + d; splashStrokeAdjust(adj0, adj1, &xi0, &xi1, strokeAdjMode, w); + if (clipTweak) { + SplashCoord c0, c1; + int ci0, ci1; + if (adjusts[i].vert) { + c0 = cx0; + c1 = cx1; + ci0 = cxi0; + ci1 = cxi1; + } else { + c0 = cy0; + c1 = cy1; + ci0 = cyi0; + ci1 = cyi1; + } + if (adj0 < c0 && c0 < adj1 && adj1 < c1 && + adj1 - c0 > (adj1 - adj0) * 0.2 && + xi1 <= ci0) { + xi0 = ci0; + xi1 = xi0 + 1; + } else if (c0 < adj0 && adj0 < c1 && c1 < adj1 && + c1 - adj0 > (adj1 - adj0) * 0.2 && + ci1 < xi0) { + xi0 = ci1; + xi1 = ci1 + 1; + } + } adjusts[i].x0 = (SplashCoord)xi0; // the "minus epsilon" thing here is needed when vector // antialiasing is turned off -- otherwise stroke adjusted lines diff --git a/src/xpdf-4.04/splash/SplashXPath.h b/src/xpdf-4.06/splash/SplashXPath.h old mode 100644 new mode 100755 similarity index 95% rename from src/xpdf-4.04/splash/SplashXPath.h rename to src/xpdf-4.06/splash/SplashXPath.h index 82d7889..3318866 --- a/src/xpdf-4.04/splash/SplashXPath.h +++ b/src/xpdf-4.06/splash/SplashXPath.h @@ -11,13 +11,10 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #include "SplashTypes.h" class SplashPath; +class SplashClip; struct SplashXPathPoint; struct SplashPathHint; @@ -94,7 +91,8 @@ class SplashXPath { // subpaths. SplashXPath(SplashPath *path, SplashCoord *matrix, SplashCoord flatness, GBool closeSubpaths, - GBool simplify, SplashStrokeAdjustMode strokeAdjMode); + GBool simplify, SplashStrokeAdjustMode strokeAdjMode, + SplashClip *clip); // Copy an expanded path. SplashXPath *copy() { return new SplashXPath(this); } @@ -114,7 +112,8 @@ class SplashXPath { SplashCoord *xo, SplashCoord *yo); GBool strokeAdjust(SplashXPathPoint *pts, SplashPathHint *hints, int nHints, - SplashStrokeAdjustMode strokeAdjMode); + SplashStrokeAdjustMode strokeAdjMode, + SplashClip *clip); void grow(int nSegs); void addCurve(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1, diff --git a/src/xpdf-4.04/splash/SplashXPathScanner.cc b/src/xpdf-4.06/splash/SplashXPathScanner.cc old mode 100644 new mode 100755 similarity index 97% rename from src/xpdf-4.04/splash/SplashXPathScanner.cc rename to src/xpdf-4.06/splash/SplashXPathScanner.cc index 3f167b8..b642866 --- a/src/xpdf-4.04/splash/SplashXPathScanner.cc +++ b/src/xpdf-4.06/splash/SplashXPathScanner.cc @@ -8,10 +8,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include #include #if HAVE_STD_SORT @@ -36,23 +32,25 @@ #define aaVert 4 #define aaHoriz 4 +// 4x4 oversampling tends to generate alpha (coverage) values that are +// too high, so we reduce them here. (Yes, this is a kludge.) static Guchar map16to255[17] = { 0, - 16, - 32, - 48, - 64, - 80, - 96, - 112, - 128, - 143, - 159, - 175, - 191, - 207, - 223, - 239, + 16 / 2, + 32 / 2, + 48 / 2, + 64 - 32, + 80 - 32, + 96 - 32, + 112 - 32, + 128 - 32, + 143 - 32, + 159 - 32, + 175 - 32, + 191 - 32, + 207 - 32, + 223 - 32, + 239 - 32, 255 }; diff --git a/src/xpdf-4.04/splash/SplashXPathScanner.h b/src/xpdf-4.06/splash/SplashXPathScanner.h old mode 100644 new mode 100755 similarity index 98% rename from src/xpdf-4.04/splash/SplashXPathScanner.h rename to src/xpdf-4.06/splash/SplashXPathScanner.h index 39cc0eb..decfc50 --- a/src/xpdf-4.04/splash/SplashXPathScanner.h +++ b/src/xpdf-4.06/splash/SplashXPathScanner.h @@ -11,10 +11,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #include "SplashTypes.h" #include "SplashXPath.h" diff --git a/src/xpdf-4.04/xpdf-qt/CMakeLists.txt b/src/xpdf-4.06/xpdf-qt/CMakeLists.txt old mode 100644 new mode 100755 similarity index 98% rename from src/xpdf-4.04/xpdf-qt/CMakeLists.txt rename to src/xpdf-4.06/xpdf-qt/CMakeLists.txt index 026174a..cecb926 --- a/src/xpdf-4.04/xpdf-qt/CMakeLists.txt +++ b/src/xpdf-4.06/xpdf-qt/CMakeLists.txt @@ -19,7 +19,7 @@ if ((QT4_FOUND OR Qt5Widgets_FOUND OR Qt6Widgets_FOUND) if (QT4_FOUND) include(${QT_USE_FILE}) else () - include_directories(SYSTEM "${QT_INCLUDES}") + include_directories(SYSTEM ${QT_INCLUDES}) add_definitions(${QT_DEFINITIONS}) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${QT_CFLAGS}") endif () diff --git a/src/xpdf-4.04/xpdf-qt/QtPDFCore.cc b/src/xpdf-4.06/xpdf-qt/QtPDFCore.cc old mode 100644 new mode 100755 similarity index 98% rename from src/xpdf-4.04/xpdf-qt/QtPDFCore.cc rename to src/xpdf-4.06/xpdf-qt/QtPDFCore.cc index 9a082ed..f98c565 --- a/src/xpdf-4.04/xpdf-qt/QtPDFCore.cc +++ b/src/xpdf-4.06/xpdf-qt/QtPDFCore.cc @@ -8,10 +8,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include #include #include @@ -23,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -55,8 +52,6 @@ QtPDFCore::QtPDFCore(QWidget *viewportA, GBool reverseVideo): PDFCore(splashModeRGB8, 4, reverseVideo, paperColor) { - int dpiX, dpiY; - viewport = viewportA; hScrollBar = hScrollBarA; vScrollBar = vScrollBarA; @@ -76,6 +71,7 @@ QtPDFCore::QtPDFCore(QWidget *viewportA, dragging = gFalse; + panning = gFalse; inUpdateScrollbars = gFalse; @@ -95,23 +91,28 @@ QtPDFCore::QtPDFCore(QWidget *viewportA, panEnabled = gTrue; showPasswordDialog = gTrue; + scaleFactor = computeScaleFactor(); + displayDpi = computeDisplayDpi(); +} + +QtPDFCore::~QtPDFCore() { +} + +double QtPDFCore::computeScaleFactor() { // get Qt's HiDPI scale factor + QGuiApplication *app = (QGuiApplication *)QGuiApplication::instance(); + QScreen *screen = app->primaryScreen(); #if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) - scaleFactor = viewport->devicePixelRatioF(); -#elif QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) - scaleFactor = viewport->devicePixelRatio(); + return screen->devicePixelRatio(); #else - scaleFactor = 1; + return 1; #endif - - // get the display resolution (used for HiDPI scaling) - dpiX = viewport->logicalDpiX(); - dpiY = viewport->logicalDpiY(); - displayDpi = dpiX < dpiY ? dpiX : dpiY; - displayDpi = (int)(displayDpi * scaleFactor); } -QtPDFCore::~QtPDFCore() { +int QtPDFCore::computeDisplayDpi() { + QGuiApplication *app = (QGuiApplication *)QGuiApplication::instance(); + QScreen *screen = app->primaryScreen(); + return (int)(screen->logicalDotsPerInch() * computeScaleFactor()); } //------------------------------------------------------------------------ diff --git a/src/xpdf-4.04/xpdf-qt/QtPDFCore.h b/src/xpdf-4.06/xpdf-qt/QtPDFCore.h old mode 100644 new mode 100755 similarity index 98% rename from src/xpdf-4.04/xpdf-qt/QtPDFCore.h rename to src/xpdf-4.06/xpdf-qt/QtPDFCore.h index cbd1e3b..dfd5afa --- a/src/xpdf-4.04/xpdf-qt/QtPDFCore.h +++ b/src/xpdf-4.06/xpdf-qt/QtPDFCore.h @@ -11,10 +11,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #include #include "gtypes.h" #include "SplashTypes.h" @@ -163,6 +159,9 @@ class QtPDFCore: public PDFCore { void scrollEvent(); virtual void tick(); + static double computeScaleFactor(); + static int computeDisplayDpi(); + private: //----- hyperlinks diff --git a/src/xpdf-4.04/xpdf-qt/XpdfApp.cc b/src/xpdf-4.06/xpdf-qt/XpdfApp.cc old mode 100644 new mode 100755 similarity index 70% rename from src/xpdf-4.04/xpdf-qt/XpdfApp.cc rename to src/xpdf-4.06/xpdf-qt/XpdfApp.cc index fdcaea5..3b1d31d --- a/src/xpdf-4.04/xpdf-qt/XpdfApp.cc +++ b/src/xpdf-4.06/xpdf-qt/XpdfApp.cc @@ -12,15 +12,14 @@ #include #include #include -#ifdef _WIN32 -# include -#endif +#include #include "config.h" #include "parseargs.h" #include "GString.h" #include "GList.h" #include "gfile.h" #include "GlobalParams.h" +#include "QtPDFCore.h" #include "XpdfViewer.h" #include "XpdfApp.h" #include "gmempp.h" @@ -94,12 +93,15 @@ XpdfApp::XpdfApp(int &argc, char **argv): setApplicationVersion(xpdfVersion); ok = parseArgs(argDesc, &argc, argv); - if (!ok || printVersionArg || printHelpArg) { + if (printVersionArg) { + printf("xpdf version %s [www.xpdfreader.com]\n", xpdfVersion); + printf("%s\n", xpdfCopyright); + ::exit(99); + } + if (!ok || printHelpArg) { fprintf(stderr, "xpdf version %s [www.xpdfreader.com]\n", xpdfVersion); fprintf(stderr, "%s\n", xpdfCopyright); - if (!printVersionArg) { - printUsage("xpdf", "[ [: | +]] ...", argDesc); - } + printUsage("xpdf", "[ [: | +]] ...", argDesc); ::exit(99); } @@ -166,11 +168,47 @@ XpdfApp::XpdfApp(int &argc, char **argv): if (printCommandsArg) { globalParams->setPrintCommands(gTrue); } + zoomScaleFactor = globalParams->getZoomScaleFactor(); + if (zoomScaleFactor != 1) { + if (zoomScaleFactor <= 0) { + zoomScaleFactor = QtPDFCore::computeDisplayDpi() / 72.0; + } + GString *initialZoomStr = globalParams->getInitialZoom(); + double initialZoom = atoi(initialZoomStr->getCString()); + delete initialZoomStr; + if (initialZoom > 0) { + initialZoomStr = GString::format("{0:d}", + (int)(initialZoom * zoomScaleFactor)); + globalParams->setInitialZoom(initialZoomStr->getCString()); + delete initialZoomStr; + } + int defaultFitZoom = globalParams->getDefaultFitZoom(); + if (defaultFitZoom > 0) { + globalParams->setDefaultFitZoom((int)(defaultFitZoom * zoomScaleFactor)); + } + } + GList *zoomValueList = globalParams->getZoomValues(); + nZoomValues = 0; + for (i = 0; i < zoomValueList->getLength() && i < maxZoomValues; ++i) { + GString *val = (GString *)zoomValueList->get(i); + zoomValues[nZoomValues++] = atoi(val->getCString()); + } errorEventType = QEvent::registerEventType(); viewers = new GList(); +#ifndef DISABLE_SESSION_MANAGEMENT + //--- session management + connect(this, SIGNAL(saveStateRequest(QSessionManager&)), + this, SLOT(saveSessionSlot(QSessionManager&)), + Qt::DirectConnection); + if (isSessionRestored()) { + loadSession(sessionId().toLocal8Bit().constData(), gFalse); + return; + } +#endif + //--- remote server mode if (remoteServerArg[0]) { sock = new QLocalSocket(this); @@ -299,13 +337,19 @@ int XpdfApp::getNumViewers() { } XpdfViewer *XpdfApp::newWindow(GBool fullScreen, - const char *remoteServerName) { + const char *remoteServerName, + int x, int y, int width, int height) { XpdfViewer *viewer = new XpdfViewer(this, fullScreen); viewers->append(viewer); if (remoteServerName) { viewer->startRemoteServer(remoteServerName); } - viewer->tweakSize(); + if (width > 0 && height > 0) { + viewer->resize(width, height); + viewer->move(x, y); + } else { + viewer->tweakSize(); + } viewer->show(); return viewer; } @@ -315,7 +359,7 @@ GBool XpdfApp::openInNewWindow(QString fileName, int page, QString dest, const char *remoteServerName) { XpdfViewer *viewer; - viewer = XpdfViewer::create(this, fileName, page, dest, rotate, + viewer = XpdfViewer::create(this, fileName, 1, "", rotate, password, fullScreen); if (!viewer) { return gFalse; @@ -326,6 +370,18 @@ GBool XpdfApp::openInNewWindow(QString fileName, int page, QString dest, } viewer->tweakSize(); viewer->show(); + + // NB: do this after calling show() to avoid weird glitches if show + // resizes the new window + if (!dest.isEmpty()) { + viewer->gotoNamedDestination(dest); + } else { + if (page < 0) { + page = getSavedPageNumber(fileName); + } + viewer->gotoPage(page); + } + return gTrue; } @@ -344,6 +400,9 @@ void XpdfApp::closeWindowOrQuit(XpdfViewer *viewer) { void XpdfApp::quit() { XpdfViewer *viewer; + if (globalParams->getSaveSessionOnQuit()) { + saveSession(NULL, gFalse); + } while (viewers->getLength()) { viewer = (XpdfViewer *)viewers->del(0); viewer->close(); @@ -351,6 +410,127 @@ void XpdfApp::quit() { QApplication::quit(); } +void XpdfApp::saveSession(const char *id, GBool interactive) { + GString *path = globalParams->getSessionFile(); + if (id) { +#if 1 + // We use a single session save file for session manager sessions + // -- this prevents using multiple sessions, but it also avoids + // dealing with stale session save files. + // + // We can't use the same save file for both session manager + // sessions and save-on-quit sessions, because the session manager + // sends a 'save' request immediately on starting, which will + // overwrite the last save-on-quit session. + path->append(".managed"); +#else + path->append('.'); + path->append(id); +#endif + } + FILE *out = openFile(path->getCString(), "wb"); + if (!out) { + if (interactive) { + GString *msg = GString::format("Couldn't write the session file '{0:t}'", + path); + QMessageBox::warning(NULL, "Xpdf Error", msg->getCString()); + delete msg; + } + delete path; + return; + } + delete path; + + fprintf(out, "xpdf-session-1\n"); + for (int i = 0; i < viewers->getLength(); ++i) { + XpdfViewer *viewer = (XpdfViewer *)viewers->get(i); + fprintf(out, "window %d %d %d %d\n", + viewer->x(), viewer->y(), viewer->width(), viewer->height()); + viewer->saveSession(out, 1); + } + + fclose(out); +} + +void XpdfApp::loadSession(const char *id, GBool interactive) { + GString *path = globalParams->getSessionFile(); + if (id) { +#if 1 + // see comment in XpdfApp::saveSession + path->append(".managed"); +#else + path->append('.'); + path->append(id); +#endif + } + FILE *in = openFile(path->getCString(), "rb"); + if (!in) { + if (interactive) { + GString *msg = GString::format("Couldn't read the session file '{0:t}'", + path); + QMessageBox::warning(NULL, "Xpdf Error", msg->getCString()); + delete msg; + } + delete path; + return; + } + delete path; + + char line[1024]; + if (!fgets(line, sizeof(line), in)) { + fclose(in); + return; + } + size_t n = strlen(line); + if (n > 0 && line[n-1] == '\n') { + line[--n] = '\0'; + } + if (n > 0 && line[n-1] == '\r') { + line[--n] = '\0'; + } + if (strcmp(line, "xpdf-session-1")) { + fclose(in); + return; + } + + // if this function is called explicitly (e.g., bound to a key), and + // there is a single empty viewer (because the user has just started + // xpdf), we want to close that viewer + XpdfViewer *viewerToClose = nullptr; + if (viewers->getLength() == 1 && + ((XpdfViewer *)viewers->get(0))->isEmpty()) { + viewerToClose = (XpdfViewer *)viewers->get(0); + } + + while (fgets(line, sizeof(line), in)) { + int x, y, width, height; + if (sscanf(line, "window %d %d %d %d\n", &x, &y, &width, &height) != 4) { + fclose(in); + return; + } + + XpdfViewer *viewer = newWindow(gFalse, NULL, x, y, width, height); + viewer->loadSession(in, 1); + + if (viewerToClose) { + closeWindowOrQuit(viewerToClose); + viewerToClose = nullptr; + } + } + + fclose(in); +} + +void XpdfApp::saveSessionSlot(QSessionManager &sessionMgr) { + // Removing the saveSessionSlot function/slot would be better, but + // that causes problems with moc/cmake -- so just comment out the + // guts. In any case, this function should never even be called if + // DISABLE_SESSION_MANAGEMENT is defined. +#ifndef DISABLE_SESSION_MANAGEMENT + saveSession(sessionMgr.sessionId().toLocal8Bit().constData(), gFalse); +#endif +} + //------------------------------------------------------------------------ void XpdfApp::startUpdatePagesFile() { @@ -413,22 +593,13 @@ int XpdfApp::getSavedPageNumber(const QString &fileName) { void XpdfApp::readPagesFile() { // construct the file name (first time only) if (savedPagesFileName.isEmpty()) { + GString *s = globalParams->getPagesFile(); #ifdef _WIN32 - char path[MAX_PATH]; - if (SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, - SHGFP_TYPE_CURRENT, path) != S_OK) { - return; - } - savedPagesFileName = QString::fromLocal8Bit(path); - savedPagesFileName.append("/xpdf"); - CreateDirectory(savedPagesFileName.toLocal8Bit().constData(), NULL); - savedPagesFileName.append("/xpdf.pages"); + savedPagesFileName = QString::fromLocal8Bit(s->getCString()); #else - GString *path = getHomeDir(); - savedPagesFileName = QString::fromUtf8(path->getCString()); - delete path; - savedPagesFileName.append("/.xpdf.pages"); + savedPagesFileName = QString::fromUtf8(s->getCString()); #endif + delete s; } // no change since last read, so no need to re-read diff --git a/src/xpdf-4.04/xpdf-qt/XpdfApp.h b/src/xpdf-4.06/xpdf-qt/XpdfApp.h old mode 100644 new mode 100755 similarity index 73% rename from src/xpdf-4.04/xpdf-qt/XpdfApp.h rename to src/xpdf-4.06/xpdf-qt/XpdfApp.h index 3ac2d2f..348100c --- a/src/xpdf-4.04/xpdf-qt/XpdfApp.h +++ b/src/xpdf-4.06/xpdf-qt/XpdfApp.h @@ -14,8 +14,10 @@ #include #include #include +#include #include "gtypes.h" +class GString; class GList; class XpdfViewer; @@ -31,6 +33,10 @@ struct XpdfSavedPageNumber { #define maxSavedPageNumbers 100 +//------------------------------------------------------------------------ + +#define maxZoomValues 100 + //------------------------------------------------------------------------ // XpdfApp //------------------------------------------------------------------------ @@ -46,7 +52,9 @@ class XpdfApp: public QApplication { int getNumViewers(); XpdfViewer *newWindow(GBool fullScreen = gFalse, - const char *remoteServerName = NULL); + const char *remoteServerName = NULL, + int x = -1, int y = -1, + int width = -1, int height = -1); GBool openInNewWindow(QString fileName, int page = 1, QString dest = QString(), @@ -67,6 +75,14 @@ class XpdfApp: public QApplication { void quit(); + // Save the current session state. For managed sessions, {id} is the + // session ID. + void saveSession(const char *id, GBool interactive); + + // Load the last saved session. For managed sessions, {id} is the + // session ID to load. + void loadSession(const char *id, GBool interactive); + //--- for use by XpdfViewer int getErrorEventType() { return errorEventType; } @@ -75,6 +91,13 @@ class XpdfApp: public QApplication { const QColor &getFullScreenMatteColor() { return fsMatteColor; } const QColor &getSelectionColor() { return selectionColor; } GBool getReverseVideo() { return reverseVideo; } + double getZoomScaleFactor() { return zoomScaleFactor; } + int getNZoomValues() { return nZoomValues; } + int getZoomValue(int idx) { return zoomValues[idx]; } + +private slots: + + void saveSessionSlot(QSessionManager &sessionMgr); private: @@ -87,6 +110,9 @@ class XpdfApp: public QApplication { QColor fsMatteColor; QColor selectionColor; GBool reverseVideo; + double zoomScaleFactor; + int zoomValues[maxZoomValues]; + int nZoomValues; GList *viewers; // [XpdfViewer] diff --git a/src/xpdf-4.04/xpdf-qt/XpdfViewer.cc b/src/xpdf-4.06/xpdf-qt/XpdfViewer.cc old mode 100644 new mode 100755 similarity index 93% rename from src/xpdf-4.04/xpdf-qt/XpdfViewer.cc rename to src/xpdf-4.06/xpdf-qt/XpdfViewer.cc index 5ed5661..c91ce14 --- a/src/xpdf-4.04/xpdf-qt/XpdfViewer.cc +++ b/src/xpdf-4.06/xpdf-qt/XpdfViewer.cc @@ -83,19 +83,14 @@ static const char *aboutHTML = "
" "XpdfReader uses the following open source libraries:" "
    " - "FreeType is copyright 2006-2020 David Turner, Robert Wilhelm, and Werner Lemberg. FreeType is used here under the terms of the FreeType Project License." - "
  • The Qt Toolkit is Copyright 2015 The Qt Company Ltd. Qt is used here under the terms of the LGPL v2.1." + "
  • FreeType is copyright 2006-2025 David Turner, Robert Wilhelm, and Werner Lemberg. FreeType is used here under the terms of the FreeType Project License." + "
  • The Qt Toolkit is Copyright 2025 The Qt Company Ltd. Qt is used here under the terms of the LGPL v2.1." "
"; const char *helpURL = "http://www.xpdfreader.com/help"; //------------------------------------------------------------------------ -#define nZoomComboBoxVals 13 -static int zoomComboBoxVals[nZoomComboBoxVals] = { - 25, 50, 75, 100, 110, 125, 150, 175, 200, 300, 400, 600, 800 -}; - #define maxZoom 2000 // Maximum number of errors to show in the error window. Beyond this @@ -155,12 +150,14 @@ XpdfViewerCmd XpdfViewer::cmdTab[] = { { "hideToolbar", 0, gFalse, gFalse, &XpdfViewer::cmdHideToolbar }, { "horizontalContinuousMode",0, gFalse, gFalse, &XpdfViewer::cmdHorizontalContinuousMode }, { "linearSelectMode", 0, gFalse, gFalse, &XpdfViewer::cmdLinearSelectMode }, + { "loadSession", 0, gFalse, gFalse, &XpdfViewer::cmdLoadSession }, { "loadTabState", 0, gFalse, gFalse, &XpdfViewer::cmdLoadTabState }, { "newTab", 0, gFalse, gFalse, &XpdfViewer::cmdNewTab }, { "newWindow", 0, gFalse, gFalse, &XpdfViewer::cmdNewWindow }, { "nextPage", 0, gTrue, gFalse, &XpdfViewer::cmdNextPage }, { "nextPageNoScroll", 0, gTrue, gFalse, &XpdfViewer::cmdNextPageNoScroll }, { "nextTab", 0, gFalse, gFalse, &XpdfViewer::cmdNextTab }, + { "normalVideoMode", 0, gFalse, gFalse, &XpdfViewer::cmdNormalVideoMode }, { "open", 0, gFalse, gFalse, &XpdfViewer::cmdOpen }, { "openErrorWindow", 0, gFalse, gFalse, &XpdfViewer::cmdOpenErrorWindow }, { "openFile", 1, gFalse, gFalse, &XpdfViewer::cmdOpenFile }, @@ -187,11 +184,13 @@ XpdfViewerCmd XpdfViewer::cmdTab[] = { { "raise", 0, gFalse, gFalse, &XpdfViewer::cmdRaise }, //~ { "redraw", 0, gTrue, gFalse, &XpdfViewer::cmdRedraw }, { "reload", 0, gTrue, gFalse, &XpdfViewer::cmdReload }, + { "reverseVideoMode", 0, gFalse, gFalse, &XpdfViewer::cmdReverseVideoMode }, { "rotateCCW", 0, gTrue, gFalse, &XpdfViewer::cmdRotateCCW }, { "rotateCW", 0, gTrue, gFalse, &XpdfViewer::cmdRotateCW }, { "run", 1, gFalse, gFalse, &XpdfViewer::cmdRun }, { "saveAs", 0, gTrue, gFalse, &XpdfViewer::cmdSaveAs }, { "saveImage", 0, gTrue, gFalse, &XpdfViewer::cmdSaveImage }, + { "saveSession", 0, gFalse, gFalse, &XpdfViewer::cmdSaveSession }, { "saveTabState", 0, gFalse, gFalse, &XpdfViewer::cmdSaveTabState }, { "scrollDown", 1, gTrue, gFalse, &XpdfViewer::cmdScrollDown }, { "scrollDownNextPage", 1, gTrue, gFalse, &XpdfViewer::cmdScrollDownNextPage }, @@ -227,6 +226,7 @@ XpdfViewerCmd XpdfViewer::cmdTab[] = { { "toggleContinuousMode", 0, gFalse, gFalse, &XpdfViewer::cmdToggleContinuousMode }, { "toggleFullScreenMode", 0, gFalse, gFalse, &XpdfViewer::cmdToggleFullScreenMode }, { "toggleMenuBar", 0, gFalse, gFalse, &XpdfViewer::cmdToggleMenuBar }, + { "toggleReverseVideoMode", 0, gFalse, gFalse, &XpdfViewer::cmdToggleReverseVideoMode }, { "toggleSelectMode", 0, gFalse, gFalse, &XpdfViewer::cmdToggleSelectMode }, { "toggleSidebar", 0, gFalse, gFalse, &XpdfViewer::cmdToggleSidebar }, { "toggleSidebarMoveResizeWin", 0, gFalse, gFalse, &XpdfViewer::cmdToggleSidebarMoveResizeWin }, @@ -391,7 +391,7 @@ QValidator::State ZoomValidator::validate(QString &input, int &pos) const { QChar c; int n, i; - n = input.length(); + n = (int)input.length(); if (n == 0) { return QValidator::Intermediate; } @@ -447,11 +447,11 @@ QVariant PropertyListAnimation::interpolated(const QVariant &from, qreal progress) const { int i; - i = (int)(progress * valueList.size()); + i = (int)(progress * (int)valueList.size()); if (i < 0) { i = 0; } else if (i >= valueList.size()) { - i = valueList.size() - 1; + i = (int)valueList.size() - 1; } return valueList[i]; } @@ -822,6 +822,7 @@ class XpdfTabInfo { XpdfViewer::XpdfViewer(XpdfApp *appA, GBool fullScreen) { setAttribute(Qt::WA_DeleteOnClose, true); app = appA; + reverseVideo = (bool)app->getReverseVideo(); createWindow(); if (fullScreen) { move(0, 0); @@ -1008,6 +1009,118 @@ QMenu *XpdfViewer::createPopupMenu() { return NULL; } +void XpdfViewer::saveSession(FILE *out, int format) { + fprintf(out, "%d\n", tabInfo->getLength()); + for (int i = 0; i < tabInfo->getLength(); ++i) { + XpdfWidget *pdf = ((XpdfTabInfo *)tabInfo->get(i))->pdf; + QString fileName = pdf->getFileName(); + if (!fileName.isEmpty()) { + fprintf(out, "%s\n", fileName.toUtf8().constData()); + char displayModeChar; + switch (pdf->getDisplayMode()) { + case XpdfWidget::pdfDisplaySingle: + displayModeChar = 's'; + break; + case XpdfWidget::pdfDisplayContinuous: + displayModeChar = 'c'; + break; + case XpdfWidget::pdfDisplaySideBySideSingle: + displayModeChar = 'b'; + break; + case XpdfWidget::pdfDisplaySideBySideContinuous: + displayModeChar = 'B'; + break; + case XpdfWidget::pdfDisplayHorizontalContinuous: + displayModeChar = 'h'; + break; + default: + displayModeChar = 'c'; + break; + } + fprintf(out, "%c %d %g %d %d %d\n", + displayModeChar, pdf->getMidPage(), pdf->getZoom(), + pdf->getRotate(), pdf->getScrollX(), pdf->getScrollY()); + } + } +} + +void XpdfViewer::loadSession(FILE *in, int format) { + char line1[1024], line2[1024]; + if (!fgets(line1, sizeof(line1), in)) { + return; + } + int nTabs; + if (sscanf(line1, "%d", &nTabs) != 1) { + return; + } + + GBool first = gTrue; + for (int i = 0; i < nTabs; ++i) { + if (!fgets(line1, sizeof(line1), in) || !fgets(line2, sizeof(line2), in)) { + return; + } + size_t n = strlen(line1); + if (n > 0 && line1[n-1] == '\n') { + line1[--n] = '\0'; + } + if (n > 0 && line1[n-1] == '\r') { + line1[--n] = '\0'; + } + char displayModeChar; + int page, rotate, scrollX, scrollY; + double zoom; + if (sscanf(line2, "%c %d %lf %d %d %d", + &displayModeChar, &page, &zoom, &rotate, + &scrollX, &scrollY) != 6) { + return; + } + GBool ok; + if (first && !currentTab->pdf->hasOpenDocument()) { + ok = open(line1, page, "", rotate, ""); + } else { + ok = openInNewTab(line1, page, "", rotate, "", gFalse); + } + if (ok) { + XpdfWidget *pdf = lastOpenedTab->pdf; + switch (displayModeChar) { + case 's': + pdf->setDisplayMode(XpdfWidget::pdfDisplaySingle); + break; + case 'c': + pdf->setDisplayMode(XpdfWidget::pdfDisplayContinuous); + break; + case 'b': + pdf->setDisplayMode(XpdfWidget::pdfDisplaySideBySideSingle); + break; + case 'B': + pdf->setDisplayMode(XpdfWidget::pdfDisplaySideBySideContinuous); + break; + case 'h': + pdf->setDisplayMode(XpdfWidget::pdfDisplayHorizontalContinuous); + break; + default: break; + } + pdf->setRotate(rotate); + pdf->setZoom(zoom); + pdf->scrollTo(scrollX, scrollY); + } + first = gFalse; + } +} + +GBool XpdfViewer::isEmpty() { + return tabInfo->getLength() == 1 && + ((XpdfTabInfo *)tabInfo->get(0))->pdf->getFileName().isEmpty(); +} + +void XpdfViewer::gotoPage(int page) { + currentTab->pdf->gotoPage(page); +} + +void XpdfViewer::gotoNamedDestination(QString destName) { + currentTab->pdf->gotoNamedDestination(destName); +} + //------------------------------------------------------------------------ // remote server //------------------------------------------------------------------------ @@ -1095,6 +1208,7 @@ void XpdfViewer::execCmd(const char *cmd, QInputEvent *event) { //----- find the command a = -1; b = nCmds; + cmp = 0; // invariant: cmdTab[a].name < name < cmdTab[b].name while (b - a > 1) { m = (a + b) / 2; @@ -1336,10 +1450,7 @@ void XpdfViewer::cmdFindFirst(GString *args[], int nArgs, QInputEvent *event) { int flags; clearFindError(); - flags = 0; - if (findCaseSensitiveAction->isChecked()) { - flags |= XpdfWidget::findCaseSensitive; - } + flags = getFindCaseFlag(); if (findWholeWordsAction->isChecked()) { flags |= XpdfWidget::findWholeWord; } @@ -1352,10 +1463,7 @@ void XpdfViewer::cmdFindNext(GString *args[], int nArgs, QInputEvent *event) { int flags; clearFindError(); - flags = XpdfWidget::findNext; - if (findCaseSensitiveAction->isChecked()) { - flags |= XpdfWidget::findCaseSensitive; - } + flags = XpdfWidget::findNext | getFindCaseFlag(); if (findWholeWordsAction->isChecked()) { flags |= XpdfWidget::findWholeWord; } @@ -1369,10 +1477,7 @@ void XpdfViewer::cmdFindPrevious(GString *args[], int nArgs, int flags; clearFindError(); - flags = XpdfWidget::findBackward | XpdfWidget::findNext; - if (findCaseSensitiveAction->isChecked()) { - flags |= XpdfWidget::findCaseSensitive; - } + flags = XpdfWidget::findBackward | XpdfWidget::findNext | getFindCaseFlag(); if (findWholeWordsAction->isChecked()) { flags |= XpdfWidget::findWholeWord; } @@ -1483,6 +1588,11 @@ void XpdfViewer::cmdLinearSelectMode(GString *args[], int nArgs, updateSelectModeInfo(); } +void XpdfViewer::cmdLoadSession(GString *args[], int nArgs, + QInputEvent *event) { + app->loadSession(NULL, gTrue); +} + void XpdfViewer::cmdLoadTabState(GString *args[], int nArgs, QInputEvent *event) { GString *path = globalParams->getTabStateFile(); @@ -1617,6 +1727,17 @@ void XpdfViewer::cmdNextTab(GString *args[], int nArgs, QInputEvent *event) { } } +void XpdfViewer::cmdNormalVideoMode(GString *args[], int nArgs, + QInputEvent *event) { + if (reverseVideo) { + reverseVideo = false; + for (int i = 0; i < tabInfo->getLength(); ++i) { + ((XpdfTabInfo *)tabInfo->get(i))->pdf->setReverseVideo(reverseVideo); + } + reverseVideoMenuItem->setChecked(reverseVideo); + } +} + void XpdfViewer::cmdOpen(GString *args[], int nArgs, QInputEvent *event) { QString startFile, fileName; @@ -1854,6 +1975,17 @@ void XpdfViewer::cmdReload(GString *args[], int nArgs, QInputEvent *event) { } } +void XpdfViewer::cmdReverseVideoMode(GString *args[], int nArgs, + QInputEvent *event) { + if (!reverseVideo) { + reverseVideo = true; + for (int i = 0; i < tabInfo->getLength(); ++i) { + ((XpdfTabInfo *)tabInfo->get(i))->pdf->setReverseVideo(reverseVideo); + } + reverseVideoMenuItem->setChecked(reverseVideo); + } +} + void XpdfViewer::cmdRotateCW(GString *args[], int nArgs, QInputEvent *event) { currentTab->pdf->setRotate((currentTab->pdf->getRotate() + 90) % 360); } @@ -1899,6 +2031,8 @@ void XpdfViewer::cmdRun(GString *args[], int nArgs, QInputEvent *event) { fmt = args[0]; i = 0; gotSel = gotMouse = gFalse; + selPage = mPage = 0; + selURX = selURY = selLRX = selLRY = mX = mY = 0; while (i < fmt->getLength()) { c0 = fmt->getChar(i); if (c0 == '%' && i+1 < fmt->getLength()) { @@ -1939,6 +2073,11 @@ void XpdfViewer::cmdRun(GString *args[], int nArgs, QInputEvent *event) { (c1 == 'y') ? selURY : (c1 == 'X') ? selLRX : selLRY); break; + case 't': + s = currentTab->pdf->getSelectedText().left(500); + s.replace('\n', ' ').replace('\r', ' '); + cmd->append(s.toLocal8Bit().constData()); + break; case 'i': case 'j': case 'k': @@ -2011,6 +2150,11 @@ void XpdfViewer::cmdSaveImage(GString *args[], int nArgs, QInputEvent *event) { execSaveImageDialog(); } +void XpdfViewer::cmdSaveSession(GString *args[], int nArgs, + QInputEvent *event) { + app->saveSession(NULL, gTrue); +} + void XpdfViewer::cmdSaveTabState(GString *args[], int nArgs, QInputEvent *event) { GString *path = globalParams->getTabStateFile(); @@ -2280,6 +2424,15 @@ void XpdfViewer::cmdToggleMenuBar(GString *args[], int nArgs, } } +void XpdfViewer::cmdToggleReverseVideoMode(GString *args[], int nArgs, + QInputEvent *event) { + reverseVideo = !reverseVideo; + for (int i = 0; i < tabInfo->getLength(); ++i) { + ((XpdfTabInfo *)tabInfo->get(i))->pdf->setReverseVideo(reverseVideo); + } + reverseVideoMenuItem->setChecked(reverseVideo); +} + void XpdfViewer::cmdToggleSelectMode(GString *args[], int nArgs, QInputEvent *event) { if (currentTab->pdf->isBlockSelectMode()) { @@ -2361,13 +2514,16 @@ void XpdfViewer::cmdZoomFitWidth(GString *args[], int nArgs, } void XpdfViewer::cmdZoomIn(GString *args[], int nArgs, QInputEvent *event) { - double z; + double zsf, z; int i; - z = currentTab->pdf->getZoomPercent(currentTab->pdf->getMidPage()); - for (i = 0; i < zoomComboBox->count(); ++i) { - if (zoomComboBoxVals[i] > z) { - currentTab->pdf->zoomCentered(zoomComboBoxVals[i]); + zsf = app->getZoomScaleFactor(); + z = currentTab->pdf->getZoomPercent(currentTab->pdf->getMidPage()) / zsf; + for (i = 0; i < app->getNZoomValues(); ++i) { + // the 1.0001 factor is to allow for floating point jitter when + // multiplying and dividing by zoomScaleFactor + if (app->getZoomValue(i) > 1.0001 * z) { + currentTab->pdf->zoomCentered(app->getZoomValue(i) * zsf); zoomComboBox->setCurrentIndex(i); updateZoomInfo(); break; @@ -2376,13 +2532,16 @@ void XpdfViewer::cmdZoomIn(GString *args[], int nArgs, QInputEvent *event) { } void XpdfViewer::cmdZoomOut(GString *args[], int nArgs, QInputEvent *event) { - double z; + double zsf, z; int i; - z = currentTab->pdf->getZoomPercent(currentTab->pdf->getMidPage()); - for (i = zoomComboBox->count() - 1; i >= 0; --i) { - if (zoomComboBoxVals[i] < z) { - currentTab->pdf->zoomCentered(zoomComboBoxVals[i]); + zsf = app->getZoomScaleFactor(); + z = currentTab->pdf->getZoomPercent(currentTab->pdf->getMidPage()) / zsf; + for (i = app->getNZoomValues() - 1; i >= 0; --i) { + // the 0.9999 factor is to allow for floating point jitter when + // multiplying and dividing by zoomScaleFactor + if (app->getZoomValue(i) < 0.9999 * z) { + currentTab->pdf->zoomCentered(app->getZoomValue(i) * zsf); zoomComboBox->setCurrentIndex(i); updateZoomInfo(); break; @@ -2399,7 +2558,7 @@ void XpdfViewer::cmdZoomPercent(GString *args[], int nArgs, if (z > maxZoom) { z = maxZoom; } - currentTab->pdf->zoomCentered(z); + currentTab->pdf->zoomCentered(z * app->getZoomScaleFactor()); updateZoomInfo(); } @@ -2409,7 +2568,7 @@ void XpdfViewer::cmdZoomToSelection(GString *args[], int nArgs, int pg, xx0, yy0, xx1, yy1; if (currentTab->pdf->getCurrentSelection(&pg, &x0, &y0, &x1, &y1)) { - z = currentTab->pdf->getZoomPercent(pg); + z = currentTab->pdf->getZoomPercent(pg) / app->getZoomScaleFactor(); currentTab->pdf->getCore()->cvtUserToDev(pg, x0, y0, &xx0, &yy0); currentTab->pdf->getCore()->cvtUserToDev(pg, x1, y1, &xx1, &yy1); rx = (double)currentTab->pdf->getCore()->getWindowWidth() @@ -2432,6 +2591,26 @@ void XpdfViewer::cmdZoomToSelection(GString *args[], int nArgs, } } +// Check the find settings menu items and the find text to determine +// the effective case sensitivity setting. +int XpdfViewer::getFindCaseFlag() { + // could use QString::isLower(), but it's only available in Qt 5.12+ + if (findCaseSensitiveAction->isChecked()) { + return XpdfWidget::findCaseSensitive; + } else if (findSmartCaseAction->isChecked()) { + QString s = findEdit->text(); + for (int i = 0; i < s.length(); ++i) { + QChar c = s[i]; + if (c != c.toLower()) { + return XpdfWidget::findCaseSensitive; + } + } + return 0; + } else { + return 0; + } +} + int XpdfViewer::scaleScroll(int delta) { int scaledDelta; @@ -2672,6 +2851,8 @@ void XpdfViewer::mouseWheel(QWheelEvent *e) { keyCode = xpdfKeyCodeMousePress6; } else if (delta.x() < 0) { keyCode = xpdfKeyCodeMousePress7; + } else { + return; } if ((cmds = globalParams->getKeyBinding(keyCode, getModifiers(e->modifiers()), @@ -2848,6 +3029,10 @@ void XpdfViewer::openInNewWinMenuAction() { execCmd("openIn(win)", NULL); } +void XpdfViewer::closeMenuAction() { + execCmd("closeTabOrQuit", NULL); +} + void XpdfViewer::reloadMenuAction() { execCmd("reload", NULL); } @@ -2856,6 +3041,10 @@ void XpdfViewer::saveAsMenuAction() { execCmd("saveAs", NULL); } +void XpdfViewer::loadSessionMenuAction() { + execCmd("loadSession", NULL); +} + void XpdfViewer::saveImageMenuAction() { execCmd("saveImage", NULL); } @@ -2898,6 +3087,10 @@ void XpdfViewer::fullScreenMenuAction(bool checked) { execCmd(checked ? "fullScreenMode" : "windowMode", NULL); } +void XpdfViewer::reverseVideoMenuAction(bool checked) { + execCmd(checked ? "reverseVideoMode" : "normalVideoMode", NULL); +} + void XpdfViewer::rotateClockwiseMenuAction() { execCmd("rotateCW", NULL); } @@ -3191,6 +3384,10 @@ void XpdfViewer::createWindow() { // it will be updated by open/close/toggleSidebar sidebarWidth = 200; + if (globalParams->getInitialMaximized()) { + setWindowState(windowState() | Qt::WindowMaximized); + } + linkTargetBar = new QLabel(this); linkTargetBar->setStyleSheet("padding:2px; background:#00ffff;"); linkTargetBar->setAttribute(Qt::WA_TransparentForMouseEvents, true); @@ -3305,8 +3502,8 @@ void XpdfViewer::createToolBar() { addToolBarSpacing(4); zoomComboBox = new QComboBox(); zoomComboBox->setToolTip("change zoom level"); - for (i = 0; i < nZoomComboBoxVals; ++i) { - zoomVal.setNum(zoomComboBoxVals[i]); + for (i = 0; i < app->getNZoomValues(); ++i) { + zoomVal.setNum(app->getZoomValue(i)); zoomVal.append('%'); zoomComboBox->addItem(zoomVal); } @@ -3353,8 +3550,18 @@ void XpdfViewer::createToolBar() { addToolBarButton(QIcon(":/findPrevious-button"), SLOT(findPrevButtonPressed()), "find previous occurrence"); QMenu *findSettingsMenu = new QMenu(this); + QActionGroup *findCaseGroup = new QActionGroup(findSettingsMenu); + findCaseInsensitiveAction = findSettingsMenu->addAction("case insensitive"); + findCaseInsensitiveAction->setCheckable(true); + findCaseGroup->addAction(findCaseInsensitiveAction); findCaseSensitiveAction = findSettingsMenu->addAction("case sensitive"); findCaseSensitiveAction->setCheckable(true); + findCaseGroup->addAction(findCaseSensitiveAction); + findSmartCaseAction = findSettingsMenu->addAction("smart case"); + findSmartCaseAction->setCheckable(true); + findSmartCaseAction->setChecked(true); + findCaseGroup->addAction(findSmartCaseAction); + findSettingsMenu->addSeparator(); findWholeWordsAction = findSettingsMenu->addAction("whole words"); findWholeWordsAction->setCheckable(true); addToolBarMenuButton(QIcon(":/findSettings-button"), @@ -3411,8 +3618,11 @@ void XpdfViewer::createMainMenu() { fileSubmenu->addAction("&Open...", this, SLOT(openMenuAction())); fileSubmenu->addAction("Open in new window...", this, SLOT(openInNewWinMenuAction())); + fileSubmenu->addAction("Close tab", this, SLOT(closeMenuAction())); fileSubmenu->addAction("Reload", this, SLOT(reloadMenuAction())); fileSubmenu->addAction("&Save as...", this, SLOT(saveAsMenuAction())); + fileSubmenu->addAction("Load last session", + this, SLOT(loadSessionMenuAction())); fileSubmenu->addSeparator(); fileSubmenu->addAction("Save image...", this, SLOT(saveImageMenuAction())); #if XPDFWIDGET_PRINTING @@ -3475,6 +3685,11 @@ void XpdfViewer::createMainMenu() { fullScreenMenuItem = viewSubmenu->addAction("Full screen", this, SLOT(fullScreenMenuAction(bool))); fullScreenMenuItem->setCheckable(true); + reverseVideoMenuItem = + viewSubmenu->addAction("Reverse video", this, + SLOT(reverseVideoMenuAction(bool))); + reverseVideoMenuItem->setCheckable(true); + reverseVideoMenuItem->setChecked(reverseVideo); viewSubmenu->addSeparator(); viewSubmenu->addAction("Rotate clockwise", this, SLOT(rotateClockwiseMenuAction())); @@ -3546,6 +3761,8 @@ QWidget *XpdfViewer::createTabPane() { tabList = new QListWidget(); tabList->setSelectionMode(QAbstractItemView::SingleSelection); + tabList->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + tabList->setTextElideMode(Qt::ElideNone); tabList->setDragEnabled(true); tabList->setDragDropMode(QAbstractItemView::InternalMove); tabList->viewport()->setAcceptDrops(true); @@ -3559,7 +3776,7 @@ QWidget *XpdfViewer::createTabPane() { const QModelIndex&, int))); tabPaneLayout->addWidget(tabList); - QPushButton *newTabBtn = new QPushButton("+ tab"); + QPushButton *newTabBtn = new QPushButton("+ new tab"); connect(newTabBtn, SIGNAL(clicked()), this, SLOT(newTabButtonPressed())); tabPaneLayout->addWidget(newTabBtn); @@ -3670,7 +3887,7 @@ void XpdfViewer::addTab() { GString *initialSelectMode; pdf = new XpdfWidget(NULL, app->getPaperColor(), app->getMatteColor(), - app->getReverseVideo()); + reverseVideo); pdf->setSelectionColor(app->getSelectionColor()); pdf->enableHyperlinks(false); pdf->setKeyPassthrough(true); @@ -3847,7 +4064,8 @@ void XpdfViewer::updateZoomInfo() { } else { pg = 1; } - z = (int)floor(currentTab->pdf->getZoomPercent(pg) + 0.5); + z = (int)floor(currentTab->pdf->getZoomPercent(pg) / + app->getZoomScaleFactor() + 0.5); zoomStr.setNum(z); zoomStr.append('%'); zoomComboBox->setEditText(zoomStr); @@ -3879,23 +4097,13 @@ void XpdfViewer::updateSelectModeInfo() { // - a tab switch happens // It updates all visible info related to the document. void XpdfViewer::updateDocInfo() { - //--- window title - QString windowTitle; - if (currentTab->pdf->hasOpenDocument()) { - windowTitle = currentTab->pdf->getFileName(); - windowTitle += " - XpdfReader"; - } else { - windowTitle = "XpdfReader"; - } - setWindowTitle(windowTitle); - - //--- tab title - QString tabTitle; + //--- window and tab titles + QString windowTitle, tabTitle; if (currentTab->pdf->hasOpenDocument()) { tabTitle = currentTab->pdf->getFileName(); - int i = tabTitle.lastIndexOf('/'); + int i = (int)tabTitle.lastIndexOf('/'); #ifdef _WIN32 - int j = tabTitle.lastIndexOf('\\'); + int j = (int)tabTitle.lastIndexOf('\\'); if (j > i) { i = j; } @@ -3903,9 +4111,12 @@ void XpdfViewer::updateDocInfo() { if (i >= 0) { tabTitle = tabTitle.mid(i + 1) + " [" + tabTitle.left(i + 1) + "]"; } + windowTitle = tabTitle + " - XpdfReader"; } else { tabTitle = "(empty)"; + windowTitle = "XpdfReader"; } + setWindowTitle(windowTitle); currentTab->listItem->setText(tabTitle); currentTab->listItem->setToolTip(tabTitle); @@ -4584,6 +4795,7 @@ QString XpdfViewer::createDocumentInfoFontsHTML(XpdfWidget *view) { char *seenObjs = (char *)gmalloc(numObjects); memset(seenObjs, 0, numObjects); + Annots *annots = doc->getAnnots(); for (int pg = 1; pg <= doc->getNumPages(); ++pg) { Page *page = doc->getCatalog()->getPage(pg); Dict *resDict = page->getResourceDict(); @@ -4591,17 +4803,15 @@ QString XpdfViewer::createDocumentInfoFontsHTML(XpdfWidget *view) { html += scanFonts(resDict, doc, seenObjs); } Object obj1, obj2; - Annots *annots = new Annots(doc, page->getAnnots(&obj1)); - obj1.free(); - for (int i = 0; i < annots->getNumAnnots(); ++i) { - if (annots->getAnnot(i)->getAppearance(&obj1)->isStream()) { + int nAnnots = annots->getNumAnnots(pg); + for (int i = 0; i < nAnnots; ++i) { + if (annots->getAnnot(pg, i)->getAppearance(&obj1)->isStream()) { obj1.streamGetDict()->lookupNF("Resources", &obj2); html += scanFonts(&obj2, doc, seenObjs); obj2.free(); } obj1.free(); } - delete annots; } AcroForm *form = doc->getCatalog()->getForm(); if (form) { @@ -4862,6 +5072,21 @@ void XpdfViewer::execSaveImageDialog() { regionBox->addWidget(selectionBtn); selectionBtn->setEnabled(currentTab->pdf->hasSelection()); + grid->addWidget(new QLabel("Color:"), 1, 0); + + QHBoxLayout *colorBox = new QHBoxLayout(); + grid->addLayout(colorBox, 1, 1); + + QComboBox *colorCombo = new QComboBox(); + colorBox->addWidget(colorCombo); + colorCombo->setEditable(false); + colorCombo->addItem("RGB"); + colorCombo->addItem("Gray"); + colorCombo->addItem("Monochrome"); + colorCombo->setCurrentIndex(0); + + colorBox->addStretch(); + grid->addWidget(new QLabel("Resolution:"), 2, 0); QHBoxLayout *resolutionBox = new QHBoxLayout(); @@ -4926,6 +5151,17 @@ void XpdfViewer::execSaveImageDialog() { currentTab->pdf->getCurrentSelection(&page, &x0, &y0, &x1, &y1); } int fmt = formatCombo->currentIndex(); + XpdfWidget::ImageColorMode color; + if (colorCombo->currentIndex() == 1) { + color = XpdfWidget::pdfImageColorGray; + } else if (colorCombo->currentIndex() == 2) { + color = XpdfWidget::pdfImageColorMono; + if (strcmp(saveImageFormats[fmt].qImageFormat, "TIFF")) { + color = XpdfWidget::pdfImageColorGray; + } + } else { + color = XpdfWidget::pdfImageColorRGB; + } QString fileName = QFileDialog::getSaveFileName(this, "Save Image", QString(), @@ -4933,9 +5169,10 @@ void XpdfViewer::execSaveImageDialog() { if (!fileName.isEmpty()) { QImage img; if (wholePage) { - img = currentTab->pdf->convertPageToImage(page, res); + img = currentTab->pdf->convertPageToImage(page, res, false, color); } else { - img = currentTab->pdf->convertRegionToImage(page, x0, y0, x1, y1, res); + img = currentTab->pdf->convertRegionToImage(page, x0, y0, x1, y1, res, + false, color); } img.save(fileName, saveImageFormats[fmt].qImageFormat); } diff --git a/src/xpdf-4.04/xpdf-qt/XpdfViewer.h b/src/xpdf-4.06/xpdf-qt/XpdfViewer.h old mode 100644 new mode 100755 similarity index 94% rename from src/xpdf-4.04/xpdf-qt/XpdfViewer.h rename to src/xpdf-4.06/xpdf-qt/XpdfViewer.h index f957626..66c3998 --- a/src/xpdf-4.04/xpdf-qt/XpdfViewer.h +++ b/src/xpdf-4.06/xpdf-qt/XpdfViewer.h @@ -154,6 +154,22 @@ class XpdfViewer: public QMainWindow { // Execute a command [cmd], with [event] for context. void execCmd(const char *cmd, QInputEvent *event); + // Used by XpdfApp::saveSession() to save session info for one + // window. + void saveSession(FILE *out, int format); + + // Used by XpdfApp::loadSession() to load a session for one window. + void loadSession(FILE *in, int format); + + // Returns true if this viewer contains a single empty tab. + GBool isEmpty(); + + // Goto [page] in the current tab. + void gotoPage(int page); + + // Goto [destName] in the current tab. + void gotoNamedDestination(QString destName); + public slots: bool close(); @@ -184,8 +200,10 @@ private slots: void openMenuAction(); void openInNewWinMenuAction(); + void closeMenuAction(); void reloadMenuAction(); void saveAsMenuAction(); + void loadSessionMenuAction(); void saveImageMenuAction(); #if XPDFWIDGET_PRINTING void printMenuAction(); @@ -198,6 +216,7 @@ private slots: void sideBySideContinuousModeMenuAction(); void horizontalContinuousModeMenuAction(); void fullScreenMenuAction(bool checked); + void reverseVideoMenuAction(bool checked); void rotateClockwiseMenuAction(); void rotateCounterclockwiseMenuAction(); void zoomToSelectionMenuAction(); @@ -292,12 +311,14 @@ private slots: void cmdHideToolbar(GString *args[], int nArgs, QInputEvent *event); void cmdHorizontalContinuousMode(GString *args[], int nArgs, QInputEvent *event); void cmdLinearSelectMode(GString *args[], int nArgs, QInputEvent *event); + void cmdLoadSession(GString *args[], int nArgs, QInputEvent *event); void cmdLoadTabState(GString *args[], int nArgs, QInputEvent *event); void cmdNewTab(GString *args[], int nArgs, QInputEvent *event); void cmdNewWindow(GString *args[], int nArgs, QInputEvent *event); void cmdNextPage(GString *args[], int nArgs, QInputEvent *event); void cmdNextPageNoScroll(GString *args[], int nArgs, QInputEvent *event); void cmdNextTab(GString *args[], int nArgs, QInputEvent *event); + void cmdNormalVideoMode(GString *args[], int nArgs, QInputEvent *event); void cmdOpen(GString *args[], int nArgs, QInputEvent *event); void cmdOpenErrorWindow(GString *args[], int nArgs, QInputEvent *event); void cmdOpenFile(GString *args[], int nArgs, QInputEvent *event); @@ -323,11 +344,13 @@ private slots: void cmdQuit(GString *args[], int nArgs, QInputEvent *event); void cmdRaise(GString *args[], int nArgs, QInputEvent *event); void cmdReload(GString *args[], int nArgs, QInputEvent *event); + void cmdReverseVideoMode(GString *args[], int nArgs, QInputEvent *event); void cmdRotateCW(GString *args[], int nArgs, QInputEvent *event); void cmdRotateCCW(GString *args[], int nArgs, QInputEvent *event); void cmdRun(GString *args[], int nArgs, QInputEvent *event); void cmdSaveAs(GString *args[], int nArgs, QInputEvent *event); void cmdSaveImage(GString *args[], int nArgs, QInputEvent *event); + void cmdSaveSession(GString *args[], int nArgs, QInputEvent *event); void cmdSaveTabState(GString *args[], int nArgs, QInputEvent *event); void cmdScrollDown(GString *args[], int nArgs, QInputEvent *event); void cmdScrollDownNextPage(GString *args[], int nArgs, QInputEvent *event); @@ -363,6 +386,7 @@ private slots: void cmdToggleContinuousMode(GString *args[], int nArgs, QInputEvent *event); void cmdToggleFullScreenMode(GString *args[], int nArgs, QInputEvent *event); void cmdToggleMenuBar(GString *args[], int nArgs, QInputEvent *event); + void cmdToggleReverseVideoMode(GString *args[], int nArgs, QInputEvent *event); void cmdToggleSelectMode(GString *args[], int nArgs, QInputEvent *event); void cmdToggleSidebar(GString *args[], int nArgs, QInputEvent *event); void cmdToggleSidebarMoveResizeWin(GString *args[], int nArgs, QInputEvent *event); @@ -377,6 +401,7 @@ private slots: void cmdZoomOut(GString *args[], int nArgs, QInputEvent *event); void cmdZoomPercent(GString *args[], int nArgs, QInputEvent *event); void cmdZoomToSelection(GString *args[], int nArgs, QInputEvent *event); + int getFindCaseFlag(); int scaleScroll(int delta); void followLink(QInputEvent *event, GBool onlyIfNoSel, GBool newTab, GBool newWindow); @@ -441,6 +466,7 @@ private slots: QMenuBar *mainMenu; QMenu *displayModeSubmenu; QAction *fullScreenMenuItem; + QAction *reverseVideoMenuItem; QAction *toggleToolbarMenuItem; QAction *toggleSidebarMenuItem; QAction *viewPageLabelsMenuItem; @@ -462,7 +488,9 @@ private slots: QList indicatorIcons; QList indicatorErrIcons; QLineEdit *findEdit; + QAction *findCaseInsensitiveAction; QAction *findCaseSensitiveAction; + QAction *findSmartCaseAction; QAction *findWholeWordsAction; // sidebar pane @@ -483,6 +511,8 @@ private slots: XpdfTabInfo *currentTab; XpdfTabInfo *lastOpenedTab; + bool reverseVideo; + double scaleFactor; XpdfWidget::DisplayMode fullScreenPreviousDisplayMode; diff --git a/src/xpdf-4.04/xpdf-qt/XpdfWidget.cc b/src/xpdf-4.06/xpdf-qt/XpdfWidget.cc old mode 100644 new mode 100755 similarity index 96% rename from src/xpdf-4.04/xpdf-qt/XpdfWidget.cc rename to src/xpdf-4.06/xpdf-qt/XpdfWidget.cc index f5ad763..3be50d2 --- a/src/xpdf-4.04/xpdf-qt/XpdfWidget.cc +++ b/src/xpdf-4.06/xpdf-qt/XpdfWidget.cc @@ -8,10 +8,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #ifdef _WIN32 #include #endif @@ -1266,7 +1262,8 @@ void XpdfWidget::setPrintDPI(int hDPI, int vDPI) { #endif // XPDFWIDGET_PRINTING -QImage XpdfWidget::convertPageToImage(int page, double dpi, bool transparent) { +QImage XpdfWidget::convertPageToImage(int page, double dpi, bool transparent, + ImageColorMode color) { try { PDFDoc *doc = core->getDoc(); if (!doc) { @@ -1275,18 +1272,34 @@ QImage XpdfWidget::convertPageToImage(int page, double dpi, bool transparent) { if (page < 1 || page > doc->getNumPages()) { return QImage(); } - if (transparent) { - SplashColor paperColor; - paperColor[0] = paperColor[1] = paperColor[2] = 0xff; // unused - SplashOutputDev *out = new SplashOutputDev(splashModeRGB8, 1, gFalse, - paperColor); + SplashColorMode mode; + SplashColor paperColor; + QImage::Format format; + if (color == pdfImageColorMono) { + mode = splashModeMono1; + paperColor[0] = 0xff; + format = QImage::Format_Mono; + } else if (color == pdfImageColorGray) { + mode = splashModeMono8; + paperColor[0] = 0xff; + format = QImage::Format_Grayscale8; + } else { + mode = splashModeRGB8; + paperColor[0] = paperColor[1] = paperColor[2] = 0xff; + if (transparent) { + format = QImage::Format_ARGB32; + } else { + format = QImage::Format_RGB888; + } + } + if (format == QImage::Format_ARGB32) { + SplashOutputDev *out = new SplashOutputDev(mode, 1, gFalse, paperColor); out->setNoComposite(gTrue); out->startDoc(doc->getXRef()); - doc->displayPage(out, page, dpi, dpi, core->getRotate(), + doc->displayPage(out, NULL, page, dpi, dpi, core->getRotate(), gFalse, gTrue, gFalse); SplashBitmap *bitmap = out->getBitmap(); - QImage img(bitmap->getWidth(), bitmap->getHeight(), - QImage::Format_ARGB32); + QImage img(bitmap->getWidth(), bitmap->getHeight(), format); Guchar *pix = bitmap->getDataPtr(); Guchar *alpha = bitmap->getAlphaPtr(); Guint *argb = (Guint *)img.bits(); @@ -1301,17 +1314,14 @@ QImage XpdfWidget::convertPageToImage(int page, double dpi, bool transparent) { delete out; return img; } else { - SplashColor paperColor; - paperColor[0] = paperColor[1] = paperColor[2] = 0xff; - SplashOutputDev *out = new SplashOutputDev(splashModeRGB8, 4, gFalse, - paperColor); + SplashOutputDev *out = new SplashOutputDev(mode, 4, gFalse, paperColor); out->startDoc(doc->getXRef()); - doc->displayPage(out, page, dpi, dpi, core->getRotate(), + doc->displayPage(out, NULL, page, dpi, dpi, core->getRotate(), gFalse, gTrue, gFalse); SplashBitmap *bitmap = out->getBitmap(); QImage *img = new QImage((const uchar *)bitmap->getDataPtr(), bitmap->getWidth(), bitmap->getHeight(), - QImage::Format_RGB888); + format); // force a copy QImage img2(img->copy()); delete img; @@ -1325,7 +1335,8 @@ QImage XpdfWidget::convertPageToImage(int page, double dpi, bool transparent) { QImage XpdfWidget::convertRegionToImage(int page, double x0, double y0, double x1, double y1, double dpi, - bool transparent) { + bool transparent, + ImageColorMode color) { try { PDFDoc *doc = core->getDoc(); if (!doc) { @@ -1367,19 +1378,35 @@ QImage XpdfWidget::convertRegionToImage(int page, double x0, double y0, sliceH = (int)(k * (y1 - y0)); } - if (transparent) { - SplashColor paperColor; - paperColor[0] = paperColor[1] = paperColor[2] = 0xff; // unused - SplashOutputDev *out = new SplashOutputDev(splashModeRGB8, 1, gFalse, - paperColor); + SplashColorMode mode; + SplashColor paperColor; + QImage::Format format; + if (color == pdfImageColorMono) { + mode = splashModeMono1; + paperColor[0] = 0xff; + format = QImage::Format_Mono; + } else if (color == pdfImageColorGray) { + mode = splashModeMono8; + paperColor[0] = 0xff; + format = QImage::Format_Grayscale8; + } else { + mode = splashModeRGB8; + paperColor[0] = paperColor[1] = paperColor[2] = 0xff; + if (transparent) { + format = QImage::Format_ARGB32; + } else { + format = QImage::Format_RGB888; + } + } + if (format == QImage::Format_ARGB32) { + SplashOutputDev *out = new SplashOutputDev(mode, 1, gFalse, paperColor); out->setNoComposite(gTrue); out->startDoc(doc->getXRef()); - doc->displayPageSlice(out, page, dpi, dpi, core->getRotate(), + doc->displayPageSlice(out, NULL, page, dpi, dpi, core->getRotate(), gFalse, gTrue, gFalse, sliceX, sliceY, sliceW, sliceH); SplashBitmap *bitmap = out->getBitmap(); - QImage img(bitmap->getWidth(), bitmap->getHeight(), - QImage::Format_ARGB32); + QImage img(bitmap->getWidth(), bitmap->getHeight(), format); Guchar *pix = bitmap->getDataPtr(); Guchar *alpha = bitmap->getAlphaPtr(); Guint *argb = (Guint *)img.bits(); @@ -1394,18 +1421,15 @@ QImage XpdfWidget::convertRegionToImage(int page, double x0, double y0, delete out; return img; } else { - SplashColor paperColor; - paperColor[0] = paperColor[1] = paperColor[2] = 0xff; - SplashOutputDev *out = new SplashOutputDev(splashModeRGB8, 4, gFalse, - paperColor); + SplashOutputDev *out = new SplashOutputDev(mode, 4, gFalse, paperColor); out->startDoc(doc->getXRef()); - doc->displayPageSlice(out, page, dpi, dpi, core->getRotate(), + doc->displayPageSlice(out, NULL, page, dpi, dpi, core->getRotate(), gFalse, gTrue, gFalse, sliceX, sliceY, sliceW, sliceH); SplashBitmap *bitmap = out->getBitmap(); QImage *img = new QImage((const uchar *)bitmap->getDataPtr(), bitmap->getWidth(), bitmap->getHeight(), - QImage::Format_RGB888); + format); // force a copy QImage img2(img->copy()); delete img; @@ -1572,7 +1596,7 @@ bool XpdfWidget::find(const QString &text, int flags) { if (!core->getDoc()) { return false; } - len = text.length(); + len = (int)text.length(); u = (Unicode *)gmallocn(len, sizeof(Unicode)); for (i = 0; i < len; ++i) { u[i] = (Unicode)text[i].unicode(); @@ -1597,7 +1621,7 @@ QVector XpdfWidget::findAll(const QString &text, int firstPage, if (!core->getDoc()) { return v; } - int len = text.length(); + int len = (int)text.length(); Unicode *u = (Unicode *)gmallocn(len, sizeof(Unicode)); for (int i = 0; i < len; ++i) { u[i] = (Unicode)text[i].unicode(); diff --git a/src/xpdf-4.04/xpdf-qt/XpdfWidget.h b/src/xpdf-4.06/xpdf-qt/XpdfWidget.h old mode 100644 new mode 100755 similarity index 95% rename from src/xpdf-4.04/xpdf-qt/XpdfWidget.h rename to src/xpdf-4.06/xpdf-qt/XpdfWidget.h index 0e33d0d..25a8474 --- a/src/xpdf-4.04/xpdf-qt/XpdfWidget.h +++ b/src/xpdf-4.06/xpdf-qt/XpdfWidget.h @@ -2,7 +2,7 @@ // // XpdfWidget.h // -// Copyright 2009-2021 Glyph & Cog, LLC +// Copyright 2009-2025 Glyph & Cog, LLC // //======================================================================== @@ -12,7 +12,7 @@ //!

//! Change history //!

-//! Copyright 2009-2022 Glyph & Cog, LLC +//! Copyright 2009-2025 Glyph & Cog, LLC //! \file @@ -21,10 +21,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #include class QMutex; @@ -74,10 +70,10 @@ struct XpdfFindResult { /*! Page number. */ int page; - /*! \name Bounding box. */ - ///@{ - double xMin, yMin, xMax, yMax; - ///@} + double xMin, /*!< Bounding box - minimum x coordinate. */ + yMin, /*!< Bounding box - minimum y coordinate. */ + xMax, /*!< Bounding box - maximum x coordinate. */ + yMax; /*!< Bounding box - maximum y coordinate. */ }; //------------------------------------------------------------------------ @@ -141,6 +137,15 @@ class XpdfWidget: public QAbstractScrollArea { static const int findWholeWord = 0x00000010; //@} + //! Color modes, to be passed to the image conversion functions. + //! These can be used with XpdfWidget::convertPageToImage() and + //! XpdfWidget::convertRegionToImage(). + enum ImageColorMode { + pdfImageColorRGB, + pdfImageColorGray, + pdfImageColorMono + }; + //! Initialize the XpdfWidget class, reading a configuration file. //! If \a configFileName is non-empty, the specified file is //! tried first. If \a configFileName is empty, or the file @@ -238,7 +243,7 @@ class XpdfWidget: public QAbstractScrollArea { //! Control the password dialog. //! If enabled, the viewer will show a password dialog for encrypted //! files; if disabled, it will simply return \c pdfErrEncrypted unless - //! the correct password is passed to \c pdfLoadFileWithPassword. The + //! the correct password is passed to \c loadFile or \c loadMem. The //! default is enabled. void showPasswordDialog(bool showDlg); @@ -638,22 +643,30 @@ class XpdfWidget: public QAbstractScrollArea { void setPrintDPI(int hDPI, int vDPI); #endif // XPDFWIDGET_PRINTING - //! Convert a page to a color image. - //! This function converts the page number \a page to a 24-bit RGB - //! bitmap, at a resolution of \a dpi dots per inch. If \a - //! transparent is true, the returned image will be 32-bit ARGB + //! Convert a page to an image. + //! This function converts page number \a page to a bitmap, at a + //! resolution of \a dpi dots per inch. The image is 24-bit RGB if + //! \a color is \c pdfImageColorRGB, 8-bit grayscale if \a color is + //! \c pdfImageColorGray, or 1-bit monochrome if \a color is \c + //! pdfImageColorMono. If \a transparent is true and \a color is \c + //! pdfImageColorRGB, the returned image will be 32-bit ARGB //! instead, and will include an alpha channel. - QImage convertPageToImage(int page, double dpi, bool transparent = false); + QImage convertPageToImage(int page, double dpi, bool transparent = false, + ImageColorMode color = pdfImageColorRGB); - //! Convert a rectangular region of a page to a color image. + //! Convert a rectangular region of a page to an image. //! This function converts a rectangular region, defined by corners //! (\a x0,\a y0) and (\a x1,\a y1), of page number \a page to a - //! 24-bit RGB bitmap, at a resolution of \a dpi dots per inch. If - //! \a transparent is true, the returned image will be 32-bit ARGB - //! instead, and will include an alpha channel. + //! bitmap, at a resolution of \a dpi dots per inch. The image is + //! 24-bit RGB if \a color is \c pdfImageColorRGB, 8-bit grayscale + //! if \a color is \c pdfImageColorGray, or 1-bit monochrome if \a + //! color is \c pdfImageColorMono. If \a transparent is true and \a + //! color is \c pdfImageColorRGB, the returned image will be 32-bit + //! ARGB instead, and will include an alpha channel. QImage convertRegionToImage(int page, double x0, double y0, double x1, double y1, double dpi, - bool transparent = false); + bool transparent = false, + ImageColorMode color = pdfImageColorRGB); //! Retrieve an embedded thumbnail image. //! This function returns the embedded thumbnail image for the diff --git a/src/xpdf-4.04/xpdf-qt/XpdfWidgetPrint.cc b/src/xpdf-4.06/xpdf-qt/XpdfWidgetPrint.cc old mode 100644 new mode 100755 similarity index 95% rename from src/xpdf-4.04/xpdf-qt/XpdfWidgetPrint.cc rename to src/xpdf-4.06/xpdf-qt/XpdfWidgetPrint.cc index e57ae10..f9aff45 --- a/src/xpdf-4.04/xpdf-qt/XpdfWidgetPrint.cc +++ b/src/xpdf-4.06/xpdf-qt/XpdfWidgetPrint.cc @@ -60,7 +60,7 @@ XpdfWidget::ErrorCode printPDF(PDFDoc *doc, QPrinter *prt, CGContextRef ctx; CGAffineTransform pageTransform; QPrinter::ColorMode colorMode; - QSizeF paperSize; + QSize paperSize; QPrinter::PaperSource paperSource; QPageLayout::Orientation pageOrientation; FILE *f; @@ -117,7 +117,7 @@ XpdfWidget::ErrorCode printPDF(PDFDoc *doc, QPrinter *prt, //--- get other parameters colorMode = prt->colorMode(); - paperSize = prt->paperSize(QPrinter::Point); + paperSize = prt->pageLayout().pageSize().sizePoints(); paperSource = prt->paperSource(); pageOrientation = prt->pageLayout().orientation(); @@ -325,8 +325,8 @@ XpdfWidget::ErrorCode printPDF(PDFDoc *doc, QPrinter *prt, int hDPI, int vDPI, XpdfWidget *widget) { int startPage, endPage; - QPrinter::PaperSize paperSize; - QSizeF paperSizePts; + QPageSize::PageSizeId paperSize; + QSize paperSizePts; QPrinter::PaperSource paperSource; QPrinter::DuplexMode duplex; GString *psFileName; @@ -356,8 +356,8 @@ XpdfWidget::ErrorCode printPDF(PDFDoc *doc, QPrinter *prt, //--- get other parameters - paperSize = prt->paperSize(); - paperSizePts = prt->paperSize(QPrinter::Point); + paperSize = prt->pageLayout().pageSize().id(); + paperSizePts = prt->pageLayout().pageSize().sizePoints(); paperSource = prt->paperSource(); duplex = prt->duplex(); @@ -395,7 +395,7 @@ XpdfWidget::ErrorCode printPDF(PDFDoc *doc, QPrinter *prt, fclose(psFile); goto err1; } - doc->displayPage(psOut, pg, 72, 72, 0, + doc->displayPage(psOut, NULL, pg, 72, 72, 0, !globalParams->getPSUseCropBoxAsPage(), gTrue, gTrue); widget->updatePrintStatus(pg + 1, startPage, endPage); @@ -425,11 +425,11 @@ XpdfWidget::ErrorCode printPDF(PDFDoc *doc, QPrinter *prt, nOptions = 0; switch (paperSize) { - case QPrinter::A4: paperSizeStr = "A4"; break; - case QPrinter::Comm10E: paperSizeStr = "COM10"; break; - case QPrinter::DLE: paperSizeStr = "DL"; break; - case QPrinter::Legal: paperSizeStr = "Legal"; break; - case QPrinter::Letter: paperSizeStr = "Letter"; break; + case QPageSize::A4: paperSizeStr = "A4"; break; + case QPageSize::Comm10E: paperSizeStr = "COM10"; break; + case QPageSize::DLE: paperSizeStr = "DL"; break; + case QPageSize::Legal: paperSizeStr = "Legal"; break; + case QPageSize::Letter: paperSizeStr = "Letter"; break; default: paperSizeStr = NULL; break; } switch (paperSource) { diff --git a/src/xpdf-4.04/xpdf-qt/XpdfWidgetPrint.h b/src/xpdf-4.06/xpdf-qt/XpdfWidgetPrint.h old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf-qt/XpdfWidgetPrint.h rename to src/xpdf-4.06/xpdf-qt/XpdfWidgetPrint.h diff --git a/src/xpdf-4.04/xpdf-qt/back.svg b/src/xpdf-4.06/xpdf-qt/back.svg old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf-qt/back.svg rename to src/xpdf-4.06/xpdf-qt/back.svg diff --git a/src/xpdf-4.04/xpdf-qt/findNext.svg b/src/xpdf-4.06/xpdf-qt/findNext.svg old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf-qt/findNext.svg rename to src/xpdf-4.06/xpdf-qt/findNext.svg diff --git a/src/xpdf-4.04/xpdf-qt/findPrevious.svg b/src/xpdf-4.06/xpdf-qt/findPrevious.svg old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf-qt/findPrevious.svg rename to src/xpdf-4.06/xpdf-qt/findPrevious.svg diff --git a/src/xpdf-4.04/xpdf-qt/findSettings.svg b/src/xpdf-4.06/xpdf-qt/findSettings.svg old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf-qt/findSettings.svg rename to src/xpdf-4.06/xpdf-qt/findSettings.svg diff --git a/src/xpdf-4.04/xpdf-qt/fitPage.svg b/src/xpdf-4.06/xpdf-qt/fitPage.svg old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf-qt/fitPage.svg rename to src/xpdf-4.06/xpdf-qt/fitPage.svg diff --git a/src/xpdf-4.04/xpdf-qt/fitPageOn.svg b/src/xpdf-4.06/xpdf-qt/fitPageOn.svg old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf-qt/fitPageOn.svg rename to src/xpdf-4.06/xpdf-qt/fitPageOn.svg diff --git a/src/xpdf-4.04/xpdf-qt/fitWidth.svg b/src/xpdf-4.06/xpdf-qt/fitWidth.svg old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf-qt/fitWidth.svg rename to src/xpdf-4.06/xpdf-qt/fitWidth.svg diff --git a/src/xpdf-4.04/xpdf-qt/fitWidthOn.svg b/src/xpdf-4.06/xpdf-qt/fitWidthOn.svg old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf-qt/fitWidthOn.svg rename to src/xpdf-4.06/xpdf-qt/fitWidthOn.svg diff --git a/src/xpdf-4.04/xpdf-qt/forward.svg b/src/xpdf-4.06/xpdf-qt/forward.svg old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf-qt/forward.svg rename to src/xpdf-4.06/xpdf-qt/forward.svg diff --git a/src/xpdf-4.04/xpdf-qt/icons.qrc b/src/xpdf-4.06/xpdf-qt/icons.qrc old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf-qt/icons.qrc rename to src/xpdf-4.06/xpdf-qt/icons.qrc diff --git a/src/xpdf-4.04/xpdf-qt/indicator-icon-err0.svg b/src/xpdf-4.06/xpdf-qt/indicator-icon-err0.svg old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf-qt/indicator-icon-err0.svg rename to src/xpdf-4.06/xpdf-qt/indicator-icon-err0.svg diff --git a/src/xpdf-4.04/xpdf-qt/indicator-icon-err1.svg b/src/xpdf-4.06/xpdf-qt/indicator-icon-err1.svg old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf-qt/indicator-icon-err1.svg rename to src/xpdf-4.06/xpdf-qt/indicator-icon-err1.svg diff --git a/src/xpdf-4.04/xpdf-qt/indicator-icon-err2.svg b/src/xpdf-4.06/xpdf-qt/indicator-icon-err2.svg old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf-qt/indicator-icon-err2.svg rename to src/xpdf-4.06/xpdf-qt/indicator-icon-err2.svg diff --git a/src/xpdf-4.04/xpdf-qt/indicator-icon-err3.svg b/src/xpdf-4.06/xpdf-qt/indicator-icon-err3.svg old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf-qt/indicator-icon-err3.svg rename to src/xpdf-4.06/xpdf-qt/indicator-icon-err3.svg diff --git a/src/xpdf-4.04/xpdf-qt/indicator-icon-err4.svg b/src/xpdf-4.06/xpdf-qt/indicator-icon-err4.svg old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf-qt/indicator-icon-err4.svg rename to src/xpdf-4.06/xpdf-qt/indicator-icon-err4.svg diff --git a/src/xpdf-4.04/xpdf-qt/indicator-icon-err5.svg b/src/xpdf-4.06/xpdf-qt/indicator-icon-err5.svg old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf-qt/indicator-icon-err5.svg rename to src/xpdf-4.06/xpdf-qt/indicator-icon-err5.svg diff --git a/src/xpdf-4.04/xpdf-qt/indicator-icon-err6.svg b/src/xpdf-4.06/xpdf-qt/indicator-icon-err6.svg old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf-qt/indicator-icon-err6.svg rename to src/xpdf-4.06/xpdf-qt/indicator-icon-err6.svg diff --git a/src/xpdf-4.04/xpdf-qt/indicator-icon-err7.svg b/src/xpdf-4.06/xpdf-qt/indicator-icon-err7.svg old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf-qt/indicator-icon-err7.svg rename to src/xpdf-4.06/xpdf-qt/indicator-icon-err7.svg diff --git a/src/xpdf-4.04/xpdf-qt/indicator-icon0.svg b/src/xpdf-4.06/xpdf-qt/indicator-icon0.svg old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf-qt/indicator-icon0.svg rename to src/xpdf-4.06/xpdf-qt/indicator-icon0.svg diff --git a/src/xpdf-4.04/xpdf-qt/indicator-icon1.svg b/src/xpdf-4.06/xpdf-qt/indicator-icon1.svg old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf-qt/indicator-icon1.svg rename to src/xpdf-4.06/xpdf-qt/indicator-icon1.svg diff --git a/src/xpdf-4.04/xpdf-qt/indicator-icon2.svg b/src/xpdf-4.06/xpdf-qt/indicator-icon2.svg old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf-qt/indicator-icon2.svg rename to src/xpdf-4.06/xpdf-qt/indicator-icon2.svg diff --git a/src/xpdf-4.04/xpdf-qt/indicator-icon3.svg b/src/xpdf-4.06/xpdf-qt/indicator-icon3.svg old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf-qt/indicator-icon3.svg rename to src/xpdf-4.06/xpdf-qt/indicator-icon3.svg diff --git a/src/xpdf-4.04/xpdf-qt/indicator-icon4.svg b/src/xpdf-4.06/xpdf-qt/indicator-icon4.svg old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf-qt/indicator-icon4.svg rename to src/xpdf-4.06/xpdf-qt/indicator-icon4.svg diff --git a/src/xpdf-4.04/xpdf-qt/indicator-icon5.svg b/src/xpdf-4.06/xpdf-qt/indicator-icon5.svg old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf-qt/indicator-icon5.svg rename to src/xpdf-4.06/xpdf-qt/indicator-icon5.svg diff --git a/src/xpdf-4.04/xpdf-qt/indicator-icon6.svg b/src/xpdf-4.06/xpdf-qt/indicator-icon6.svg old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf-qt/indicator-icon6.svg rename to src/xpdf-4.06/xpdf-qt/indicator-icon6.svg diff --git a/src/xpdf-4.04/xpdf-qt/indicator-icon7.svg b/src/xpdf-4.06/xpdf-qt/indicator-icon7.svg old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf-qt/indicator-icon7.svg rename to src/xpdf-4.06/xpdf-qt/indicator-icon7.svg diff --git a/src/xpdf-4.04/xpdf-qt/selectModeBlock.svg b/src/xpdf-4.06/xpdf-qt/selectModeBlock.svg old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf-qt/selectModeBlock.svg rename to src/xpdf-4.06/xpdf-qt/selectModeBlock.svg diff --git a/src/xpdf-4.04/xpdf-qt/selectModeLinear.svg b/src/xpdf-4.06/xpdf-qt/selectModeLinear.svg old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf-qt/selectModeLinear.svg rename to src/xpdf-4.06/xpdf-qt/selectModeLinear.svg diff --git a/src/xpdf-4.04/xpdf-qt/toggleSidebar.svg b/src/xpdf-4.06/xpdf-qt/toggleSidebar.svg old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf-qt/toggleSidebar.svg rename to src/xpdf-4.06/xpdf-qt/toggleSidebar.svg diff --git a/src/xpdf-4.04/xpdf-qt/xpdf-icon.ico b/src/xpdf-4.06/xpdf-qt/xpdf-icon.ico old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf-qt/xpdf-icon.ico rename to src/xpdf-4.06/xpdf-qt/xpdf-icon.ico diff --git a/src/xpdf-4.04/xpdf-qt/xpdf-icon.svg b/src/xpdf-4.06/xpdf-qt/xpdf-icon.svg old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf-qt/xpdf-icon.svg rename to src/xpdf-4.06/xpdf-qt/xpdf-icon.svg diff --git a/src/xpdf-4.04/xpdf-qt/xpdf.cc b/src/xpdf-4.06/xpdf-qt/xpdf.cc old mode 100644 new mode 100755 similarity index 98% rename from src/xpdf-4.04/xpdf-qt/xpdf.cc rename to src/xpdf-4.06/xpdf-qt/xpdf.cc index 63e52d8..550738f --- a/src/xpdf-4.04/xpdf-qt/xpdf.cc +++ b/src/xpdf-4.06/xpdf-qt/xpdf.cc @@ -11,6 +11,7 @@ #include "gmem.h" #include "Object.h" #include "XpdfApp.h" +#include "gmempp.h" int main(int argc, char *argv[]) { int exitCode; diff --git a/src/xpdf-4.04/xpdf-qt/xpdf.rc b/src/xpdf-4.06/xpdf-qt/xpdf.rc old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf-qt/xpdf.rc rename to src/xpdf-4.06/xpdf-qt/xpdf.rc diff --git a/src/xpdf-4.04/xpdf-qt/zoomIn.svg b/src/xpdf-4.06/xpdf-qt/zoomIn.svg old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf-qt/zoomIn.svg rename to src/xpdf-4.06/xpdf-qt/zoomIn.svg diff --git a/src/xpdf-4.04/xpdf-qt/zoomOut.svg b/src/xpdf-4.06/xpdf-qt/zoomOut.svg old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf-qt/zoomOut.svg rename to src/xpdf-4.06/xpdf-qt/zoomOut.svg diff --git a/src/xpdf-4.04/xpdf/AcroForm.cc b/src/xpdf-4.06/xpdf/AcroForm.cc old mode 100644 new mode 100755 similarity index 98% rename from src/xpdf-4.04/xpdf/AcroForm.cc rename to src/xpdf-4.06/xpdf/AcroForm.cc index 695c286..5c417e5 --- a/src/xpdf-4.04/xpdf/AcroForm.cc +++ b/src/xpdf-4.06/xpdf/AcroForm.cc @@ -8,10 +8,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include #include #include "gmem.h" @@ -343,8 +339,12 @@ AcroForm *AcroForm::load(PDFDoc *docA, Catalog *catalog, Object *acroFormObjA) { AcroForm *acroForm; AcroFormField *field; Object xfaObj, fieldsObj, annotsObj, annotRef, annotObj, obj1, obj2; + char *touchedObjs; int pageNum, i, j; + touchedObjs = (char *)gmalloc(docA->getXRef()->getNumObjects()); + memset(touchedObjs, 0, docA->getXRef()->getNumObjects()); + // this is the normal case: acroFormObj is a dictionary, as expected if (acroFormObjA->isDict()) { acroForm = new AcroForm(docA, acroFormObjA); @@ -372,11 +372,12 @@ AcroForm *AcroForm::load(PDFDoc *docA, Catalog *catalog, Object *acroFormObjA) { } obj1.free(); delete acroForm; + gfree(touchedObjs); return NULL; } for (i = 0; i < obj1.arrayGetLength(); ++i) { obj1.arrayGetNF(i, &obj2); - acroForm->scanField(&obj2); + acroForm->scanField(&obj2, touchedObjs); obj2.free(); } obj1.free(); @@ -400,7 +401,7 @@ AcroForm *AcroForm::load(PDFDoc *docA, Catalog *catalog, Object *acroFormObjA) { annotRef.fetch(acroForm->doc->getXRef(), &annotObj); if (annotObj.isDict()) { if (annotObj.dictLookup("Subtype", &obj1)->isName("Widget")) { - acroForm->scanField(&annotRef); + acroForm->scanField(&annotRef, touchedObjs); } obj1.free(); } @@ -431,7 +432,7 @@ AcroForm *AcroForm::load(PDFDoc *docA, Catalog *catalog, Object *acroFormObjA) { annotRef.fetch(acroForm->doc->getXRef(), &annotObj); if (annotObj.isDict()) { if (annotObj.dictLookup("Subtype", &obj1)->isName("Widget")) { - acroForm->scanField(&annotRef); + acroForm->scanField(&annotRef, touchedObjs); } obj1.free(); } @@ -449,6 +450,8 @@ AcroForm *AcroForm::load(PDFDoc *docA, Catalog *catalog, Object *acroFormObjA) { } } + gfree(touchedObjs); + return acroForm; } @@ -512,34 +515,51 @@ int AcroForm::lookupAnnotPage(Object *annotRef) { return 0; } -void AcroForm::scanField(Object *fieldRef) { - int startDepth = depth; - depth++; +void AcroForm::scanField(Object *fieldRef, char *touchedObjs) { AcroFormField *field; - Object fieldObj, kidsObj, kidRef, kidObj, subtypeObj; + Object fieldObj, kidsRef, kidsObj, kidRef, kidObj, subtypeObj; GBool isTerminal; int i; - if (depth > maxDepth) { - error(errInternal, -1, "Recursion depth exceeded"); - depth = startDepth; - return; + // check for an object loop + if (fieldRef->isRef()) { + if (fieldRef->getRefNum() < 0 || + fieldRef->getRefNum() >= doc->getXRef()->getNumObjects() || + touchedObjs[fieldRef->getRefNum()]) { + return; + } + touchedObjs[fieldRef->getRefNum()] = 1; } fieldRef->fetch(doc->getXRef(), &fieldObj); if (!fieldObj.isDict()) { error(errSyntaxError, -1, "AcroForm field object is wrong type"); fieldObj.free(); - depth = startDepth; return; } + // look for a Kids entry, and check for an object loop there + if (fieldObj.dictLookupNF("Kids", &kidsRef)->isRef()) { + if (kidsRef.getRefNum() < 0 || + kidsRef.getRefNum() >= doc->getXRef()->getNumObjects() || + touchedObjs[kidsRef.getRefNum()]) { + kidsRef.free(); + fieldObj.free(); + return; + } + touchedObjs[kidsRef.getRefNum()] = 1; + kidsRef.fetch(doc->getXRef(), &kidsObj); + } else { + kidsRef.copy(&kidsObj); + } + kidsRef.free(); + // if this field has a Kids array, and all of the kids have a Parent // reference (i.e., they're all form fields, not widget // annotations), then this is a non-terminal field, and we need to // scan the kids isTerminal = gTrue; - if (fieldObj.dictLookup("Kids", &kidsObj)->isArray()) { + if (kidsObj.isArray()) { isTerminal = gFalse; for (i = 0; !isTerminal && i < kidsObj.arrayGetLength(); ++i) { kidsObj.arrayGet(i, &kidObj); @@ -554,7 +574,7 @@ void AcroForm::scanField(Object *fieldRef) { if (!isTerminal) { for (i = 0; !isTerminal && i < kidsObj.arrayGetLength(); ++i) { kidsObj.arrayGetNF(i, &kidRef); - scanField(&kidRef); + scanField(&kidRef, touchedObjs); kidRef.free(); } } @@ -568,7 +588,6 @@ void AcroForm::scanField(Object *fieldRef) { } fieldObj.free(); - depth = startDepth; } void AcroForm::draw(int pageNum, Gfx *gfx, GBool printing) { @@ -870,7 +889,7 @@ Unicode *AcroFormField::getValue(int *length) { // if this field has a counterpart in the XFA form, take the value // from the XFA field (NB: an XFA field with no value overrides the // AcroForm value) - if (xfaField) { + if (globalParams->getPreferXFAFieldValues() && xfaField) { if (xfaField->getValue()) { u = utf8ToUnicode(xfaField->getValue(), length); } @@ -2043,21 +2062,18 @@ void AcroFormField::drawText(GString *text, GString *da, GfxFontDict *fontDict, wMax = dx - 2 * border - 4; -#if 1 //~tmp // this is a kludge that appears to match Adobe's behavior if (height > 15) { topBorder = 5; } else { topBorder = 2; } -#else - topBorder = 5; -#endif // compute font autosize if (fontSize == 0) { for (fontSize = 10; fontSize > 1; --fontSize) { yy = dy - topBorder; + w = 0; i = 0; while (i < text2->getLength()) { getNextLine(text2, i, font, fontSize, wMax, &j, &w, &k); @@ -2190,6 +2206,18 @@ void AcroFormField::drawText(GString *text, GString *da, GfxFontDict *fontDict, // comb formatting if (comb > 0) { + // Acrobat apparently reduces the field width by the sum of the + // left and right margins (but doesn't shift the text to the + // right at all) -- I'm not really sure what's going on here + // (maybe a bug in Acrobat?), but rendering SSN fields in tax + // forms depends on this. + if (xfaField) { + XFAFieldLayoutInfo *layoutInfo = xfaField->getLayoutInfo(); + if (layoutInfo) { + dx -= layoutInfo->marginLeft + layoutInfo->marginRight; + } + } + // compute comb spacing w = dx / comb; @@ -3193,7 +3221,7 @@ GBool AcroFormField::unicodeStringEqual(Unicode *u, int unicodeLength, return gFalse; } for (int i = 0; i < unicodeLength; ++i) { - if ((s->getChar(i) & 0xff) != u[i]) { + if ((Unicode)(s->getChar(i) & 0xff) != u[i]) { return gFalse; } } @@ -3203,7 +3231,7 @@ GBool AcroFormField::unicodeStringEqual(Unicode *u, int unicodeLength, GBool AcroFormField::unicodeStringEqual(Unicode *u, int unicodeLength, const char *s) { for (int i = 0; i < unicodeLength; ++i) { - if (!s[i] || (s[i] & 0xff) != u[i]) { + if (!s[i] || (Unicode)(s[i] & 0xff) != u[i]) { return gFalse; } } diff --git a/src/xpdf-4.04/xpdf/AcroForm.h b/src/xpdf-4.06/xpdf/AcroForm.h old mode 100644 new mode 100755 similarity index 97% rename from src/xpdf-4.04/xpdf/AcroForm.h rename to src/xpdf-4.06/xpdf/AcroForm.h index b43e46d..0e922d1 --- a/src/xpdf-4.04/xpdf/AcroForm.h +++ b/src/xpdf-4.06/xpdf/AcroForm.h @@ -11,10 +11,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - class TextString; class Gfx; class GfxFont; @@ -47,10 +43,7 @@ class AcroForm { AcroForm(PDFDoc *docA, Object *acroFormObjA); void buildAnnotPageList(Catalog *catalog); int lookupAnnotPage(Object *annotRef); - void scanField(Object *fieldRef); - - int depth = 0; - int maxDepth = 100; + void scanField(Object *fieldRef, char *touchedObjs); PDFDoc *doc; Object acroFormObj; diff --git a/src/xpdf-4.04/xpdf/Annot.cc b/src/xpdf-4.06/xpdf/Annot.cc old mode 100644 new mode 100755 similarity index 82% rename from src/xpdf-4.04/xpdf/Annot.cc rename to src/xpdf-4.06/xpdf/Annot.cc index 82ef600..1f39f46 --- a/src/xpdf-4.04/xpdf/Annot.cc +++ b/src/xpdf-4.06/xpdf/Annot.cc @@ -2,18 +2,15 @@ // // Annot.cc // -// Copyright 2000-2003 Glyph & Cog, LLC +// Copyright 2000-2022 Glyph & Cog, LLC // //======================================================================== #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include #include +#include #include "gmem.h" #include "gmempp.h" #include "GList.h" @@ -278,6 +275,8 @@ Annot::Annot(PDFDoc *docA, Dict *dict, Ref *refA) { obj3.free(); } else if (obj2.isRef()) { obj2.copy(&appearance); + } else if (obj2.isStream()) { + obj2.copy(&appearance); } obj1.free(); obj2.free(); @@ -306,29 +305,48 @@ Annot::~Annot() { ocObj.free(); } -void Annot::generateAnnotAppearance() { +void Annot::generateAnnotAppearance(Object *annotObj) { Object obj; - appearance.fetch(doc->getXRef(), &obj); - if (!obj.isStream()) { - if (type) { - if (!type->cmp("Line")) { - generateLineAppearance(); - } else if (!type->cmp("PolyLine")) { - generatePolyLineAppearance(); - } else if (!type->cmp("Polygon")) { - generatePolygonAppearance(); - } else if (!type->cmp("FreeText")) { - generateFreeTextAppearance(); - } - } - } + GBool alreadyHaveAppearance = obj.isStream(); obj.free(); + if (alreadyHaveAppearance) { + return; + } + + if (!type || (type->cmp("Line") && + type->cmp("PolyLine") && + type->cmp("Polygon") && + type->cmp("FreeText"))) { + return; + } + + Object annotObj2; + if (!annotObj) { + getObject(&annotObj2); + annotObj = &annotObj2; + } + if (!annotObj->isDict()) { + annotObj2.free(); + return; + } + + if (!type->cmp("Line")) { + generateLineAppearance(annotObj); + } else if (!type->cmp("PolyLine")) { + generatePolyLineAppearance(annotObj); + } else if (!type->cmp("Polygon")) { + generatePolygonAppearance(annotObj); + } else if (!type->cmp("FreeText")) { + generateFreeTextAppearance(annotObj); + } + + annotObj2.free(); } //~ this doesn't draw the caption -void Annot::generateLineAppearance() { - Object annotObj, gfxStateDict, appearDict, obj1, obj2; +void Annot::generateLineAppearance(Object *annotObj) { + Object gfxStateDict, appearDict, obj1, obj2; MemStream *appearStream; double x1, y1, x2, y2, dx, dy, len, w; double lx1, ly1, lx2, ly2; @@ -339,15 +357,10 @@ void Annot::generateLineAppearance() { AnnotLineEndType lineEnd1, lineEnd2; GBool fill; - if (!getObject(&annotObj)->isDict()) { - annotObj.free(); - return; - } - appearBuf = new GString(); //----- check for transparency - if (annotObj.dictLookup("CA", &obj1)->isNum()) { + if (annotObj->dictLookup("CA", &obj1)->isNum()) { gfxStateDict.initDict(doc->getXRef()); gfxStateDict.dictAdd(copyString("ca"), obj1.copy(&obj2)); appearBuf->append("/GS1 gs\n"); @@ -358,7 +371,7 @@ void Annot::generateLineAppearance() { setLineStyle(borderStyle, &w); setStrokeColor(borderStyle->getColor(), borderStyle->getNumColorComps()); fill = gFalse; - if (annotObj.dictLookup("IC", &obj1)->isArray()) { + if (annotObj->dictLookup("IC", &obj1)->isArray()) { if (setFillColor(&obj1)) { fill = gTrue; } @@ -366,14 +379,14 @@ void Annot::generateLineAppearance() { obj1.free(); //----- get line properties - if (annotObj.dictLookup("L", &obj1)->isArray() && + if (annotObj->dictLookup("L", &obj1)->isArray() && obj1.arrayGetLength() == 4) { if (obj1.arrayGet(0, &obj2)->isNum()) { x1 = obj2.getNum(); } else { obj2.free(); obj1.free(); - goto err1; + return; } obj2.free(); if (obj1.arrayGet(1, &obj2)->isNum()) { @@ -381,7 +394,7 @@ void Annot::generateLineAppearance() { } else { obj2.free(); obj1.free(); - goto err1; + return; } obj2.free(); if (obj1.arrayGet(2, &obj2)->isNum()) { @@ -389,7 +402,7 @@ void Annot::generateLineAppearance() { } else { obj2.free(); obj1.free(); - goto err1; + return; } obj2.free(); if (obj1.arrayGet(3, &obj2)->isNum()) { @@ -397,16 +410,16 @@ void Annot::generateLineAppearance() { } else { obj2.free(); obj1.free(); - goto err1; + return; } obj2.free(); } else { obj1.free(); - goto err1; + return; } obj1.free(); lineEnd1 = lineEnd2 = annotLineEndNone; - if (annotObj.dictLookup("LE", &obj1)->isArray() && + if (annotObj->dictLookup("LE", &obj1)->isArray() && obj1.arrayGetLength() == 2) { lineEnd1 = parseLineEndType(obj1.arrayGet(0, &obj2)); obj2.free(); @@ -414,19 +427,19 @@ void Annot::generateLineAppearance() { obj2.free(); } obj1.free(); - if (annotObj.dictLookup("LL", &obj1)->isNum()) { + if (annotObj->dictLookup("LL", &obj1)->isNum()) { leaderLen = obj1.getNum(); } else { leaderLen = 0; } obj1.free(); - if (annotObj.dictLookup("LLE", &obj1)->isNum()) { + if (annotObj->dictLookup("LLE", &obj1)->isNum()) { leaderExtLen = obj1.getNum(); } else { leaderExtLen = 0; } obj1.free(); - if (annotObj.dictLookup("LLO", &obj1)->isNum()) { + if (annotObj->dictLookup("LLO", &obj1)->isNum()) { leaderOffLen = obj1.getNum(); } else { leaderOffLen = 0; @@ -513,27 +526,19 @@ void Annot::generateLineAppearance() { appearBuf->getLength(), &appearDict); appearance.free(); appearance.initStream(appearStream); - - err1: - annotObj.free(); } //~ this doesn't handle line ends (arrows) -void Annot::generatePolyLineAppearance() { - Object annotObj, gfxStateDict, appearDict, obj1, obj2; +void Annot::generatePolyLineAppearance(Object *annotObj) { + Object gfxStateDict, appearDict, obj1, obj2; MemStream *appearStream; double x1, y1, w; int i; - if (!getObject(&annotObj)->isDict()) { - annotObj.free(); - return; - } - appearBuf = new GString(); //----- check for transparency - if (annotObj.dictLookup("CA", &obj1)->isNum()) { + if (annotObj->dictLookup("CA", &obj1)->isNum()) { gfxStateDict.initDict(doc->getXRef()); gfxStateDict.dictAdd(copyString("ca"), obj1.copy(&obj2)); appearBuf->append("/GS1 gs\n"); @@ -544,7 +549,7 @@ void Annot::generatePolyLineAppearance() { setLineStyle(borderStyle, &w); setStrokeColor(borderStyle->getColor(), borderStyle->getNumColorComps()); // fill = gFalse; - // if (annotObj.dictLookup("IC", &obj1)->isArray()) { + // if (annotObj->dictLookup("IC", &obj1)->isArray()) { // if (setFillColor(&obj1)) { // fill = gTrue; // } @@ -552,22 +557,22 @@ void Annot::generatePolyLineAppearance() { // obj1.free(); //----- draw line - if (!annotObj.dictLookup("Vertices", &obj1)->isArray()) { + if (!annotObj->dictLookup("Vertices", &obj1)->isArray()) { obj1.free(); - goto err1; + return; } for (i = 0; i+1 < obj1.arrayGetLength(); i += 2) { if (!obj1.arrayGet(i, &obj2)->isNum()) { obj2.free(); obj1.free(); - goto err1; + return; } x1 = obj2.getNum(); obj2.free(); if (!obj1.arrayGet(i+1, &obj2)->isNum()) { obj2.free(); obj1.free(); - goto err1; + return; } y1 = obj2.getNum(); obj2.free(); @@ -606,26 +611,18 @@ void Annot::generatePolyLineAppearance() { appearBuf->getLength(), &appearDict); appearance.free(); appearance.initStream(appearStream); - - err1: - annotObj.free(); } -void Annot::generatePolygonAppearance() { - Object annotObj, gfxStateDict, appearDict, obj1, obj2; +void Annot::generatePolygonAppearance(Object *annotObj) { + Object gfxStateDict, appearDict, obj1, obj2; MemStream *appearStream; double x1, y1; int i; - if (!getObject(&annotObj)->isDict()) { - annotObj.free(); - return; - } - appearBuf = new GString(); //----- check for transparency - if (annotObj.dictLookup("CA", &obj1)->isNum()) { + if (annotObj->dictLookup("CA", &obj1)->isNum()) { gfxStateDict.initDict(doc->getXRef()); gfxStateDict.dictAdd(copyString("ca"), obj1.copy(&obj2)); appearBuf->append("/GS1 gs\n"); @@ -633,30 +630,30 @@ void Annot::generatePolygonAppearance() { obj1.free(); //----- set fill color - if (!annotObj.dictLookup("IC", &obj1)->isArray() || + if (!annotObj->dictLookup("IC", &obj1)->isArray() || !setFillColor(&obj1)) { obj1.free(); - goto err1; + return; } obj1.free(); //----- fill polygon - if (!annotObj.dictLookup("Vertices", &obj1)->isArray()) { + if (!annotObj->dictLookup("Vertices", &obj1)->isArray()) { obj1.free(); - goto err1; + return; } for (i = 0; i+1 < obj1.arrayGetLength(); i += 2) { if (!obj1.arrayGet(i, &obj2)->isNum()) { obj2.free(); obj1.free(); - goto err1; + return; } x1 = obj2.getNum(); obj2.free(); if (!obj1.arrayGet(i+1, &obj2)->isNum()) { obj2.free(); obj1.free(); - goto err1; + return; } y1 = obj2.getNum(); obj2.free(); @@ -695,31 +692,23 @@ void Annot::generatePolygonAppearance() { appearBuf->getLength(), &appearDict); appearance.free(); appearance.initStream(appearStream); - - err1: - annotObj.free(); } //~ this doesn't handle rich text //~ this doesn't handle the callout //~ this doesn't handle the RD field -void Annot::generateFreeTextAppearance() { - Object annotObj, gfxStateDict, appearDict, obj1, obj2; +void Annot::generateFreeTextAppearance(Object *annotObj) { + Object gfxStateDict, appearDict, obj1, obj2; Object resources, gsResources, fontResources, defaultFont; GString *text, *da; double lineWidth; int quadding, rot; MemStream *appearStream; - if (!getObject(&annotObj)->isDict()) { - annotObj.free(); - return; - } - appearBuf = new GString(); //----- check for transparency - if (annotObj.dictLookup("CA", &obj1)->isNum()) { + if (annotObj->dictLookup("CA", &obj1)->isNum()) { gfxStateDict.initDict(doc->getXRef()); gfxStateDict.dictAdd(copyString("ca"), obj1.copy(&obj2)); appearBuf->append("/GS1 gs\n"); @@ -727,19 +716,19 @@ void Annot::generateFreeTextAppearance() { obj1.free(); //----- draw the text - if (annotObj.dictLookup("Contents", &obj1)->isString()) { + if (annotObj->dictLookup("Contents", &obj1)->isString()) { text = obj1.getString()->copy(); } else { text = new GString(); } obj1.free(); - if (annotObj.dictLookup("Q", &obj1)->isInt()) { + if (annotObj->dictLookup("Q", &obj1)->isInt()) { quadding = obj1.getInt(); } else { quadding = 0; } obj1.free(); - if (annotObj.dictLookup("DA", &obj1)->isString()) { + if (annotObj->dictLookup("DA", &obj1)->isString()) { da = obj1.getString()->copy(); } else { da = new GString(); @@ -747,7 +736,7 @@ void Annot::generateFreeTextAppearance() { obj1.free(); // the "Rotate" field is not defined in the PDF spec, but Acrobat // looks at it - if (annotObj.dictLookup("Rotate", &obj1)->isInt()) { + if (annotObj->dictLookup("Rotate", &obj1)->isInt()) { rot = obj1.getInt(); } else { rot = 0; @@ -797,8 +786,6 @@ void Annot::generateFreeTextAppearance() { appearBuf->getLength(), &appearDict); appearance.free(); appearance.initStream(appearStream); - - annotObj.free(); } void Annot::setLineStyle(AnnotBorderStyle *bs, double *lineWidth) { @@ -1344,105 +1331,219 @@ Object *Annot::getObject(Object *obj) { } //------------------------------------------------------------------------ -// Annots +// PageAnnots //------------------------------------------------------------------------ -Annots::Annots(PDFDoc *docA, Object *annotsObj) { - Annot *annot; - Object obj1, obj2; - Ref ref; - GBool drawWidgetAnnots; - int size; - int i; +class PageAnnots { +public: + + PageAnnots(); + ~PageAnnots(); + GList *annots; // list of annots on the page [Annot] + GBool appearancesGenerated; // set after appearances have been generated +}; + +PageAnnots::PageAnnots() { + annots = new GList(); + appearancesGenerated = gFalse; +} + +PageAnnots::~PageAnnots() { + deleteGList(annots, Annot); +} + +//------------------------------------------------------------------------ +// Annots +//------------------------------------------------------------------------ + +Annots::Annots(PDFDoc *docA) { doc = docA; - annots = NULL; - size = 0; - nAnnots = 0; - - if (annotsObj->isArray()) { - // Kludge: some PDF files define an empty AcroForm, but still - // include Widget-type annotations -- in that case, we want to - // draw the widgets (since the form code won't). This really - // ought to look for Widget-type annotations that are not included - // in any form field. - drawWidgetAnnots = !doc->getCatalog()->getForm() || - doc->getCatalog()->getForm()->getNumFields() == 0; - for (i = 0; i < annotsObj->arrayGetLength(); ++i) { - if (annotsObj->arrayGetNF(i, &obj1)->isRef()) { - ref = obj1.getRef(); - obj1.free(); - annotsObj->arrayGet(i, &obj1); - } else { - ref.num = ref.gen = -1; - } - if (obj1.isDict()) { - if (drawWidgetAnnots || - !obj1.dictLookup("Subtype", &obj2)->isName("Widget")) { - annot = new Annot(doc, obj1.getDict(), &ref); - if (annot->isOk()) { - if (nAnnots >= size) { - size += 16; - annots = (Annot **)greallocn(annots, size, sizeof(Annot *)); - } - annots[nAnnots++] = annot; - } else { - delete annot; - } - } - obj2.free(); - } - obj1.free(); + pageAnnots = (PageAnnots **)gmallocn(doc->getNumPages(), sizeof(PageAnnots*)); + for (int page = 1; page <= doc->getNumPages(); ++page) { + pageAnnots[page - 1] = NULL; + } + formFieldRefsSize = 0; + formFieldRefs = NULL; +#if MULTITHREADED + gInitMutex(&mutex); +#endif +} + +Annots::~Annots() { + for (int page = 1; page <= doc->getNumPages(); ++page) { + delete pageAnnots[page - 1]; + } + gfree(pageAnnots); + gfree(formFieldRefs); +#if MULTITHREADED + gDestroyMutex(&mutex); +#endif +} + +void Annots::loadAnnots(int page) { +#if MULTITHREADED + gLockMutex(&mutex); +#endif + if (pageAnnots[page - 1]) { +#if MULTITHREADED + gUnlockMutex(&mutex); +#endif + return; + } + + pageAnnots[page - 1] = new PageAnnots(); + + Object annotsObj; + doc->getCatalog()->getPage(page)->getAnnots(&annotsObj); + if (!annotsObj.isArray()) { + annotsObj.free(); +#if MULTITHREADED + gUnlockMutex(&mutex); +#endif + return; + } + + loadFormFieldRefs(); + + for (int i = 0; i < annotsObj.arrayGetLength(); ++i) { + Object annotObj; + Ref annotRef; + if (annotsObj.arrayGetNF(i, &annotObj)->isRef()) { + annotRef = annotObj.getRef(); + annotObj.free(); + annotsObj.arrayGet(i, &annotObj); + } else { + annotRef.num = annotRef.gen = -1; + } + if (!annotObj.isDict()) { + annotObj.free(); + continue; + } + + // skip any annotations which are used as AcroForm fields -- + // they'll be rendered by the AcroForm module + if (annotRef.num >= 0 && annotRef.num < formFieldRefsSize && + formFieldRefs[annotRef.num]) { + annotObj.free(); + continue; + } + + Annot *annot = new Annot(doc, annotObj.getDict(), &annotRef); + annotObj.free(); + if (annot->isOk()) { + pageAnnots[page - 1]->annots->append(annot); + } else { + delete annot; } } + + annotsObj.free(); + +#if MULTITHREADED + gUnlockMutex(&mutex); +#endif } -Annots::~Annots() { - int i; +// Build a set of object refs for AcroForm fields. +void Annots::loadFormFieldRefs() { + if (formFieldRefs) { + return; + } - for (i = 0; i < nAnnots; ++i) { - delete annots[i]; + AcroForm *form = doc->getCatalog()->getForm(); + if (!form) { + return; + } + + int newFormFieldRefsSize = 256; + for (int i = 0; i < form->getNumFields(); ++i) { + AcroFormField *field = form->getField(i); + Object fieldRef; + field->getFieldRef(&fieldRef); + if (fieldRef.isRef()) { + if (fieldRef.getRefNum() >= formFieldRefsSize) { + while (fieldRef.getRefNum() >= newFormFieldRefsSize && + newFormFieldRefsSize <= INT_MAX / 2) { + newFormFieldRefsSize *= 2; + } + if (fieldRef.getRefNum() >= newFormFieldRefsSize) { + continue; + } + formFieldRefs = (char *)grealloc(formFieldRefs, newFormFieldRefsSize); + for (int j = formFieldRefsSize; j < newFormFieldRefsSize; ++j) { + formFieldRefs[j] = (char)0; + } + formFieldRefsSize = newFormFieldRefsSize; + } + formFieldRefs[fieldRef.getRefNum()] = (char)1; + } + fieldRef.free(); } - gfree(annots); } -Annot *Annots::find(double x, double y) { - int i; +int Annots::getNumAnnots(int page) { + loadAnnots(page); + return pageAnnots[page - 1]->annots->getLength(); +} + +Annot *Annots::getAnnot(int page, int idx) { + loadAnnots(page); + return (Annot *)pageAnnots[page - 1]->annots->get(idx); +} - for (i = nAnnots - 1; i >= 0; --i) { - if (annots[i]->inRect(x, y)) { - return annots[i]; +Annot *Annots::find(int page, double x, double y) { + loadAnnots(page); + PageAnnots *pa = pageAnnots[page - 1]; + for (int i = pa->annots->getLength() - 1; i >= 0; --i) { + Annot *annot = (Annot *)pa->annots->get(i); + if (annot->inRect(x, y)) { + return annot; } } return NULL; } -int Annots::findIdx(double x, double y) { - int i; - - for (i = nAnnots - 1; i >= 0; --i) { - if (annots[i]->inRect(x, y)) { +int Annots::findIdx(int page, double x, double y) { + loadAnnots(page); + PageAnnots *pa = pageAnnots[page - 1]; + for (int i = pa->annots->getLength() - 1; i >= 0; --i) { + Annot *annot = (Annot *)pa->annots->get(i); + if (annot->inRect(x, y)) { return i; } } return -1; } -void Annots::generateAnnotAppearances() { - int i; - - for (i = 0; i < nAnnots; ++i) { - annots[i]->generateAnnotAppearance(); +void Annots::add(int page, Object *annotObj) { + if (!annotObj->isDict()) { + return; + } + Ref annotRef = {-1, -1}; + Annot *annot = new Annot(doc, annotObj->getDict(), &annotRef); + if (annot->isOk()) { + annot->generateAnnotAppearance(annotObj); + pageAnnots[page - 1]->annots->append(annot); + } else { + delete annot; } } -Annot *Annots::findAnnot(Ref *ref) { - int i; - - for (i = 0; i < nAnnots; ++i) { - if (annots[i]->match(ref)) { - return annots[i]; +void Annots::generateAnnotAppearances(int page) { + loadAnnots(page); + PageAnnots *pa = pageAnnots[page - 1]; +#if MULTITHREADED + gLockMutex(&mutex); +#endif + if (!pa->appearancesGenerated) { + for (int i = 0; i < pa->annots->getLength(); ++i) { + Annot *annot = (Annot *)pa->annots->get(i); + annot->generateAnnotAppearance(NULL); } + pa->appearancesGenerated = gTrue; } - return NULL; +#if MULTITHREADED + gUnlockMutex(&mutex); +#endif } diff --git a/src/xpdf-4.04/xpdf/Annot.h b/src/xpdf-4.06/xpdf/Annot.h old mode 100644 new mode 100755 similarity index 77% rename from src/xpdf-4.04/xpdf/Annot.h rename to src/xpdf-4.06/xpdf/Annot.h index 6ba5ff4..6ae89da --- a/src/xpdf-4.04/xpdf/Annot.h +++ b/src/xpdf-4.06/xpdf/Annot.h @@ -2,7 +2,7 @@ // // Annot.h // -// Copyright 2000-2003 Glyph & Cog, LLC +// Copyright 2000-2022 Glyph & Cog, LLC // //======================================================================== @@ -10,9 +10,8 @@ #define ANNOT_H #include - -#ifdef USE_GCC_PRAGMAS -#pragma interface +#if MULTITHREADED +#include "GMutex.h" #endif class XRef; @@ -20,6 +19,7 @@ class Catalog; class Gfx; class GfxFontDict; class PDFDoc; +class PageAnnots; //------------------------------------------------------------------------ // AnnotBorderStyle @@ -105,14 +105,14 @@ class Annot { GBool match(Ref *refA) { return ref.num == refA->num && ref.gen == refA->gen; } - void generateAnnotAppearance(); + void generateAnnotAppearance(Object *annotObj); private: - void generateLineAppearance(); - void generatePolyLineAppearance(); - void generatePolygonAppearance(); - void generateFreeTextAppearance(); + void generateLineAppearance(Object *annotObj); + void generatePolyLineAppearance(Object *annotObj); + void generatePolygonAppearance(Object *annotObj); + void generateFreeTextAppearance(Object *annotObj); void setLineStyle(AnnotBorderStyle *bs, double *lineWidth); void setStrokeColor(double *color, int nComps); GBool setFillColor(Object *colorObj); @@ -152,34 +152,38 @@ class Annot { class Annots { public: - // Build a list of Annot objects. - Annots(PDFDoc *docA, Object *annotsObj); + Annots(PDFDoc *docA); ~Annots(); - // Iterate through list of annotations. - int getNumAnnots() { return nAnnots; } - Annot *getAnnot(int i) { return annots[i]; } + // Iterate over annotations on a specific page. + int getNumAnnots(int page); + Annot *getAnnot(int page, int idx); + + // If point (,) is in an annotation, return the associated + // annotation (or annotation index); else return NULL (or -1). + Annot *find(int page, double x, double y); + int findIdx(int page, double x, double y); - // If point , is in an annotation, return the associated - // annotation; else return NULL. - Annot *find(double x, double y); - int findIdx(double x, double y); + // Add an annotation [annotObj] on page [page]. + void add(int page, Object *annotObj); // Generate an appearance stream for any non-form-field annotation - // that is missing it. - void generateAnnotAppearances(); + // on the specified page that is missing an appearance. + void generateAnnotAppearances(int page); private: - void scanFieldAppearances(Dict *node, Ref *ref, Dict *parent, - Dict *acroForm); - - Annot *findAnnot(Ref *ref); + void loadAnnots(int page); + void loadFormFieldRefs(); PDFDoc *doc; - Annot **annots; - int nAnnots; + PageAnnots **pageAnnots; // list of annots for each page + int formFieldRefsSize; // number of entries in formFieldRefs[] + char *formFieldRefs; // set of AcroForm field refs +#if MULTITHREADED + GMutex mutex; +#endif }; #endif diff --git a/src/xpdf-4.04/xpdf/Array.cc b/src/xpdf-4.06/xpdf/Array.cc old mode 100644 new mode 100755 similarity index 93% rename from src/xpdf-4.04/xpdf/Array.cc rename to src/xpdf-4.06/xpdf/Array.cc index 2bf948e..2771186 --- a/src/xpdf-4.04/xpdf/Array.cc +++ b/src/xpdf-4.06/xpdf/Array.cc @@ -8,10 +8,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include #include #include "gmem.h" @@ -53,7 +49,7 @@ void Array::add(Object *elem) { Object *Array::get(int i, Object *obj, int recursion) { if (i < 0 || i >= length) { -#ifdef DEBUG_MEM +#ifdef DEBUG_OBJECT_MEM abort(); #else return obj->initNull(); @@ -64,7 +60,7 @@ Object *Array::get(int i, Object *obj, int recursion) { Object *Array::getNF(int i, Object *obj) { if (i < 0 || i >= length) { -#ifdef DEBUG_MEM +#ifdef DEBUG_OBJECT_MEM abort(); #else return obj->initNull(); diff --git a/src/xpdf-4.04/xpdf/Array.h b/src/xpdf-4.06/xpdf/Array.h old mode 100644 new mode 100755 similarity index 96% rename from src/xpdf-4.04/xpdf/Array.h rename to src/xpdf-4.06/xpdf/Array.h index 8d10ead..9a887f4 --- a/src/xpdf-4.04/xpdf/Array.h +++ b/src/xpdf-4.06/xpdf/Array.h @@ -11,10 +11,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #if MULTITHREADED #include "GMutex.h" #endif diff --git a/src/xpdf-4.04/xpdf/BuiltinFont.cc b/src/xpdf-4.06/xpdf/BuiltinFont.cc old mode 100644 new mode 100755 similarity index 96% rename from src/xpdf-4.04/xpdf/BuiltinFont.cc rename to src/xpdf-4.06/xpdf/BuiltinFont.cc index d2f875e..51c2d33 --- a/src/xpdf-4.04/xpdf/BuiltinFont.cc +++ b/src/xpdf-4.06/xpdf/BuiltinFont.cc @@ -8,10 +8,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include #include #include "gmem.h" diff --git a/src/xpdf-4.04/xpdf/BuiltinFont.h b/src/xpdf-4.06/xpdf/BuiltinFont.h old mode 100644 new mode 100755 similarity index 95% rename from src/xpdf-4.04/xpdf/BuiltinFont.h rename to src/xpdf-4.06/xpdf/BuiltinFont.h index f24cbf9..042e4e0 --- a/src/xpdf-4.04/xpdf/BuiltinFont.h +++ b/src/xpdf-4.06/xpdf/BuiltinFont.h @@ -11,10 +11,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #include "gtypes.h" struct BuiltinFont; diff --git a/src/xpdf-4.04/xpdf/BuiltinFontTables.cc b/src/xpdf-4.06/xpdf/BuiltinFontTables.cc old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf/BuiltinFontTables.cc rename to src/xpdf-4.06/xpdf/BuiltinFontTables.cc diff --git a/src/xpdf-4.04/xpdf/BuiltinFontTables.h b/src/xpdf-4.06/xpdf/BuiltinFontTables.h old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf/BuiltinFontTables.h rename to src/xpdf-4.06/xpdf/BuiltinFontTables.h diff --git a/src/xpdf-4.04/xpdf/CMakeLists.txt b/src/xpdf-4.06/xpdf/CMakeLists.txt old mode 100644 new mode 100755 similarity index 99% rename from src/xpdf-4.04/xpdf/CMakeLists.txt rename to src/xpdf-4.06/xpdf/CMakeLists.txt index 63a8dec..a965cd7 --- a/src/xpdf-4.04/xpdf/CMakeLists.txt +++ b/src/xpdf-4.06/xpdf/CMakeLists.txt @@ -53,6 +53,7 @@ add_library(xpdf_objs OBJECT JPXStream.cc Lexer.cc Link.cc + LocalParams.cc NameToCharCode.cc Object.cc OptionalContent.cc diff --git a/src/xpdf-4.04/xpdf/CMap.cc b/src/xpdf-4.06/xpdf/CMap.cc old mode 100644 new mode 100755 similarity index 84% rename from src/xpdf-4.04/xpdf/CMap.cc rename to src/xpdf-4.06/xpdf/CMap.cc index 12632c5..31e2a27 --- a/src/xpdf-4.04/xpdf/CMap.cc +++ b/src/xpdf-4.06/xpdf/CMap.cc @@ -8,10 +8,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include #include #include @@ -20,6 +16,7 @@ #include "gmempp.h" #include "gfile.h" #include "GString.h" +#include "GHash.h" #include "Error.h" #include "GlobalParams.h" #include "PSTokenizer.h" @@ -49,7 +46,8 @@ static int getCharFromStream(void *data) { //------------------------------------------------------------------------ -CMap *CMap::parse(CMapCache *cache, GString *collectionA, Object *obj) { +CMap *CMap::parse(CMapCache *cache, GString *collectionA, Object *obj, + GHash *usedCMaps) { CMap *cMap; GString *cMapNameA; @@ -62,9 +60,17 @@ CMap *CMap::parse(CMapCache *cache, GString *collectionA, Object *obj) { } delete cMapNameA; } else if (obj->isStream()) { - if (!(cMap = CMap::parse(NULL, collectionA, obj->getStream()))) { + GHash *newUsedCMaps = NULL; + if (!usedCMaps) { + usedCMaps = newUsedCMaps = new GHash(gTrue); + } + if (!(cMap = CMap::parse(NULL, collectionA, obj->getStream(), + usedCMaps))) { error(errSyntaxError, -1, "Invalid CMap in Type 0 font"); } + if (newUsedCMaps) { + delete newUsedCMaps; + } } else { error(errSyntaxError, -1, "Invalid Encoding in Type 0 font"); return NULL; @@ -73,7 +79,7 @@ CMap *CMap::parse(CMapCache *cache, GString *collectionA, Object *obj) { } CMap *CMap::parse(CMapCache *cache, GString *collectionA, - GString *cMapNameA) { + GString *cMapNameA, GHash *usedCMaps) { FILE *f; CMap *cMap; @@ -93,32 +99,60 @@ CMap *CMap::parse(CMapCache *cache, GString *collectionA, return NULL; } + GHash *newUsedCMaps = NULL; + if (!usedCMaps) { + usedCMaps = newUsedCMaps = new GHash(gTrue); + } + cMap = new CMap(collectionA->copy(), cMapNameA->copy()); - cMap->parse2(cache, &getCharFromFile, f); + cMap->parse2(cache, &getCharFromFile, f, usedCMaps); + + if (newUsedCMaps) { + delete newUsedCMaps; + } fclose(f); return cMap; } -CMap *CMap::parse(CMapCache *cache, GString *collectionA, Stream *str) { +CMap *CMap::parse(CMapCache *cache, GString *collectionA, Stream *str, + GHash *usedCMaps) { Object obj1; CMap *cMap; + // check for a loop + if (usedCMaps) { + GString *name; + if (str->getDict()->lookup("CMapName", &obj1)->isName()) { + name = new GString(obj1.getName()); + } else { + name = new GString(); + } + obj1.free(); + if (usedCMaps->lookupInt(name)) { + error(errSyntaxError, -1, "Loop in usecmap"); + delete name; + return NULL; + } + usedCMaps->add(name, 1); + } + cMap = new CMap(collectionA->copy(), NULL); if (!str->getDict()->lookup("UseCMap", &obj1)->isNull()) { - cMap->useCMap(cache, &obj1); + cMap->useCMap(cache, &obj1, usedCMaps); } obj1.free(); str->reset(); - cMap->parse2(cache, &getCharFromStream, str); + cMap->parse2(cache, &getCharFromStream, str, usedCMaps); str->close(); return cMap; } -void CMap::parse2(CMapCache *cache, int (*getCharFunc)(void *), void *data) { +void CMap::parse2(CMapCache *cache, int (*getCharFunc)(void *), void *data, + GHash *usedCMaps) { PSTokenizer *pst; char tok1[256], tok2[256], tok3[256]; int n1, n2, n3; @@ -129,7 +163,7 @@ void CMap::parse2(CMapCache *cache, int (*getCharFunc)(void *), void *data) { while (pst->getToken(tok2, sizeof(tok2), &n2)) { if (!strcmp(tok2, "usecmap")) { if (tok1[0] == '/') { - useCMap(cache, tok1 + 1); + useCMap(cache, tok1 + 1, usedCMaps); } pst->getToken(tok1, sizeof(tok1), &n1); } else if (!strcmp(tok1, "/WMode")) { @@ -212,17 +246,25 @@ CMap::CMap(GString *collectionA, GString *cMapNameA, int wModeA) { refCnt = 1; } -void CMap::useCMap(CMapCache *cache, char *useName) { +void CMap::useCMap(CMapCache *cache, char *useName, GHash *usedCMaps) { GString *useNameStr; CMap *subCMap; + // check for a loop + if (usedCMaps) { + if (usedCMaps->lookupInt(useName)) { + error(errSyntaxError, -1, "Loop in usecmap"); + return; + } + usedCMaps->add(new GString(useName), 1); + } + useNameStr = new GString(useName); // if cache is non-NULL, we already have a lock, and we can use // CMapCache::getCMap() directly; otherwise, we need to use - // GlobalParams::getCMap() in order to acqure the lock need to use - // GlobalParams::getCMap + // GlobalParams::getCMap() in order to acqure the lock if (cache) { - subCMap = cache->getCMap(collection, useNameStr); + subCMap = cache->getCMap(collection, useNameStr, usedCMaps); } else { subCMap = globalParams->getCMap(collection, useNameStr); } @@ -237,10 +279,10 @@ void CMap::useCMap(CMapCache *cache, char *useName) { subCMap->decRefCnt(); } -void CMap::useCMap(CMapCache *cache, Object *obj) { +void CMap::useCMap(CMapCache *cache, Object *obj, GHash *usedCMaps) { CMap *subCMap; - subCMap = CMap::parse(cache, collection, obj); + subCMap = CMap::parse(cache, collection, obj, usedCMaps); if (!subCMap) { return; } @@ -406,7 +448,8 @@ CMapCache::~CMapCache() { } } -CMap *CMapCache::getCMap(GString *collection, GString *cMapName) { +CMap *CMapCache::getCMap(GString *collection, GString *cMapName, + GHash *usedCMaps) { CMap *cmap; int i, j; @@ -425,7 +468,7 @@ CMap *CMapCache::getCMap(GString *collection, GString *cMapName) { return cmap; } } - if ((cmap = CMap::parse(this, collection, cMapName))) { + if ((cmap = CMap::parse(this, collection, cMapName, usedCMaps))) { if (cache[cMapCacheSize - 1]) { cache[cMapCacheSize - 1]->decRefCnt(); } diff --git a/src/xpdf-4.04/xpdf/CMap.h b/src/xpdf-4.06/xpdf/CMap.h old mode 100644 new mode 100755 similarity index 87% rename from src/xpdf-4.04/xpdf/CMap.h rename to src/xpdf-4.06/xpdf/CMap.h index 55692b4..8a65575 --- a/src/xpdf-4.04/xpdf/CMap.h +++ b/src/xpdf-4.06/xpdf/CMap.h @@ -11,10 +11,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #include "gtypes.h" #include "CharTypes.h" @@ -23,6 +19,7 @@ #endif class GString; +class GHash; class Object; class Stream; struct CMapVectorEntry; @@ -35,16 +32,18 @@ class CMap { // Parse a CMap from , which can be a name or a stream. Sets // the initial reference count to 1. Returns NULL on failure. - static CMap *parse(CMapCache *cache, GString *collectionA, Object *obj); + static CMap *parse(CMapCache *cache, GString *collectionA, Object *obj, + GHash *usedCMaps = NULL); // Create the CMap specified by and . Sets // the initial reference count to 1. Returns NULL on failure. static CMap *parse(CMapCache *cache, GString *collectionA, - GString *cMapNameA); + GString *cMapNameA, GHash *usedCMaps = NULL); // Parse a CMap from . Sets the initial reference count to 1. // Returns NULL on failure. - static CMap *parse(CMapCache *cache, GString *collectionA, Stream *str); + static CMap *parse(CMapCache *cache, GString *collectionA, Stream *str, + GHash *usedCMaps = NULL); ~CMap(); @@ -68,11 +67,12 @@ class CMap { private: - void parse2(CMapCache *cache, int (*getCharFunc)(void *), void *data); + void parse2(CMapCache *cache, int (*getCharFunc)(void *), void *data, + GHash *usedCMaps); CMap(GString *collectionA, GString *cMapNameA); CMap(GString *collectionA, GString *cMapNameA, int wModeA); - void useCMap(CMapCache *cache, char *useName); - void useCMap(CMapCache *cache, Object *obj); + void useCMap(CMapCache *cache, char *useName, GHash *usedCMaps); + void useCMap(CMapCache *cache, Object *obj, GHash *usedCMaps); void copyVector(CMapVectorEntry *dest, CMapVectorEntry *src); void addCIDs(Guint start, Guint end, Guint nBytes, CID firstCID); void freeCMapVector(CMapVectorEntry *vec); @@ -105,7 +105,8 @@ class CMapCache { // Increments its reference count; there will be one reference for // the cache plus one for the caller of this function. Returns NULL // on failure. - CMap *getCMap(GString *collection, GString *cMapName); + CMap *getCMap(GString *collection, GString *cMapName, + GHash *usedCMaps = NULL); private: diff --git a/src/xpdf-4.04/xpdf/Catalog.cc b/src/xpdf-4.06/xpdf/Catalog.cc old mode 100644 new mode 100755 similarity index 73% rename from src/xpdf-4.04/xpdf/Catalog.cc rename to src/xpdf-4.06/xpdf/Catalog.cc index ddcbad5..a2cf570 --- a/src/xpdf-4.04/xpdf/Catalog.cc +++ b/src/xpdf-4.06/xpdf/Catalog.cc @@ -8,10 +8,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include #include #include @@ -405,11 +401,15 @@ LinkDest *Catalog::findDest(GString *name) { } } if (!found && nameTree.isDict()) { - if (!findDestInTree(&nameTree, name, &obj1)->isNull()) { + char *touchedObjs = (char *)gmalloc(xref->getNumObjects()); + memset(touchedObjs, 0, xref->getNumObjects()); + if (!findDestInTree(&nameTree, &nameTree, name, &obj1, touchedObjs) + ->isNull()) { found = gTrue; } else { obj1.free(); } + gfree(touchedObjs); } if (!found) { return NULL; @@ -438,12 +438,31 @@ LinkDest *Catalog::findDest(GString *name) { return dest; } -Object *Catalog::findDestInTree(Object *tree, GString *name, Object *obj) { +Object *Catalog::findDestInTree(Object *treeRef, Object *tree, GString *name, + Object *obj, char *touchedObjs) { Object names, name1; - Object kids, kid, limits, low, high; + Object kids, kidRef, kid, limits, low, high; GBool done, found; int cmp, i; + // check for invalid reference + if (treeRef->isRef() && + (treeRef->getRefNum() < 0 || + treeRef->getRefNum() >= xref->getNumObjects())) { + obj->initNull(); + return obj; + } + + // check for a destination tree loop + if (treeRef->isRef()) { + if (touchedObjs[treeRef->getRefNum()]) { + error(errSyntaxError, -1, "Loop in destination name tree"); + obj->initNull(); + return obj; + } + touchedObjs[treeRef->getRefNum()] = 1; + } + // leaf node if (tree->dictLookup("Names", &names)->isArray()) { done = found = gFalse; @@ -472,13 +491,15 @@ Object *Catalog::findDestInTree(Object *tree, GString *name, Object *obj) { done = gFalse; if (tree->dictLookup("Kids", &kids)->isArray()) { for (i = 0; !done && i < kids.arrayGetLength(); ++i) { - if (kids.arrayGet(i, &kid)->isDict()) { + kids.arrayGetNF(i, &kidRef); + kids.arrayGet(i, &kid); + if (kid.isDict()) { if (kid.dictLookup("Limits", &limits)->isArray()) { if (limits.arrayGet(0, &low)->isString() && name->cmp(low.getString()) >= 0) { if (limits.arrayGet(1, &high)->isString() && name->cmp(high.getString()) <= 0) { - findDestInTree(&kid, name, obj); + findDestInTree(&kidRef, &kid, name, obj, touchedObjs); done = gTrue; } high.free(); @@ -488,6 +509,7 @@ Object *Catalog::findDestInTree(Object *tree, GString *name, Object *obj) { limits.free(); } kid.free(); + kidRef.free(); } } kids.free(); @@ -526,7 +548,10 @@ GBool Catalog::readPageTree(Object *catDict) { // because other code tries to fetch pages 1 through n. // In both cases: ignore the given page count and scan the tree // instead. - numPages = countPageTree(&topPagesObj); + char *touchedObjs = (char *)gmalloc(xref->getNumObjects()); + memset(touchedObjs, 0, xref->getNumObjects()); + numPages = countPageTree(&topPagesRef, touchedObjs); + gfree(touchedObjs); } } else { // assume we got a Page node instead of a Pages node @@ -553,30 +578,69 @@ GBool Catalog::readPageTree(Object *catDict) { return gTrue; } -int Catalog::countPageTree(Object *pagesObj) { - Object kids, kid; - int n, n2, i; - - if (!pagesObj->isDict()) { +int Catalog::countPageTree(Object *pagesNodeRef, char *touchedObjs) { + // check for invalid reference + if (pagesNodeRef->isRef() && + (pagesNodeRef->getRefNum() < 0 || + pagesNodeRef->getRefNum() >= xref->getNumObjects())) { return 0; } - if (pagesObj->dictLookup("Kids", &kids)->isArray()) { - n = 0; - for (i = 0; i < kids.arrayGetLength(); ++i) { - kids.arrayGet(i, &kid); - n2 = countPageTree(&kid); - if (n2 < INT_MAX - n) { - n += n2; - } else { - error(errSyntaxError, -1, "Page tree contains too many pages"); - n = INT_MAX; - } - kid.free(); + + // check for a page tree loop; fetch the node object + Object pagesNode; + if (pagesNodeRef->isRef()) { + if (touchedObjs[pagesNodeRef->getRefNum()]) { + error(errSyntaxError, -1, "Loop in Pages tree"); + return 0; } + touchedObjs[pagesNodeRef->getRefNum()] = 1; + xref->fetch(pagesNodeRef->getRefNum(), pagesNodeRef->getRefGen(), + &pagesNode); } else { - n = 1; + pagesNodeRef->copy(&pagesNode); + } + + // count the subtree + int n = 0; + if (pagesNode.isDict()) { + Object kidsRef, kids; + pagesNode.dictLookupNF("Kids", &kidsRef); + if (kidsRef.isRef() && + kidsRef.getRefNum() >= 0 && + kidsRef.getRefNum() < xref->getNumObjects()) { + if (touchedObjs[kidsRef.getRefNum()]) { + error(errSyntaxError, -1, "Loop in Pages tree"); + kidsRef.free(); + pagesNode.free(); + return 0; + } + touchedObjs[kidsRef.getRefNum()] = 1; + xref->fetch(kidsRef.getRefNum(), kidsRef.getRefGen(), &kids); + } else { + kidsRef.copy(&kids); + } + kidsRef.free(); + if (kids.isArray()) { + for (int i = 0; i < kids.arrayGetLength(); ++i) { + Object kid; + kids.arrayGetNF(i, &kid); + int n2 = countPageTree(&kid, touchedObjs); + if (n2 < INT_MAX - n) { + n += n2; + } else { + error(errSyntaxError, -1, "Page tree contains too many pages"); + n = INT_MAX; + } + kid.free(); + } + } else { + n = 1; + } + kids.free(); } - kids.free(); + + pagesNode.free(); + return n; } @@ -738,37 +802,55 @@ void Catalog::readEmbeddedFileList(Dict *catDict) { Object obj1, obj2; char *touchedObjs; + touchedObjs = (char *)gmalloc(xref->getNumObjects()); + memset(touchedObjs, 0, xref->getNumObjects()); + // read the embedded file name tree if (catDict->lookup("Names", &obj1)->isDict()) { - if (obj1.dictLookup("EmbeddedFiles", &obj2)->isDict()) { - readEmbeddedFileTree(&obj2); - } + obj1.dictLookupNF("EmbeddedFiles", &obj2); + readEmbeddedFileTree(&obj2, touchedObjs); obj2.free(); } obj1.free(); // look for file attachment annotations - touchedObjs = (char *)gmalloc(xref->getNumObjects()); - memset(touchedObjs, 0, xref->getNumObjects()); readFileAttachmentAnnots(catDict->lookupNF("Pages", &obj1), touchedObjs); obj1.free(); + gfree(touchedObjs); } -void Catalog::readEmbeddedFileTree(Object *node) { - Object kidsObj, kidObj; +void Catalog::readEmbeddedFileTree(Object *nodeRef, char *touchedObjs) { + Object node, kidsObj, kidObj; Object namesObj, nameObj, fileSpecObj; int i; - if (node->dictLookup("Kids", &kidsObj)->isArray()) { + // check for an object loop + if (nodeRef->isRef()) { + if (nodeRef->getRefNum() < 0 || + nodeRef->getRefNum() >= xref->getNumObjects() || + touchedObjs[nodeRef->getRefNum()]) { + return; + } + touchedObjs[nodeRef->getRefNum()] = 1; + xref->fetch(nodeRef->getRefNum(), nodeRef->getRefGen(), &node); + } else { + nodeRef->copy(&node); + } + + if (!node.isDict()) { + node.free(); + return; + } + + if (checkDictLookup(&node, "Kids", &kidsObj, touchedObjs)->isArray()) { for (i = 0; i < kidsObj.arrayGetLength(); ++i) { - if (kidsObj.arrayGet(i, &kidObj)->isDict()) { - readEmbeddedFileTree(&kidObj); - } + kidsObj.arrayGetNF(i, &kidObj); + readEmbeddedFileTree(&kidObj, touchedObjs); kidObj.free(); } } else { - if (node->dictLookup("Names", &namesObj)->isArray()) { + if (checkDictLookup(&node, "Names", &namesObj, touchedObjs)->isArray()) { for (i = 0; i+1 < namesObj.arrayGetLength(); ++i) { namesObj.arrayGet(i, &nameObj); namesObj.arrayGet(i+1, &fileSpecObj); @@ -780,6 +862,8 @@ void Catalog::readEmbeddedFileTree(Object *node) { namesObj.free(); } kidsObj.free(); + + node.free(); } void Catalog::readFileAttachmentAnnots(Object *pageNodeRef, @@ -788,8 +872,9 @@ void Catalog::readFileAttachmentAnnots(Object *pageNodeRef, int i; // check for an invalid object reference (e.g., in a damaged PDF file) - if (pageNodeRef->getRefNum() < 0 || - pageNodeRef->getRefNum() >= xref->getNumObjects()) { + if (pageNodeRef->isRef() && + (pageNodeRef->getRefNum() < 0 || + pageNodeRef->getRefNum() >= xref->getNumObjects())) { return; } @@ -805,20 +890,22 @@ void Catalog::readFileAttachmentAnnots(Object *pageNodeRef, } if (pageNode.isDict()) { - if (pageNode.dictLookup("Kids", &kids)->isArray()) { + if (checkDictLookup(&pageNode, "Kids", &kids, touchedObjs)->isArray()) { for (i = 0; i < kids.arrayGetLength(); ++i) { readFileAttachmentAnnots(kids.arrayGetNF(i, &kid), touchedObjs); kid.free(); } } else { - if (pageNode.dictLookup("Annots", &annots)->isArray()) { + if (checkDictLookup(&pageNode, "Annots", + &annots, touchedObjs)->isArray()) { for (i = 0; i < annots.arrayGetLength(); ++i) { - if (annots.arrayGet(i, &annot)->isDict()) { - if (annot.dictLookup("Subtype", &subtype) + if (checkArrayGet(&annots, i, &annot, touchedObjs)->isDict()) { + if (checkDictLookup(&annot, "Subtype", &subtype, touchedObjs) ->isName("FileAttachment")) { - if (annot.dictLookup("FS", &fileSpec)) { + if (checkDictLookup(&annot, "FS", &fileSpec, touchedObjs)) { readEmbeddedFile(&fileSpec, - annot.dictLookup("Contents", &contents)); + checkDictLookup(&annot, "Contents", + &contents, touchedObjs)); contents.free(); } fileSpec.free(); @@ -901,10 +988,14 @@ Object *Catalog::getEmbeddedFileStreamObj(int idx, Object *strObj) { void Catalog::readPageLabelTree(Object *root) { PageLabelNode *label0, *label1; + char *touchedObjs; int i; + touchedObjs = (char *)gmalloc(xref->getNumObjects()); + memset(touchedObjs, 0, xref->getNumObjects()); pageLabels = new GList(); - readPageLabelTree2(root); + readPageLabelTree2(root, touchedObjs); + gfree(touchedObjs); if (pageLabels->getLength() == 0) { deleteGList(pageLabels, PageLabelNode); @@ -922,15 +1013,29 @@ void Catalog::readPageLabelTree(Object *root) { label0->lastPage = numPages; } -void Catalog::readPageLabelTree2(Object *node) { - Object nums, num, labelObj, kids, kid; +void Catalog::readPageLabelTree2(Object *nodeRef, char *touchedObjs) { + Object node, nums, num, labelObj, kidsRef, kids, kid; int i; - if (!node->isDict()) { + // check for an object loop + if (nodeRef->isRef()) { + if (nodeRef->getRefNum() < 0 || + nodeRef->getRefNum() >= xref->getNumObjects() || + touchedObjs[nodeRef->getRefNum()]) { + return; + } + touchedObjs[nodeRef->getRefNum()] = 1; + xref->fetch(nodeRef->getRefNum(), nodeRef->getRefGen(), &node); + } else { + nodeRef->copy(&node); + } + + if (!node.isDict()) { + node.free(); return; } - if (node->dictLookup("Nums", &nums)->isArray()) { + if (node.dictLookup("Nums", &nums)->isArray()) { for (i = 0; i < nums.arrayGetLength() - 1; i += 2) { if (nums.arrayGet(i, &num)->isInt()) { if (nums.arrayGet(i+1, &labelObj)->isDict()) { @@ -944,14 +1049,32 @@ void Catalog::readPageLabelTree2(Object *node) { } nums.free(); - if (node->dictLookup("Kids", &kids)->isArray()) { + // check for an object loop in the Kids entry + if (node.dictLookupNF("Kids", &kidsRef)->isRef()) { + if (kidsRef.getRefNum() < 0 || + kidsRef.getRefNum() >= doc->getXRef()->getNumObjects() || + touchedObjs[kidsRef.getRefNum()]) { + kidsRef.free(); + node.free(); + return; + } + touchedObjs[kidsRef.getRefNum()] = 1; + kidsRef.fetch(doc->getXRef(), &kids); + } else { + kidsRef.copy(&kids); + } + kidsRef.free(); + + if (kids.isArray()) { for (i = 0; i < kids.arrayGetLength(); ++i) { - kids.arrayGet(i, &kid); - readPageLabelTree2(&kid); + kids.arrayGetNF(i, &kid); + readPageLabelTree2(&kid, touchedObjs); kid.free(); } } kids.free(); + + node.free(); } TextString *Catalog::getPageLabel(int pageNum) { @@ -1195,3 +1318,169 @@ GBool Catalog::convertPageLabelToInt(TextString *pageLabel, int prefixLength, } return gFalse; } + +GBool Catalog::usesJavaScript() { + Object catDict; + if (!xref->getCatalog(&catDict)->isDict()) { + catDict.free(); + return gFalse; + } + + GBool usesJS = gFalse; + + // check for Catalog.Names.JavaScript + Object namesObj; + if (catDict.dictLookup("Names", &namesObj)->isDict()) { + Object jsNamesObj; + namesObj.dictLookup("JavaScript", &jsNamesObj); + if (jsNamesObj.isDict()) { + usesJS = gTrue; + } + jsNamesObj.free(); + } + namesObj.free(); + + // look for JavaScript actionas in Page.AA + if (!usesJS) { + char *touchedObjs = (char *)gmalloc(xref->getNumObjects()); + memset(touchedObjs, 0, xref->getNumObjects()); + Object pagesObj; + usesJS = scanPageTreeForJavaScript(catDict.dictLookupNF("Pages", &pagesObj), + touchedObjs); + pagesObj.free(); + gfree(touchedObjs); + } + + catDict.free(); + + return usesJS; +} + +GBool Catalog::scanPageTreeForJavaScript(Object *pageNodeRef, + char *touchedObjs) { + // check for an invalid object reference (e.g., in a damaged PDF file) + if (pageNodeRef->isRef() && + (pageNodeRef->getRefNum() < 0 || + pageNodeRef->getRefNum() >= xref->getNumObjects())) { + return gFalse; + } + + // check for a page tree loop + Object pageNode; + if (pageNodeRef->isRef()) { + if (touchedObjs[pageNodeRef->getRefNum()]) { + return gFalse; + } + touchedObjs[pageNodeRef->getRefNum()] = 1; + xref->fetch(pageNodeRef->getRefNum(), pageNodeRef->getRefGen(), &pageNode); + } else { + pageNodeRef->copy(&pageNode); + } + + // scan the page tree node + GBool usesJS = gFalse; + if (pageNode.isDict()) { + Object kids; + if (checkDictLookup(&pageNode, "Kids", &kids, touchedObjs)->isArray()) { + for (int i = 0; i < kids.arrayGetLength() && !usesJS; ++i) { + Object kid; + if (scanPageTreeForJavaScript(kids.arrayGetNF(i, &kid), touchedObjs)) { + usesJS = gTrue; + } + kid.free(); + } + } else { + + // scan Page.AA + Object pageAA; + if (checkDictLookup(&pageNode, "AA", &pageAA, touchedObjs)->isDict()) { + if (scanAAForJavaScript(&pageAA)) { + usesJS = gTrue; + } + } + pageAA.free(); + + // scanPage.Annots + if (!usesJS) { + Object annots; + if (checkDictLookup(&pageNode, "Annots", + &annots, touchedObjs)->isArray()) { + for (int i = 0; i < annots.arrayGetLength() && !usesJS; ++i) { + Object annot; + if (checkArrayGet(&annots, i, &annot, touchedObjs)->isDict()) { + Object annotAA; + if (checkDictLookup(&annot, "AA", &annotAA, + touchedObjs)->isDict()) { + if (scanAAForJavaScript(&annotAA)) { + usesJS = gTrue; + } + } + annotAA.free(); + } + annot.free(); + } + } + annots.free(); + } + } + kids.free(); + } + + pageNode.free(); + + return usesJS; +} + +GBool Catalog::scanAAForJavaScript(Object *aaObj) { + GBool usesJS = gFalse; + for (int i = 0; i < aaObj->dictGetLength() && !usesJS; ++i) { + Object action; + if (aaObj->dictGetVal(i, &action)->isDict()) { + Object js; + if (!action.dictLookupNF("JS", &js)->isNull()) { + usesJS = gTrue; + } + js.free(); + } + action.free(); + } + return usesJS; +} + +Object *Catalog::checkDictLookup(Object *dictObj, const char *key, + Object *element, char *touchedObjs) { + Object refObj; + dictObj->dictLookupNF(key, &refObj); + if (refObj.isRef()) { + int num = refObj.getRefNum(); + if (num >= 0 && num < xref->getNumObjects() && !touchedObjs[num]) { + touchedObjs[num] = 1; + xref->fetch(num, refObj.getRefGen(), element); + } else { + element->initNull(); + } + refObj.free(); + } else { + *element = refObj; + } + return element; +} + +Object *Catalog::checkArrayGet(Object *arrayObj, int i, + Object *element, char *touchedObjs) { + Object refObj; + arrayObj->arrayGetNF(i, &refObj); + if (refObj.isRef()) { + int num = refObj.getRefNum(); + if (num >= 0 && num < xref->getNumObjects() && !touchedObjs[num]) { + touchedObjs[num] = 1; + xref->fetch(num, refObj.getRefGen(), element); + } else { + element->initNull(); + } + refObj.free(); + } else { + *element = refObj; + } + return element; +} diff --git a/src/xpdf-4.04/xpdf/Catalog.h b/src/xpdf-4.06/xpdf/Catalog.h old mode 100644 new mode 100755 similarity index 86% rename from src/xpdf-4.04/xpdf/Catalog.h rename to src/xpdf-4.06/xpdf/Catalog.h index 0acdd2d..9922b28 --- a/src/xpdf-4.04/xpdf/Catalog.h +++ b/src/xpdf-4.06/xpdf/Catalog.h @@ -11,10 +11,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #if MULTITHREADED #include "GMutex.h" #endif @@ -118,6 +114,9 @@ class Catalog { Object *getViewerPreferences() { return &viewerPrefs; } + // Return true if the document uses JavaScript. + GBool usesJavaScript(); + private: PDFDoc *doc; @@ -144,23 +143,30 @@ class Catalog { Object viewerPrefs; // ViewerPreferences object GBool ok; // true if catalog is valid - Object *findDestInTree(Object *tree, GString *name, Object *obj); + Object *findDestInTree(Object *treeRef, Object *tree, GString *name, + Object *obj, char *touchedObjs); GBool readPageTree(Object *catDict); - int countPageTree(Object *pagesObj); + int countPageTree(Object *pagesNodeRef, char *touchedObjs); void loadPage(int pg); void loadPage2(int pg, int relPg, PageTreeNode *node); void readEmbeddedFileList(Dict *catDict); - void readEmbeddedFileTree(Object *node); + void readEmbeddedFileTree(Object *nodeRef, char *touchedObjs); void readFileAttachmentAnnots(Object *pageNodeRef, char *touchedObjs); void readEmbeddedFile(Object *fileSpec, Object *name1); void readPageLabelTree(Object *root); - void readPageLabelTree2(Object *node); + void readPageLabelTree2(Object *node, char *touchedObjs); 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); + GBool scanPageTreeForJavaScript(Object *pageNodeRef, char *touchedObjs); + GBool scanAAForJavaScript(Object *aaObj); + Object *checkDictLookup(Object *dictObj, const char *key, + Object *element, char *touchedObjs); + Object *checkArrayGet(Object *arrayObj, int i, + Object *element, char *touchedObjs); }; #endif diff --git a/src/xpdf-4.04/xpdf/CharCodeToUnicode.cc b/src/xpdf-4.06/xpdf/CharCodeToUnicode.cc old mode 100644 new mode 100755 similarity index 97% rename from src/xpdf-4.04/xpdf/CharCodeToUnicode.cc rename to src/xpdf-4.06/xpdf/CharCodeToUnicode.cc index 0a2100f..8372006 --- a/src/xpdf-4.04/xpdf/CharCodeToUnicode.cc +++ b/src/xpdf-4.06/xpdf/CharCodeToUnicode.cc @@ -8,10 +8,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include #include #include "gmem.h" @@ -274,7 +270,18 @@ GBool CharCodeToUnicode::parseCMap1(int (*getCharFunc)(void *), void *data, pst = new PSTokenizer(getCharFunc, data); pst->getToken(tok1, sizeof(tok1), &n1); while (pst->getToken(tok2, sizeof(tok2), &n2)) { - if (!strcmp(tok2, "usecmap")) { + if (!strcmp(tok1, "begincodespacerange")) { + if (globalParams->getIgnoreWrongSizeToUnicode() && + tok2[0] == '<' && tok2[n2 - 1] == '>' && + n2 - 2 != nBits / 4) { + error(errSyntaxWarning, -1, + "Incorrect character size in ToUnicode CMap"); + ok = gFalse; + break; + } + while (pst->getToken(tok1, sizeof(tok1), &n1) && + strcmp(tok1, "endcodespacerange")) ; + } else if (!strcmp(tok2, "usecmap")) { if (tok1[0] == '/') { name = new GString(tok1 + 1); if ((f = globalParams->findToUnicodeFile(name))) { @@ -465,6 +472,7 @@ GBool CharCodeToUnicode::parseCMap1(int (*getCharFunc)(void *), void *data, pst->getToken(tok1, sizeof(tok1), &n1); } else { strcpy(tok1, tok2); + n1 = n2; } } delete pst; diff --git a/src/xpdf-4.04/xpdf/CharCodeToUnicode.h b/src/xpdf-4.06/xpdf/CharCodeToUnicode.h old mode 100644 new mode 100755 similarity index 98% rename from src/xpdf-4.04/xpdf/CharCodeToUnicode.h rename to src/xpdf-4.06/xpdf/CharCodeToUnicode.h index be90251..7bbc97f --- a/src/xpdf-4.04/xpdf/CharCodeToUnicode.h +++ b/src/xpdf-4.06/xpdf/CharCodeToUnicode.h @@ -13,10 +13,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #include "CharTypes.h" #if MULTITHREADED diff --git a/src/xpdf-4.04/xpdf/CharTypes.h b/src/xpdf-4.06/xpdf/CharTypes.h old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf/CharTypes.h rename to src/xpdf-4.06/xpdf/CharTypes.h diff --git a/src/xpdf-4.04/xpdf/CompactFontTables.h b/src/xpdf-4.06/xpdf/CompactFontTables.h old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf/CompactFontTables.h rename to src/xpdf-4.06/xpdf/CompactFontTables.h diff --git a/src/xpdf-4.04/xpdf/Decrypt.cc b/src/xpdf-4.06/xpdf/Decrypt.cc old mode 100644 new mode 100755 similarity index 98% rename from src/xpdf-4.04/xpdf/Decrypt.cc rename to src/xpdf-4.06/xpdf/Decrypt.cc index d4f8d4e..d36626d --- a/src/xpdf-4.04/xpdf/Decrypt.cc +++ b/src/xpdf-4.06/xpdf/Decrypt.cc @@ -8,10 +8,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include #include "gmem.h" #include "gmempp.h" @@ -1492,14 +1488,14 @@ static void sha512(Guchar *msg, int msgLen, Guchar *hash) { SHA512Uint64 H[8]; int blkLen, i; - H[0] = 0x6a09e667f3bcc908LL; - H[1] = 0xbb67ae8584caa73bLL; - H[2] = 0x3c6ef372fe94f82bLL; - H[3] = 0xa54ff53a5f1d36f1LL; - H[4] = 0x510e527fade682d1LL; - H[5] = 0x9b05688c2b3e6c1fLL; - H[6] = 0x1f83d9abfb41bd6bLL; - H[7] = 0x5be0cd19137e2179LL; + H[0] = 0x6a09e667f3bcc908ULL; + H[1] = 0xbb67ae8584caa73bULL; + H[2] = 0x3c6ef372fe94f82bULL; + H[3] = 0xa54ff53a5f1d36f1ULL; + H[4] = 0x510e527fade682d1ULL; + H[5] = 0x9b05688c2b3e6c1fULL; + H[6] = 0x1f83d9abfb41bd6bULL; + H[7] = 0x5be0cd19137e2179ULL; blkLen = 0; for (i = 0; i + 128 <= msgLen; i += 128) { @@ -1558,14 +1554,14 @@ static void sha384(Guchar *msg, int msgLen, Guchar *hash) { SHA512Uint64 H[8]; int blkLen, i; - H[0] = 0xcbbb9d5dc1059ed8LL; - H[1] = 0x629a292a367cd507LL; - H[2] = 0x9159015a3070dd17LL; - H[3] = 0x152fecd8f70e5939LL; - H[4] = 0x67332667ffc00b31LL; - H[5] = 0x8eb44a8768581511LL; - H[6] = 0xdb0c2e0d64f98fa7LL; - H[7] = 0x47b5481dbefa4fa4LL; + H[0] = 0xcbbb9d5dc1059ed8ULL; + H[1] = 0x629a292a367cd507ULL; + H[2] = 0x9159015a3070dd17ULL; + H[3] = 0x152fecd8f70e5939ULL; + H[4] = 0x67332667ffc00b31ULL; + H[5] = 0x8eb44a8768581511ULL; + H[6] = 0xdb0c2e0d64f98fa7ULL; + H[7] = 0x47b5481dbefa4fa4ULL; blkLen = 0; for (i = 0; i + 128 <= msgLen; i += 128) { diff --git a/src/xpdf-4.04/xpdf/Decrypt.h b/src/xpdf-4.06/xpdf/Decrypt.h old mode 100644 new mode 100755 similarity index 98% rename from src/xpdf-4.04/xpdf/Decrypt.h rename to src/xpdf-4.06/xpdf/Decrypt.h index 2b10abd..d0f3840 --- a/src/xpdf-4.04/xpdf/Decrypt.h +++ b/src/xpdf-4.06/xpdf/Decrypt.h @@ -11,10 +11,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #include "gtypes.h" #include "GString.h" #include "Object.h" diff --git a/src/xpdf-4.04/xpdf/Dict.cc b/src/xpdf-4.06/xpdf/Dict.cc old mode 100644 new mode 100755 similarity index 98% rename from src/xpdf-4.04/xpdf/Dict.cc rename to src/xpdf-4.06/xpdf/Dict.cc index c8c2973..71ea377 --- a/src/xpdf-4.04/xpdf/Dict.cc +++ b/src/xpdf-4.06/xpdf/Dict.cc @@ -8,10 +8,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include #include #include "gmem.h" diff --git a/src/xpdf-4.04/xpdf/Dict.h b/src/xpdf-4.06/xpdf/Dict.h old mode 100644 new mode 100755 similarity index 97% rename from src/xpdf-4.04/xpdf/Dict.h rename to src/xpdf-4.06/xpdf/Dict.h index b05f729..804fcdf --- a/src/xpdf-4.04/xpdf/Dict.h +++ b/src/xpdf-4.06/xpdf/Dict.h @@ -11,10 +11,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #if MULTITHREADED #include "GMutex.h" #endif diff --git a/src/xpdf-4.04/xpdf/DisplayState.cc b/src/xpdf-4.06/xpdf/DisplayState.cc old mode 100644 new mode 100755 similarity index 98% rename from src/xpdf-4.04/xpdf/DisplayState.cc rename to src/xpdf-4.06/xpdf/DisplayState.cc index e0d3068..f1e8dcf --- a/src/xpdf-4.04/xpdf/DisplayState.cc +++ b/src/xpdf-4.06/xpdf/DisplayState.cc @@ -8,10 +8,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include #include "gmempp.h" #include "GString.h" diff --git a/src/xpdf-4.04/xpdf/DisplayState.h b/src/xpdf-4.06/xpdf/DisplayState.h old mode 100644 new mode 100755 similarity index 99% rename from src/xpdf-4.04/xpdf/DisplayState.h rename to src/xpdf-4.06/xpdf/DisplayState.h index 12c8170..a078c75 --- a/src/xpdf-4.04/xpdf/DisplayState.h +++ b/src/xpdf-4.06/xpdf/DisplayState.h @@ -11,10 +11,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #include "gtypes.h" #include "SplashTypes.h" diff --git a/src/xpdf-4.04/xpdf/Error.cc b/src/xpdf-4.06/xpdf/Error.cc old mode 100644 new mode 100755 similarity index 97% rename from src/xpdf-4.04/xpdf/Error.cc rename to src/xpdf-4.06/xpdf/Error.cc index 5a97505..c46378e --- a/src/xpdf-4.04/xpdf/Error.cc +++ b/src/xpdf-4.06/xpdf/Error.cc @@ -8,10 +8,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include #include #include diff --git a/src/xpdf-4.04/xpdf/Error.h b/src/xpdf-4.06/xpdf/Error.h old mode 100644 new mode 100755 similarity index 96% rename from src/xpdf-4.04/xpdf/Error.h rename to src/xpdf-4.06/xpdf/Error.h index 39e7613..574330f --- a/src/xpdf-4.04/xpdf/Error.h +++ b/src/xpdf-4.06/xpdf/Error.h @@ -11,10 +11,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #include #include "config.h" #include "gfile.h" diff --git a/src/xpdf-4.04/xpdf/ErrorCodes.h b/src/xpdf-4.06/xpdf/ErrorCodes.h old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf/ErrorCodes.h rename to src/xpdf-4.06/xpdf/ErrorCodes.h diff --git a/src/xpdf-4.04/xpdf/FontEncodingTables.cc b/src/xpdf-4.06/xpdf/FontEncodingTables.cc old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf/FontEncodingTables.cc rename to src/xpdf-4.06/xpdf/FontEncodingTables.cc diff --git a/src/xpdf-4.04/xpdf/FontEncodingTables.h b/src/xpdf-4.06/xpdf/FontEncodingTables.h old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf/FontEncodingTables.h rename to src/xpdf-4.06/xpdf/FontEncodingTables.h diff --git a/src/xpdf-4.04/xpdf/Function.cc b/src/xpdf-4.06/xpdf/Function.cc old mode 100644 new mode 100755 similarity index 99% rename from src/xpdf-4.04/xpdf/Function.cc rename to src/xpdf-4.06/xpdf/Function.cc index 82f32b9..a0554db --- a/src/xpdf-4.04/xpdf/Function.cc +++ b/src/xpdf-4.06/xpdf/Function.cc @@ -8,10 +8,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include #include #include @@ -1292,7 +1288,7 @@ int PostScriptFunction::exec(double *stack, int sp0) { goto underflow; } nn = (int)stack[sp++]; - if (nn < 0) { + if (nn < 0 || nn > psStackSize) { goto invalidArg; } if (sp + nn > psStackSize) { @@ -1408,8 +1404,8 @@ int PostScriptFunction::exec(double *stack, int sp0) { goto underflow; } k = (int)stack[sp]; - if (k < 0) { - goto invalidArg; + if (k < 0 || k > psStackSize) { + goto invalidArg; } if (sp + 1 + k >= psStackSize) { goto underflow; @@ -1498,8 +1494,8 @@ int PostScriptFunction::exec(double *stack, int sp0) { } k = (int)stack[sp++]; nn = (int)stack[sp++]; - if (nn < 0) { - goto invalidArg; + if (k < -psStackSize || k > psStackSize || nn < 0 || nn > psStackSize) { + goto invalidArg; } if (nn > 0) { if (sp + nn > psStackSize) { diff --git a/src/xpdf-4.04/xpdf/Function.h b/src/xpdf-4.06/xpdf/Function.h old mode 100644 new mode 100755 similarity index 99% rename from src/xpdf-4.04/xpdf/Function.h rename to src/xpdf-4.06/xpdf/Function.h index bf1f25e..73c92ab --- a/src/xpdf-4.04/xpdf/Function.h +++ b/src/xpdf-4.06/xpdf/Function.h @@ -11,10 +11,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #include "gtypes.h" #include "Object.h" diff --git a/src/xpdf-4.04/xpdf/Gfx.cc b/src/xpdf-4.06/xpdf/Gfx.cc old mode 100644 new mode 100755 similarity index 92% rename from src/xpdf-4.04/xpdf/Gfx.cc rename to src/xpdf-4.06/xpdf/Gfx.cc index 1539b84..b9fb006 --- a/src/xpdf-4.04/xpdf/Gfx.cc +++ b/src/xpdf-4.06/xpdf/Gfx.cc @@ -8,10 +8,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include #include #include @@ -516,7 +512,8 @@ GBool GfxResources::lookupPropertiesNF(const char *name, Object *obj) { // Gfx //------------------------------------------------------------------------ -Gfx::Gfx(PDFDoc *docA, OutputDev *outA, int pageNum, Dict *resDict, +Gfx::Gfx(PDFDoc *docA, OutputDev *outA, LocalParams *localParams, + int pageNum, Dict *resDict, double hDPI, double vDPI, PDFRectangle *box, PDFRectangle *cropBox, int rotate, GBool (*abortCheckCbkA)(void *data), @@ -534,8 +531,10 @@ Gfx::Gfx(PDFDoc *docA, OutputDev *outA, int pageNum, Dict *resDict, // initialize out = outA; - state = new GfxState(hDPI, vDPI, box, rotate, out->upsideDown()); + state = new GfxState(localParams, hDPI, vDPI, + box, rotate, out->upsideDown()); fontChanged = gFalse; + haveSavedClipPath = gFalse; clip = clipNone; ignoreUndef = 0; out->startPage(pageNum, state); @@ -565,8 +564,8 @@ Gfx::Gfx(PDFDoc *docA, OutputDev *outA, int pageNum, Dict *resDict, } } -Gfx::Gfx(PDFDoc *docA, OutputDev *outA, Dict *resDict, - PDFRectangle *box, PDFRectangle *cropBox, +Gfx::Gfx(PDFDoc *docA, OutputDev *outA, LocalParams *localParams, + Dict *resDict, PDFRectangle *box, PDFRectangle *cropBox, GBool (*abortCheckCbkA)(void *data), void *abortCheckCbkDataA) { int i; @@ -582,8 +581,9 @@ Gfx::Gfx(PDFDoc *docA, OutputDev *outA, Dict *resDict, // initialize out = outA; - state = new GfxState(72, 72, box, 0, gFalse); + state = new GfxState(localParams, 72, 72, box, 0, gFalse); fontChanged = gFalse; + haveSavedClipPath = gFalse; clip = clipNone; ignoreUndef = 0; for (i = 0; i < 6; ++i) { @@ -1169,6 +1169,13 @@ void Gfx::opSetExtGState(Object args[], int numArgs) { } obj2.free(); + // alpha is shape + if (obj1.dictLookup("AIS", &obj2)->isBool()) { + state->setAlphaIsShape(obj2.getBool()); + out->updateAlphaIsShape(state); + } + obj2.free(); + // soft mask if (!obj1.dictLookup("SMask", &obj2)->isNull()) { if (obj2.isName("None")) { @@ -1246,11 +1253,6 @@ void Gfx::doSoftMask(Object *str, Object *strRef, GBool alpha, Object obj1, obj2; int i; - // check for excessive recursion - if (formDepth > 20) { - return; - } - // get stream dict dict = str->streamGetDict(); @@ -1295,10 +1297,8 @@ void Gfx::doSoftMask(Object *str, Object *strRef, GBool alpha, resDict = obj1.isDict() ? obj1.getDict() : (Dict *)NULL; // draw it - ++formDepth; drawForm(strRef, resDict, m, bbox, gTrue, gTrue, isolated, knockout, alpha, transferFunc, backdropColorObj); - --formDepth; obj1.free(); } @@ -1829,15 +1829,20 @@ void Gfx::opFillStroke(Object args[], int numArgs) { } if (state->isPath()) { if (ocState) { - if (state->getFillColorSpace()->getMode() == csPattern) { - doPatternFill(gFalse); + if (state->getFillColorSpace()->getMode() == csPattern || + state->getStrokeColorSpace()->getMode() == csPattern) { + if (state->getFillColorSpace()->getMode() == csPattern) { + doPatternFill(gFalse); + } else { + out->fill(state); + } + if (state->getStrokeColorSpace()->getMode() == csPattern) { + doPatternStroke(); + } else { + out->stroke(state); + } } else { - out->fill(state); - } - if (state->getStrokeColorSpace()->getMode() == csPattern) { - doPatternStroke(); - } else { - out->stroke(state); + out->fillStroke(state, gFalse); } } } @@ -1852,15 +1857,20 @@ void Gfx::opCloseFillStroke(Object args[], int numArgs) { if (state->isPath()) { state->closePath(); if (ocState) { - if (state->getFillColorSpace()->getMode() == csPattern) { - doPatternFill(gFalse); - } else { - out->fill(state); - } - if (state->getStrokeColorSpace()->getMode() == csPattern) { - doPatternStroke(); + if (state->getFillColorSpace()->getMode() == csPattern || + state->getStrokeColorSpace()->getMode() == csPattern) { + if (state->getFillColorSpace()->getMode() == csPattern) { + doPatternFill(gFalse); + } else { + out->fill(state); + } + if (state->getStrokeColorSpace()->getMode() == csPattern) { + doPatternStroke(); + } else { + out->stroke(state); + } } else { - out->stroke(state); + out->fillStroke(state, gFalse); } } } @@ -1874,15 +1884,20 @@ void Gfx::opEOFillStroke(Object args[], int numArgs) { } if (state->isPath()) { if (ocState) { - if (state->getFillColorSpace()->getMode() == csPattern) { - doPatternFill(gTrue); - } else { - out->eoFill(state); - } - if (state->getStrokeColorSpace()->getMode() == csPattern) { - doPatternStroke(); + if (state->getFillColorSpace()->getMode() == csPattern || + state->getStrokeColorSpace()->getMode() == csPattern) { + if (state->getFillColorSpace()->getMode() == csPattern) { + doPatternFill(gTrue); + } else { + out->eoFill(state); + } + if (state->getStrokeColorSpace()->getMode() == csPattern) { + doPatternStroke(); + } else { + out->stroke(state); + } } else { - out->stroke(state); + out->fillStroke(state, gTrue); } } } @@ -1897,15 +1912,20 @@ void Gfx::opCloseEOFillStroke(Object args[], int numArgs) { if (state->isPath()) { state->closePath(); if (ocState) { - if (state->getFillColorSpace()->getMode() == csPattern) { - doPatternFill(gTrue); - } else { - out->eoFill(state); - } - if (state->getStrokeColorSpace()->getMode() == csPattern) { - doPatternStroke(); + if (state->getFillColorSpace()->getMode() == csPattern || + state->getStrokeColorSpace()->getMode() == csPattern) { + if (state->getFillColorSpace()->getMode() == csPattern) { + doPatternFill(gTrue); + } else { + out->eoFill(state); + } + if (state->getStrokeColorSpace()->getMode() == csPattern) { + doPatternStroke(); + } else { + out->stroke(state); + } } else { - out->stroke(state); + out->fillStroke(state, gTrue); } } } @@ -1966,7 +1986,7 @@ void Gfx::doPatternStroke() { } } -void Gfx::doPatternText() { +void Gfx::doPatternText(GBool stroke) { GfxPattern *pattern; // this is a bit of a kludge -- patterns can be really slow, so we @@ -1976,7 +1996,8 @@ void Gfx::doPatternText() { return; } - if (!(pattern = state->getFillPattern())) { + pattern = stroke ? state->getStrokePattern() : state->getFillPattern(); + if (!pattern) { return; } switch (pattern->getType()) { @@ -2193,16 +2214,30 @@ void Gfx::doTilingPatternFill(GfxTilingPattern *tPat, if (bbox[1] > bbox[3]) { t = bbox[1]; bbox[1] = bbox[3]; bbox[3] = t; } - xstep = fabs(tPat->getXStep()); - ystep = fabs(tPat->getYStep()); - xi0 = (int)ceil((xMin - bbox[2]) / xstep); - xi1 = (int)floor((xMax - bbox[0]) / xstep) + 1; - yi0 = (int)ceil((yMin - bbox[3]) / ystep); - yi1 = (int)floor((yMax - bbox[1]) / ystep) + 1; + xstep = tPat->getXStep(); + ystep = tPat->getYStep(); + if (xstep == 0 || ystep == 0) { + error(errSyntaxError, getPos(), "Zero x or y step in tiling pattern fill"); + goto err; + } + if (xstep > 0) { + xi0 = (int)ceil((xMin - bbox[2]) / xstep); + xi1 = (int)floor((xMax - bbox[0]) / xstep) + 1; + } else { + xi0 = (int)ceil((xMax - bbox[0]) / xstep); + xi1 = (int)floor((xMin - bbox[2]) / xstep) + 1; + } + if (ystep > 0) { + yi0 = (int)ceil((yMin - bbox[3]) / ystep); + yi1 = (int)floor((yMax - bbox[1]) / ystep) + 1; + } else { + yi0 = (int)ceil((yMax - bbox[1]) / ystep); + yi1 = (int)floor((yMin - bbox[3]) / ystep) + 1; + } for (i = 0; i < 4; ++i) { m1[i] = m[i]; } - if (out->useTilingPatternFill()) { + if (out->useTilingPatternFill() && !tPat->usesBlendMode(xref)) { m1[4] = m[4]; m1[5] = m[5]; out->tilingPatternFill(state, this, tPat->getContentStreamRef(), @@ -3521,12 +3556,16 @@ void Gfx::fillPatch(GfxPatch *patch, GfxPatchMeshShading *shading, int depth) { } void Gfx::doEndPath() { - if (state->isCurPt() && clip != clipNone) { - state->clip(); - if (clip == clipNormal) { - out->clip(state); + if (clip != clipNone) { + if (state->isCurPt()) { + state->clip(); + if (clip == clipNormal) { + out->clip(state); + } else { + out->eoClip(state); + } } else { - out->eoClip(state); + error(errSyntaxError, getPos(), "Empty path in clip"); } } clip = clipNone; @@ -3555,9 +3594,15 @@ void Gfx::opBeginText(Object args[], int numArgs) { out->updateTextMat(state); out->updateTextPos(state); fontChanged = gTrue; + haveSavedClipPath = gFalse; } void Gfx::opEndText(Object args[], int numArgs) { + if (haveSavedClipPath) { + out->clipToSavedClipPath(state); + haveSavedClipPath = gFalse; + } + out->endTextObject(state); } @@ -3786,27 +3831,8 @@ void Gfx::opShowSpaceText(Object args[], int numArgs) { } void Gfx::doShowText(GString *s) { - GfxFont *font; - int wMode; - double riseX, riseY; - CharCode code; - Unicode u[8]; - double x, y, dx, dy, dx2, dy2, curX, curY, tdx, tdy, ddx, ddy; - double originX, originY, tOriginX, tOriginY; - double x0, y0, x1, y1; - double oldCTM[6], newCTM[6]; - double *mat; - Object charProcRef, charProc; - Dict *resDict; - Parser *oldParser; - GfxState *savedState; - char *p; - int render; - GBool patternFill; - int len, n, uLen, nChars, nSpaces, i; - - font = state->getFont(); - wMode = font->getWMode(); + GfxFont *font = state->getFont(); + int wMode = font->getWMode(); if (globalParams->isDroppedFont(font->getName() ? font->getName()->getCString() : "")) { @@ -3818,35 +3844,63 @@ void Gfx::doShowText(GString *s) { out->beginString(state, s); } - // if we're doing a pattern fill, set up clipping - render = state->getRender(); - if (!(render & 1) && - state->getFillColorSpace()->getMode() == csPattern) { - patternFill = gTrue; - saveState(); - // disable fill, enable clipping, leave stroke unchanged - if ((render ^ (render >> 1)) & 1) { - render = 5; + // figure out the drawing mode + // note: clipping, pattern fill, and pattern stroke are all handled + // by saving the path and then performing the appropriate + // actions in opEndText() + GBool doFill = gFalse; + GBool doStroke = gFalse; + GBool doMakePath = gFalse; + int render = state->getRender() & 7; + switch (render & 7) { + case 0: // fill + if (state->getFillColorSpace()->getMode() == csPattern) { + doMakePath = gTrue; } else { - render = 7; + doFill = gTrue; } - state->setRender(render); - out->updateRender(state); - } else { - patternFill = gFalse; + break; + case 1: // stroke + if (state->getStrokeColorSpace()->getMode() == csPattern) { + doMakePath = gTrue; + } else { + doStroke = gTrue; + } + break; + case 2: // fill + stroke + if (state->getFillColorSpace()->getMode() == csPattern || + state->getStrokeColorSpace()->getMode() == csPattern) { + doMakePath = gTrue; + } else { + doFill = gTrue; + doStroke = gTrue; + } + break; + case 3: // invisible + // nothing + break; + case 4: // fill + clip + case 5: // stroke + clip + case 6: // fill + stroke + clip + case 7: // clip + doMakePath = gTrue; + break; } + double riseX, riseY; state->textTransformDelta(0, state->getRise(), &riseX, &riseY); - x0 = state->getCurX() + riseX; - y0 = state->getCurY() + riseY; + double xMin = state->getCurX() + riseX; + double yMin = state->getCurY() + riseY; // handle a Type 3 char if (font->getType() == fontType3 && out->interpretType3Chars()) { - mat = state->getCTM(); - for (i = 0; i < 6; ++i) { + double *mat = state->getCTM(); + double oldCTM[6]; + for (int i = 0; i < 6; ++i) { oldCTM[i] = mat[i]; } mat = state->getTextMat(); + double newCTM[6]; newCTM[0] = mat[0] * oldCTM[0] + mat[1] * oldCTM[2]; newCTM[1] = mat[0] * oldCTM[1] + mat[1] * oldCTM[3]; newCTM[2] = mat[2] * oldCTM[0] + mat[3] * oldCTM[2]; @@ -3862,24 +3916,29 @@ void Gfx::doShowText(GString *s) { newCTM[3] *= state->getFontSize(); newCTM[0] *= state->getHorizScaling(); newCTM[1] *= state->getHorizScaling(); - curX = state->getCurX(); - curY = state->getCurY(); - oldParser = parser; - p = s->getCString(); - len = s->getLength(); + double curX = state->getCurX(); + double curY = state->getCurY(); + Parser *oldParser = parser; + char *p = s->getCString(); + int len = s->getLength(); while (len > 0) { - n = font->getNextChar(p, len, &code, - u, (int)(sizeof(u) / sizeof(Unicode)), &uLen, - &dx, &dy, &originX, &originY); + CharCode code; + Unicode u[8]; + int uLen; + double dx, dy, originX, originY; + int n = font->getNextChar(p, len, &code, + u, (int)(sizeof(u) / sizeof(Unicode)), &uLen, + &dx, &dy, &originX, &originY); dx = dx * state->getFontSize() + state->getCharSpace(); if (n == 1 && *p == ' ') { dx += state->getWordSpace(); } dx *= state->getHorizScaling(); dy *= state->getFontSize(); + double tdx, tdy, ddx, ddy, x, y; state->textTransformDelta(dx, dy, &tdx, &tdy); state->transform(curX + riseX, curY + riseY, &x, &y); - savedState = saveStateStack(); + GfxState *savedState = saveStateStack(); state->setCTM(newCTM[0], newCTM[1], newCTM[2], newCTM[3], x, y); //~ the CTM concat values here are wrong (but never used) out->updateCTM(state, 1, 0, 0, 1, 0, 0); @@ -3899,9 +3958,11 @@ void Gfx::doShowText(GString *s) { #endif if (!out->beginType3Char(state, curX + riseX, curY + riseY, ddx, ddy, code, u, uLen)) { + Object charProcRef, charProc; ((Gfx8BitFont *)font)->getCharProcNF(code, &charProcRef); charProcRef.fetch(xref, &charProc); - if ((resDict = ((Gfx8BitFont *)font)->getResources())) { + Dict *resDict = ((Gfx8BitFont *)font)->getResources(); + if (resDict) { pushResources(resDict); } if (charProc.isStream()) { @@ -3927,12 +3988,16 @@ void Gfx::doShowText(GString *s) { parser = oldParser; } else if (out->useDrawChar()) { - p = s->getCString(); - len = s->getLength(); + char *p = s->getCString(); + int len = s->getLength(); while (len > 0) { - n = font->getNextChar(p, len, &code, - u, (int)(sizeof(u) / sizeof(Unicode)), &uLen, - &dx, &dy, &originX, &originY); + CharCode code; + Unicode u[8]; + int uLen; + double dx, dy, originX, originY; + int n = font->getNextChar(p, len, &code, + u, (int)(sizeof(u) / sizeof(Unicode)), &uLen, + &dx, &dy, &originX, &originY); if (wMode) { dx *= state->getFontSize(); dy = dy * state->getFontSize() + state->getCharSpace(); @@ -3947,26 +4012,32 @@ void Gfx::doShowText(GString *s) { dx *= state->getHorizScaling(); dy *= state->getFontSize(); } + double tdx, tdy, tOriginX, tOriginY; state->textTransformDelta(dx, dy, &tdx, &tdy); originX *= state->getFontSize(); originY *= state->getFontSize(); state->textTransformDelta(originX, originY, &tOriginX, &tOriginY); out->drawChar(state, state->getCurX() + riseX, state->getCurY() + riseY, - tdx, tdy, tOriginX, tOriginY, code, n, u, uLen); + tdx, tdy, tOriginX, tOriginY, code, n, u, uLen, + doFill, doStroke, doMakePath); state->shift(tdx, tdy); p += n; len -= n; } } else { - dx = dy = 0; - p = s->getCString(); - len = s->getLength(); - nChars = nSpaces = 0; + double dx = 0, dy = 0; + char *p = s->getCString(); + int len = s->getLength(); + int nChars = 0, nSpaces = 0; while (len > 0) { - n = font->getNextChar(p, len, &code, - u, (int)(sizeof(u) / sizeof(Unicode)), &uLen, - &dx2, &dy2, &originX, &originY); + CharCode code; + Unicode u[8]; + int uLen; + double dx2, dy2, originX, originY; + int n = font->getNextChar(p, len, &code, + u, (int)(sizeof(u) / sizeof(Unicode)), &uLen, + &dx2, &dy2, &originX, &originY); dx += dx2; dy += dy2; if (n == 1 && *p == ' ') { @@ -3988,8 +4059,9 @@ void Gfx::doShowText(GString *s) { dx *= state->getHorizScaling(); dy *= state->getFontSize(); } + double tdx, tdy; state->textTransformDelta(dx, dy, &tdx, &tdy); - out->drawString(state, s); + out->drawString(state, s, doFill, doStroke, doMakePath); state->shift(tdx, tdy); } @@ -3997,40 +4069,70 @@ void Gfx::doShowText(GString *s) { out->endString(state); } - if (patternFill) { - out->saveTextPos(state); - // tell the OutputDev to do the clipping - out->endTextObject(state); - // set up a clipping bbox so doPatternText will work -- assume + if (doMakePath) { + // compute the clipping bbox for the saved text path -- assume // that the text bounding box does not extend past the baseline in // any direction by more than twice the font size - x1 = state->getCurX() + riseX; - y1 = state->getCurY() + riseY; - if (x0 > x1) { - x = x0; x0 = x1; x1 = x; + double xMax = state->getCurX() + riseX; + double yMax = state->getCurY() + riseY; + double t; + if (xMin > xMax) { + t = xMin; xMin = xMax; xMax = t; } - if (y0 > y1) { - y = y0; y0 = y1; y1 = y; + if (yMin > yMax) { + t = yMin; yMin = yMax; yMax = t; } - state->textTransformDelta(0, state->getFontSize(), &dx, &dy); + double dx1, dy1, dx2, dy2; + state->textTransformDelta(0, state->getFontSize(), &dx1, &dy1); state->textTransformDelta(state->getFontSize(), 0, &dx2, &dy2); - dx = fabs(dx); + dx1 = fabs(dx1); dx2 = fabs(dx2); - if (dx2 > dx) { - dx = dx2; + if (dx2 > dx1) { + dx1 = dx2; } - dy = fabs(dy); + dy1 = fabs(dy1); dy2 = fabs(dy2); - if (dy2 > dy) { - dy = dy2; - } - state->clipToRect(x0 - 2 * dx, y0 - 2 * dy, x1 + 2 * dx, y1 + 2 * dy); - // set render mode to fill-only - state->setRender(0); - out->updateRender(state); - doPatternText(); - restoreState(); - out->restoreTextPos(state); + if (dy2 > dy1) { + dy1 = dy2; + } + xMin -= 2 * dx1; + yMin -= 2 * dy1; + xMax += 2 * dx1; + yMax += 2 * dy1; + + //--- fill + if ((render & 3) == 0 || (render & 3) == 2) { + if (state->getFillColorSpace()->getMode() == csPattern) { + saveState(); + state->clipToRect(xMin, yMin, xMax, yMax); + out->clipToTextPath(state); + doPatternText(gFalse); + restoreState(); + } else { + out->fillTextPath(state); + } + } + + //--- stroke + if ((render & 3) == 1 || (render & 3) == 2) { + if (state->getStrokeColorSpace()->getMode() == csPattern) { + saveState(); + state->clipToRect(xMin, yMin, xMax, yMax); + out->clipToTextStrokePath(state); + doPatternText(gTrue); + restoreState(); + } else { + out->strokeTextPath(state); + } + } + + //--- clip + if (render & 4) { + out->addTextPathToSavedClipPath(state); + haveSavedClipPath = gTrue; + } else { + out->clearTextPath(state); + } } opCounter += 10 * s->getLength(); @@ -4116,6 +4218,7 @@ void Gfx::opXObject(Object args[], int numArgs) { xObj.streamGetDict()->lookup("Level1", &obj3); out->psXObject(xObj.getStream(), obj3.isStream() ? obj3.getStream() : (Stream *)NULL); + obj3.free(); } } else if (obj2.isName()) { error(errSyntaxError, getPos(), @@ -4191,10 +4294,14 @@ GBool Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { obj1.free(); dict->lookup("W", &obj1); } - if (!obj1.isInt()) { + if (obj1.isInt()) { + width = obj1.getInt(); + } else if (obj1.isReal()) { + error(errSyntaxWarning, getPos(), "Non-integer image width"); + width = (int)obj1.getReal(); + } else { goto err2; } - width = obj1.getInt(); obj1.free(); if (width <= 0) { goto err1; @@ -4204,10 +4311,14 @@ GBool Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { obj1.free(); dict->lookup("H", &obj1); } - if (!obj1.isInt()) { + if (obj1.isInt()) { + height = obj1.getInt(); + } else if (obj1.isReal()) { + error(errSyntaxWarning, getPos(), "Non-integer image height"); + height = (int)obj1.getReal(); + } else { goto err2; } - height = obj1.getInt(); obj1.free(); if (height <= 0) { goto err1; @@ -4233,8 +4344,14 @@ GBool Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { obj1.free(); dict->lookup("BPC", &obj1); } - if (obj1.isInt()) { - bits = obj1.getInt(); + if (obj1.isNum()) { + if (obj1.isInt()) { + bits = obj1.getInt(); + } else if (obj1.isReal()) { + error(errSyntaxWarning, getPos(), + "Non-integer image bits per component"); + bits = (int)obj1.getReal(); + } if (bits < 1 || bits > 16) { goto err2; } @@ -4377,26 +4494,34 @@ GBool Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { obj1.free(); maskDict->lookup("W", &obj1); } - if (!obj1.isInt()) { + if (obj1.isInt()) { + maskWidth = obj1.getInt(); + } else if (obj1.isReal()) { + error(errSyntaxWarning, getPos(), "Non-integer image mask width"); + maskWidth = (int)obj1.getReal(); + } else { delete colorMap; maskObj.free(); smaskObj.free(); goto err2; } - maskWidth = obj1.getInt(); obj1.free(); maskDict->lookup("Height", &obj1); if (obj1.isNull()) { obj1.free(); maskDict->lookup("H", &obj1); } - if (!obj1.isInt()) { + if (obj1.isInt()) { + maskHeight = obj1.getInt(); + } else if (obj1.isReal()) { + error(errSyntaxWarning, getPos(), "Non-integer image mask height"); + maskHeight = (int)obj1.getReal(); + } else { delete colorMap; maskObj.free(); smaskObj.free(); goto err2; } - maskHeight = obj1.getInt(); obj1.free(); if (maskWidth <= 0 || maskHeight <= 0) { delete colorMap; @@ -4409,13 +4534,18 @@ GBool Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { obj1.free(); maskDict->lookup("BPC", &obj1); } - if (!obj1.isInt()) { + if (obj1.isInt()) { + maskBits = obj1.getInt(); + } else if (obj1.isReal()) { + error(errSyntaxWarning, getPos(), + "Non-integer image mask bits per component"); + maskBits = (int)obj1.getReal(); + } else { delete colorMap; maskObj.free(); smaskObj.free(); goto err2; } - maskBits = obj1.getInt(); obj1.free(); if (maskBits < 1 || maskBits > 16) { delete colorMap; @@ -4512,6 +4642,7 @@ GBool Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { } } else if (maskObj.isStream()) { // explicit mask + haveExplicitMask = gTrue; if (inlineImg) { delete colorMap; maskObj.free(); @@ -4526,32 +4657,31 @@ GBool Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { obj1.free(); maskDict->lookup("W", &obj1); } - if (!obj1.isInt()) { - delete colorMap; - maskObj.free(); - smaskObj.free(); - goto err2; + if (obj1.isInt()) { + maskWidth = obj1.getInt(); + } else if (obj1.isReal()) { + error(errSyntaxWarning, getPos(), "Non-integer image mask width"); + maskWidth = (int)obj1.getReal(); + } else { + haveExplicitMask = gFalse; } - maskWidth = obj1.getInt(); obj1.free(); maskDict->lookup("Height", &obj1); if (obj1.isNull()) { obj1.free(); maskDict->lookup("H", &obj1); } - if (!obj1.isInt()) { - delete colorMap; - maskObj.free(); - smaskObj.free(); - goto err2; + if (obj1.isInt()) { + maskHeight = obj1.getInt(); + } else if (obj1.isReal()) { + error(errSyntaxWarning, getPos(), "Non-integer image mask height"); + maskHeight = (int)obj1.getReal(); + } else { + haveExplicitMask = gFalse; } - maskHeight = obj1.getInt(); obj1.free(); if (maskWidth <= 0 || maskHeight <= 0) { - delete colorMap; - maskObj.free(); - smaskObj.free(); - goto err2; + haveExplicitMask = gFalse; } maskDict->lookup("ImageMask", &obj1); if (obj1.isNull()) { @@ -4559,10 +4689,7 @@ GBool Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { maskDict->lookup("IM", &obj1); } if (!obj1.isBool() || !obj1.getBool()) { - delete colorMap; - maskObj.free(); - smaskObj.free(); - goto err2; + haveExplicitMask = gFalse; } obj1.free(); maskInvert = gFalse; @@ -4576,13 +4703,12 @@ GBool Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { maskInvert = obj2.isNum() && obj2.getNum() == 1; obj2.free(); } else if (!obj1.isNull()) { - delete colorMap; - maskObj.free(); - smaskObj.free(); - goto err2; + haveExplicitMask = gFalse; } obj1.free(); - haveExplicitMask = gTrue; + if (!haveExplicitMask) { + error(errSyntaxError, getPos(), "Bad image parameters"); + } } // if drawing is disabled, skip over inline image data @@ -4666,11 +4792,6 @@ void Gfx::doForm(Object *strRef, Object *str) { Object obj1, obj2, obj3; int i; - // check for excessive recursion - if (formDepth > 100) { - return; - } - // check for optional content if (!ocState && !out->needCharCount()) { return; @@ -4747,9 +4868,7 @@ void Gfx::doForm(Object *strRef, Object *str) { obj1.free(); // draw it - ++formDepth; drawForm(strRef, resDict, m, bbox, transpGroup, gFalse, isolated, knockout); - --formDepth; resObj.free(); } @@ -4768,6 +4887,14 @@ void Gfx::drawForm(Object *strRef, Dict *resDict, double oldBaseMatrix[6]; int i; + if (formDepth > 100) { + error(errSyntaxError, getPos(), "Excessive recursion in Form XObjects"); + return; + } + ++formDepth; + + out->startStream(strRef->getRef(), state); + // push new resources on stack pushResources(resDict); @@ -4897,7 +5024,9 @@ void Gfx::drawForm(Object *strRef, Dict *resDict, delete blendingColorSpace; } - return; + out->endStream(strRef->getRef()); + + --formDepth; } void Gfx::takeContentStreamStack(Gfx *oldGfx) { @@ -4936,7 +5065,9 @@ void Gfx::opBeginImage(Object args[], int numArgs) { // if we have the stream length, skip to end-of-stream and then // skip 'EI' in the original stream } else if (haveLength) { - while ((c1 = str->getChar()) != EOF) ; + // NB: getUndecodedStream() returns the EmbedStream created by + // buildImageStream() + while ((c1 = str->getUndecodedStream()->getChar()) != EOF) ; delete str; str = parser->getStream(); c1 = str->getChar(); @@ -5091,15 +5222,28 @@ void Gfx::opBeginMarkedContent(Object args[], int numArgs) { } obj.free(); mcKind = gfxMCOptionalContent; - } else if (args[0].isName("Span") && numArgs == 2 && args[1].isDict()) { - if (args[1].dictLookup("ActualText", &obj)->isString()) { - s = new TextString(obj.getString()); - out->beginActualText(state, s->getUnicode(), s->getLength()); - delete s; - mcKind = gfxMCActualText; + } else if (numArgs == 2 && args[1].isDict()) { + if (args[0].isName("Span")) { + if (args[1].dictLookup("ActualText", &obj)->isString()) { + s = new TextString(obj.getString()); + out->beginActualText(state, s->getUnicode(), s->getLength()); + delete s; + mcKind = gfxMCActualText; + } + obj.free(); + } + if (args[1].dictLookup("MCID", &obj)->isInt()) { + out->beginStructureItem(args[0].getName(), obj.getInt(), + args[1].getDict()); + if (mcKind == gfxMCActualText) { + mcKind = gfxMCStructureItemAndActualText; + } else { + mcKind = gfxMCStructureItem; + } } obj.free(); } + mc = new GfxMarkedContent(mcKind, ocState); markedContentStack->append(mc); } @@ -5123,6 +5267,11 @@ void Gfx::opEndMarkedContent(Object args[], int numArgs) { } } else if (mcKind == gfxMCActualText) { out->endActualText(state); + } else if (mcKind == gfxMCStructureItem) { + out->endStructureItem(); + } else if (mcKind == gfxMCStructureItemAndActualText) { + out->endStructureItem(); + out->endActualText(state); } } else { error(errSyntaxWarning, getPos(), "Mismatched EMC operator"); @@ -5193,10 +5342,14 @@ void Gfx::drawAnnot(Object *strRef, AnnotBorderStyle *borderStyle, // get the form matrix dict->lookup("Matrix", &matrixObj); - if (matrixObj.isArray()) { + if (matrixObj.isArray() && matrixObj.arrayGetLength() == 6) { for (i = 0; i < 6; ++i) { matrixObj.arrayGet(i, &obj1); - m[i] = obj1.getNum(); + if (obj1.isNum()) { + m[i] = obj1.getNum(); + } else { + m[i] = 0; + } obj1.free(); } } else { @@ -5253,13 +5406,13 @@ void Gfx::drawAnnot(Object *strRef, AnnotBorderStyle *borderStyle, // [0 sy 0] // [tx ty 1] // bbox to the annotation rectangle - if (formXMin == formXMax) { + if (formXMax - formXMin < 1e-8) { // this shouldn't happen sx = 1; } else { sx = (xMax - xMin) / (formXMax - formXMin); } - if (formYMin == formYMax) { + if (formYMax - formYMin < 1e-8) { // this shouldn't happen sy = 1; } else { diff --git a/src/xpdf-4.04/xpdf/Gfx.h b/src/xpdf-4.06/xpdf/Gfx.h old mode 100644 new mode 100755 similarity index 96% rename from src/xpdf-4.04/xpdf/Gfx.h rename to src/xpdf-4.06/xpdf/Gfx.h index 14d7a60..73fff85 --- a/src/xpdf-4.04/xpdf/Gfx.h +++ b/src/xpdf-4.06/xpdf/Gfx.h @@ -11,10 +11,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #include "gtypes.h" #include "gfile.h" #include "GfxState.h" @@ -34,6 +30,7 @@ class GfxFont; class Gfx; class PDFRectangle; class AnnotBorderStyle; +class LocalParams; //------------------------------------------------------------------------ @@ -106,6 +103,8 @@ class GfxResources { enum GfxMarkedContentKind { gfxMCOptionalContent, gfxMCActualText, + gfxMCStructureItem, + gfxMCStructureItemAndActualText, gfxMCOther }; @@ -131,15 +130,16 @@ class Gfx { public: // Constructor for regular output. - Gfx(PDFDoc *docA, OutputDev *outA, int pageNum, Dict *resDict, + Gfx(PDFDoc *docA, OutputDev *outA, LocalParams *localParams, + int pageNum, Dict *resDict, double hDPI, double vDPI, PDFRectangle *box, PDFRectangle *cropBox, int rotate, GBool (*abortCheckCbkA)(void *data) = NULL, void *abortCheckCbkDataA = NULL); // Constructor for a sub-page object. - Gfx(PDFDoc *docA, OutputDev *outA, Dict *resDict, - PDFRectangle *box, PDFRectangle *cropBox, + Gfx(PDFDoc *docA, OutputDev *outA, LocalParams *localParams, + Dict *resDict, PDFRectangle *box, PDFRectangle *cropBox, GBool (*abortCheckCbkA)(void *data) = NULL, void *abortCheckCbkDataA = NULL); @@ -163,6 +163,9 @@ class Gfx { // Get the current graphics state object. GfxState *getState() { return state; } + // Get the current base matrix. + double *getBaseMatrix() { return baseMatrix; } + void drawForm(Object *strRef, Dict *resDict, double *matrix, double *bbox, GBool transpGroup = gFalse, GBool softMask = gFalse, GBool isolated = gFalse, GBool knockout = gFalse, @@ -194,6 +197,7 @@ class Gfx { GfxState *state; // current graphics state GBool fontChanged; // set if font or text matrix has changed + GBool haveSavedClipPath; GfxClipType clip; // do a clip? int ignoreUndef; // current BX/EX nesting level double baseMatrix[6]; // default matrix for most recent @@ -273,7 +277,7 @@ class Gfx { void opCloseEOFillStroke(Object args[], int numArgs); void doPatternFill(GBool eoFill); void doPatternStroke(); - void doPatternText(); + void doPatternText(GBool stroke); void doPatternImageMask(Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg, GBool interpolate); void doTilingPatternFill(GfxTilingPattern *tPat, diff --git a/src/xpdf-4.04/xpdf/GfxFont.cc b/src/xpdf-4.06/xpdf/GfxFont.cc old mode 100644 new mode 100755 similarity index 85% rename from src/xpdf-4.04/xpdf/GfxFont.cc rename to src/xpdf-4.06/xpdf/GfxFont.cc index 30e8bd1..5050ab6 --- a/src/xpdf-4.04/xpdf/GfxFont.cc +++ b/src/xpdf-4.06/xpdf/GfxFont.cc @@ -8,10 +8,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include #include #include @@ -307,26 +303,10 @@ GfxFontType GfxFont::getFontType(XRef *xref, Dict *fontDict, Ref *embID) { obj2.initNull(); } + // NB: the PDF spec doesn't say anything about precedence, but Adobe + // uses FontFile3 over FontFile2 if both are present. if (fontDict2->lookup("FontDescriptor", &fontDesc)->isDict()) { - if (fontDesc.dictLookupNF("FontFile", &obj3)->isRef()) { - *embID = obj3.getRef(); - if (expectedType != fontType1) { - err = gTrue; - } - } - obj3.free(); - if (embID->num == -1 && - fontDesc.dictLookupNF("FontFile2", &obj3)->isRef()) { - *embID = obj3.getRef(); - if (isType0) { - expectedType = fontCIDType2; - } else if (expectedType != fontTrueType) { - err = gTrue; - } - } - obj3.free(); - if (embID->num == -1 && - fontDesc.dictLookupNF("FontFile3", &obj3)->isRef()) { + if (fontDesc.dictLookupNF("FontFile3", &obj3)->isRef()) { *embID = obj3.getRef(); if (obj3.fetch(xref, &obj4)->isStream()) { obj4.streamGetDict()->lookup("Subtype", &subtype); @@ -375,6 +355,26 @@ GfxFontType GfxFont::getFontType(XRef *xref, Dict *fontDict, Ref *embID) { obj4.free(); } obj3.free(); + if (embID->num == -1) { + if (fontDesc.dictLookupNF("FontFile2", &obj3)->isRef()) { + *embID = obj3.getRef(); + if (isType0) { + expectedType = fontCIDType2; + } else if (expectedType != fontTrueType) { + err = gTrue; + } + } + obj3.free(); + } + if (embID->num == -1) { + if (fontDesc.dictLookupNF("FontFile", &obj3)->isRef()) { + *embID = obj3.getRef(); + if (expectedType != fontType1) { + err = gTrue; + } + } + obj3.free(); + } } fontDesc.free(); @@ -411,12 +411,19 @@ GfxFontType GfxFont::getFontType(XRef *xref, Dict *fontDict, Ref *embID) { error(errSyntaxError, -1, "Embedded font file may be invalid"); break; } + } else { + error(errSyntaxError, -1, "Embedded font object is wrong type"); } obj4.free(); obj3.free(); } + // If the embedded font doesn't exist, or it's not a stream object, + // or we couldn't identify its type, then remove the reference so + // nothing tries to use it later. if (t == fontUnknownType) { + embID->num = -1; + embID->gen = -1; t = expectedType; } @@ -465,8 +472,18 @@ void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) { } obj2.free(); - // get Ascent - // (CapHeight is a little more reliable - so use it if present) + // font FontBBox + if (obj1.dictLookup("FontBBox", &obj2)->isArray()) { + for (i = 0; i < 4 && i < obj2.arrayGetLength(); ++i) { + if (obj2.arrayGet(i, &obj3)->isNum()) { + fontBBox[i] = 0.001 * obj3.getNum(); + } + obj3.free(); + } + } + obj2.free(); + + // get Ascent (but also look at CapHeight) obj1.dictLookup("Ascent", &obj2); obj1.dictLookup("CapHeight", &obj3); if (obj2.isNum() || obj3.isNum()) { @@ -491,15 +508,25 @@ void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) { if (t != 0 && t < 1.9) { declaredAscent = t; } - // if both Ascent and CapHeight are set, use the smaller one - // (because the most common problem is that Ascent is too large) - if (t2 != 0 && (t == 0 || t2 < t)) { - t = t2; - } - // some broken font descriptors set ascent and descent to 0; - // others set it to ridiculous values (e.g., 32768) - if (t != 0 && t < 1.9) { + // The ascent is generally expected to be in the (0.55, 1.9) range. + // If Ascent and/or CapHeight is in that range, use the smaller one + // (because the most common problem is that Ascent is too large). + // Otherwise check for a value in (0, 0.55], and use that. + if (t > 0.55 && t < 1.9) { + if (t2 > 0.55 && t2 < 1.9) { + ascent = (t < t2) ? t : t2; + } else { + ascent = t; + } + } else if (t2 > 0.55 && t2 < 1.9) { + ascent = t2; + } else if (fontBBox[3] > 0.55 && fontBBox[3] < 1.9 && + fontBBox[1] < fontBBox[3]) { + ascent = fontBBox[3]; + } else if (t > 0 && t < 1.9) { ascent = t; + } else if (t2 > 0 && t2 < 1.9) { + ascent = t2; } } obj2.free(); @@ -514,25 +541,46 @@ void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) { t = -t; } // some broken font descriptors set ascent and descent to 0 - if (t != 0 && t > -1.9) { + if (t < 0 && t > -1.9) { descent = t; + } else if (fontBBox[1] > -1.9 && fontBBox[1] <= 0 && + fontBBox[1] < fontBBox[3]) { + descent = fontBBox[1]; } } obj2.free(); - // font FontBBox - if (obj1.dictLookup("FontBBox", &obj2)->isArray()) { - for (i = 0; i < 4 && i < obj2.arrayGetLength(); ++i) { - if (obj2.arrayGet(i, &obj3)->isNum()) { - fontBBox[i] = 0.001 * obj3.getNum(); - } - obj3.free(); + } + obj1.free(); + + // scan font name for bold/italic tags and update the flags + if (name) { + i = name->getLength(); + if (i > 2 && !strncmp(name->getCString() + i - 2, "MT", 2)) { + i -= 2; + } + if (i > 6 && !strncmp(name->getCString() + i - 6, "Italic", 6)) { + flags |= fontItalic; + i -= 6; + } else if (i > 2 && !strncmp(name->getCString() + i - 2, "It", 2)) { + flags |= fontItalic; + i -= 2; + } else if (i > 7 && !strncmp(name->getCString() + i - 7, "Oblique", 7)) { + flags |= fontItalic; + i -= 7; + } + if (i > 0) { + char c = name->getChar(i-1); + if (!((c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z') || + (c >= '0' && c <= '9'))) { + --i; } } - obj2.free(); - + if (i > 4 && !strncmp(name->getCString() + i - 4, "Bold", 4)) { + flags |= fontBold; + } } - obj1.free(); } CharCodeToUnicode *GfxFont::readToUnicodeCMap(Dict *fontDict, int nBits, @@ -665,39 +713,41 @@ GfxFontLoc *GfxFont::locateFont(XRef *xref, GBool ps) { fontLoc->locType = gfxFontLocExternal; fontLoc->path = path; fontLoc->fontNum = fontNum; - if (isCIDFont()) { - if (sysFontType == sysFontTTF || sysFontType == sysFontTTC) { - fontLoc->fontType = fontCIDType2; - 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->fontType = fontTrueType; - return fontLoc; - } else if (sysFontType == sysFontPFA || sysFontType == sysFontPFB) { - fontLoc->fontType = fontType1; - 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; - } - } + fft = FoFiIdentifier::identifyFile(fontLoc->path->getCString()); + switch (fft) { + case fofiIdType1PFA: + case fofiIdType1PFB: + fontLoc->fontType = fontType1; + break; + case fofiIdCFF8Bit: + fontLoc->fontType = fontType1C; + break; + case fofiIdCFFCID: + fontLoc->fontType = fontCIDType0C; + break; + case fofiIdTrueType: + case fofiIdTrueTypeCollection: + fontLoc->fontType = isCIDFont() ? fontCIDType2 : fontTrueType; + break; + case fofiIdOpenTypeCFF8Bit: + fontLoc->fontType = fontType1COT; + break; + case fofiIdOpenTypeCFFCID: + fontLoc->fontType = fontCIDType0COT; + break; + case fofiIdDfont: + fontLoc->fontType = isCIDFont() ? fontCIDType2 : fontTrueType; + break; + case fofiIdUnknown: + case fofiIdError: + default: + delete fontLoc; + fontLoc = NULL; + break; + } + if (fontLoc) { + return fontLoc; } - delete fontLoc; } if (!isCIDFont()) { @@ -1082,6 +1132,17 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, const char *tagA, Ref idA, GString *nameA, baseEnc = winAnsiEncoding; } + // a non-embedded Symbol or ZapfDingbats font should never use one + // of the non-symbol encodings -- I've encountered PDF files that + // set the Encoding to WinAnsiEncoding, which doesn't make any sense + // (and other viewers also seem to ignore it) + if (builtinFont && embFontID.num < 0 && + (builtinFont->defaultBaseEnc == symbolEncoding || + builtinFont->defaultBaseEnc == zapfDingbatsEncoding) && + !obj1.isDict()) { + baseEnc = NULL; + } + // check embedded font file for base encoding // (only for Type 1 fonts - trying to get an encoding out of a // TrueType font is a losing proposition) @@ -1436,7 +1497,7 @@ CharCodeToUnicode *Gfx8BitFont::getToUnicode() { int *Gfx8BitFont::getCodeToGIDMap(FoFiTrueType *ff) { int *map; int cmapPlatform, cmapEncoding; - int unicodeCmap, macRomanCmap, msSymbolCmap, cmap; + int unicodeCmap, macRomanCmap, macUnicodeCmap, msSymbolCmap, cmap; GBool nonsymbolic, useMacRoman, useUnicode; char *charName; Unicode u; @@ -1450,15 +1511,16 @@ int *Gfx8BitFont::getCodeToGIDMap(FoFiTrueType *ff) { // This is based on the cmap/encoding selection algorithm in the PDF // 2.0 spec, but with some differences to match up with Adobe's // behavior. - unicodeCmap = macRomanCmap = msSymbolCmap = -1; + unicodeCmap = macRomanCmap = macUnicodeCmap = msSymbolCmap = -1; for (i = 0; i < ff->getNumCmaps(); ++i) { cmapPlatform = ff->getCmapPlatform(i); cmapEncoding = ff->getCmapEncoding(i); - if ((cmapPlatform == 3 && cmapEncoding == 1) || - (cmapPlatform == 0 && cmapEncoding <= 4)) { + if (cmapPlatform == 3 && cmapEncoding == 1) { unicodeCmap = i; } else if (cmapPlatform == 1 && cmapEncoding == 0) { macRomanCmap = i; + } else if (cmapPlatform == 0 && cmapEncoding <= 4) { + macUnicodeCmap = i; } else if (cmapPlatform == 3 && cmapEncoding == 0) { msSymbolCmap = i; } @@ -1466,24 +1528,25 @@ int *Gfx8BitFont::getCodeToGIDMap(FoFiTrueType *ff) { useMacRoman = gFalse; useUnicode = gFalse; nonsymbolic = !(flags & fontSymbolic); - if (usesMacRomanEnc && macRomanCmap >= 0) { - cmap = macRomanCmap; - useMacRoman = gTrue; - } else if (embFontID.num < 0 && hasEncoding && unicodeCmap >= 0) { - cmap = unicodeCmap; - useUnicode = gTrue; - } else if (nonsymbolic && unicodeCmap >= 0) { + if (embFontID.num < 0 && hasEncoding && unicodeCmap >= 0) { cmap = unicodeCmap; useUnicode = gTrue; - } else if (nonsymbolic && macRomanCmap >= 0) { - cmap = macRomanCmap; - useMacRoman = gTrue; - } else if (msSymbolCmap >= 0) { + } else if (!nonsymbolic && msSymbolCmap >= 0) { cmap = msSymbolCmap; } else if (unicodeCmap >= 0) { cmap = unicodeCmap; + useUnicode = nonsymbolic; + } else if (usesMacRomanEnc && macRomanCmap >= 0) { + // MacRoman cmap has higher precedence than Mac Unicode only if + // the font uses the MacRoman encoding + cmap = macRomanCmap; + useMacRoman = gTrue; + } else if (macUnicodeCmap >= 0) { + cmap = macUnicodeCmap; + useUnicode = nonsymbolic; } else if (macRomanCmap >= 0) { cmap = macRomanCmap; + useMacRoman = nonsymbolic; } else { cmap = 0; } @@ -1630,7 +1693,8 @@ GBool Gfx8BitFont::problematicForUnicode() { return !hasToUnicode && (!hasEncoding || usedNumericHeuristic); case fontType3: - return !hasToUnicode && !hasEncoding; + // this never happens -- Type 3 fonts don't set embFontID + return !hasToUnicode && (!hasEncoding || usedNumericHeuristic); case fontTrueType: case fontTrueTypeOT: @@ -1640,6 +1704,9 @@ GBool Gfx8BitFont::problematicForUnicode() { return !hasToUnicode; } + } else if (type == fontType3) { + return !hasToUnicode && (!hasEncoding || usedNumericHeuristic); + } else { // NB: type will be fontTypeUnknown if the PDF specifies an // invalid font type -- which is ok, if we have a ToUnicode map or @@ -1648,6 +1715,10 @@ GBool Gfx8BitFont::problematicForUnicode() { } } +GBool Gfx8BitFont::parensAreSwapped(XRef *xref) { + return gFalse; +} + //------------------------------------------------------------------------ // GfxCIDFont //------------------------------------------------------------------------ @@ -2007,7 +2078,7 @@ void GfxCIDFont::readTrueTypeUnicodeMapping(XRef *xref) { int nGlyphs, nMappings, gid, i; // must be an embedded TrueType font, with an unknown char collection - if ((type != fontCIDType2 && type == fontCIDType2OT) || + if ((type != fontCIDType2 && type != fontCIDType2OT) || embFontID.num < 0 || hasKnownCollection) { goto err0; @@ -2225,79 +2296,197 @@ GBool GfxCIDFont::problematicForUnicode() { } } +GBool GfxCIDFont::parensAreSwapped(XRef *xref) { + char *buf = NULL; + FoFiTrueType *ff = NULL; + int bufLen; + int unicodeCmap, leftParenGID, rightParenGID, leftParenCID, rightParenCID; + Unicode leftParenUnicode, rightParenUnicode; + GBool swapped; + + // only relevant for embedded TrueType fonts, with unknown char + // collections, and with ToUnicode maps + if ((type != fontCIDType2 && type != fontCIDType2OT) || + embFontID.num < 0 || + hasKnownCollection || + !hasToUnicode) { + return gFalse; + } + + // read the embedded font and construct a FoFiTrueType + if (!(buf = readEmbFontFile(xref, &bufLen))) { + goto err; + } + if (!(ff = FoFiTrueType::make(buf, bufLen, 0))) { + goto err; + } + + // find the TrueType Unicode cmap + unicodeCmap = -1; + for (int i = 0; i < ff->getNumCmaps(); ++i) { + int cmapPlatform = ff->getCmapPlatform(i); + int cmapEncoding = ff->getCmapEncoding(i); + if ((cmapPlatform == 3 && cmapEncoding == 1) || + (cmapPlatform == 0 && cmapEncoding <= 4)) { + unicodeCmap = i; + break; + } + } + if (unicodeCmap < 0) { + goto err; + } + + // map parens to GIDs using the TrueType Unicode cmap + leftParenGID = ff->mapCodeToGID(unicodeCmap, 0x28); + rightParenGID = ff->mapCodeToGID(unicodeCmap, 0x29); + if (leftParenGID == 0 || rightParenGID == 0) { + goto err; + } + + // map GIDs to CIDs using the inverted CIDToGID map + leftParenCID = -1; + rightParenCID = -1; + if (cidToGID) { + for (int i = 0; + i <= cidToGIDLen && leftParenCID < 0 && rightParenCID < 0; + ++i) { + if (cidToGID[i] == leftParenGID) { + leftParenCID = i; + } else if (cidToGID[i] == rightParenGID) { + rightParenCID = i; + } + } + if (leftParenCID < 0 || rightParenCID < 0) { + goto err; + } + } else { + leftParenCID = leftParenGID; + rightParenCID = rightParenGID; + } + + // map CIDs to Unicode using the ToUnicode map + if (ctu->mapToUnicode((CharCode)leftParenCID, &leftParenUnicode, 1) < 1 || + ctu->mapToUnicode((CharCode)rightParenCID, &rightParenUnicode, 1) < 1) { + goto err; + } + + // check for swap + swapped = leftParenUnicode == 0x29 && rightParenUnicode == 0x28; + + delete ff; + ff = NULL; + gfree(buf); + buf = NULL; + + return swapped; + + err: + if (ff) { + delete ff; + } + if (buf) { + gfree(buf); + } + return gFalse; +} + //------------------------------------------------------------------------ // GfxFontDict //------------------------------------------------------------------------ -GfxFontDict::GfxFontDict(XRef *xref, Ref *fontDictRef, Dict *fontDict) { - GfxFont *font; - char *tag; - Object obj1, obj2; - Ref r; - int i; +class GfxFontDictEntry { +public: + + GfxFontDictEntry(Ref refA, Object *fontObjA); + ~GfxFontDictEntry(); + void load(GfxFont *fontA); + + GBool loaded; + Ref ref; + Object fontObj; // valid if unloaded + GfxFont *font; // valid if loaded +}; + +GfxFontDictEntry::GfxFontDictEntry(Ref refA, Object *fontObjA) { + loaded = gFalse; + ref = refA; + fontObjA->copy(&fontObj); + font = NULL; +} +GfxFontDictEntry::~GfxFontDictEntry() { + // NB: If the font has been loaded, font is non-NULL and is owned by + // GfxFontDict.uniqueFonts. + if (!loaded) { + fontObj.free(); + } +} + +void GfxFontDictEntry::load(GfxFont *fontA) { + loaded = gTrue; + font = fontA; + fontObj.free(); +} + +GfxFontDict::GfxFontDict(XRef *xrefA, Ref *fontDictRef, Dict *fontDict) { + xref = xrefA; fonts = new GHash(gTrue); uniqueFonts = new GList(); - for (i = 0; i < fontDict->getLength(); ++i) { - tag = fontDict->getKey(i); - fontDict->getValNF(i, &obj1); - obj1.fetch(xref, &obj2); - if (!obj2.isDict()) { - error(errSyntaxError, -1, "font resource is not a dictionary"); - } else if (obj1.isRef() && (font = lookupByRef(obj1.getRef()))) { - fonts->add(new GString(tag), font); + + for (int i = 0; i < fontDict->getLength(); ++i) { + char *tag = fontDict->getKey(i); + Object fontObj; + fontDict->getValNF(i, &fontObj); + Ref r; + if (fontObj.isRef()) { + r = fontObj.getRef(); + } else if (fontDictRef) { + // legal generation numbers are five digits, so we use a + // 6-digit number here + r.gen = 100000 + fontDictRef->num; + r.num = i; } else { - if (obj1.isRef()) { - r = obj1.getRef(); - } else if (fontDictRef) { - // legal generation numbers are five digits, so we use a - // 6-digit number here - r.gen = 100000 + fontDictRef->num; - r.num = i; - } else { - // no indirect reference for this font, or for the containing - // font dict, so hash the font and use that - r.gen = 100000; - r.num = hashFontObject(&obj2); - } - if ((font = GfxFont::makeFont(xref, tag, r, obj2.getDict()))) { - if (!font->isOk()) { - delete font; - } else { - uniqueFonts->append(font); - fonts->add(new GString(tag), font); - } - } + // no indirect reference for this font, or for the containing + // font dict, so hash the font and use that + r.gen = 100000; + r.num = hashFontObject(&fontObj); } - obj1.free(); - obj2.free(); + fonts->add(new GString(tag), new GfxFontDictEntry(r, &fontObj)); + fontObj.free(); } } GfxFontDict::~GfxFontDict() { deleteGList(uniqueFonts, GfxFont); - delete fonts; + deleteGHash(fonts, GfxFontDictEntry); } GfxFont *GfxFontDict::lookup(char *tag) { - return (GfxFont *)fonts->lookup(tag); + GfxFontDictEntry *entry = (GfxFontDictEntry *)fonts->lookup(tag); + if (!entry) { + return NULL; + } + load(tag, entry); + return entry->font; } GfxFont *GfxFontDict::lookupByRef(Ref ref) { - GfxFont *font; - int i; - - for (i = 0; i < uniqueFonts->getLength(); ++i) { - font = (GfxFont *)uniqueFonts->get(i); - if (font->getID()->num == ref.num && - font->getID()->gen == ref.gen) { - return font; + GHashIter *iter; + GString *tag; + GfxFontDictEntry *entry; + fonts->startIter(&iter); + while (fonts->getNext(&iter, &tag, (void **)&entry)) { + if (entry->ref.num == ref.num && entry->ref.gen == ref.gen) { + fonts->killIter(&iter); + load(tag->getCString(), entry); + return entry->font; } } return NULL; } int GfxFontDict::getNumFonts() { + loadAll(); return uniqueFonts->getLength(); } @@ -2305,6 +2494,52 @@ GfxFont *GfxFontDict::getFont(int i) { return (GfxFont *)uniqueFonts->get(i); } +void GfxFontDict::loadAll() { + GHashIter *iter; + GString *tag; + GfxFontDictEntry *entry; + fonts->startIter(&iter); + while (fonts->getNext(&iter, &tag, (void **)&entry)) { + load(tag->getCString(), entry); + } +} + +void GfxFontDict::load(char *tag, GfxFontDictEntry *entry) { + if (entry->loaded) { + return; + } + + // check for a duplicate that has already been loaded + // (don't do this for "synthetic" refs) + if (entry->fontObj.isRef()) { + for (int i = 0; i < uniqueFonts->getLength(); ++i) { + GfxFont *font = (GfxFont *)uniqueFonts->get(i); + if (font->getID()->num == entry->ref.num && + font->getID()->gen == entry->ref.gen) { + entry->load(font); + return; + } + } + } + + GfxFont *font = NULL; + Object obj; + entry->fontObj.fetch(xref, &obj); + if (obj.isDict()) { + font = GfxFont::makeFont(xref, tag, entry->ref, obj.getDict()); + if (font->isOk()) { + uniqueFonts->append(font); + } else { + delete font; + font = NULL; + } + } else { + error(errSyntaxError, -1, "font resource is not a dictionary"); + } + obj.free(); + entry->load(font); +} + // FNV-1a hash class FNVHash { public: diff --git a/src/xpdf-4.04/xpdf/GfxFont.h b/src/xpdf-4.06/xpdf/GfxFont.h old mode 100644 new mode 100755 similarity index 94% rename from src/xpdf-4.04/xpdf/GfxFont.h rename to src/xpdf-4.06/xpdf/GfxFont.h index e752ded..cc27ff7 --- a/src/xpdf-4.04/xpdf/GfxFont.h +++ b/src/xpdf-4.06/xpdf/GfxFont.h @@ -11,10 +11,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #include "gtypes.h" #include "GString.h" #include "Object.h" @@ -29,6 +25,7 @@ class FoFiTrueType; class FoFiType1C; struct GfxFontCIDWidths; struct Base14FontMapEntry; +class GfxFontDictEntry; class FNVHash; //------------------------------------------------------------------------ @@ -218,6 +215,11 @@ class GfxFont { // converting text to Unicode. virtual GBool problematicForUnicode() = 0; + // Returns true if this font swaps the left and right parens in its + // ToUnicode map. This is likely a kludge used by bad PDF generators + // with Arabic fonts. + virtual GBool parensAreSwapped(XRef *xref) = 0; + protected: static GfxFontType getFontType(XRef *xref, Dict *fontDict, Ref *embID); @@ -298,6 +300,8 @@ class Gfx8BitFont: public GfxFont { virtual GBool problematicForUnicode(); + virtual GBool parensAreSwapped(XRef *xref); + private: Base14FontMapEntry *base14; // for Base-14 fonts only; NULL otherwise @@ -359,6 +363,8 @@ class GfxCIDFont: public GfxFont { virtual GBool problematicForUnicode(); + virtual GBool parensAreSwapped(XRef *xref); + private: void readTrueTypeUnicodeMapping(XRef *xref); @@ -388,7 +394,7 @@ class GfxFontDict { public: // Build the font dictionary, given the PDF font dictionary. - GfxFontDict(XRef *xref, Ref *fontDictRef, Dict *fontDict); + GfxFontDict(XRef *xrefA, Ref *fontDictRef, Dict *fontDict); // Destructor. ~GfxFontDict(); @@ -405,13 +411,18 @@ class GfxFontDict { friend class GfxFont; + void loadAll(); + void load(char *tag, GfxFontDictEntry *entry); static int hashFontObject(Object *obj); static void hashFontObject1(Object *obj, FNVHash *h); - GHash *fonts; // hash table of fonts -- this may - // include duplicates, i.e., when - // two tags map to the same font + XRef *xref; + GHash *fonts; // hash table of fonts, mapping from + // tag to GfxFontDictEntry; this may + // contain duplicates, i.e., two + // tags that map to the same font GList *uniqueFonts; // list of all unique font objects (no dups) + // that have been loaded }; #endif diff --git a/src/xpdf-4.04/xpdf/GfxState.cc b/src/xpdf-4.06/xpdf/GfxState.cc old mode 100644 new mode 100755 similarity index 93% rename from src/xpdf-4.04/xpdf/GfxState.cc rename to src/xpdf-4.06/xpdf/GfxState.cc index 43503aa..6e5bb6c --- a/src/xpdf-4.04/xpdf/GfxState.cc +++ b/src/xpdf-4.06/xpdf/GfxState.cc @@ -8,10 +8,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include #include #include @@ -19,6 +15,7 @@ #include "gmempp.h" #include "Error.h" #include "GlobalParams.h" +#include "LocalParams.h" #include "Object.h" #include "Array.h" #include "Page.h" @@ -936,15 +933,15 @@ GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr, } nCompsA = obj2.getInt(); obj2.free(); - if (nCompsA > 4) { - error(errSyntaxError, -1, - "ICCBased color space with too many ({0:d} > 4) components", - nCompsA); - nCompsA = 4; - } - if (dict->lookup("Alternate", &obj2)->isNull() || - !(altA = GfxColorSpace::parse(&obj2, - recursion + 1))) { + if (!dict->lookup("Alternate", &obj2)->isNull() && + (altA = GfxColorSpace::parse(&obj2, + recursion + 1))) { + if (altA->getNComps() != nCompsA) { + error(errSyntaxError, -1, + "Number of components in ICCBased color space doesn't match alternate color space"); + nCompsA = altA->getNComps(); + } + } else { switch (nCompsA) { case 1: altA = GfxColorSpace::create(csDeviceGray); @@ -1784,6 +1781,258 @@ GfxPattern *GfxTilingPattern::copy() { &resDict, matrix, &contentStreamRef); } +GBool GfxTilingPattern::usesBlendMode(XRef *xref) { + char *scannedObjs = (char *)gmalloc(xref->getNumObjects()); + memset(scannedObjs, 0, xref->getNumObjects()); + GBool ret = scanResourcesForBlendMode(&resDict, scannedObjs, xref); + gfree(scannedObjs); + return ret; +} + +GBool GfxTilingPattern::scanResourcesForBlendMode(Object *resDict2, + char *scannedObjs, + XRef *xref) { + Object ref1, obj1, obj2; + + if (!resDict2->isDict()) { + return gFalse; + } + + //----- ExtGStates + resDict2->dictLookupNF("ExtGState", &ref1); + if (!ref1.isRef() || (ref1.getRefNum() < xref->getNumObjects() && + !scannedObjs[ref1.getRefNum()])) { + if (ref1.isRef()) { + scannedObjs[ref1.getRefNum()] = 1; + ref1.fetch(xref, &obj1); + } else { + ref1.copy(&obj1); + } + if (obj1.isDict()) { + for (int i = 0; i < obj1.dictGetLength(); ++i) { + if (scanExtGStateForBlendMode(obj1.dictGetValNF(i, &obj2), + scannedObjs, xref)) { + obj2.free(); + obj1.free(); + ref1.free(); + return gTrue; + } + obj2.free(); + } + } + obj1.free(); + } + ref1.free(); + + //----- patterns + resDict2->dictLookupNF("Pattern", &ref1); + if (!ref1.isRef() || (ref1.getRefNum() < xref->getNumObjects() && + !scannedObjs[ref1.getRefNum()])) { + if (ref1.isRef()) { + scannedObjs[ref1.getRefNum()] = 1; + ref1.fetch(xref, &obj1); + } else { + ref1.copy(&obj1); + } + if (obj1.isDict()) { + for (int i = 0; i < obj1.dictGetLength(); ++i) { + if (scanPatternForBlendMode(obj1.dictGetValNF(i, &obj2), + scannedObjs, xref)) { + obj2.free(); + obj1.free(); + ref1.free(); + return gTrue; + } + obj2.free(); + } + } + obj1.free(); + } + ref1.free(); + + //----- XObjects + resDict2->dictLookupNF("XObject", &ref1); + if (!ref1.isRef() || (ref1.getRefNum() < xref->getNumObjects() && + !scannedObjs[ref1.getRefNum()])) { + if (ref1.isRef()) { + scannedObjs[ref1.getRefNum()] = 1; + ref1.fetch(xref, &obj1); + } else { + ref1.copy(&obj1); + } + if (obj1.isDict()) { + for (int i = 0; i < obj1.dictGetLength(); ++i) { + if (scanXObjectForBlendMode(obj1.dictGetValNF(i, &obj2), + scannedObjs, xref)) { + obj2.free(); + obj1.free(); + ref1.free(); + return gTrue; + } + obj2.free(); + } + } + obj1.free(); + } + ref1.free(); + + return gFalse; +} + +GBool GfxTilingPattern::scanExtGStateForBlendMode(Object *gsObj, + char *scannedObjs, + XRef *xref) { + Object gsDict, obj1; + + if (gsObj->isRef()) { + if (gsObj->getRefNum() >= xref->getNumObjects() || + scannedObjs[gsObj->getRefNum()]) { + return gFalse; + } + scannedObjs[gsObj->getRefNum()] = 1; + gsObj->fetch(xref, &gsDict); + } else { + gsObj->copy(&gsDict); + } + if (!gsDict.isDict()) { + gsDict.free(); + return gFalse; + } + + gsDict.dictLookup("BM", &obj1); + if (obj1.isName() && !obj1.isName("Normal")) { + obj1.free(); + gsDict.free(); + return gTrue; + } + obj1.free(); + + if (!gsDict.dictLookupNF("SMask", &obj1)->isNull()) { + if (scanSoftMaskForBlendMode(&obj1, scannedObjs, xref)) { + obj1.free(); + gsDict.free(); + return gTrue; + } + } + obj1.free(); + + gsDict.free(); + + return gFalse; +} + +GBool GfxTilingPattern::scanSoftMaskForBlendMode(Object *softMaskObj, + char *scannedObjs, + XRef *xref) { + Object softMaskDict, obj1; + + if (softMaskObj->isRef()) { + if (softMaskObj->getRefNum() >= xref->getNumObjects() || + scannedObjs[softMaskObj->getRefNum()]) { + return gFalse; + } + scannedObjs[softMaskObj->getRefNum()] = 1; + softMaskObj->fetch(xref, &softMaskDict); + } else { + softMaskObj->copy(&softMaskDict); + } + if (!softMaskDict.isDict()) { + softMaskDict.free(); + return gFalse; + } + + if (!softMaskDict.dictLookupNF("G", &obj1)->isNull()) { + if (scanXObjectForBlendMode(&obj1, scannedObjs, xref)) { + obj1.free(); + softMaskDict.free(); + return gTrue; + } + } + obj1.free(); + + softMaskDict.free(); + + return gFalse; +} + +GBool GfxTilingPattern::scanPatternForBlendMode(Object *patternObj, + char *scannedObjs, + XRef *xref) { + Object patternObj2, obj1; + Dict *patternDict; + + if (patternObj->isRef()) { + if (patternObj->getRefNum() >= xref->getNumObjects() || + scannedObjs[patternObj->getRefNum()]) { + return gFalse; + } + scannedObjs[patternObj->getRefNum()] = 1; + patternObj->fetch(xref, &patternObj2); + } else { + patternObj->copy(&patternObj2); + } + if (patternObj2.isDict()) { + patternDict = patternObj2.getDict(); + } else if (patternObj2.isStream()) { + patternDict = patternObj2.streamGetDict(); + } else { + patternObj2.free(); + return gFalse; + } + + if (!patternDict->lookupNF("Resources", &obj1)->isNull()) { + if (scanResourcesForBlendMode(&obj1, scannedObjs, xref)) { + obj1.free(); + patternObj2.free(); + return gTrue; + } + } + obj1.free(); + + patternObj2.free(); + + return gFalse; +} + +GBool GfxTilingPattern::scanXObjectForBlendMode(Object *xObj, + char *scannedObjs, + XRef *xref) { + Object xObj2, obj1; + Dict *dict; + + if (xObj->isRef()) { + if (xObj->getRefNum() >= xref->getNumObjects() || + scannedObjs[xObj->getRefNum()]) { + return gFalse; + } + scannedObjs[xObj->getRefNum()] = 1; + xObj->fetch(xref, &xObj2); + } else { + xObj->copy(&xObj2); + } + if (xObj2.isDict()) { + dict = xObj2.getDict(); + } else if (xObj2.isStream()) { + dict = xObj2.streamGetDict(); + } else { + xObj2.free(); + return gFalse; + } + + if (!dict->lookupNF("Resources", &obj1)->isNull()) { + if (scanResourcesForBlendMode(&obj1, scannedObjs, xref)) { + obj1.free(); + xObj2.free(); + return gTrue; + } + } + obj1.free(); + + xObj2.free(); + + return gFalse; +} + //------------------------------------------------------------------------ // GfxShadingPattern //------------------------------------------------------------------------ @@ -2880,6 +3129,11 @@ GfxGouraudTriangleShading *GfxGouraudTriangleShading::parse( delete bitBuf; if (typeA == 5) { nRows = nVerticesA / vertsPerRow; + if (nRows == 0) { + error(errSyntaxError, -1, + "Invalid VerticesPerRow in shading dictionary"); + goto err3; + } nTrianglesA = (nRows - 1) * 2 * (vertsPerRow - 1); trianglesA = (int (*)[3])gmallocn(nTrianglesA * 3, sizeof(int)); k = 0; @@ -2926,6 +3180,12 @@ GfxGouraudTriangleShading *GfxGouraudTriangleShading::parse( return shading; + err3: + gfree(trianglesA); + gfree(verticesA); + for (i = 0; i < nFuncsA; ++i) { + delete funcsA[i]; + } err2: obj1.free(); err1: @@ -2963,8 +3223,8 @@ void GfxGouraudTriangleShading::getTriangle( } } -void GfxGouraudTriangleShading::getBBox(double *xMin, double *yMin, - double *xMax, double *yMax) { +void GfxGouraudTriangleShading::getBBox(double *xMinA, double *yMinA, + double *xMaxA, double *yMaxA) { double xxMin = 0; double yyMin = 0; double xxMax = 0; @@ -2985,10 +3245,10 @@ void GfxGouraudTriangleShading::getBBox(double *xMin, double *yMin, yyMax = vertices[i].y; } } - *xMin = xxMin; - *yMin = yyMin; - *xMax = xxMax; - *yMax = yyMax; + *xMinA = xxMin; + *yMinA = yyMin; + *xMaxA = xxMax; + *yMaxA = yyMax; } void GfxGouraudTriangleShading::getColor(double *in, GfxColor *out) { @@ -3621,8 +3881,8 @@ GfxShading *GfxPatchMeshShading::copy() { return new GfxPatchMeshShading(this); } -void GfxPatchMeshShading::getBBox(double *xMin, double *yMin, - double *xMax, double *yMax) { +void GfxPatchMeshShading::getBBox(double *xMinA, double *yMinA, + double *xMaxA, double *yMaxA) { double xxMin = 0; double yyMin = 0; double xxMax = 0; @@ -3647,10 +3907,10 @@ void GfxPatchMeshShading::getBBox(double *xMin, double *yMin, } } } - *xMin = xxMin; - *yMin = yyMin; - *xMax = xxMax; - *yMax = yyMax; + *xMinA = xxMin; + *yMinA = yyMin; + *xMaxA = xxMax; + *yMaxA = yyMax; } void GfxPatchMeshShading::getColor(double *in, GfxColor *out) { @@ -4240,11 +4500,13 @@ void GfxPath::offset(double dx, double dy) { // GfxState //------------------------------------------------------------------------ -GfxState::GfxState(double hDPIA, double vDPIA, PDFRectangle *pageBox, +GfxState::GfxState(LocalParams *localParamsA, + double hDPIA, double vDPIA, PDFRectangle *pageBox, int rotateA, GBool upsideDown ) { double kx, ky; + localParams = localParamsA; hDPI = hDPIA; vDPI = vDPIA; rotate = rotateA; @@ -4303,7 +4565,11 @@ GfxState::GfxState(double hDPIA, double vDPIA, PDFRectangle *pageBox, strokeOpacity = 1; fillOverprint = gFalse; strokeOverprint = gFalse; - renderingIntent = gfxRenderingIntentRelativeColorimetric; + if (localParams) { + renderingIntent = localParams->getDefaultRenderingIntent(); + } else { + renderingIntent = gfxRenderingIntentRelativeColorimetric; + } overprintMode = 0; transfer[0] = transfer[1] = transfer[2] = transfer[3] = NULL; @@ -4316,6 +4582,7 @@ GfxState::GfxState(double hDPIA, double vDPIA, PDFRectangle *pageBox, lineCap = 0; miterLimit = 10; strokeAdjust = gFalse; + alphaIsShape = gFalse; font = NULL; fontSize = 0; @@ -4577,6 +4844,12 @@ void GfxState::setStrokePattern(GfxPattern *pattern) { strokePattern = pattern; } +void GfxState::setRenderingIntent(GfxRenderingIntent ri) { + if (!(localParams && localParams->getForceRenderingIntent())) { + renderingIntent = ri; + } +} + void GfxState::setTransfer(Function **funcs) { int i; @@ -4651,35 +4924,36 @@ void GfxState::clipToStrokePath() { // There are two cases for each point on the path: // (1) miter join, under miter limit => compute the miter point // (2) all other joins and caps => use the path point +/- 0.5 * line width - double xMin = 0, yMin = 0, xMax = 0, yMax = 0; + double uxMin = 0, uyMin = 0, uxMax = 0, uyMax = 0; double w = 0.5 * lineWidth; for (int i = 0; i < path->getNumSubpaths(); ++i) { GfxSubpath *subpath = path->getSubpath(i); - for (int j = 0; j < subpath->getNumPoints(); ++j) { + int nPoints; + if (subpath->isClosed()) { + nPoints = subpath->getNumPoints() - 1; + } else { + nPoints = subpath->getNumPoints(); + } + for (int j = 0; j < nPoints; ++j) { double x1 = subpath->getX(j); double y1 = subpath->getY(j); if (i == 0 && j == 0) { - xMin = xMax = x1; - yMin = yMax = y1; + uxMin = uxMax = x1; + uyMin = uyMax = y1; } GBool useMiter = gFalse; if (lineJoin == 0 && // miter join - ((j > 0 && j < subpath->getNumPoints() - 1) || subpath->isClosed())) { + (subpath->isClosed() || (j > 0 && j < subpath->getNumPoints() - 1))) { double x0, y0, x2, y2; - if (j > 0) { + if (j == 0) { + x0 = subpath->getX(nPoints - 1); + y0 = subpath->getY(nPoints - 1); + } else { x0 = subpath->getX(j - 1); y0 = subpath->getY(j - 1); - } else { - x0 = subpath->getLastX(); - y0 = subpath->getLastY(); - } - if (j < subpath->getNumPoints() - 1) { - x2 = subpath->getX(j + 1); - y2 = subpath->getY(j + 1); - } else { - x2 = subpath->getX(0); - y2 = subpath->getY(0); } + x2 = subpath->getX(j + 1); + y2 = subpath->getY(j + 1); if ((fabs(x1 - x0) > 0.0001 || fabs(y1 - y0) > 0.0001) && (fabs(x2 - x1) > 0.0001 || fabs(y2 - y1) > 0.0001)) { double d01 = 1 / sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0)); @@ -4704,15 +4978,15 @@ void GfxState::clipToStrokePath() { } double mx = ax + m * w * ux; double my = ay + m * w * uy; - if (mx < xMin) { - xMin = mx; - } else if (mx > xMax) { - xMax = mx; + if (mx < uxMin) { + uxMin = mx; + } else if (mx > uxMax) { + uxMax = mx; } - if (my < yMin) { - yMin = my; - } else if (my > yMax) { - yMax = my; + if (my < uyMin) { + uyMin = my; + } else if (my > uyMax) { + uyMax = my; } useMiter = gTrue; } @@ -4720,66 +4994,71 @@ void GfxState::clipToStrokePath() { } } if (!useMiter) { - if (x1 - w < xMin) { - xMin = x1 - w; + if (x1 - w < uxMin) { + uxMin = x1 - w; } - if (x1 + w > xMax) { - xMax = x1 + w; + if (x1 + w > uxMax) { + uxMax = x1 + w; } - if (y1 - w < yMin) { - yMin = y1 - w; + if (y1 - w < uyMin) { + uyMin = y1 - w; } - if (y1 + w > yMax) { - yMax = y1 + w; + if (y1 + w > uyMax) { + uyMax = y1 + w; } } } } - double xx, yy; - transform(xMin, yMin, &xx, &yy); - if (xx < clipXMin) { - clipXMin = xx; - } else if (xx > clipXMax) { - clipXMax = xx; - } - if (yy < clipYMin) { - clipYMin = yy; - } else if (yy > clipYMax) { - clipYMax = yy; - } - transform(xMin, yMax, &xx, &yy); - if (xx < clipXMin) { - clipXMin = xx; - } else if (xx > clipXMax) { - clipXMax = xx; - } - if (yy < clipYMin) { - clipYMin = yy; - } else if (yy > clipYMax) { - clipYMax = yy; - } - transform(xMax, yMin, &xx, &yy); - if (xx < clipXMin) { - clipXMin = xx; - } else if (xx > clipXMax) { - clipXMax = xx; - } - if (yy < clipYMin) { - clipYMin = yy; - } else if (yy > clipYMax) { - clipYMax = yy; - } - transform(xMax, yMax, &xx, &yy); - if (xx < clipXMin) { - clipXMin = xx; - } else if (xx > clipXMax) { - clipXMax = xx; - } - if (yy < clipYMin) { - clipYMin = yy; - } else if (yy > clipYMax) { - clipYMax = yy; + double dxMin, dyMin, dxMax, dyMax, xx, yy; + transform(uxMin, uyMin, &xx, &yy); + dxMin = dxMax = xx; + dyMin = dyMax = yy; + transform(uxMin, uyMax, &xx, &yy); + if (xx < dxMin) { + dxMin = xx; + } else if (xx > dxMax) { + dxMax = xx; + } + if (yy < dyMin) { + dyMin = yy; + } else if (yy > dyMax) { + dyMax = yy; + } + transform(uxMax, uyMin, &xx, &yy); + if (xx < dxMin) { + dxMin = xx; + } else if (xx > dxMax) { + dxMax = xx; + } + if (yy < dyMin) { + dyMin = yy; + } else if (yy > dyMax) { + dyMax = yy; + } + transform(uxMax, uyMax, &xx, &yy); + if (xx < dxMin) { + dxMin = xx; + } else if (xx > dxMax) { + dxMax = xx; + } + if (yy < dyMin) { + dyMin = yy; + } else if (yy > dyMax) { + dyMax = yy; + } + + if (dxMin > clipXMin) { + clipXMin = dxMin; + } + if (dyMin > clipYMin) { + clipYMin = dyMin; + } + if (dxMax < clipXMax) { + clipXMax = dxMax; + } + if (dyMax < clipYMax) { + clipYMax = dyMax; } } diff --git a/src/xpdf-4.04/xpdf/GfxState.h b/src/xpdf-4.06/xpdf/GfxState.h old mode 100644 new mode 100755 similarity index 97% rename from src/xpdf-4.04/xpdf/GfxState.h rename to src/xpdf-4.06/xpdf/GfxState.h index 60d4852..594329a --- a/src/xpdf-4.04/xpdf/GfxState.h +++ b/src/xpdf-4.06/xpdf/GfxState.h @@ -11,10 +11,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #include "gtypes.h" #include "Object.h" #include "Function.h" @@ -26,6 +22,7 @@ class GfxDeviceNColorSpace; class GfxSeparationColorSpace; class GfxShading; class GfxState; +class LocalParams; //------------------------------------------------------------------------ // GfxBlendMode @@ -663,6 +660,7 @@ class GfxTilingPattern: public GfxPattern { { return resDict.isDict() ? resDict.getDict() : (Dict *)NULL; } double *getMatrix() { return matrix; } Object *getContentStreamRef() { return &contentStreamRef; } + GBool usesBlendMode(XRef *xref); private: @@ -670,6 +668,16 @@ class GfxTilingPattern: public GfxPattern { double *bboxA, double xStepA, double yStepA, Object *resDictA, double *matrixA, Object *contentStreamA); + GBool scanResourcesForBlendMode(Object *resDict2, + char *scannedObjs, XRef *xref); + GBool scanExtGStateForBlendMode(Object *gsObj, + char *scannedObjs, XRef *xref); + GBool scanSoftMaskForBlendMode(Object *softMaskObj, + char *scannedObjs, XRef *xref); + GBool scanPatternForBlendMode(Object *patternObj, + char *scannedObjs, XRef *xref); + GBool scanXObjectForBlendMode(Object *xObj, + char *scannedObjs, XRef *xref); int paintType; int tilingType; @@ -883,7 +891,7 @@ class GfxGouraudTriangleShading: public GfxShading { void getTriangle(int i, double *x0, double *y0, double *color0, double *x1, double *y1, double *color1, double *x2, double *y2, double *color2); - void getBBox(double *xMin, double *yMin, double *xMax, double *yMax); + void getBBox(double *xMinA, double *yMinA, double *xMaxA, double *yMaxA); void getColor(double *in, GfxColor *out); private: @@ -923,7 +931,7 @@ class GfxPatchMeshShading: public GfxShading { int getNComps() { return nComps; } int getNPatches() { return nPatches; } GfxPatch *getPatch(int i) { return &patches[i]; } - void getBBox(double *xMin, double *yMin, double *xMax, double *yMax); + void getBBox(double *xMinA, double *yMinA, double *xMaxA, double *yMaxA); void getColor(double *in, GfxColor *out); private: @@ -1121,7 +1129,8 @@ class GfxState { // Construct a default GfxState, for a device with resolution // x , page box , page rotation , and // coordinate system specified by . - GfxState(double hDPIA, double vDPIA, PDFRectangle *pageBox, + GfxState(LocalParams *localParamsA, + double hDPIA, double vDPIA, PDFRectangle *pageBox, int rotateA, GBool upsideDown ); @@ -1177,6 +1186,7 @@ class GfxState { int getLineCap() { return lineCap; } double getMiterLimit() { return miterLimit; } GBool getStrokeAdjust() { return strokeAdjust; } + GBool getAlphaIsShape() { return alphaIsShape; } GfxFont *getFont() { return font; } double getFontSize() { return fontSize; } double *getTextMat() { return textMat; } @@ -1238,7 +1248,7 @@ class GfxState { void setFillOverprint(GBool op) { fillOverprint = op; } void setStrokeOverprint(GBool op) { strokeOverprint = op; } void setOverprintMode(int opm) { overprintMode = opm; } - void setRenderingIntent(GfxRenderingIntent ri) { renderingIntent = ri; } + void setRenderingIntent(GfxRenderingIntent ri); void setTransfer(Function **funcs); void setLineWidth(double width) { lineWidth = width; } void setLineDash(double *dash, int length, double start); @@ -1247,6 +1257,7 @@ class GfxState { void setLineCap(int lineCap1) { lineCap = lineCap1; } void setMiterLimit(double limit) { miterLimit = limit; } void setStrokeAdjust(GBool sa) { strokeAdjust = sa; } + void setAlphaIsShape(GBool ais) { alphaIsShape = ais; } void setFont(GfxFont *fontA, double fontSizeA) { font = fontA; fontSize = fontSizeA; } void setTextMat(double a, double b, double c, @@ -1306,6 +1317,8 @@ class GfxState { private: + LocalParams *localParams; + double hDPI, vDPI; // resolution double ctm[6]; // coord transform matrix double px1, py1, px2, py2; // page corners (user coords) @@ -1339,6 +1352,7 @@ class GfxState { int lineCap; // line cap style double miterLimit; // line miter limit GBool strokeAdjust; // stroke adjustment + GBool alphaIsShape; GfxFont *font; // font double fontSize; // font size diff --git a/src/xpdf-4.04/xpdf/GlobalParams.cc b/src/xpdf-4.06/xpdf/GlobalParams.cc old mode 100644 new mode 100755 similarity index 86% rename from src/xpdf-4.04/xpdf/GlobalParams.cc rename to src/xpdf-4.06/xpdf/GlobalParams.cc index 5fd4393..92f77d7 --- a/src/xpdf-4.04/xpdf/GlobalParams.cc +++ b/src/xpdf-4.06/xpdf/GlobalParams.cc @@ -8,10 +8,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include #include #include @@ -44,9 +40,11 @@ #include "GlobalParams.h" #ifdef _WIN32 +#ifndef __GNUC__ # define strcasecmp stricmp # define strncasecmp strnicmp #endif +#endif #if MULTITHREADED # define lockGlobalParams gLockMutex(&mutex) @@ -81,34 +79,119 @@ static struct { const char *ttFileName; const char *macFileName; // may be .dfont, .ttf, or .ttc const char *macFontName; // font name inside .dfont or .ttc + const char *fcFontName; // fontconfig font name const char *obliqueFont; // name of font to oblique double obliqueFactor; // oblique sheer factor } displayFontTab[] = { - {"Courier", "n022003l.pfb", "cour.ttf", "Courier", "Courier", NULL, 0}, - {"Courier-Bold", "n022004l.pfb", "courbd.ttf", "Courier", "Courier Bold", NULL, 0}, - {"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-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 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}, + {"Courier", // name + "n022003l.pfb", // t1FileName + "cour.ttf", // ttFileName + "Courier", "Courier", // macFileName, macFontName + "NimbusMonoPS-Regular", // fcFontName + NULL, 0 // obliqueFont, obliqueFactor + }, + {"Courier-Bold", // name + "n022004l.pfb", // t1FileName + "courbd.ttf", // ttFileName + "Courier", "Courier Bold", // macFileName, macFontName + "NimbusMonoPS-Bold", // fcFontName + NULL, 0 // obliqueFont, obliqueFactor + }, + {"Courier-BoldOblique", // name + "n022024l.pfb", // t1FileName + "courbi.ttf", // ttFileName + "Courier", "Courier Bold Oblique", // macFileName, macFontName + "NimbusMonoPS-BoldItalic", // fcFontName + "Courier-Bold", 0.212557 // obliqueFont, obliqueFactor + }, + {"Courier-Oblique", // name + "n022023l.pfb", // t1FileName + "couri.ttf", // ttFileName + "Courier", "Courier Oblique", // macFileName, macFontName + "NimbusMonoPS-Italic", // fcFontName + "Courier", 0.212557 // obliqueFont, obliqueFactor + }, + {"Helvetica", // name + "n019003l.pfb", // t1FileName + "arial.ttf", // ttFileName + "Helvetica", "Helvetica", // macFileName, macFontName + "NimbusSans-Regular", // fcFontName + NULL, 0 // obliqueFont, obliqueFactor + }, + {"Helvetica-Bold", // name + "n019004l.pfb", // t1FileName + "arialbd.ttf", // ttFileName + "Helvetica", "Helvetica Bold", // macFileName, macFontName + "NimbusSans-Bold", // fcFontName + NULL, 0 // obliqueFont, obliqueFactor + }, + {"Helvetica-BoldOblique", // name + "n019024l.pfb", // t1FileName + "arialbi.ttf", // ttFileName + "Helvetica", "Helvetica Bold Oblique", // macFileName, macFontName + "NimbusSans-BoldItalic", // fcFontName + "Helvetica-Bold", 0.212557 // obliqueFont, obliqueFactor + }, + {"Helvetica-Oblique", // name + "n019023l.pfb", // t1FileName + "ariali.ttf", // ttFileName + "Helvetica", "Helvetica Oblique", // macFileName, macFontName + "NimbusSans-Italic", // fcFontName + "Helvetica", 0.212557 // obliqueFont, obliqueFactor + }, + {"Symbol", // name + "s050000l.pfb", // t1FileName + NULL, // ttFileName + "Symbol", "Symbol", // macFileName, macFontName + "Standard Symbols PS", // fcFontName + NULL, 0 // obliqueFont, obliqueFactor + }, + {"Times-Bold", // name + "n021004l.pfb", // t1FileName + "timesbd.ttf", // ttFileName + "Times", "Times Bold", // macFileName, macFontName + "NimbusRoman-Bold", // fcFontName + NULL, 0 // obliqueFont, obliqueFactor + }, + {"Times-BoldItalic", // name + "n021024l.pfb", // t1FileName + "timesbi.ttf", // ttFileName + "Times", "Times Bold Italic", // macFileName, macFontName + "NimbusRoman-BoldItalic", // fcFontName + NULL, 0 // obliqueFont, obliqueFactor + }, + {"Times-Italic", // name + "n021023l.pfb", // t1FileName + "timesi.ttf", // ttFileName + "Times", "Times Italic", // macFileName, macFontName + "NimbusRoman-Italic", // fcFontName + NULL, 0 // obliqueFont, obliqueFactor + }, + {"Times-Roman", // name + "n021003l.pfb", // t1FileName + "times.ttf", // ttFileName + "Times", "Times Roman", // macFileName, macFontName + "NimbusRoman-Regular", // fcFontName + NULL, 0 // obliqueFont, obliqueFactor + }, + {"ZapfDingbats", // name + "d050000l.pfb", // t1FileName + NULL, // ttFileName + "ZapfDingbats", "Zapf Dingbats", // macFileName, macFontName + "D050000L", // fcFontName + NULL, 0 // obliqueFont, obliqueFactor + }, {NULL} }; -#ifdef _WIN32 static const char *displayFontDirs[] = { +#ifdef BASE14_FONT_DIR + BASE14_FONT_DIR, +#endif +#ifdef _WIN32 "c:/windows/fonts", "c:/winnt/fonts", - NULL -}; -#else -static const char *displayFontDirs[] = { +#else // _WIN32 "/usr/share/ghostscript/fonts", "/usr/local/share/ghostscript/fonts", "/usr/share/fonts/default/Type1", @@ -117,9 +200,9 @@ static const char *displayFontDirs[] = { #if defined(__sun) && defined(__SVR4) "/usr/sfw/share/ghostscript/fonts", #endif +#endif // _WIN32 NULL }; -#endif #ifdef __APPLE__ static const char *macSystemFontPath = "/System/Library/Fonts"; @@ -179,7 +262,7 @@ class SysFontInfo { ~SysFontInfo(); GString *mungeName1(GString *in); GString *mungeName2(GString *in); - void mungeName3(GString *name, GBool *bold, GBool *italic); + void mungeName3(GString *nameA, GBool *bold, GBool *italic); int match(GString *nameA); }; @@ -256,24 +339,24 @@ GString *SysFontInfo::mungeName2(GString *in) { // Remove trailing bold/italic/regular/roman tags from the name. // (Note: the names have already been uppercased by mungeName1/2.) -void SysFontInfo::mungeName3(GString *name, GBool *bold, GBool *italic) { +void SysFontInfo::mungeName3(GString *nameA, GBool *bold, GBool *italic) { *bold = gFalse; *italic = gFalse; - int n = name->getLength(); + int n = nameA->getLength(); while (1) { - if (n >= 4 && !strcmp(name->getCString() + n - 4, "BOLD")) { - name->del(n - 4, 4); + if (n >= 4 && !strcmp(nameA->getCString() + n - 4, "BOLD")) { + nameA->del(n - 4, 4); n -= 4; *bold = gTrue; - } else if (n >= 6 && !strcmp(name->getCString() + n - 6, "ITALIC")) { - name->del(n - 6, 6); + } else if (n >= 6 && !strcmp(nameA->getCString() + n - 6, "ITALIC")) { + nameA->del(n - 6, 6); n -= 6; *italic = gTrue; - } else if (n >= 7 && !strcmp(name->getCString() + n - 7, "REGULAR")) { - name->del(n - 7, 7); + } else if (n >= 7 && !strcmp(nameA->getCString() + n - 7, "REGULAR")) { + nameA->del(n - 7, 7); n -= 7; - } else if (n >= 5 && !strcmp(name->getCString() + n - 5, "ROMAN")) { - name->del(n - 5, 5); + } else if (n >= 5 && !strcmp(nameA->getCString() + n - 5, "ROMAN")) { + nameA->del(n - 5, 5); n -= 5; } else { break; @@ -655,7 +738,7 @@ GlobalParams::GlobalParams(const char *cfgFileName) { base14SysFonts = new GHash(gTrue); sysFonts = new SysFontList(); #if HAVE_PAPER_H - char *paperName; + const char *paperName; const struct paper *paperType; paperinit(); if ((paperName = systempapername())) { @@ -681,7 +764,7 @@ GlobalParams::GlobalParams(const char *cfgFileName) { psShrinkLarger = gTrue; psCenter = gTrue; psDuplex = gFalse; - psLevel = psLevel2; + psLevel = psLevel3; psResidentFonts = new GHash(gTrue); psResidentFonts16 = new GList(); psResidentFontsCC = new GList(); @@ -711,11 +794,27 @@ GlobalParams::GlobalParams(const char *cfgFileName) { textKeepTinyChars = gTrue; initialZoom = new GString("125"); defaultFitZoom = 0; + zoomScaleFactor = 1; + zoomValues = new GList(); + zoomValues->append(new GString("25")); + zoomValues->append(new GString("50")); + zoomValues->append(new GString("75")); + zoomValues->append(new GString("100")); + zoomValues->append(new GString("110")); + zoomValues->append(new GString("125")); + zoomValues->append(new GString("150")); + zoomValues->append(new GString("175")); + zoomValues->append(new GString("200")); + zoomValues->append(new GString("300")); + zoomValues->append(new GString("400")); + zoomValues->append(new GString("600")); + zoomValues->append(new GString("800")); initialDisplayMode = new GString("continuous"); initialToolbarState = gTrue; initialSidebarState = gTrue; initialSidebarWidth = 0; initialSelectMode = new GString("linear"); + initialMaximized = gFalse; maxTileWidth = 1500; maxTileHeight = 1500; tileCacheSize = 10; @@ -738,12 +837,14 @@ GlobalParams::GlobalParams(const char *cfgFileName) { drawAnnotations = gTrue; drawFormFields = gTrue; enableXFA = gTrue; + preferXFAFieldValues = gTrue; overprintPreview = gFalse; paperColor = new GString("#ffffff"); matteColor = new GString("#808080"); fullScreenMatteColor = new GString("#000000"); selectionColor = new GString("#8080ff"); reverseVideoInvertImages = gFalse; + allowLinksToChangeZoom = gTrue; launchCommand = NULL; movieCommand = NULL; defaultPrinter = NULL; @@ -751,10 +852,14 @@ GlobalParams::GlobalParams(const char *cfgFileName) { mapUnknownCharNames = gFalse; mapExtTrueTypeFontsViaUnicode = gTrue; useTrueTypeUnicodeMapping = gFalse; + ignoreWrongSizeToUnicode = gFalse; droppedFonts = new GHash(gTrue); + separateRotatedText = gFalse; + discardCoveredText = gFalse; createDefaultKeyBindings(); popupMenuCmds = new GList(); - tabStateFile = appendToPath(getHomeDir(), ".xpdf.tab-state"); + initStateFilePaths(); + saveSessionOnQuit = gTrue; savePageNumbers = gTrue; printCommands = gFalse; printStatusInfo = gFalse; @@ -790,38 +895,8 @@ GlobalParams::GlobalParams(const char *cfgFileName) { map = new UnicodeMap("UCS-2", gTrue, &mapUCS2); residentUnicodeMaps->add(map->getEncodingName(), map); - // look for a user config file, then a system-wide config file - f = NULL; - fileName = NULL; - if (cfgFileName && cfgFileName[0]) { - fileName = new GString(cfgFileName); - if (!(f = fopen(fileName->getCString(), "r"))) { - delete fileName; - } - } - if (!f) { - fileName = appendToPath(getHomeDir(), xpdfUserConfigFile); - if (!(f = fopen(fileName->getCString(), "r"))) { - delete fileName; - } - } - if (!f) { -#ifdef _WIN32 - char buf[512]; - i = GetModuleFileNameA(NULL, buf, sizeof(buf)); - if (i <= 0 || i >= sizeof(buf)) { - // error or path too long for buffer - just use the current dir - buf[0] = '\0'; - } - fileName = grabPath(buf); - appendToPath(fileName, xpdfSysConfigFile); -#else - fileName = new GString(xpdfSysConfigFile); -#endif - if (!(f = fopen(fileName->getCString(), "r"))) { - delete fileName; - } - } + // read the config file + f = openConfigFile(cfgFileName, &fileName); if (f) { parseFile(fileName, f); delete fileName; @@ -1011,6 +1086,130 @@ void GlobalParams::createDefaultKeyBindings() { xpdfKeyContextAny, "zoomFitWidth")); } +void GlobalParams::initStateFilePaths() { +#ifdef _WIN32 + // Windows state files are {APPDATA}/xpdf/xpdf.pages etc + char path[MAX_PATH]; + if (SHGetFolderPathA(NULL, CSIDL_APPDATA, NULL, + SHGFP_TYPE_CURRENT, path) != S_OK) { + return; + } + GString *stateDir = appendToPath(new GString(path), "xpdf"); + CreateDirectoryA(stateDir->getCString(), NULL); + pagesFile = appendToPath(stateDir->copy(), "xpdf.pages"); + tabStateFile = appendToPath(stateDir->copy(), "xpdf.tab-state"); + sessionFile = appendToPath(stateDir, "xpdf.session"); +#elif USE_XDG + // XDG state files are {XDG_STATE}/xpdf/pages etc + char *path = getenv("XDG_STATE_HOME"); + GString *stateDir; + if (path) { + stateDir = new GString(path); + } else { + stateDir = appendToPath(getHomeDir(), ".local/state"); + } + createDir(stateDir->getCString(), 0700); + appendToPath(stateDir, "xpdf"); + createDir(stateDir->getCString(), 0700); + pagesFile = appendToPath(stateDir->copy(), "pages"); + tabStateFile = appendToPath(stateDir->copy(), "tab-state"); + sessionFile = appendToPath(stateDir, "session"); +#else + // Unix (non-XDG) state files are ~/.xpdf.pages etc + GString *stateDir = getHomeDir(); + pagesFile = appendToPath(stateDir->copy(), ".xpdf.pages"); + tabStateFile = appendToPath(stateDir->copy(), ".xpdf.tab-state"); + sessionFile = appendToPath(stateDir, ".xpdf.session"); +#endif +} + +// Try all supported paths for the config file. +FILE *GlobalParams::openConfigFile(const char *cfgFileName, + GString **fileName) { + FILE *f = NULL; + GString *actualName = NULL; + + //--- try the path specified on the command line + if (cfgFileName && cfgFileName[0]) { + actualName = new GString(cfgFileName); + if (!(f = fopen(actualName->getCString(), "r"))) { + delete actualName; + } + } + + //--- try the XDG config path: {XDG_CONFIG}/xpdf/xpdfrc +#if USE_XDG + if (!f) { + char *path = getenv("XDG_CONFIG_HOME"); + if (path) { + actualName = new GString(path); + } else { + actualName = appendToPath(getHomeDir(), ".config"); + } + appendToPath(actualName, "xpdf/xpdfrc"); + if (!(f = fopen(actualName->getCString(), "r"))) { + delete actualName; + } + } +#endif + +#ifdef _WIN32 + //--- try the Windows user path: {APPDATA}/xpdf/xpdfrc + if (!f) { + char path[MAX_PATH]; + if (SHGetFolderPathA(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, path) + == S_OK) { + actualName = appendToPath(new GString(path), "xpdf/xpdfrc"); + if (!(f = fopen(actualName->getCString(), "r"))) { + delete actualName; + } + } + } + +#else + //--- try the Unix user path: ~/.xpdfrc + if (!f) { + actualName = appendToPath(getHomeDir(), ".xpdfrc"); + if (!(f = fopen(actualName->getCString(), "r"))) { + delete actualName; + } + } +#endif + +#ifdef _WIN32 + //--- try the Windows system path: {EXEDIR}/xpdfrc + if (!f) { + char buf[512]; + int i = GetModuleFileNameA(NULL, buf, sizeof(buf)); + if (i <= 0 || i >= sizeof(buf)) { + // error or path too long for buffer - just use the current dir + buf[0] = '\0'; + } + actualName = grabPath(buf); + appendToPath(actualName, "xpdfrc"); + if (!(f = fopen(actualName->getCString(), "r"))) { + delete actualName; + } + } + +#else + //--- try the Unix system path: {xpdfSysConfigFile} + if (!f) { + actualName = new GString(xpdfSysConfigFile); + if (!(f = fopen(actualName->getCString(), "r"))) { + delete actualName; + } + } +#endif + + if (f) { + *fileName = actualName; + } else { + *fileName = NULL; + } + return f; +} + void GlobalParams::parseFile(GString *fileName, FILE *f) { int line; char buf[512]; @@ -1151,6 +1350,10 @@ 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("zoomScaleFactor")) { + parseZoomScaleFactor(tokens, fileName, line); + } else if (!cmd->cmp("zoomValues")) { + parseZoomValues(tokens, fileName, line); } else if (!cmd->cmp("initialDisplayMode")) { parseString("initialDisplayMode", &initialDisplayMode, tokens, fileName, line); @@ -1166,6 +1369,9 @@ void GlobalParams::parseLine(char *buf, GString *fileName, int line) { } else if (!cmd->cmp("initialSelectMode")) { parseString("initialSelectMode", &initialSelectMode, tokens, fileName, line); + } else if (!cmd->cmp("initialMaximized")) { + parseYesNo("initialMaximized", &initialMaximized, + tokens, fileName, line); } else if (!cmd->cmp("maxTileWidth")) { parseInteger("maxTileWidth", &maxTileWidth, tokens, fileName, line); } else if (!cmd->cmp("maxTileHeight")) { @@ -1223,6 +1429,9 @@ void GlobalParams::parseLine(char *buf, GString *fileName, int line) { } else if (!cmd->cmp("enableXFA")) { parseYesNo("enableXFA", &enableXFA, tokens, fileName, line); + } else if (!cmd->cmp("preferXFAFieldValues")) { + parseYesNo("preferXFAFieldValues", &preferXFAFieldValues, + tokens, fileName, line); } else if (!cmd->cmp("overprintPreview")) { parseYesNo("overprintPreview", &overprintPreview, tokens, fileName, line); @@ -1238,6 +1447,9 @@ void GlobalParams::parseLine(char *buf, GString *fileName, int line) { } else if (!cmd->cmp("reverseVideoInvertImages")) { parseYesNo("reverseVideoInvertImages", &reverseVideoInvertImages, tokens, fileName, line); + } else if (!cmd->cmp("allowLinksToChangeZoom")) { + parseYesNo("allowLinksToChangeZoom", &allowLinksToChangeZoom, + tokens, fileName, line); } else if (!cmd->cmp("launchCommand")) { parseString("launchCommand", &launchCommand, tokens, fileName, line); } else if (!cmd->cmp("movieCommand")) { @@ -1255,11 +1467,19 @@ void GlobalParams::parseLine(char *buf, GString *fileName, int line) { &mapExtTrueTypeFontsViaUnicode, tokens, fileName, line); } else if (!cmd->cmp("useTrueTypeUnicodeMapping")) { - parseYesNo("useTrueTypeUnicodeMapping", - &useTrueTypeUnicodeMapping, + parseYesNo("useTrueTypeUnicodeMapping", &useTrueTypeUnicodeMapping, + tokens, fileName, line); + } else if (!cmd->cmp("ignoreWrongSizeToUnicode")) { + parseYesNo("ignoreWrongSizeToUnicode", &ignoreWrongSizeToUnicode, tokens, fileName, line); } else if (!cmd->cmp("dropFont")) { parseDropFont(tokens, fileName, line); + } else if (!cmd->cmp("separateRotatedText")) { + parseYesNo("separateRotatedText", &separateRotatedText, + tokens, fileName, line); + } else if (!cmd->cmp("discardCoveredText")) { + parseYesNo("discardCoveredText", &discardCoveredText, + tokens, fileName, line); } else if (!cmd->cmp("bind")) { parseBind(tokens, fileName, line); } else if (!cmd->cmp("unbind")) { @@ -1268,6 +1488,11 @@ void GlobalParams::parseLine(char *buf, GString *fileName, int line) { parsePopupMenuCmd(tokens, fileName, line); } else if (!cmd->cmp("tabStateFile")) { parseString("tabStateFile", &tabStateFile, tokens, fileName, line); + } else if (!cmd->cmp("sessionFile")) { + parseString("sessionFile", &sessionFile, tokens, fileName, line); + } else if (!cmd->cmp("saveSessionOnQuit")) { + parseYesNo("saveSessionOnQuit", &saveSessionOnQuit, + tokens, fileName, line); } else if (!cmd->cmp("savePageNumbers")) { parseYesNo("savePageNumbers", &savePageNumbers, tokens, fileName, line); } else if (!cmd->cmp("printCommands")) { @@ -1967,6 +2192,59 @@ void GlobalParams::parsePopupMenuCmd(GList *tokens, cmds)); } +void GlobalParams::parseZoomScaleFactor(GList *tokens, + GString *fileName, int line) { + if (tokens->getLength() != 2) { + error(errConfig, -1, "Bad 'zoomScaleFactor' config file command ({0:t}:{1:d})", + fileName, line); + return; + } + GString *tok = (GString *)tokens->get(1); + if (tok->getLength() == 0) { + error(errConfig, -1, "Bad 'zoomScaleFactor' config file command ({0:t}:{1:d})", + fileName, line); + return; + } + if (tok->cmp("actual") == 0) { + zoomScaleFactor = -1; + } else { + for (int i = 0; i < tok->getLength(); ++i) { + if (!((tok->getChar(i) >= '0' && tok->getChar(i) <= '9') || + tok->getChar(i) == '.')) { + error(errConfig, -1, "Bad 'zoomScaleFactor' config file command ({0:t}:{1:d})", + fileName, line); + return; + } + } + zoomScaleFactor = atof(tok->getCString()); + } +} + +void GlobalParams::parseZoomValues(GList *tokens, + GString *fileName, int line) { + if (tokens->getLength() < 2) { + error(errConfig, -1, "Bad 'zoomValues' config file command ({0:t}:{1:d})", + fileName, line); + return; + } + for (int i = 1; i < tokens->getLength(); ++i) { + GString *tok = (GString *)tokens->get(i); + for (int j = 0; j < tok->getLength(); ++j) { + if (tok->getChar(j) < '0' || tok->getChar(j) > '9') { + error(errConfig, -1, "Bad 'zoomValues' config file command ({0:t}:{1:d})", + fileName, line); + return; + } + } + } + deleteGList(zoomValues, GString); + zoomValues = new GList(); + for (int i = 1; i < tokens->getLength(); ++i) { + GString *tok = (GString *)tokens->get(i); + zoomValues->append(tok->copy()); + } +} + void GlobalParams::parseYesNo(const char *cmdName, GBool *flag, GList *tokens, GString *fileName, int line) { GString *tok; @@ -2098,6 +2376,7 @@ GlobalParams::~GlobalParams() { deleteGList(psResidentFontsCC, PSFontParam16); delete textEncoding; delete initialZoom; + deleteGList(zoomValues, GString); delete initialDisplayMode; delete initialSelectMode; if (paperColor) { @@ -2124,7 +2403,9 @@ GlobalParams::~GlobalParams() { delete droppedFonts; deleteGList(keyBindings, KeyBinding); deleteGList(popupMenuCmds, PopupMenuCmd); + delete pagesFile; delete tabStateFile; + delete sessionFile; delete debugLogFile; cMapDirs->startIter(&iter); @@ -2249,6 +2530,10 @@ void GlobalParams::setupBaseFonts(const char *dir) { GList *dfontFontNames; GBool found; int k; +#endif +#if HAVE_FONTCONFIG + SysFontInfo *fi; + GString *fcName; #endif FILE *f; int i, j; @@ -2258,6 +2543,14 @@ void GlobalParams::setupBaseFonts(const char *dir) { #endif #ifdef __APPLE__ dfontFontNames = NULL; +#endif +#ifdef _WIN32 + if (winFontDir[0]) { + sysFonts->scanWindowsFonts(winFontDir); + } +#endif +#if HAVE_FONTCONFIG + sysFonts->scanFontconfigFonts(); #endif for (i = 0; displayFontTab[i].name; ++i) { if (fontFiles->lookup(displayFontTab[i].name)) { @@ -2334,6 +2627,16 @@ void GlobalParams::setupBaseFonts(const char *dir) { } } #endif // __APPLE__ +#if HAVE_FONTCONFIG + if (!fileName) { + fcName = new GString(displayFontTab[i].fcFontName); + if ((fi = sysFonts->find(fcName))) { + fileName = fi->path->copy(); + fontNum = fi->fontNum; + } + delete fcName; + } +#endif // HAVE_FONTCONFIG // On Linux, this checks the "standard" ghostscript font // directories. On Windows, it checks the "standard" system font // directories (because SHGetSpecialFolderPath(CSIDL_FONTS) @@ -2383,14 +2686,6 @@ void GlobalParams::setupBaseFonts(const char *dir) { } } } -#ifdef _WIN32 - if (winFontDir[0]) { - sysFonts->scanWindowsFonts(winFontDir); - } -#endif -#if HAVE_FONTCONFIG - sysFonts->scanFontconfigFonts(); -#endif } //------------------------------------------------------------------------ @@ -2950,6 +3245,19 @@ int GlobalParams::getDefaultFitZoom() { return z; } +double GlobalParams::getZoomScaleFactor() { + double z; + + lockGlobalParams; + z = zoomScaleFactor; + unlockGlobalParams; + return z; +} + +GList *GlobalParams::getZoomValues() { + return zoomValues; +} + GString *GlobalParams::getInitialDisplayMode() { GString *s; @@ -2995,6 +3303,15 @@ GString *GlobalParams::getInitialSelectMode() { return s; } +GBool GlobalParams::getInitialMaximized() { + GBool state; + + lockGlobalParams; + state = initialMaximized; + unlockGlobalParams; + return state; +} + int GlobalParams::getMaxTileWidth() { int w; @@ -3194,6 +3511,15 @@ GBool GlobalParams::getEnableXFA() { return xfa; } +GBool GlobalParams::getPreferXFAFieldValues() { + GBool xfa; + + lockGlobalParams; + xfa = preferXFAFieldValues; + unlockGlobalParams; + return xfa; +} + GString *GlobalParams::getPaperColor() { @@ -3241,6 +3567,15 @@ GBool GlobalParams::getReverseVideoInvertImages() { return invert; } +GBool GlobalParams::getAllowLinksToChangeZoom() { + GBool allow; + + lockGlobalParams; + allow = allowLinksToChangeZoom; + unlockGlobalParams; + return allow; +} + GString *GlobalParams::getDefaultPrinter() { GString *s; @@ -3286,6 +3621,15 @@ GBool GlobalParams::getUseTrueTypeUnicodeMapping() { return use; } +GBool GlobalParams::getIgnoreWrongSizeToUnicode() { + GBool ignore; + + lockGlobalParams; + ignore = ignoreWrongSizeToUnicode; + unlockGlobalParams; + return ignore; +} + GBool GlobalParams::isDroppedFont(const char *fontName) { GBool isDropped; @@ -3295,6 +3639,24 @@ GBool GlobalParams::isDroppedFont(const char *fontName) { return isDropped; } +GBool GlobalParams::getSeparateRotatedText() { + GBool sep; + + lockGlobalParams; + sep = separateRotatedText; + unlockGlobalParams; + return sep; +} + +GBool GlobalParams::getDiscardCoveredText() { + GBool discard; + + lockGlobalParams; + discard = discardCoveredText; + unlockGlobalParams; + return discard; +} + GList *GlobalParams::getKeyBinding(int code, int mods, int context) { KeyBinding *binding; GList *cmds; @@ -3347,6 +3709,15 @@ PopupMenuCmd *GlobalParams::getPopupMenuCmd(int idx) { return cmd; } +GString *GlobalParams::getPagesFile() { + GString *s; + + lockGlobalParams; + s = pagesFile->copy(); + unlockGlobalParams; + return s; +} + GString *GlobalParams::getTabStateFile() { GString *s; @@ -3356,6 +3727,15 @@ GString *GlobalParams::getTabStateFile() { return s; } +GString *GlobalParams::getSessionFile() { + GString *s; + + lockGlobalParams; + s = sessionFile->copy(); + unlockGlobalParams; + return s; +} + GBool GlobalParams::getSavePageNumbers() { GBool s; @@ -3365,6 +3745,15 @@ GBool GlobalParams::getSavePageNumbers() { return s; } +GBool GlobalParams::getSaveSessionOnQuit() { + GBool s; + + lockGlobalParams; + s = saveSessionOnQuit; + unlockGlobalParams; + return s; +} + GBool GlobalParams::getPrintCommands() { GBool p; @@ -3703,6 +4092,12 @@ void GlobalParams::setInitialZoom(char *s) { unlockGlobalParams; } +void GlobalParams::setDefaultFitZoom(int z) { + lockGlobalParams; + defaultFitZoom = z; + unlockGlobalParams; +} + GBool GlobalParams::setEnableFreeType(char *s) { GBool ok; @@ -3806,6 +4201,13 @@ void GlobalParams::setTabStateFile(char *tabStateFileA) { unlockGlobalParams; } +void GlobalParams::setSessionFile(char *sessionFileA) { + lockGlobalParams; + delete sessionFile; + sessionFile = new GString(sessionFileA); + unlockGlobalParams; +} + void GlobalParams::setPrintCommands(GBool printCommandsA) { lockGlobalParams; printCommands = printCommandsA; diff --git a/src/xpdf-4.04/xpdf/GlobalParams.h b/src/xpdf-4.06/xpdf/GlobalParams.h old mode 100644 new mode 100755 similarity index 93% rename from src/xpdf-4.04/xpdf/GlobalParams.h rename to src/xpdf-4.06/xpdf/GlobalParams.h index b8299fc..b92088a --- a/src/xpdf-4.04/xpdf/GlobalParams.h +++ b/src/xpdf-4.06/xpdf/GlobalParams.h @@ -11,10 +11,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - #include #ifdef _WIN32 # include @@ -300,11 +296,14 @@ class GlobalParams { GBool getTextKeepTinyChars(); GString *getInitialZoom(); int getDefaultFitZoom(); + double getZoomScaleFactor(); + GList *getZoomValues(); GString *getInitialDisplayMode(); GBool getInitialToolbarState(); GBool getInitialSidebarState(); int getInitialSidebarWidth(); GString *getInitialSelectMode(); + GBool getInitialMaximized(); int getMaxTileWidth(); int getMaxTileHeight(); int getTileCacheSize(); @@ -327,12 +326,14 @@ class GlobalParams { GBool getDrawAnnotations(); GBool getDrawFormFields(); GBool getEnableXFA(); + GBool getPreferXFAFieldValues(); GBool getOverprintPreview() { return overprintPreview; } GString *getPaperColor(); GString *getMatteColor(); GString *getFullScreenMatteColor(); GString *getSelectionColor(); GBool getReverseVideoInvertImages(); + GBool getAllowLinksToChangeZoom(); GString *getLaunchCommand() { return launchCommand; } GString *getMovieCommand() { return movieCommand; } GString *getDefaultPrinter(); @@ -340,12 +341,18 @@ class GlobalParams { GBool getMapUnknownCharNames(); GBool getMapExtTrueTypeFontsViaUnicode(); GBool getUseTrueTypeUnicodeMapping(); + GBool getIgnoreWrongSizeToUnicode(); GBool isDroppedFont(const char *fontName); + GBool getSeparateRotatedText(); + GBool getDiscardCoveredText(); GList *getKeyBinding(int code, int mods, int context); GList *getAllKeyBindings(); int getNumPopupMenuCmds(); PopupMenuCmd *getPopupMenuCmd(int idx); + GString *getPagesFile(); GString *getTabStateFile(); + GString *getSessionFile(); + GBool getSaveSessionOnQuit(); GBool getSavePageNumbers(); GBool getPrintCommands(); GBool getPrintStatusInfo(); @@ -387,6 +394,7 @@ class GlobalParams { void setTextPageBreaks(GBool pageBreaks); void setTextKeepTinyChars(GBool keep); void setInitialZoom(char *s); + void setDefaultFitZoom(int z); GBool setEnableFreeType(char *s); GBool setAntialias(char *s); GBool setVectorAntialias(char *s); @@ -402,6 +410,7 @@ class GlobalParams { void setMapUnknownCharNames(GBool map); void setMapExtTrueTypeFontsViaUnicode(GBool map); void setTabStateFile(char *tabStateFileA); + void setSessionFile(char *sessionFileA); void setPrintCommands(GBool printCommandsA); void setPrintStatusInfo(GBool printStatusInfoA); void setErrQuiet(GBool errQuietA); @@ -417,6 +426,8 @@ class GlobalParams { void setDataDirVar(); void createDefaultKeyBindings(); + void initStateFilePaths(); + FILE *openConfigFile(const char *cfgFileName, GString **fileName); void parseFile(GString *fileName, FILE *f); GList *parseLineTokens(char *buf, GString *fileName, int line); void parseNameToUnicode(GList *tokens, GString *fileName, int line); @@ -447,6 +458,8 @@ class GlobalParams { const char *cmdName, GList *tokens, GString *fileName, int line); void parsePopupMenuCmd(GList *tokens, GString *fileName, int line); + void parseZoomScaleFactor(GList *tokens, GString *fileName, int line); + void parseZoomValues(GList *tokens, GString *fileName, int line); void parseYesNo(const char *cmdName, GBool *flag, GList *tokens, GString *fileName, int line); GBool parseYesNo2(char *token, GBool *flag); @@ -545,7 +558,9 @@ class GlobalParams { GBool textKeepTinyChars; // keep all characters in text output GString *initialZoom; // initial zoom level int defaultFitZoom; // default zoom factor if initialZoom is - // 'page' or 'width'. + // 'page' or 'width' + double zoomScaleFactor; // displayed zoom values are scaled by this + GList *zoomValues; // zoom values for the combo box GString *initialDisplayMode; // initial display mode (single, // continuous, etc.) GBool initialToolbarState; // initial toolbar state - open (true) @@ -554,6 +569,7 @@ class GlobalParams { // or closed (false) int initialSidebarWidth; // initial sidebar width GString *initialSelectMode; // initial selection mode (block or linear) + GBool initialMaximized; // initial window maximized state int maxTileWidth; // maximum rasterization tile width int maxTileHeight; // maximum rasterization tile height int tileCacheSize; // number of rasterization tiles in cache @@ -577,12 +593,14 @@ class GlobalParams { GBool drawAnnotations; // draw annotations or not GBool drawFormFields; // draw form fields or not GBool enableXFA; // enable XFA form parsing + GBool preferXFAFieldValues; // prefer XFA field values over AcroForm values GBool overprintPreview; // enable overprint preview GString *paperColor; // paper (page background) color GString *matteColor; // matte (background outside of page) color GString *fullScreenMatteColor; // matte color in full-screen mode GString *selectionColor; // selection color GBool reverseVideoInvertImages; // invert images in reverse video mode + GBool allowLinksToChangeZoom; // allow clicking on a link to change the zoom GString *launchCommand; // command executed for 'launch' links GString *movieCommand; // command executed for movie annotations GString *defaultPrinter; // default printer (for interactive printing @@ -594,10 +612,17 @@ class GlobalParams { GBool useTrueTypeUnicodeMapping; // use the Unicode cmaps in TrueType // fonts, rather than the PDF // ToUnicode mapping + GBool ignoreWrongSizeToUnicode; // ignore ToUnicode CMaps if their size + // (8-bit vs 16-bit) doesn't match the font GHash *droppedFonts; // dropped fonts [int] + GBool separateRotatedText; // separate text at each rotation + GBool discardCoveredText; // discard text covered by fill or image GList *keyBindings; // key & mouse button bindings [KeyBinding] GList *popupMenuCmds; // popup menu commands [PopupMenuCmd] + GString *pagesFile; // path for the page number save file GString *tabStateFile; // path for the tab state save file + GString *sessionFile; // path for the session save file + GBool saveSessionOnQuit; // save session info when xpdf is quit GBool savePageNumbers; // save page number when file is closed // and restore page number when opened GBool printCommands; // print the drawing commands diff --git a/src/xpdf-4.04/xpdf/HTMLGen.cc b/src/xpdf-4.06/xpdf/HTMLGen.cc old mode 100644 new mode 100755 similarity index 90% rename from src/xpdf-4.04/xpdf/HTMLGen.cc rename to src/xpdf-4.06/xpdf/HTMLGen.cc index a077655..15bd497 --- a/src/xpdf-4.04/xpdf/HTMLGen.cc +++ b/src/xpdf-4.06/xpdf/HTMLGen.cc @@ -13,7 +13,6 @@ //~ generic serif/sans-serif/monospace name) //~ - check that htmlDir exists and is a directory //~ - links: -//~ - internal links (to pages, to named destinations) //~ - links from non-text content //~ - rotated text should go in the background image //~ - metadata @@ -21,10 +20,6 @@ #include -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - #include #include #include "gmem.h" @@ -35,6 +30,7 @@ #include "PDFDoc.h" #include "GfxFont.h" #include "AcroForm.h" +#include "TextString.h" #include "TextOutputDev.h" #include "SplashOutputDev.h" #include "ErrorCodes.h" @@ -42,9 +38,11 @@ #include "HTMLGen.h" #ifdef _WIN32 +#ifndef __GNUC__ # define strcasecmp stricmp # define strncasecmp strnicmp #endif +#endif //------------------------------------------------------------------------ @@ -297,6 +295,7 @@ HTMLGen::HTMLGen(double backgroundResolutionA, GBool tableMode) { convertFormFields = gFalse; embedBackgroundImage = gFalse; embedFonts = gFalse; + includeMetadata = gFalse; // set up the TextOutputDev textOutControl.mode = tableMode ? textOutTableLayout : textOutReadingOrder; @@ -312,6 +311,10 @@ HTMLGen::HTMLGen(double backgroundResolutionA, GBool tableMode) { splashOut = new SplashOutputDev(splashModeRGB8, 1, gFalse, paperColor); fontDefns = NULL; + + nVisibleChars = 0; + nInvisibleChars = 0; + nRemovedDupChars = 0; } HTMLGen::~HTMLGen() { @@ -394,7 +397,7 @@ int HTMLGen::convertPage( // generate the background bitmap splashOut->setSkipText(!allTextInvisible, gFalse); - doc->displayPage(splashOut, pg, + doc->displayPage(splashOut, NULL, pg, backgroundResolution, backgroundResolution * vStretch, 0, gFalse, gTrue, gFalse); bitmap = splashOut->getBitmap(); @@ -409,7 +412,7 @@ int HTMLGen::convertPage( } // get the PDF text - doc->displayPage(textOut, pg, 72, 72, 0, gFalse, gTrue, gFalse); + doc->displayPage(textOut, NULL, pg, 72, 72, 0, gFalse, gTrue, gFalse); doc->processLinks(textOut, pg); text = textOut->takeText(); primaryDir = text->primaryDirectionIsLR() ? 1 : -1; @@ -462,11 +465,11 @@ int HTMLGen::convertPage( llyI = bitmap->getHeight() - 1; } if (uryI <= llyI && llxI <= urxI) { - SplashColorPtr p = bitmap->getDataPtr() - + uryI * bitmap->getRowSize() + llxI * 3; - for (int y = uryI; y <= llyI; ++y) { - memset(p, 0xff, (urxI - llxI + 1) * 3); - p += bitmap->getRowSize(); + SplashColorPtr pix = bitmap->getDataPtr() + + uryI * bitmap->getRowSize() + llxI * 3; + for (y = uryI; y <= llyI; ++y) { + memset(pix, 0xff, (urxI - llxI + 1) * 3); + pix += bitmap->getRowSize(); } } @@ -483,8 +486,13 @@ int HTMLGen::convertPage( pr(writeHTML, htmlStream, "\n"); pr(writeHTML, htmlStream, "\n"); pr(writeHTML, htmlStream, "\n"); + if (includeMetadata) { + genDocMetadata(writeHTML, htmlStream); + } pr(writeHTML, htmlStream, "\n" + "\n" + "\n" + "
\n" + " \n" + "
\n" + " \n" + "
\n" + "
\n" + "\n" + "\n" + "\n"; + +static GBool createFrameIndex(char *htmlDir) { + GString *htmlFileName; + FILE *html; + int pg; + + htmlFileName = GString::format("{0:s}/index.html", htmlDir); + html = openFile(htmlFileName->getCString(), "w"); + if (!html) { + error(errIO, -1, "Couldn't open HTML file '{0:t}'", htmlFileName); + delete htmlFileName; + return gFalse; + } + delete htmlFileName; + + fputs(frameHead, html); + for (pg = firstPage; pg <= lastPage; ++pg) { + fprintf(html, "
  • page %d
  • \n", + pg, pg); + } + fputs(frameTail, html); + + fclose(html); + + return gTrue; +} diff --git a/src/xpdf-4.04/xpdf/pdftopng.cc b/src/xpdf-4.06/xpdf/pdftopng.cc old mode 100644 new mode 100755 similarity index 95% rename from src/xpdf-4.04/xpdf/pdftopng.cc rename to src/xpdf-4.06/xpdf/pdftopng.cc index 7f3b97b..a8827cd --- a/src/xpdf-4.04/xpdf/pdftopng.cc +++ b/src/xpdf-4.06/xpdf/pdftopng.cc @@ -99,6 +99,10 @@ static void writePNGData(png_structp png, SplashBitmap *bitmap); static void finishPNG(png_structp *png, png_infop *pngInfo); int main(int argc, char *argv[]) { +#if USE_EXCEPTIONS + try { +#endif + PDFDoc *doc; char *fileName; char *pngRoot; @@ -126,12 +130,15 @@ int main(int argc, char *argv[]) { fprintf(stderr, "The -alpha flag cannot be used with -mono\n"); goto err0; } - if (!ok || argc != 3 || printVersion || printHelp) { + if (printVersion) { + printf("pdftopng version %s [www.xpdfreader.com]\n", xpdfVersion); + printf("%s\n", xpdfCopyright); + goto err0; + } + if (!ok || argc != 3 || printHelp) { fprintf(stderr, "pdftopng version %s [www.xpdfreader.com]\n", xpdfVersion); fprintf(stderr, "%s\n", xpdfCopyright); - if (!printVersion) { - printUsage("pdftopng", " ", argDesc); - } + printUsage("pdftopng", " ", argDesc); goto err0; } fileName = argv[1]; @@ -221,7 +228,7 @@ int main(int argc, char *argv[]) { printf("[processing page %d]\n", pg); fflush(stdout); } - doc->displayPage(splashOut, pg, resolution, resolution, rotate, + doc->displayPage(splashOut, NULL, pg, resolution, resolution, rotate, gFalse, gTrue, gFalse); if (mono) { if (toStdout) { @@ -296,6 +303,13 @@ int main(int argc, char *argv[]) { gMemReport(stderr); return exitCode; + +#if USE_EXCEPTIONS + } catch (GMemException e) { + fprintf(stderr, "Out of memory\n"); + return 98; + } +#endif } static void setupPNG(png_structp *png, png_infop *pngInfo, FILE *f, diff --git a/src/xpdf-4.04/xpdf/pdftoppm.cc b/src/xpdf-4.06/xpdf/pdftoppm.cc old mode 100644 new mode 100755 similarity index 94% rename from src/xpdf-4.04/xpdf/pdftoppm.cc rename to src/xpdf-4.06/xpdf/pdftoppm.cc index 28861ef..f78b959 --- a/src/xpdf-4.04/xpdf/pdftoppm.cc +++ b/src/xpdf-4.06/xpdf/pdftoppm.cc @@ -98,6 +98,10 @@ static ArgDesc argDesc[] = { }; int main(int argc, char *argv[]) { +#if USE_EXCEPTIONS + try { +#endif + PDFDoc *doc; char *fileName; char *ppmRoot; @@ -139,12 +143,15 @@ int main(int argc, char *argv[]) { if (n > 1) { ok = gFalse; } - if (!ok || argc != 3 || printVersion || printHelp) { + if (printVersion) { + printf("pdftoppm version %s [www.xpdfreader.com]\n", xpdfVersion); + printf("%s\n", xpdfCopyright); + goto err0; + } + if (!ok || argc != 3 || printHelp) { fprintf(stderr, "pdftoppm version %s [www.xpdfreader.com]\n", xpdfVersion); fprintf(stderr, "%s\n", xpdfCopyright); - if (!printVersion) { - printUsage("pdftoppm", " ", argDesc); - } + printUsage("pdftoppm", " ", argDesc); goto err0; } fileName = argv[1]; @@ -249,7 +256,7 @@ int main(int argc, char *argv[]) { printf("[processing page %d]\n", pg); fflush(stdout); } - doc->displayPage(splashOut, pg, resolution, resolution, rotate, + doc->displayPage(splashOut, NULL, pg, resolution, resolution, rotate, gFalse, gTrue, gFalse); if (toStdout) { #ifdef _WIN32 @@ -277,4 +284,11 @@ int main(int argc, char *argv[]) { gMemReport(stderr); return exitCode; + +#if USE_EXCEPTIONS + } catch (GMemException e) { + fprintf(stderr, "Out of memory\n"); + return 98; + } +#endif } diff --git a/src/xpdf-4.04/xpdf/pdftops.cc b/src/xpdf-4.06/xpdf/pdftops.cc old mode 100644 new mode 100755 similarity index 95% rename from src/xpdf-4.04/xpdf/pdftops.cc rename to src/xpdf-4.06/xpdf/pdftops.cc index 77e90fe..685b3aa --- a/src/xpdf-4.04/xpdf/pdftops.cc +++ b/src/xpdf-4.06/xpdf/pdftops.cc @@ -153,6 +153,10 @@ static ArgDesc argDesc[] = { }; int main(int argc, char *argv[]) { +#if USE_EXCEPTIONS + try { +#endif + PDFDoc *doc; char *fileName; GString *psFileName; @@ -184,12 +188,15 @@ int main(int argc, char *argv[]) { // parse args fixCommandLine(&argc, &argv); ok = parseArgs(argDesc, &argc, argv); - if (!ok || argc < 2 || argc > 3 || printVersion || printHelp) { + if (printVersion) { + printf("pdftops version %s [www.xpdfreader.com]\n", xpdfVersion); + printf("%s\n", xpdfCopyright); + exit(1); + } + if (!ok || argc < 2 || argc > 3 || printHelp) { fprintf(stderr, "pdftops version %s [www.xpdfreader.com]\n", xpdfVersion); fprintf(stderr, "%s\n", xpdfCopyright); - if (!printVersion) { - printUsage("pdftops", " []", argDesc); - } + printUsage("pdftops", " []", argDesc); exit(1); } if ((level1 ? 1 : 0) + @@ -211,6 +218,8 @@ int main(int argc, char *argv[]) { level = psLevel1; } else if (level1Sep) { level = psLevel1Sep; + } else if (level2) { + level = psLevel2; } else if (level2Gray) { level = psLevel2Gray; } else if (level2Sep) { @@ -222,7 +231,7 @@ int main(int argc, char *argv[]) { } else if (level3Sep) { level = psLevel3Sep; } else { - level = psLevel2; + level = psLevel3; } if (doForm && level < psLevel2) { fprintf(stderr, "Error: forms are only available with Level 2 output.\n"); @@ -374,7 +383,7 @@ int main(int argc, char *argv[]) { exitCode = 2; goto err2; } - doc->displayPages(psOut, firstPage, lastPage, 72, 72, + doc->displayPages(psOut, NULL, firstPage, lastPage, 72, 72, 0, !globalParams->getPSUseCropBoxAsPage(), globalParams->getPSCrop(), gTrue); exitCode = 0; @@ -396,4 +405,11 @@ int main(int argc, char *argv[]) { gMemReport(stderr); return exitCode; + +#if USE_EXCEPTIONS + } catch (GMemException e) { + fprintf(stderr, "Out of memory\n"); + return 98; + } +#endif } diff --git a/src/xpdf-4.04/xpdf/pdftotext.cc b/src/xpdf-4.06/xpdf/pdftotext.cc old mode 100644 new mode 100755 similarity index 95% rename from src/xpdf-4.04/xpdf/pdftotext.cc rename to src/xpdf-4.06/xpdf/pdftotext.cc index d8bf6df..470a901 --- a/src/xpdf-4.04/xpdf/pdftotext.cc +++ b/src/xpdf-4.06/xpdf/pdftotext.cc @@ -132,6 +132,10 @@ static ArgDesc argDesc[] = { }; int main(int argc, char *argv[]) { +#if USE_EXCEPTIONS + try { +#endif + PDFDoc *doc; char *fileName; GString *textFileName; @@ -178,12 +182,15 @@ int main(int argc, char *argv[]) { delete globalParams; goto err0; } - if (!ok || argc < 2 || argc > 3 || printVersion || printHelp) { + if (printVersion) { + printf("pdftotext version %s [www.xpdfreader.com]\n", xpdfVersion); + printf("%s\n", xpdfCopyright); + goto err0; + } + if (!ok || argc < 2 || argc > 3 || printHelp) { fprintf(stderr, "pdftotext version %s [www.xpdfreader.com]\n", xpdfVersion); fprintf(stderr, "%s\n", xpdfCopyright); - if (!printVersion) { - printUsage("pdftotext", " []", argDesc); - } + printUsage("pdftotext", " []", argDesc); goto err0; } fileName = argv[1]; @@ -303,7 +310,7 @@ int main(int argc, char *argv[]) { textOut = new TextOutputDev(textFileName->getCString(), &textOutControl, gFalse, gTrue); if (textOut->isOk()) { - doc->displayPages(textOut, firstPage, lastPage, 72, 72, 0, + doc->displayPages(textOut, NULL, firstPage, lastPage, 72, 72, 0, gFalse, gTrue, gFalse); } else { delete textOut; @@ -329,4 +336,11 @@ int main(int argc, char *argv[]) { gMemReport(stderr); return exitCode; + +#if USE_EXCEPTIONS + } catch (GMemException e) { + fprintf(stderr, "Out of memory\n"); + return 98; + } +#endif } diff --git a/src/xpdf-4.04/xpdf/winLongPath.exe.manifest b/src/xpdf-4.06/xpdf/winLongPath.exe.manifest old mode 100644 new mode 100755 similarity index 100% rename from src/xpdf-4.04/xpdf/winLongPath.exe.manifest rename to src/xpdf-4.06/xpdf/winLongPath.exe.manifest diff --git a/src/xpydf/ImageDataDev.cc b/src/xpydf/ImageDataDev.cc old mode 100644 new mode 100755 diff --git a/src/xpydf/ImageDataDev.h b/src/xpydf/ImageDataDev.h old mode 100644 new mode 100755 index f16a789..2e5b9f2 --- a/src/xpydf/ImageDataDev.h +++ b/src/xpydf/ImageDataDev.h @@ -20,11 +20,19 @@ typedef struct Image { class ImageDataDev: public ImageOutputDev { public: - ImageDataDev(char *fileRootA, GBool dumpJPEGA, GBool dumpRawA, - GBool listA, std::vector *imagesA) : ImageOutputDev(fileRootA, dumpJPEGA, dumpRawA, listA) { - imgNum = 0; - images = imagesA; - }; + ImageDataDev( + char *fileRootA, + GBool dumpJPEGA, + GBool dumpJPXA, + GBool dumpRawA, + GBool uniqueA, + GBool listA, + GBool listOnlyA, + std::vector *imagesA + ) : ImageOutputDev(fileRootA, dumpJPEGA, dumpJPXA, dumpRawA, uniqueA, listA, listOnlyA) { + imgNum = 0; + images = imagesA; + }; virtual void startPage(int pageNum, GfxState *state); diff --git a/src/xpydf/ImageInfoDev.cc b/src/xpydf/ImageInfoDev.cc old mode 100644 new mode 100755 diff --git a/src/xpydf/ImageInfoDev.h b/src/xpydf/ImageInfoDev.h old mode 100644 new mode 100755 index 51d0619..61f279b --- a/src/xpydf/ImageInfoDev.h +++ b/src/xpydf/ImageInfoDev.h @@ -16,8 +16,15 @@ typedef struct ImageInfo { class ImageInfoDev: public ImageOutputDev { public: - ImageInfoDev(char *fileRootA, GBool dumpJPEGA, GBool dumpRawA, - GBool listA) : ImageOutputDev(fileRootA, dumpJPEGA, dumpRawA, listA) {}; + ImageInfoDev( + char *fileRootA, + GBool dumpJPEGA, + GBool dumpJPXA, + GBool dumpRawA, + GBool uniqueA, + GBool listA, + GBool listOnlyA + ) : ImageOutputDev(fileRootA, dumpJPEGA, dumpJPXA, dumpRawA, uniqueA, listA, listOnlyA) {}; virtual void startPage(int pageNum, GfxState *state); diff --git a/src/xpydf/PdfLoader.cc b/src/xpydf/PdfLoader.cc old mode 100644 new mode 100755 index e3a248e..c915de6 --- a/src/xpydf/PdfLoader.cc +++ b/src/xpydf/PdfLoader.cc @@ -119,7 +119,7 @@ std::vector PdfLoader::extractText() { if (textOut->isOk()) { for (int page = firstPage; page <= lastPage; page++) { stream->str(""); - doc->displayPages(textOut, page, page, 72, 72, 0, gFalse, gTrue, gFalse); + doc->displayPages(textOut, NULL, page, page, 72, 72, 0, gFalse, gTrue, gFalse); pages.push_back(stream->str()); } } @@ -147,7 +147,7 @@ std::vector PdfLoader::extractPageInfo() { firstPage = 1; lastPage = doc->getNumPages(); - imageOut = new ImageInfoDev(dummyFile, gFalse, gFalse, gTrue); + imageOut = new ImageInfoDev(dummyFile, gFalse, gFalse, gFalse, gFalse, gTrue, gFalse); if (imageOut->isOk()) { for (int page = firstPage; page <= lastPage; page++) { @@ -156,7 +156,7 @@ std::vector PdfLoader::extractPageInfo() { double page_width = box->x2 - box->x1; double page_height = box->y2 - box->y1; - doc->displayPages(imageOut, page, page, 72, 72, 0, gFalse, gTrue, gFalse); + doc->displayPages(imageOut, NULL, page, page, 72, 72, 0, gFalse, gTrue, gFalse); std::vector images(imageOut->images); pagesInfo.push_back(PageImageInfo{ @@ -187,10 +187,10 @@ std::vector PdfLoader::extractImages(int pageNum) { goto err; } - imageOut = new ImageDataDev(dummyFile, gFalse, gFalse, gTrue, &images); + imageOut = new ImageDataDev(dummyFile, gFalse, gFalse, gFalse, gFalse, gTrue, gFalse, &images); if (imageOut->isOk()) { - doc->displayPages(imageOut, pageNum, pageNum, 72, 72, 0, gFalse, gTrue, gFalse); + doc->displayPages(imageOut, NULL, pageNum, pageNum, 72, 72, 0, gFalse, gTrue, gFalse); } delete imageOut; @@ -222,7 +222,7 @@ Image PdfLoader::pageToImage(int pageNum, int dpi) { splashOut->startDoc(doc->getXRef()); - doc->displayPages(splashOut, pageNum, pageNum, dpi, dpi, 0, gFalse, gTrue, gFalse); + doc->displayPages(splashOut, NULL, pageNum, pageNum, dpi, dpi, 0, gFalse, gTrue, gFalse); bitmap = splashOut->getBitmap(); pageImage = { diff --git a/src/xpydf/PdfLoader.h b/src/xpydf/PdfLoader.h old mode 100644 new mode 100755 diff --git a/src/xpydf/PdfLoaderWrapper.cc b/src/xpydf/PdfLoaderWrapper.cc old mode 100644 new mode 100755 diff --git a/src/xpydf/PyCppConversion.cc b/src/xpydf/PyCppConversion.cc old mode 100644 new mode 100755 diff --git a/src/xpydf/PyCppConversion.h b/src/xpydf/PyCppConversion.h old mode 100644 new mode 100755 diff --git a/src/xpydf/__init__.py b/src/xpydf/__init__.py old mode 100644 new mode 100755 diff --git a/src/xpydf/__init__.pyi b/src/xpydf/__init__.pyi old mode 100644 new mode 100755 diff --git a/src/xpydf/cXpdfPython.pyi b/src/xpydf/cXpdfPython.pyi old mode 100644 new mode 100755 diff --git a/src/xpydf/pdf_loader.py b/src/xpydf/pdf_loader.py old mode 100644 new mode 100755 diff --git a/src/xpydf/pdf_loader.pyi b/src/xpydf/pdf_loader.pyi old mode 100644 new mode 100755 diff --git a/tests/__init__.py b/tests/__init__.py old mode 100644 new mode 100755 diff --git a/tests/test_data/xpdf_tests.pdf b/tests/test_data/xpdf_tests.pdf old mode 100644 new mode 100755 diff --git a/tests/test_data/xpdf_tests_password.pdf b/tests/test_data/xpdf_tests_password.pdf old mode 100644 new mode 100755 diff --git a/tests/test_pdf_loader.py b/tests/test_pdf_loader.py old mode 100644 new mode 100755