diff options
author | Calvin Morrison <calvin@pobox.com> | 2023-04-05 14:13:39 -0400 |
---|---|---|
committer | Calvin Morrison <calvin@pobox.com> | 2023-04-05 14:13:39 -0400 |
commit | 835e373b3eeaabcd0621ed6798ab500f37982fae (patch) | |
tree | dfa16b0e2e1b4956b38f693220eac4e607802133 /splash |
Diffstat (limited to 'splash')
75 files changed, 18425 insertions, 0 deletions
diff --git a/splash/CMakeFiles/CMakeDirectoryInformation.cmake b/splash/CMakeFiles/CMakeDirectoryInformation.cmake new file mode 100644 index 0000000..aef4d6c --- /dev/null +++ b/splash/CMakeFiles/CMakeDirectoryInformation.cmake @@ -0,0 +1,16 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.18 + +# Relative path conversion top directories. +set(CMAKE_RELATIVE_PATH_TOP_SOURCE "/home/calvin/src/xpdf-4.04") +set(CMAKE_RELATIVE_PATH_TOP_BINARY "/home/calvin/src/xpdf-4.04") + +# Force unix paths in dependencies. +set(CMAKE_FORCE_UNIX_PATHS 1) + + +# The C and CXX include file regular expressions for this directory. +set(CMAKE_C_INCLUDE_REGEX_SCAN "^.*$") +set(CMAKE_C_INCLUDE_REGEX_COMPLAIN "^$") +set(CMAKE_CXX_INCLUDE_REGEX_SCAN ${CMAKE_C_INCLUDE_REGEX_SCAN}) +set(CMAKE_CXX_INCLUDE_REGEX_COMPLAIN ${CMAKE_C_INCLUDE_REGEX_COMPLAIN}) diff --git a/splash/CMakeFiles/progress.marks b/splash/CMakeFiles/progress.marks new file mode 100644 index 0000000..48082f7 --- /dev/null +++ b/splash/CMakeFiles/progress.marks @@ -0,0 +1 @@ +12 diff --git a/splash/CMakeFiles/splash.dir/DependInfo.cmake b/splash/CMakeFiles/splash.dir/DependInfo.cmake new file mode 100644 index 0000000..19fab21 --- /dev/null +++ b/splash/CMakeFiles/splash.dir/DependInfo.cmake @@ -0,0 +1,11 @@ +# The set of languages for which implicit dependencies are needed: +set(CMAKE_DEPENDS_LANGUAGES + ) +# The set of files for implicit dependencies of each language: + +# Targets to which this target links. +set(CMAKE_TARGET_LINKED_INFO_FILES + ) + +# Fortran module output directory. +set(CMAKE_Fortran_TARGET_MODULE_DIR "") diff --git a/splash/CMakeFiles/splash.dir/build.make b/splash/CMakeFiles/splash.dir/build.make new file mode 100644 index 0000000..3d6695a --- /dev/null +++ b/splash/CMakeFiles/splash.dir/build.make @@ -0,0 +1,135 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.18 + +# Delete rule output on recipe failure. +.DELETE_ON_ERROR: + + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + + +# Disable VCS-based implicit rules. +% : %,v + + +# Disable VCS-based implicit rules. +% : RCS/% + + +# Disable VCS-based implicit rules. +% : RCS/%,v + + +# Disable VCS-based implicit rules. +% : SCCS/s.% + + +# Disable VCS-based implicit rules. +% : s.% + + +.SUFFIXES: .hpux_make_needs_suffix_list + + +# Command-line flag to silence nested $(MAKE). +$(VERBOSE)MAKESILENT = -s + +#Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: + +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /usr/bin/cmake + +# The command to remove a file. +RM = /usr/bin/cmake -E rm -f + +# Escaping for special characters. +EQUALS = = + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /home/calvin/src/xpdf-4.04 + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /home/calvin/src/xpdf-4.04 + +# Include any dependencies generated for this target. +include splash/CMakeFiles/splash.dir/depend.make + +# Include the progress variables for this target. +include splash/CMakeFiles/splash.dir/progress.make + +# Include the compile flags for this target's objects. +include splash/CMakeFiles/splash.dir/flags.make + +# Object files for target splash +splash_OBJECTS = + +# External object files for target splash +splash_EXTERNAL_OBJECTS = \ +"/home/calvin/src/xpdf-4.04/splash/CMakeFiles/splash_objs.dir/Splash.cc.o" \ +"/home/calvin/src/xpdf-4.04/splash/CMakeFiles/splash_objs.dir/SplashBitmap.cc.o" \ +"/home/calvin/src/xpdf-4.04/splash/CMakeFiles/splash_objs.dir/SplashClip.cc.o" \ +"/home/calvin/src/xpdf-4.04/splash/CMakeFiles/splash_objs.dir/SplashFTFont.cc.o" \ +"/home/calvin/src/xpdf-4.04/splash/CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.o" \ +"/home/calvin/src/xpdf-4.04/splash/CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.o" \ +"/home/calvin/src/xpdf-4.04/splash/CMakeFiles/splash_objs.dir/SplashFont.cc.o" \ +"/home/calvin/src/xpdf-4.04/splash/CMakeFiles/splash_objs.dir/SplashFontEngine.cc.o" \ +"/home/calvin/src/xpdf-4.04/splash/CMakeFiles/splash_objs.dir/SplashFontFile.cc.o" \ +"/home/calvin/src/xpdf-4.04/splash/CMakeFiles/splash_objs.dir/SplashFontFileID.cc.o" \ +"/home/calvin/src/xpdf-4.04/splash/CMakeFiles/splash_objs.dir/SplashPath.cc.o" \ +"/home/calvin/src/xpdf-4.04/splash/CMakeFiles/splash_objs.dir/SplashPattern.cc.o" \ +"/home/calvin/src/xpdf-4.04/splash/CMakeFiles/splash_objs.dir/SplashScreen.cc.o" \ +"/home/calvin/src/xpdf-4.04/splash/CMakeFiles/splash_objs.dir/SplashState.cc.o" \ +"/home/calvin/src/xpdf-4.04/splash/CMakeFiles/splash_objs.dir/SplashXPath.cc.o" \ +"/home/calvin/src/xpdf-4.04/splash/CMakeFiles/splash_objs.dir/SplashXPathScanner.cc.o" + +splash/libsplash.a: splash/CMakeFiles/splash_objs.dir/Splash.cc.o +splash/libsplash.a: splash/CMakeFiles/splash_objs.dir/SplashBitmap.cc.o +splash/libsplash.a: splash/CMakeFiles/splash_objs.dir/SplashClip.cc.o +splash/libsplash.a: splash/CMakeFiles/splash_objs.dir/SplashFTFont.cc.o +splash/libsplash.a: splash/CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.o +splash/libsplash.a: splash/CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.o +splash/libsplash.a: splash/CMakeFiles/splash_objs.dir/SplashFont.cc.o +splash/libsplash.a: splash/CMakeFiles/splash_objs.dir/SplashFontEngine.cc.o +splash/libsplash.a: splash/CMakeFiles/splash_objs.dir/SplashFontFile.cc.o +splash/libsplash.a: splash/CMakeFiles/splash_objs.dir/SplashFontFileID.cc.o +splash/libsplash.a: splash/CMakeFiles/splash_objs.dir/SplashPath.cc.o +splash/libsplash.a: splash/CMakeFiles/splash_objs.dir/SplashPattern.cc.o +splash/libsplash.a: splash/CMakeFiles/splash_objs.dir/SplashScreen.cc.o +splash/libsplash.a: splash/CMakeFiles/splash_objs.dir/SplashState.cc.o +splash/libsplash.a: splash/CMakeFiles/splash_objs.dir/SplashXPath.cc.o +splash/libsplash.a: splash/CMakeFiles/splash_objs.dir/SplashXPathScanner.cc.o +splash/libsplash.a: splash/CMakeFiles/splash.dir/build.make +splash/libsplash.a: splash/CMakeFiles/splash.dir/link.txt + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --bold --progress-dir=/home/calvin/src/xpdf-4.04/CMakeFiles --progress-num=$(CMAKE_PROGRESS_1) "Linking CXX static library libsplash.a" + cd /home/calvin/src/xpdf-4.04/splash && $(CMAKE_COMMAND) -P CMakeFiles/splash.dir/cmake_clean_target.cmake + cd /home/calvin/src/xpdf-4.04/splash && $(CMAKE_COMMAND) -E cmake_link_script CMakeFiles/splash.dir/link.txt --verbose=$(VERBOSE) + +# Rule to build all files generated by this target. +splash/CMakeFiles/splash.dir/build: splash/libsplash.a + +.PHONY : splash/CMakeFiles/splash.dir/build + +splash/CMakeFiles/splash.dir/clean: + cd /home/calvin/src/xpdf-4.04/splash && $(CMAKE_COMMAND) -P CMakeFiles/splash.dir/cmake_clean.cmake +.PHONY : splash/CMakeFiles/splash.dir/clean + +splash/CMakeFiles/splash.dir/depend: + cd /home/calvin/src/xpdf-4.04 && $(CMAKE_COMMAND) -E cmake_depends "Unix Makefiles" /home/calvin/src/xpdf-4.04 /home/calvin/src/xpdf-4.04/splash /home/calvin/src/xpdf-4.04 /home/calvin/src/xpdf-4.04/splash /home/calvin/src/xpdf-4.04/splash/CMakeFiles/splash.dir/DependInfo.cmake --color=$(COLOR) +.PHONY : splash/CMakeFiles/splash.dir/depend + diff --git a/splash/CMakeFiles/splash.dir/cmake_clean.cmake b/splash/CMakeFiles/splash.dir/cmake_clean.cmake new file mode 100644 index 0000000..905e817 --- /dev/null +++ b/splash/CMakeFiles/splash.dir/cmake_clean.cmake @@ -0,0 +1,9 @@ +file(REMOVE_RECURSE + "libsplash.a" + "libsplash.pdb" +) + +# Per-language clean rules from dependency scanning. +foreach(lang CXX) + include(CMakeFiles/splash.dir/cmake_clean_${lang}.cmake OPTIONAL) +endforeach() diff --git a/splash/CMakeFiles/splash.dir/cmake_clean_target.cmake b/splash/CMakeFiles/splash.dir/cmake_clean_target.cmake new file mode 100644 index 0000000..4294aad --- /dev/null +++ b/splash/CMakeFiles/splash.dir/cmake_clean_target.cmake @@ -0,0 +1,3 @@ +file(REMOVE_RECURSE + "libsplash.a" +) diff --git a/splash/CMakeFiles/splash.dir/depend.internal b/splash/CMakeFiles/splash.dir/depend.internal new file mode 100644 index 0000000..756f521 --- /dev/null +++ b/splash/CMakeFiles/splash.dir/depend.internal @@ -0,0 +1,3 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.18 + diff --git a/splash/CMakeFiles/splash.dir/depend.make b/splash/CMakeFiles/splash.dir/depend.make new file mode 100644 index 0000000..756f521 --- /dev/null +++ b/splash/CMakeFiles/splash.dir/depend.make @@ -0,0 +1,3 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.18 + diff --git a/splash/CMakeFiles/splash.dir/flags.make b/splash/CMakeFiles/splash.dir/flags.make new file mode 100644 index 0000000..ae623ab --- /dev/null +++ b/splash/CMakeFiles/splash.dir/flags.make @@ -0,0 +1,10 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.18 + +# compile CXX with /usr/bin/c++ +CXX_DEFINES = + +CXX_INCLUDES = -I/home/calvin/src/xpdf-4.04 -I/home/calvin/src/xpdf-4.04/goo -I/home/calvin/src/xpdf-4.04/fofi -I/usr/include/freetype2 + +CXX_FLAGS = + diff --git a/splash/CMakeFiles/splash.dir/link.txt b/splash/CMakeFiles/splash.dir/link.txt new file mode 100644 index 0000000..1c08a0a --- /dev/null +++ b/splash/CMakeFiles/splash.dir/link.txt @@ -0,0 +1,2 @@ +/usr/bin/ar qc libsplash.a CMakeFiles/splash_objs.dir/Splash.cc.o CMakeFiles/splash_objs.dir/SplashBitmap.cc.o CMakeFiles/splash_objs.dir/SplashClip.cc.o CMakeFiles/splash_objs.dir/SplashFTFont.cc.o CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.o CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.o CMakeFiles/splash_objs.dir/SplashFont.cc.o CMakeFiles/splash_objs.dir/SplashFontEngine.cc.o CMakeFiles/splash_objs.dir/SplashFontFile.cc.o CMakeFiles/splash_objs.dir/SplashFontFileID.cc.o CMakeFiles/splash_objs.dir/SplashPath.cc.o CMakeFiles/splash_objs.dir/SplashPattern.cc.o CMakeFiles/splash_objs.dir/SplashScreen.cc.o CMakeFiles/splash_objs.dir/SplashState.cc.o CMakeFiles/splash_objs.dir/SplashXPath.cc.o CMakeFiles/splash_objs.dir/SplashXPathScanner.cc.o +/usr/bin/ranlib libsplash.a diff --git a/splash/CMakeFiles/splash.dir/progress.make b/splash/CMakeFiles/splash.dir/progress.make new file mode 100644 index 0000000..225de34 --- /dev/null +++ b/splash/CMakeFiles/splash.dir/progress.make @@ -0,0 +1,2 @@ +CMAKE_PROGRESS_1 = + diff --git a/splash/CMakeFiles/splash_objs.dir/CXX.includecache b/splash/CMakeFiles/splash_objs.dir/CXX.includecache new file mode 100644 index 0000000..408e937 --- /dev/null +++ b/splash/CMakeFiles/splash_objs.dir/CXX.includecache @@ -0,0 +1,596 @@ +#IncludeRegexLine: ^[ ]*[#%][ ]*(include|import)[ ]*[<"]([^">]+)([">]) + +#IncludeRegexScan: ^.*$ + +#IncludeRegexComplain: ^$ + +#IncludeRegexTransform: + +/home/calvin/src/xpdf-4.04/splash/Splash.cc +aconf.h +- +stdlib.h +- +string.h +- +limits.h +- +math.h +- +gmem.h +/home/calvin/src/xpdf-4.04/splash/gmem.h +gmempp.h +/home/calvin/src/xpdf-4.04/splash/gmempp.h +GString.h +/home/calvin/src/xpdf-4.04/splash/GString.h +SplashErrorCodes.h +/home/calvin/src/xpdf-4.04/splash/SplashErrorCodes.h +SplashMath.h +/home/calvin/src/xpdf-4.04/splash/SplashMath.h +SplashBitmap.h +/home/calvin/src/xpdf-4.04/splash/SplashBitmap.h +SplashState.h +/home/calvin/src/xpdf-4.04/splash/SplashState.h +SplashPath.h +/home/calvin/src/xpdf-4.04/splash/SplashPath.h +SplashXPath.h +/home/calvin/src/xpdf-4.04/splash/SplashXPath.h +SplashXPathScanner.h +/home/calvin/src/xpdf-4.04/splash/SplashXPathScanner.h +SplashPattern.h +/home/calvin/src/xpdf-4.04/splash/SplashPattern.h +SplashScreen.h +/home/calvin/src/xpdf-4.04/splash/SplashScreen.h +SplashFont.h +/home/calvin/src/xpdf-4.04/splash/SplashFont.h +SplashGlyphBitmap.h +/home/calvin/src/xpdf-4.04/splash/SplashGlyphBitmap.h +Splash.h +/home/calvin/src/xpdf-4.04/splash/Splash.h + +/home/calvin/src/xpdf-4.04/splash/Splash.h +aconf.h +- +SplashTypes.h +/home/calvin/src/xpdf-4.04/splash/SplashTypes.h +SplashClip.h +/home/calvin/src/xpdf-4.04/splash/SplashClip.h + +/home/calvin/src/xpdf-4.04/splash/SplashBitmap.cc +aconf.h +- +stdio.h +- +limits.h +- +gmem.h +/home/calvin/src/xpdf-4.04/splash/gmem.h +gmempp.h +/home/calvin/src/xpdf-4.04/splash/gmempp.h +gfile.h +/home/calvin/src/xpdf-4.04/splash/gfile.h +Trace.h +/home/calvin/src/xpdf-4.04/splash/Trace.h +SplashErrorCodes.h +/home/calvin/src/xpdf-4.04/splash/SplashErrorCodes.h +SplashBitmap.h +/home/calvin/src/xpdf-4.04/splash/SplashBitmap.h + +/home/calvin/src/xpdf-4.04/splash/SplashBitmap.h +aconf.h +- +stdio.h +- +limits.h +- +stdint.h +- +SplashTypes.h +/home/calvin/src/xpdf-4.04/splash/SplashTypes.h + +/home/calvin/src/xpdf-4.04/splash/SplashClip.cc +aconf.h +- +stdlib.h +- +string.h +- +gmem.h +/home/calvin/src/xpdf-4.04/splash/gmem.h +gmempp.h +/home/calvin/src/xpdf-4.04/splash/gmempp.h +SplashErrorCodes.h +/home/calvin/src/xpdf-4.04/splash/SplashErrorCodes.h +SplashPath.h +/home/calvin/src/xpdf-4.04/splash/SplashPath.h +SplashXPath.h +/home/calvin/src/xpdf-4.04/splash/SplashXPath.h +SplashXPathScanner.h +/home/calvin/src/xpdf-4.04/splash/SplashXPathScanner.h +SplashClip.h +/home/calvin/src/xpdf-4.04/splash/SplashClip.h + +/home/calvin/src/xpdf-4.04/splash/SplashClip.h +aconf.h +- +SplashTypes.h +/home/calvin/src/xpdf-4.04/splash/SplashTypes.h +SplashMath.h +/home/calvin/src/xpdf-4.04/splash/SplashMath.h + +/home/calvin/src/xpdf-4.04/splash/SplashErrorCodes.h +aconf.h +- + +/home/calvin/src/xpdf-4.04/splash/SplashFTFont.cc +aconf.h +- +ft2build.h +- +gmem.h +/home/calvin/src/xpdf-4.04/splash/gmem.h +gmempp.h +/home/calvin/src/xpdf-4.04/splash/gmempp.h +SplashMath.h +/home/calvin/src/xpdf-4.04/splash/SplashMath.h +SplashGlyphBitmap.h +/home/calvin/src/xpdf-4.04/splash/SplashGlyphBitmap.h +SplashPath.h +/home/calvin/src/xpdf-4.04/splash/SplashPath.h +SplashFontEngine.h +/home/calvin/src/xpdf-4.04/splash/SplashFontEngine.h +SplashFTFontEngine.h +/home/calvin/src/xpdf-4.04/splash/SplashFTFontEngine.h +SplashFTFontFile.h +/home/calvin/src/xpdf-4.04/splash/SplashFTFontFile.h +SplashFTFont.h +/home/calvin/src/xpdf-4.04/splash/SplashFTFont.h + +/home/calvin/src/xpdf-4.04/splash/SplashFTFont.h +aconf.h +- +ft2build.h +- +SplashFont.h +/home/calvin/src/xpdf-4.04/splash/SplashFont.h + +/home/calvin/src/xpdf-4.04/splash/SplashFTFontEngine.cc +aconf.h +- +stdio.h +- +unistd.h +- +gmem.h +/home/calvin/src/xpdf-4.04/splash/gmem.h +gmempp.h +/home/calvin/src/xpdf-4.04/splash/gmempp.h +GString.h +/home/calvin/src/xpdf-4.04/splash/GString.h +gfile.h +/home/calvin/src/xpdf-4.04/splash/gfile.h +FoFiTrueType.h +/home/calvin/src/xpdf-4.04/splash/FoFiTrueType.h +FoFiType1C.h +/home/calvin/src/xpdf-4.04/splash/FoFiType1C.h +SplashFTFontFile.h +/home/calvin/src/xpdf-4.04/splash/SplashFTFontFile.h +SplashFTFontEngine.h +/home/calvin/src/xpdf-4.04/splash/SplashFTFontEngine.h + +/home/calvin/src/xpdf-4.04/splash/SplashFTFontEngine.h +aconf.h +- +ft2build.h +- +gtypes.h +/home/calvin/src/xpdf-4.04/splash/gtypes.h + +/home/calvin/src/xpdf-4.04/splash/SplashFTFontFile.cc +aconf.h +- +gmem.h +/home/calvin/src/xpdf-4.04/splash/gmem.h +gmempp.h +/home/calvin/src/xpdf-4.04/splash/gmempp.h +GString.h +/home/calvin/src/xpdf-4.04/splash/GString.h +SplashFTFontEngine.h +/home/calvin/src/xpdf-4.04/splash/SplashFTFontEngine.h +SplashFTFont.h +/home/calvin/src/xpdf-4.04/splash/SplashFTFont.h +SplashFTFontFile.h +/home/calvin/src/xpdf-4.04/splash/SplashFTFontFile.h + +/home/calvin/src/xpdf-4.04/splash/SplashFTFontFile.h +aconf.h +- +ft2build.h +- +SplashFontFile.h +/home/calvin/src/xpdf-4.04/splash/SplashFontFile.h + +/home/calvin/src/xpdf-4.04/splash/SplashFont.cc +aconf.h +- +string.h +- +gmem.h +/home/calvin/src/xpdf-4.04/splash/gmem.h +gmempp.h +/home/calvin/src/xpdf-4.04/splash/gmempp.h +SplashMath.h +/home/calvin/src/xpdf-4.04/splash/SplashMath.h +SplashGlyphBitmap.h +/home/calvin/src/xpdf-4.04/splash/SplashGlyphBitmap.h +SplashFontFile.h +/home/calvin/src/xpdf-4.04/splash/SplashFontFile.h +SplashFont.h +/home/calvin/src/xpdf-4.04/splash/SplashFont.h + +/home/calvin/src/xpdf-4.04/splash/SplashFont.h +aconf.h +- +gtypes.h +/home/calvin/src/xpdf-4.04/splash/gtypes.h +SplashTypes.h +/home/calvin/src/xpdf-4.04/splash/SplashTypes.h +SplashMath.h +/home/calvin/src/xpdf-4.04/splash/SplashMath.h + +/home/calvin/src/xpdf-4.04/splash/SplashFontEngine.cc +aconf.h +- +stdlib.h +- +stdio.h +- +unistd.h +- +gmem.h +/home/calvin/src/xpdf-4.04/splash/gmem.h +gmempp.h +/home/calvin/src/xpdf-4.04/splash/gmempp.h +GString.h +/home/calvin/src/xpdf-4.04/splash/GString.h +GList.h +/home/calvin/src/xpdf-4.04/splash/GList.h +SplashMath.h +/home/calvin/src/xpdf-4.04/splash/SplashMath.h +SplashFTFontEngine.h +/home/calvin/src/xpdf-4.04/splash/SplashFTFontEngine.h +SplashFontFile.h +/home/calvin/src/xpdf-4.04/splash/SplashFontFile.h +SplashFontFileID.h +/home/calvin/src/xpdf-4.04/splash/SplashFontFileID.h +SplashFont.h +/home/calvin/src/xpdf-4.04/splash/SplashFont.h +SplashFontEngine.h +/home/calvin/src/xpdf-4.04/splash/SplashFontEngine.h + +/home/calvin/src/xpdf-4.04/splash/SplashFontEngine.h +aconf.h +- +gtypes.h +/home/calvin/src/xpdf-4.04/splash/gtypes.h + +/home/calvin/src/xpdf-4.04/splash/SplashFontFile.cc +aconf.h +- +stdio.h +- +unistd.h +- +gmempp.h +/home/calvin/src/xpdf-4.04/splash/gmempp.h +GString.h +/home/calvin/src/xpdf-4.04/splash/GString.h +SplashFontFile.h +/home/calvin/src/xpdf-4.04/splash/SplashFontFile.h +SplashFontFileID.h +/home/calvin/src/xpdf-4.04/splash/SplashFontFileID.h + +/home/calvin/src/xpdf-4.04/splash/SplashFontFile.h +aconf.h +- +gtypes.h +/home/calvin/src/xpdf-4.04/splash/gtypes.h +SplashTypes.h +/home/calvin/src/xpdf-4.04/splash/SplashTypes.h +GMutex.h +/home/calvin/src/xpdf-4.04/splash/GMutex.h + +/home/calvin/src/xpdf-4.04/splash/SplashFontFileID.cc +aconf.h +- +gmempp.h +/home/calvin/src/xpdf-4.04/splash/gmempp.h +SplashFontFileID.h +/home/calvin/src/xpdf-4.04/splash/SplashFontFileID.h + +/home/calvin/src/xpdf-4.04/splash/SplashFontFileID.h +aconf.h +- +gtypes.h +/home/calvin/src/xpdf-4.04/splash/gtypes.h + +/home/calvin/src/xpdf-4.04/splash/SplashGlyphBitmap.h +aconf.h +- +gtypes.h +/home/calvin/src/xpdf-4.04/splash/gtypes.h + +/home/calvin/src/xpdf-4.04/splash/SplashMath.h +aconf.h +- +FixedPoint.h +/home/calvin/src/xpdf-4.04/splash/FixedPoint.h +math.h +- +emmintrin.h +- +SplashTypes.h +/home/calvin/src/xpdf-4.04/splash/SplashTypes.h + +/home/calvin/src/xpdf-4.04/splash/SplashPath.cc +aconf.h +- +string.h +- +gmem.h +/home/calvin/src/xpdf-4.04/splash/gmem.h +gmempp.h +/home/calvin/src/xpdf-4.04/splash/gmempp.h +SplashErrorCodes.h +/home/calvin/src/xpdf-4.04/splash/SplashErrorCodes.h +SplashPath.h +/home/calvin/src/xpdf-4.04/splash/SplashPath.h + +/home/calvin/src/xpdf-4.04/splash/SplashPath.h +aconf.h +- +SplashTypes.h +/home/calvin/src/xpdf-4.04/splash/SplashTypes.h + +/home/calvin/src/xpdf-4.04/splash/SplashPattern.cc +aconf.h +- +gmempp.h +/home/calvin/src/xpdf-4.04/splash/gmempp.h +SplashMath.h +/home/calvin/src/xpdf-4.04/splash/SplashMath.h +SplashScreen.h +/home/calvin/src/xpdf-4.04/splash/SplashScreen.h +SplashPattern.h +/home/calvin/src/xpdf-4.04/splash/SplashPattern.h + +/home/calvin/src/xpdf-4.04/splash/SplashPattern.h +aconf.h +- +SplashTypes.h +/home/calvin/src/xpdf-4.04/splash/SplashTypes.h + +/home/calvin/src/xpdf-4.04/splash/SplashScreen.cc +aconf.h +- +stdlib.h +- +string.h +- +algorithm +- +gmem.h +/home/calvin/src/xpdf-4.04/splash/gmem.h +gmempp.h +/home/calvin/src/xpdf-4.04/splash/gmempp.h +SplashMath.h +/home/calvin/src/xpdf-4.04/splash/SplashMath.h +SplashScreen.h +/home/calvin/src/xpdf-4.04/splash/SplashScreen.h + +/home/calvin/src/xpdf-4.04/splash/SplashScreen.h +aconf.h +- +SplashTypes.h +/home/calvin/src/xpdf-4.04/splash/SplashTypes.h + +/home/calvin/src/xpdf-4.04/splash/SplashState.cc +aconf.h +- +string.h +- +gmem.h +/home/calvin/src/xpdf-4.04/splash/gmem.h +gmempp.h +/home/calvin/src/xpdf-4.04/splash/gmempp.h +SplashPattern.h +/home/calvin/src/xpdf-4.04/splash/SplashPattern.h +SplashScreen.h +/home/calvin/src/xpdf-4.04/splash/SplashScreen.h +SplashClip.h +/home/calvin/src/xpdf-4.04/splash/SplashClip.h +SplashBitmap.h +/home/calvin/src/xpdf-4.04/splash/SplashBitmap.h +SplashState.h +/home/calvin/src/xpdf-4.04/splash/SplashState.h + +/home/calvin/src/xpdf-4.04/splash/SplashState.h +aconf.h +- +SplashTypes.h +/home/calvin/src/xpdf-4.04/splash/SplashTypes.h + +/home/calvin/src/xpdf-4.04/splash/SplashTypes.h +aconf.h +- +gtypes.h +/home/calvin/src/xpdf-4.04/splash/gtypes.h +FixedPoint.h +/home/calvin/src/xpdf-4.04/splash/FixedPoint.h + +/home/calvin/src/xpdf-4.04/splash/SplashXPath.cc +aconf.h +- +stdlib.h +- +string.h +- +algorithm +- +gmem.h +/home/calvin/src/xpdf-4.04/splash/gmem.h +gmempp.h +/home/calvin/src/xpdf-4.04/splash/gmempp.h +SplashMath.h +/home/calvin/src/xpdf-4.04/splash/SplashMath.h +SplashPath.h +/home/calvin/src/xpdf-4.04/splash/SplashPath.h +SplashXPath.h +/home/calvin/src/xpdf-4.04/splash/SplashXPath.h + +/home/calvin/src/xpdf-4.04/splash/SplashXPath.h +aconf.h +- +SplashTypes.h +/home/calvin/src/xpdf-4.04/splash/SplashTypes.h + +/home/calvin/src/xpdf-4.04/splash/SplashXPathScanner.cc +aconf.h +- +stdlib.h +- +string.h +- +algorithm +- +gmem.h +/home/calvin/src/xpdf-4.04/splash/gmem.h +gmempp.h +/home/calvin/src/xpdf-4.04/splash/gmempp.h +GList.h +/home/calvin/src/xpdf-4.04/splash/GList.h +SplashMath.h +/home/calvin/src/xpdf-4.04/splash/SplashMath.h +SplashXPath.h +/home/calvin/src/xpdf-4.04/splash/SplashXPath.h +SplashXPathScanner.h +/home/calvin/src/xpdf-4.04/splash/SplashXPathScanner.h + +/home/calvin/src/xpdf-4.04/splash/SplashXPathScanner.h +aconf.h +- +SplashTypes.h +/home/calvin/src/xpdf-4.04/splash/SplashTypes.h +SplashXPath.h +/home/calvin/src/xpdf-4.04/splash/SplashXPath.h + +/usr/include/freetype2/freetype/config/ftheader.h + +/usr/include/freetype2/ft2build.h +freetype/config/ftheader.h +- + +aconf.h +aconf2.h +- + +aconf2.h +AvailabilityMacros.h +- + +fofi/FoFiBase.h +aconf.h +- +gtypes.h +fofi/gtypes.h + +fofi/FoFiTrueType.h +aconf.h +- +gtypes.h +fofi/gtypes.h +FoFiBase.h +fofi/FoFiBase.h + +fofi/FoFiType1C.h +aconf.h +- +gtypes.h +fofi/gtypes.h +FoFiBase.h +fofi/FoFiBase.h + +goo/FixedPoint.h +aconf.h +- +stdio.h +- +stdlib.h +- +gtypes.h +goo/gtypes.h + +goo/GList.h +aconf.h +- +gtypes.h +goo/gtypes.h + +goo/GMutex.h +aconf.h +- +windows.h +- +intrin.h +- +pthread.h +- + +goo/GString.h +aconf.h +- +limits.h +- +stdarg.h +- +gtypes.h +goo/gtypes.h + +goo/Trace.h +aconf.h +- + +goo/gfile.h +aconf.h +- +stdio.h +- +stdlib.h +- +stddef.h +- +sys/stat.h +- +win32lib.h +- +windows.h +- +unistd.h +- +sys/types.h +- +gtypes.h +goo/gtypes.h + +goo/gmem.h +stdio.h +- +aconf.h +- + +goo/gmempp.h +stdlib.h +- + +goo/gtypes.h + diff --git a/splash/CMakeFiles/splash_objs.dir/DependInfo.cmake b/splash/CMakeFiles/splash_objs.dir/DependInfo.cmake new file mode 100644 index 0000000..66c827f --- /dev/null +++ b/splash/CMakeFiles/splash_objs.dir/DependInfo.cmake @@ -0,0 +1,39 @@ +# The set of languages for which implicit dependencies are needed: +set(CMAKE_DEPENDS_LANGUAGES + "CXX" + ) +# The set of files for implicit dependencies of each language: +set(CMAKE_DEPENDS_CHECK_CXX + "/home/calvin/src/xpdf-4.04/splash/Splash.cc" "/home/calvin/src/xpdf-4.04/splash/CMakeFiles/splash_objs.dir/Splash.cc.o" + "/home/calvin/src/xpdf-4.04/splash/SplashBitmap.cc" "/home/calvin/src/xpdf-4.04/splash/CMakeFiles/splash_objs.dir/SplashBitmap.cc.o" + "/home/calvin/src/xpdf-4.04/splash/SplashClip.cc" "/home/calvin/src/xpdf-4.04/splash/CMakeFiles/splash_objs.dir/SplashClip.cc.o" + "/home/calvin/src/xpdf-4.04/splash/SplashFTFont.cc" "/home/calvin/src/xpdf-4.04/splash/CMakeFiles/splash_objs.dir/SplashFTFont.cc.o" + "/home/calvin/src/xpdf-4.04/splash/SplashFTFontEngine.cc" "/home/calvin/src/xpdf-4.04/splash/CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.o" + "/home/calvin/src/xpdf-4.04/splash/SplashFTFontFile.cc" "/home/calvin/src/xpdf-4.04/splash/CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.o" + "/home/calvin/src/xpdf-4.04/splash/SplashFont.cc" "/home/calvin/src/xpdf-4.04/splash/CMakeFiles/splash_objs.dir/SplashFont.cc.o" + "/home/calvin/src/xpdf-4.04/splash/SplashFontEngine.cc" "/home/calvin/src/xpdf-4.04/splash/CMakeFiles/splash_objs.dir/SplashFontEngine.cc.o" + "/home/calvin/src/xpdf-4.04/splash/SplashFontFile.cc" "/home/calvin/src/xpdf-4.04/splash/CMakeFiles/splash_objs.dir/SplashFontFile.cc.o" + "/home/calvin/src/xpdf-4.04/splash/SplashFontFileID.cc" "/home/calvin/src/xpdf-4.04/splash/CMakeFiles/splash_objs.dir/SplashFontFileID.cc.o" + "/home/calvin/src/xpdf-4.04/splash/SplashPath.cc" "/home/calvin/src/xpdf-4.04/splash/CMakeFiles/splash_objs.dir/SplashPath.cc.o" + "/home/calvin/src/xpdf-4.04/splash/SplashPattern.cc" "/home/calvin/src/xpdf-4.04/splash/CMakeFiles/splash_objs.dir/SplashPattern.cc.o" + "/home/calvin/src/xpdf-4.04/splash/SplashScreen.cc" "/home/calvin/src/xpdf-4.04/splash/CMakeFiles/splash_objs.dir/SplashScreen.cc.o" + "/home/calvin/src/xpdf-4.04/splash/SplashState.cc" "/home/calvin/src/xpdf-4.04/splash/CMakeFiles/splash_objs.dir/SplashState.cc.o" + "/home/calvin/src/xpdf-4.04/splash/SplashXPath.cc" "/home/calvin/src/xpdf-4.04/splash/CMakeFiles/splash_objs.dir/SplashXPath.cc.o" + "/home/calvin/src/xpdf-4.04/splash/SplashXPathScanner.cc" "/home/calvin/src/xpdf-4.04/splash/CMakeFiles/splash_objs.dir/SplashXPathScanner.cc.o" + ) +set(CMAKE_CXX_COMPILER_ID "GNU") + +# The include file search paths: +set(CMAKE_CXX_TARGET_INCLUDE_PATH + "." + "goo" + "fofi" + "/usr/include/freetype2" + ) + +# Targets to which this target links. +set(CMAKE_TARGET_LINKED_INFO_FILES + ) + +# Fortran module output directory. +set(CMAKE_Fortran_TARGET_MODULE_DIR "") diff --git a/splash/CMakeFiles/splash_objs.dir/Splash.cc.o b/splash/CMakeFiles/splash_objs.dir/Splash.cc.o Binary files differnew file mode 100644 index 0000000..cdaae0f --- /dev/null +++ b/splash/CMakeFiles/splash_objs.dir/Splash.cc.o diff --git a/splash/CMakeFiles/splash_objs.dir/SplashBitmap.cc.o b/splash/CMakeFiles/splash_objs.dir/SplashBitmap.cc.o Binary files differnew file mode 100644 index 0000000..a90c30a --- /dev/null +++ b/splash/CMakeFiles/splash_objs.dir/SplashBitmap.cc.o diff --git a/splash/CMakeFiles/splash_objs.dir/SplashClip.cc.o b/splash/CMakeFiles/splash_objs.dir/SplashClip.cc.o Binary files differnew file mode 100644 index 0000000..9475a08 --- /dev/null +++ b/splash/CMakeFiles/splash_objs.dir/SplashClip.cc.o diff --git a/splash/CMakeFiles/splash_objs.dir/SplashFTFont.cc.o b/splash/CMakeFiles/splash_objs.dir/SplashFTFont.cc.o Binary files differnew file mode 100644 index 0000000..140121f --- /dev/null +++ b/splash/CMakeFiles/splash_objs.dir/SplashFTFont.cc.o diff --git a/splash/CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.o b/splash/CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.o Binary files differnew file mode 100644 index 0000000..8680956 --- /dev/null +++ b/splash/CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.o diff --git a/splash/CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.o b/splash/CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.o Binary files differnew file mode 100644 index 0000000..d5eb5bf --- /dev/null +++ b/splash/CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.o diff --git a/splash/CMakeFiles/splash_objs.dir/SplashFont.cc.o b/splash/CMakeFiles/splash_objs.dir/SplashFont.cc.o Binary files differnew file mode 100644 index 0000000..d83e7e5 --- /dev/null +++ b/splash/CMakeFiles/splash_objs.dir/SplashFont.cc.o diff --git a/splash/CMakeFiles/splash_objs.dir/SplashFontEngine.cc.o b/splash/CMakeFiles/splash_objs.dir/SplashFontEngine.cc.o Binary files differnew file mode 100644 index 0000000..c5ea42d --- /dev/null +++ b/splash/CMakeFiles/splash_objs.dir/SplashFontEngine.cc.o diff --git a/splash/CMakeFiles/splash_objs.dir/SplashFontFile.cc.o b/splash/CMakeFiles/splash_objs.dir/SplashFontFile.cc.o Binary files differnew file mode 100644 index 0000000..73ca08f --- /dev/null +++ b/splash/CMakeFiles/splash_objs.dir/SplashFontFile.cc.o diff --git a/splash/CMakeFiles/splash_objs.dir/SplashFontFileID.cc.o b/splash/CMakeFiles/splash_objs.dir/SplashFontFileID.cc.o Binary files differnew file mode 100644 index 0000000..de10eb8 --- /dev/null +++ b/splash/CMakeFiles/splash_objs.dir/SplashFontFileID.cc.o diff --git a/splash/CMakeFiles/splash_objs.dir/SplashPath.cc.o b/splash/CMakeFiles/splash_objs.dir/SplashPath.cc.o Binary files differnew file mode 100644 index 0000000..296a5e6 --- /dev/null +++ b/splash/CMakeFiles/splash_objs.dir/SplashPath.cc.o diff --git a/splash/CMakeFiles/splash_objs.dir/SplashPattern.cc.o b/splash/CMakeFiles/splash_objs.dir/SplashPattern.cc.o Binary files differnew file mode 100644 index 0000000..fd9038c --- /dev/null +++ b/splash/CMakeFiles/splash_objs.dir/SplashPattern.cc.o diff --git a/splash/CMakeFiles/splash_objs.dir/SplashScreen.cc.o b/splash/CMakeFiles/splash_objs.dir/SplashScreen.cc.o Binary files differnew file mode 100644 index 0000000..808a540 --- /dev/null +++ b/splash/CMakeFiles/splash_objs.dir/SplashScreen.cc.o diff --git a/splash/CMakeFiles/splash_objs.dir/SplashState.cc.o b/splash/CMakeFiles/splash_objs.dir/SplashState.cc.o Binary files differnew file mode 100644 index 0000000..5693eee --- /dev/null +++ b/splash/CMakeFiles/splash_objs.dir/SplashState.cc.o diff --git a/splash/CMakeFiles/splash_objs.dir/SplashXPath.cc.o b/splash/CMakeFiles/splash_objs.dir/SplashXPath.cc.o Binary files differnew file mode 100644 index 0000000..61c8bdd --- /dev/null +++ b/splash/CMakeFiles/splash_objs.dir/SplashXPath.cc.o diff --git a/splash/CMakeFiles/splash_objs.dir/SplashXPathScanner.cc.o b/splash/CMakeFiles/splash_objs.dir/SplashXPathScanner.cc.o Binary files differnew file mode 100644 index 0000000..5f90f60 --- /dev/null +++ b/splash/CMakeFiles/splash_objs.dir/SplashXPathScanner.cc.o diff --git a/splash/CMakeFiles/splash_objs.dir/build.make b/splash/CMakeFiles/splash_objs.dir/build.make new file mode 100644 index 0000000..ab89f9f --- /dev/null +++ b/splash/CMakeFiles/splash_objs.dir/build.make @@ -0,0 +1,319 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.18 + +# Delete rule output on recipe failure. +.DELETE_ON_ERROR: + + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + + +# Disable VCS-based implicit rules. +% : %,v + + +# Disable VCS-based implicit rules. +% : RCS/% + + +# Disable VCS-based implicit rules. +% : RCS/%,v + + +# Disable VCS-based implicit rules. +% : SCCS/s.% + + +# Disable VCS-based implicit rules. +% : s.% + + +.SUFFIXES: .hpux_make_needs_suffix_list + + +# Command-line flag to silence nested $(MAKE). +$(VERBOSE)MAKESILENT = -s + +#Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: + +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /usr/bin/cmake + +# The command to remove a file. +RM = /usr/bin/cmake -E rm -f + +# Escaping for special characters. +EQUALS = = + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /home/calvin/src/xpdf-4.04 + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /home/calvin/src/xpdf-4.04 + +# Include any dependencies generated for this target. +include splash/CMakeFiles/splash_objs.dir/depend.make + +# Include the progress variables for this target. +include splash/CMakeFiles/splash_objs.dir/progress.make + +# Include the compile flags for this target's objects. +include splash/CMakeFiles/splash_objs.dir/flags.make + +splash/CMakeFiles/splash_objs.dir/Splash.cc.o: splash/CMakeFiles/splash_objs.dir/flags.make +splash/CMakeFiles/splash_objs.dir/Splash.cc.o: splash/Splash.cc + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/calvin/src/xpdf-4.04/CMakeFiles --progress-num=$(CMAKE_PROGRESS_1) "Building CXX object splash/CMakeFiles/splash_objs.dir/Splash.cc.o" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/splash_objs.dir/Splash.cc.o -c /home/calvin/src/xpdf-4.04/splash/Splash.cc + +splash/CMakeFiles/splash_objs.dir/Splash.cc.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/splash_objs.dir/Splash.cc.i" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/calvin/src/xpdf-4.04/splash/Splash.cc > CMakeFiles/splash_objs.dir/Splash.cc.i + +splash/CMakeFiles/splash_objs.dir/Splash.cc.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/splash_objs.dir/Splash.cc.s" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/calvin/src/xpdf-4.04/splash/Splash.cc -o CMakeFiles/splash_objs.dir/Splash.cc.s + +splash/CMakeFiles/splash_objs.dir/SplashBitmap.cc.o: splash/CMakeFiles/splash_objs.dir/flags.make +splash/CMakeFiles/splash_objs.dir/SplashBitmap.cc.o: splash/SplashBitmap.cc + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/calvin/src/xpdf-4.04/CMakeFiles --progress-num=$(CMAKE_PROGRESS_2) "Building CXX object splash/CMakeFiles/splash_objs.dir/SplashBitmap.cc.o" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/splash_objs.dir/SplashBitmap.cc.o -c /home/calvin/src/xpdf-4.04/splash/SplashBitmap.cc + +splash/CMakeFiles/splash_objs.dir/SplashBitmap.cc.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/splash_objs.dir/SplashBitmap.cc.i" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/calvin/src/xpdf-4.04/splash/SplashBitmap.cc > CMakeFiles/splash_objs.dir/SplashBitmap.cc.i + +splash/CMakeFiles/splash_objs.dir/SplashBitmap.cc.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/splash_objs.dir/SplashBitmap.cc.s" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/calvin/src/xpdf-4.04/splash/SplashBitmap.cc -o CMakeFiles/splash_objs.dir/SplashBitmap.cc.s + +splash/CMakeFiles/splash_objs.dir/SplashClip.cc.o: splash/CMakeFiles/splash_objs.dir/flags.make +splash/CMakeFiles/splash_objs.dir/SplashClip.cc.o: splash/SplashClip.cc + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/calvin/src/xpdf-4.04/CMakeFiles --progress-num=$(CMAKE_PROGRESS_3) "Building CXX object splash/CMakeFiles/splash_objs.dir/SplashClip.cc.o" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/splash_objs.dir/SplashClip.cc.o -c /home/calvin/src/xpdf-4.04/splash/SplashClip.cc + +splash/CMakeFiles/splash_objs.dir/SplashClip.cc.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/splash_objs.dir/SplashClip.cc.i" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/calvin/src/xpdf-4.04/splash/SplashClip.cc > CMakeFiles/splash_objs.dir/SplashClip.cc.i + +splash/CMakeFiles/splash_objs.dir/SplashClip.cc.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/splash_objs.dir/SplashClip.cc.s" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/calvin/src/xpdf-4.04/splash/SplashClip.cc -o CMakeFiles/splash_objs.dir/SplashClip.cc.s + +splash/CMakeFiles/splash_objs.dir/SplashFTFont.cc.o: splash/CMakeFiles/splash_objs.dir/flags.make +splash/CMakeFiles/splash_objs.dir/SplashFTFont.cc.o: splash/SplashFTFont.cc + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/calvin/src/xpdf-4.04/CMakeFiles --progress-num=$(CMAKE_PROGRESS_4) "Building CXX object splash/CMakeFiles/splash_objs.dir/SplashFTFont.cc.o" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/splash_objs.dir/SplashFTFont.cc.o -c /home/calvin/src/xpdf-4.04/splash/SplashFTFont.cc + +splash/CMakeFiles/splash_objs.dir/SplashFTFont.cc.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/splash_objs.dir/SplashFTFont.cc.i" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/calvin/src/xpdf-4.04/splash/SplashFTFont.cc > CMakeFiles/splash_objs.dir/SplashFTFont.cc.i + +splash/CMakeFiles/splash_objs.dir/SplashFTFont.cc.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/splash_objs.dir/SplashFTFont.cc.s" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/calvin/src/xpdf-4.04/splash/SplashFTFont.cc -o CMakeFiles/splash_objs.dir/SplashFTFont.cc.s + +splash/CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.o: splash/CMakeFiles/splash_objs.dir/flags.make +splash/CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.o: splash/SplashFTFontEngine.cc + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/calvin/src/xpdf-4.04/CMakeFiles --progress-num=$(CMAKE_PROGRESS_5) "Building CXX object splash/CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.o" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.o -c /home/calvin/src/xpdf-4.04/splash/SplashFTFontEngine.cc + +splash/CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.i" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/calvin/src/xpdf-4.04/splash/SplashFTFontEngine.cc > CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.i + +splash/CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.s" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/calvin/src/xpdf-4.04/splash/SplashFTFontEngine.cc -o CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.s + +splash/CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.o: splash/CMakeFiles/splash_objs.dir/flags.make +splash/CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.o: splash/SplashFTFontFile.cc + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/calvin/src/xpdf-4.04/CMakeFiles --progress-num=$(CMAKE_PROGRESS_6) "Building CXX object splash/CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.o" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.o -c /home/calvin/src/xpdf-4.04/splash/SplashFTFontFile.cc + +splash/CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.i" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/calvin/src/xpdf-4.04/splash/SplashFTFontFile.cc > CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.i + +splash/CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.s" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/calvin/src/xpdf-4.04/splash/SplashFTFontFile.cc -o CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.s + +splash/CMakeFiles/splash_objs.dir/SplashFont.cc.o: splash/CMakeFiles/splash_objs.dir/flags.make +splash/CMakeFiles/splash_objs.dir/SplashFont.cc.o: splash/SplashFont.cc + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/calvin/src/xpdf-4.04/CMakeFiles --progress-num=$(CMAKE_PROGRESS_7) "Building CXX object splash/CMakeFiles/splash_objs.dir/SplashFont.cc.o" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/splash_objs.dir/SplashFont.cc.o -c /home/calvin/src/xpdf-4.04/splash/SplashFont.cc + +splash/CMakeFiles/splash_objs.dir/SplashFont.cc.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/splash_objs.dir/SplashFont.cc.i" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/calvin/src/xpdf-4.04/splash/SplashFont.cc > CMakeFiles/splash_objs.dir/SplashFont.cc.i + +splash/CMakeFiles/splash_objs.dir/SplashFont.cc.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/splash_objs.dir/SplashFont.cc.s" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/calvin/src/xpdf-4.04/splash/SplashFont.cc -o CMakeFiles/splash_objs.dir/SplashFont.cc.s + +splash/CMakeFiles/splash_objs.dir/SplashFontEngine.cc.o: splash/CMakeFiles/splash_objs.dir/flags.make +splash/CMakeFiles/splash_objs.dir/SplashFontEngine.cc.o: splash/SplashFontEngine.cc + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/calvin/src/xpdf-4.04/CMakeFiles --progress-num=$(CMAKE_PROGRESS_8) "Building CXX object splash/CMakeFiles/splash_objs.dir/SplashFontEngine.cc.o" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/splash_objs.dir/SplashFontEngine.cc.o -c /home/calvin/src/xpdf-4.04/splash/SplashFontEngine.cc + +splash/CMakeFiles/splash_objs.dir/SplashFontEngine.cc.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/splash_objs.dir/SplashFontEngine.cc.i" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/calvin/src/xpdf-4.04/splash/SplashFontEngine.cc > CMakeFiles/splash_objs.dir/SplashFontEngine.cc.i + +splash/CMakeFiles/splash_objs.dir/SplashFontEngine.cc.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/splash_objs.dir/SplashFontEngine.cc.s" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/calvin/src/xpdf-4.04/splash/SplashFontEngine.cc -o CMakeFiles/splash_objs.dir/SplashFontEngine.cc.s + +splash/CMakeFiles/splash_objs.dir/SplashFontFile.cc.o: splash/CMakeFiles/splash_objs.dir/flags.make +splash/CMakeFiles/splash_objs.dir/SplashFontFile.cc.o: splash/SplashFontFile.cc + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/calvin/src/xpdf-4.04/CMakeFiles --progress-num=$(CMAKE_PROGRESS_9) "Building CXX object splash/CMakeFiles/splash_objs.dir/SplashFontFile.cc.o" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/splash_objs.dir/SplashFontFile.cc.o -c /home/calvin/src/xpdf-4.04/splash/SplashFontFile.cc + +splash/CMakeFiles/splash_objs.dir/SplashFontFile.cc.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/splash_objs.dir/SplashFontFile.cc.i" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/calvin/src/xpdf-4.04/splash/SplashFontFile.cc > CMakeFiles/splash_objs.dir/SplashFontFile.cc.i + +splash/CMakeFiles/splash_objs.dir/SplashFontFile.cc.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/splash_objs.dir/SplashFontFile.cc.s" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/calvin/src/xpdf-4.04/splash/SplashFontFile.cc -o CMakeFiles/splash_objs.dir/SplashFontFile.cc.s + +splash/CMakeFiles/splash_objs.dir/SplashFontFileID.cc.o: splash/CMakeFiles/splash_objs.dir/flags.make +splash/CMakeFiles/splash_objs.dir/SplashFontFileID.cc.o: splash/SplashFontFileID.cc + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/calvin/src/xpdf-4.04/CMakeFiles --progress-num=$(CMAKE_PROGRESS_10) "Building CXX object splash/CMakeFiles/splash_objs.dir/SplashFontFileID.cc.o" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/splash_objs.dir/SplashFontFileID.cc.o -c /home/calvin/src/xpdf-4.04/splash/SplashFontFileID.cc + +splash/CMakeFiles/splash_objs.dir/SplashFontFileID.cc.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/splash_objs.dir/SplashFontFileID.cc.i" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/calvin/src/xpdf-4.04/splash/SplashFontFileID.cc > CMakeFiles/splash_objs.dir/SplashFontFileID.cc.i + +splash/CMakeFiles/splash_objs.dir/SplashFontFileID.cc.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/splash_objs.dir/SplashFontFileID.cc.s" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/calvin/src/xpdf-4.04/splash/SplashFontFileID.cc -o CMakeFiles/splash_objs.dir/SplashFontFileID.cc.s + +splash/CMakeFiles/splash_objs.dir/SplashPath.cc.o: splash/CMakeFiles/splash_objs.dir/flags.make +splash/CMakeFiles/splash_objs.dir/SplashPath.cc.o: splash/SplashPath.cc + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/calvin/src/xpdf-4.04/CMakeFiles --progress-num=$(CMAKE_PROGRESS_11) "Building CXX object splash/CMakeFiles/splash_objs.dir/SplashPath.cc.o" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/splash_objs.dir/SplashPath.cc.o -c /home/calvin/src/xpdf-4.04/splash/SplashPath.cc + +splash/CMakeFiles/splash_objs.dir/SplashPath.cc.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/splash_objs.dir/SplashPath.cc.i" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/calvin/src/xpdf-4.04/splash/SplashPath.cc > CMakeFiles/splash_objs.dir/SplashPath.cc.i + +splash/CMakeFiles/splash_objs.dir/SplashPath.cc.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/splash_objs.dir/SplashPath.cc.s" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/calvin/src/xpdf-4.04/splash/SplashPath.cc -o CMakeFiles/splash_objs.dir/SplashPath.cc.s + +splash/CMakeFiles/splash_objs.dir/SplashPattern.cc.o: splash/CMakeFiles/splash_objs.dir/flags.make +splash/CMakeFiles/splash_objs.dir/SplashPattern.cc.o: splash/SplashPattern.cc + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/calvin/src/xpdf-4.04/CMakeFiles --progress-num=$(CMAKE_PROGRESS_12) "Building CXX object splash/CMakeFiles/splash_objs.dir/SplashPattern.cc.o" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/splash_objs.dir/SplashPattern.cc.o -c /home/calvin/src/xpdf-4.04/splash/SplashPattern.cc + +splash/CMakeFiles/splash_objs.dir/SplashPattern.cc.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/splash_objs.dir/SplashPattern.cc.i" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/calvin/src/xpdf-4.04/splash/SplashPattern.cc > CMakeFiles/splash_objs.dir/SplashPattern.cc.i + +splash/CMakeFiles/splash_objs.dir/SplashPattern.cc.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/splash_objs.dir/SplashPattern.cc.s" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/calvin/src/xpdf-4.04/splash/SplashPattern.cc -o CMakeFiles/splash_objs.dir/SplashPattern.cc.s + +splash/CMakeFiles/splash_objs.dir/SplashScreen.cc.o: splash/CMakeFiles/splash_objs.dir/flags.make +splash/CMakeFiles/splash_objs.dir/SplashScreen.cc.o: splash/SplashScreen.cc + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/calvin/src/xpdf-4.04/CMakeFiles --progress-num=$(CMAKE_PROGRESS_13) "Building CXX object splash/CMakeFiles/splash_objs.dir/SplashScreen.cc.o" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/splash_objs.dir/SplashScreen.cc.o -c /home/calvin/src/xpdf-4.04/splash/SplashScreen.cc + +splash/CMakeFiles/splash_objs.dir/SplashScreen.cc.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/splash_objs.dir/SplashScreen.cc.i" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/calvin/src/xpdf-4.04/splash/SplashScreen.cc > CMakeFiles/splash_objs.dir/SplashScreen.cc.i + +splash/CMakeFiles/splash_objs.dir/SplashScreen.cc.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/splash_objs.dir/SplashScreen.cc.s" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/calvin/src/xpdf-4.04/splash/SplashScreen.cc -o CMakeFiles/splash_objs.dir/SplashScreen.cc.s + +splash/CMakeFiles/splash_objs.dir/SplashState.cc.o: splash/CMakeFiles/splash_objs.dir/flags.make +splash/CMakeFiles/splash_objs.dir/SplashState.cc.o: splash/SplashState.cc + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/calvin/src/xpdf-4.04/CMakeFiles --progress-num=$(CMAKE_PROGRESS_14) "Building CXX object splash/CMakeFiles/splash_objs.dir/SplashState.cc.o" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/splash_objs.dir/SplashState.cc.o -c /home/calvin/src/xpdf-4.04/splash/SplashState.cc + +splash/CMakeFiles/splash_objs.dir/SplashState.cc.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/splash_objs.dir/SplashState.cc.i" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/calvin/src/xpdf-4.04/splash/SplashState.cc > CMakeFiles/splash_objs.dir/SplashState.cc.i + +splash/CMakeFiles/splash_objs.dir/SplashState.cc.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/splash_objs.dir/SplashState.cc.s" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/calvin/src/xpdf-4.04/splash/SplashState.cc -o CMakeFiles/splash_objs.dir/SplashState.cc.s + +splash/CMakeFiles/splash_objs.dir/SplashXPath.cc.o: splash/CMakeFiles/splash_objs.dir/flags.make +splash/CMakeFiles/splash_objs.dir/SplashXPath.cc.o: splash/SplashXPath.cc + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/calvin/src/xpdf-4.04/CMakeFiles --progress-num=$(CMAKE_PROGRESS_15) "Building CXX object splash/CMakeFiles/splash_objs.dir/SplashXPath.cc.o" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/splash_objs.dir/SplashXPath.cc.o -c /home/calvin/src/xpdf-4.04/splash/SplashXPath.cc + +splash/CMakeFiles/splash_objs.dir/SplashXPath.cc.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/splash_objs.dir/SplashXPath.cc.i" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/calvin/src/xpdf-4.04/splash/SplashXPath.cc > CMakeFiles/splash_objs.dir/SplashXPath.cc.i + +splash/CMakeFiles/splash_objs.dir/SplashXPath.cc.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/splash_objs.dir/SplashXPath.cc.s" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/calvin/src/xpdf-4.04/splash/SplashXPath.cc -o CMakeFiles/splash_objs.dir/SplashXPath.cc.s + +splash/CMakeFiles/splash_objs.dir/SplashXPathScanner.cc.o: splash/CMakeFiles/splash_objs.dir/flags.make +splash/CMakeFiles/splash_objs.dir/SplashXPathScanner.cc.o: splash/SplashXPathScanner.cc + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --progress-dir=/home/calvin/src/xpdf-4.04/CMakeFiles --progress-num=$(CMAKE_PROGRESS_16) "Building CXX object splash/CMakeFiles/splash_objs.dir/SplashXPathScanner.cc.o" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o CMakeFiles/splash_objs.dir/SplashXPathScanner.cc.o -c /home/calvin/src/xpdf-4.04/splash/SplashXPathScanner.cc + +splash/CMakeFiles/splash_objs.dir/SplashXPathScanner.cc.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing CXX source to CMakeFiles/splash_objs.dir/SplashXPathScanner.cc.i" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -E /home/calvin/src/xpdf-4.04/splash/SplashXPathScanner.cc > CMakeFiles/splash_objs.dir/SplashXPathScanner.cc.i + +splash/CMakeFiles/splash_objs.dir/SplashXPathScanner.cc.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling CXX source to assembly CMakeFiles/splash_objs.dir/SplashXPathScanner.cc.s" + cd /home/calvin/src/xpdf-4.04/splash && /usr/bin/c++ $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -S /home/calvin/src/xpdf-4.04/splash/SplashXPathScanner.cc -o CMakeFiles/splash_objs.dir/SplashXPathScanner.cc.s + +splash_objs: splash/CMakeFiles/splash_objs.dir/Splash.cc.o +splash_objs: splash/CMakeFiles/splash_objs.dir/SplashBitmap.cc.o +splash_objs: splash/CMakeFiles/splash_objs.dir/SplashClip.cc.o +splash_objs: splash/CMakeFiles/splash_objs.dir/SplashFTFont.cc.o +splash_objs: splash/CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.o +splash_objs: splash/CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.o +splash_objs: splash/CMakeFiles/splash_objs.dir/SplashFont.cc.o +splash_objs: splash/CMakeFiles/splash_objs.dir/SplashFontEngine.cc.o +splash_objs: splash/CMakeFiles/splash_objs.dir/SplashFontFile.cc.o +splash_objs: splash/CMakeFiles/splash_objs.dir/SplashFontFileID.cc.o +splash_objs: splash/CMakeFiles/splash_objs.dir/SplashPath.cc.o +splash_objs: splash/CMakeFiles/splash_objs.dir/SplashPattern.cc.o +splash_objs: splash/CMakeFiles/splash_objs.dir/SplashScreen.cc.o +splash_objs: splash/CMakeFiles/splash_objs.dir/SplashState.cc.o +splash_objs: splash/CMakeFiles/splash_objs.dir/SplashXPath.cc.o +splash_objs: splash/CMakeFiles/splash_objs.dir/SplashXPathScanner.cc.o +splash_objs: splash/CMakeFiles/splash_objs.dir/build.make + +.PHONY : splash_objs + +# Rule to build all files generated by this target. +splash/CMakeFiles/splash_objs.dir/build: splash_objs + +.PHONY : splash/CMakeFiles/splash_objs.dir/build + +splash/CMakeFiles/splash_objs.dir/clean: + cd /home/calvin/src/xpdf-4.04/splash && $(CMAKE_COMMAND) -P CMakeFiles/splash_objs.dir/cmake_clean.cmake +.PHONY : splash/CMakeFiles/splash_objs.dir/clean + +splash/CMakeFiles/splash_objs.dir/depend: + cd /home/calvin/src/xpdf-4.04 && $(CMAKE_COMMAND) -E cmake_depends "Unix Makefiles" /home/calvin/src/xpdf-4.04 /home/calvin/src/xpdf-4.04/splash /home/calvin/src/xpdf-4.04 /home/calvin/src/xpdf-4.04/splash /home/calvin/src/xpdf-4.04/splash/CMakeFiles/splash_objs.dir/DependInfo.cmake --color=$(COLOR) +.PHONY : splash/CMakeFiles/splash_objs.dir/depend + diff --git a/splash/CMakeFiles/splash_objs.dir/cmake_clean.cmake b/splash/CMakeFiles/splash_objs.dir/cmake_clean.cmake new file mode 100644 index 0000000..4ddf7b4 --- /dev/null +++ b/splash/CMakeFiles/splash_objs.dir/cmake_clean.cmake @@ -0,0 +1,23 @@ +file(REMOVE_RECURSE + "CMakeFiles/splash_objs.dir/Splash.cc.o" + "CMakeFiles/splash_objs.dir/SplashBitmap.cc.o" + "CMakeFiles/splash_objs.dir/SplashClip.cc.o" + "CMakeFiles/splash_objs.dir/SplashFTFont.cc.o" + "CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.o" + "CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.o" + "CMakeFiles/splash_objs.dir/SplashFont.cc.o" + "CMakeFiles/splash_objs.dir/SplashFontEngine.cc.o" + "CMakeFiles/splash_objs.dir/SplashFontFile.cc.o" + "CMakeFiles/splash_objs.dir/SplashFontFileID.cc.o" + "CMakeFiles/splash_objs.dir/SplashPath.cc.o" + "CMakeFiles/splash_objs.dir/SplashPattern.cc.o" + "CMakeFiles/splash_objs.dir/SplashScreen.cc.o" + "CMakeFiles/splash_objs.dir/SplashState.cc.o" + "CMakeFiles/splash_objs.dir/SplashXPath.cc.o" + "CMakeFiles/splash_objs.dir/SplashXPathScanner.cc.o" +) + +# Per-language clean rules from dependency scanning. +foreach(lang CXX) + include(CMakeFiles/splash_objs.dir/cmake_clean_${lang}.cmake OPTIONAL) +endforeach() diff --git a/splash/CMakeFiles/splash_objs.dir/depend.internal b/splash/CMakeFiles/splash_objs.dir/depend.internal new file mode 100644 index 0000000..c3ffc51 --- /dev/null +++ b/splash/CMakeFiles/splash_objs.dir/depend.internal @@ -0,0 +1,240 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.18 + +splash/CMakeFiles/splash_objs.dir/Splash.cc.o + /home/calvin/src/xpdf-4.04/splash/Splash.cc + /home/calvin/src/xpdf-4.04/splash/Splash.h + /home/calvin/src/xpdf-4.04/splash/SplashBitmap.h + /home/calvin/src/xpdf-4.04/splash/SplashClip.h + /home/calvin/src/xpdf-4.04/splash/SplashErrorCodes.h + /home/calvin/src/xpdf-4.04/splash/SplashFont.h + /home/calvin/src/xpdf-4.04/splash/SplashGlyphBitmap.h + /home/calvin/src/xpdf-4.04/splash/SplashMath.h + /home/calvin/src/xpdf-4.04/splash/SplashPath.h + /home/calvin/src/xpdf-4.04/splash/SplashPattern.h + /home/calvin/src/xpdf-4.04/splash/SplashScreen.h + /home/calvin/src/xpdf-4.04/splash/SplashState.h + /home/calvin/src/xpdf-4.04/splash/SplashTypes.h + /home/calvin/src/xpdf-4.04/splash/SplashXPath.h + /home/calvin/src/xpdf-4.04/splash/SplashXPathScanner.h + aconf.h + aconf2.h + goo/FixedPoint.h + goo/GString.h + goo/gmem.h + goo/gmempp.h + goo/gtypes.h +splash/CMakeFiles/splash_objs.dir/SplashBitmap.cc.o + /home/calvin/src/xpdf-4.04/splash/SplashBitmap.cc + /home/calvin/src/xpdf-4.04/splash/SplashBitmap.h + /home/calvin/src/xpdf-4.04/splash/SplashErrorCodes.h + /home/calvin/src/xpdf-4.04/splash/SplashTypes.h + aconf.h + aconf2.h + goo/FixedPoint.h + goo/Trace.h + goo/gfile.h + goo/gmem.h + goo/gmempp.h + goo/gtypes.h +splash/CMakeFiles/splash_objs.dir/SplashClip.cc.o + /home/calvin/src/xpdf-4.04/splash/SplashClip.cc + /home/calvin/src/xpdf-4.04/splash/SplashClip.h + /home/calvin/src/xpdf-4.04/splash/SplashErrorCodes.h + /home/calvin/src/xpdf-4.04/splash/SplashMath.h + /home/calvin/src/xpdf-4.04/splash/SplashPath.h + /home/calvin/src/xpdf-4.04/splash/SplashTypes.h + /home/calvin/src/xpdf-4.04/splash/SplashXPath.h + /home/calvin/src/xpdf-4.04/splash/SplashXPathScanner.h + aconf.h + aconf2.h + goo/FixedPoint.h + goo/gmem.h + goo/gmempp.h + goo/gtypes.h +splash/CMakeFiles/splash_objs.dir/SplashFTFont.cc.o + /home/calvin/src/xpdf-4.04/splash/SplashFTFont.cc + /home/calvin/src/xpdf-4.04/splash/SplashFTFont.h + /home/calvin/src/xpdf-4.04/splash/SplashFTFontEngine.h + /home/calvin/src/xpdf-4.04/splash/SplashFTFontFile.h + /home/calvin/src/xpdf-4.04/splash/SplashFont.h + /home/calvin/src/xpdf-4.04/splash/SplashFontEngine.h + /home/calvin/src/xpdf-4.04/splash/SplashFontFile.h + /home/calvin/src/xpdf-4.04/splash/SplashGlyphBitmap.h + /home/calvin/src/xpdf-4.04/splash/SplashMath.h + /home/calvin/src/xpdf-4.04/splash/SplashPath.h + /home/calvin/src/xpdf-4.04/splash/SplashTypes.h + /usr/include/freetype2/freetype/config/ftheader.h + /usr/include/freetype2/ft2build.h + aconf.h + aconf2.h + goo/FixedPoint.h + goo/GMutex.h + goo/gmem.h + goo/gmempp.h + goo/gtypes.h +splash/CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.o + /home/calvin/src/xpdf-4.04/splash/SplashFTFontEngine.cc + /home/calvin/src/xpdf-4.04/splash/SplashFTFontEngine.h + /home/calvin/src/xpdf-4.04/splash/SplashFTFontFile.h + /home/calvin/src/xpdf-4.04/splash/SplashFontFile.h + /home/calvin/src/xpdf-4.04/splash/SplashTypes.h + /usr/include/freetype2/freetype/config/ftheader.h + /usr/include/freetype2/ft2build.h + aconf.h + aconf2.h + fofi/FoFiBase.h + fofi/FoFiTrueType.h + fofi/FoFiType1C.h + goo/FixedPoint.h + goo/GMutex.h + goo/GString.h + goo/gfile.h + goo/gmem.h + goo/gmempp.h + goo/gtypes.h +splash/CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.o + /home/calvin/src/xpdf-4.04/splash/SplashFTFont.h + /home/calvin/src/xpdf-4.04/splash/SplashFTFontEngine.h + /home/calvin/src/xpdf-4.04/splash/SplashFTFontFile.cc + /home/calvin/src/xpdf-4.04/splash/SplashFTFontFile.h + /home/calvin/src/xpdf-4.04/splash/SplashFont.h + /home/calvin/src/xpdf-4.04/splash/SplashFontFile.h + /home/calvin/src/xpdf-4.04/splash/SplashMath.h + /home/calvin/src/xpdf-4.04/splash/SplashTypes.h + /usr/include/freetype2/freetype/config/ftheader.h + /usr/include/freetype2/ft2build.h + aconf.h + aconf2.h + goo/FixedPoint.h + goo/GMutex.h + goo/GString.h + goo/gmem.h + goo/gmempp.h + goo/gtypes.h +splash/CMakeFiles/splash_objs.dir/SplashFont.cc.o + /home/calvin/src/xpdf-4.04/splash/SplashFont.cc + /home/calvin/src/xpdf-4.04/splash/SplashFont.h + /home/calvin/src/xpdf-4.04/splash/SplashFontFile.h + /home/calvin/src/xpdf-4.04/splash/SplashGlyphBitmap.h + /home/calvin/src/xpdf-4.04/splash/SplashMath.h + /home/calvin/src/xpdf-4.04/splash/SplashTypes.h + aconf.h + aconf2.h + goo/FixedPoint.h + goo/GMutex.h + goo/gmem.h + goo/gmempp.h + goo/gtypes.h +splash/CMakeFiles/splash_objs.dir/SplashFontEngine.cc.o + /home/calvin/src/xpdf-4.04/splash/SplashFTFontEngine.h + /home/calvin/src/xpdf-4.04/splash/SplashFont.h + /home/calvin/src/xpdf-4.04/splash/SplashFontEngine.cc + /home/calvin/src/xpdf-4.04/splash/SplashFontEngine.h + /home/calvin/src/xpdf-4.04/splash/SplashFontFile.h + /home/calvin/src/xpdf-4.04/splash/SplashFontFileID.h + /home/calvin/src/xpdf-4.04/splash/SplashMath.h + /home/calvin/src/xpdf-4.04/splash/SplashTypes.h + /usr/include/freetype2/freetype/config/ftheader.h + /usr/include/freetype2/ft2build.h + aconf.h + aconf2.h + goo/FixedPoint.h + goo/GList.h + goo/GMutex.h + goo/GString.h + goo/gmem.h + goo/gmempp.h + goo/gtypes.h +splash/CMakeFiles/splash_objs.dir/SplashFontFile.cc.o + /home/calvin/src/xpdf-4.04/splash/SplashFontFile.cc + /home/calvin/src/xpdf-4.04/splash/SplashFontFile.h + /home/calvin/src/xpdf-4.04/splash/SplashFontFileID.h + /home/calvin/src/xpdf-4.04/splash/SplashTypes.h + aconf.h + aconf2.h + goo/FixedPoint.h + goo/GMutex.h + goo/GString.h + goo/gmempp.h + goo/gtypes.h +splash/CMakeFiles/splash_objs.dir/SplashFontFileID.cc.o + /home/calvin/src/xpdf-4.04/splash/SplashFontFileID.cc + /home/calvin/src/xpdf-4.04/splash/SplashFontFileID.h + aconf.h + aconf2.h + goo/gmempp.h + goo/gtypes.h +splash/CMakeFiles/splash_objs.dir/SplashPath.cc.o + /home/calvin/src/xpdf-4.04/splash/SplashErrorCodes.h + /home/calvin/src/xpdf-4.04/splash/SplashPath.cc + /home/calvin/src/xpdf-4.04/splash/SplashPath.h + /home/calvin/src/xpdf-4.04/splash/SplashTypes.h + aconf.h + aconf2.h + goo/FixedPoint.h + goo/gmem.h + goo/gmempp.h + goo/gtypes.h +splash/CMakeFiles/splash_objs.dir/SplashPattern.cc.o + /home/calvin/src/xpdf-4.04/splash/SplashMath.h + /home/calvin/src/xpdf-4.04/splash/SplashPattern.cc + /home/calvin/src/xpdf-4.04/splash/SplashPattern.h + /home/calvin/src/xpdf-4.04/splash/SplashScreen.h + /home/calvin/src/xpdf-4.04/splash/SplashTypes.h + aconf.h + aconf2.h + goo/FixedPoint.h + goo/gmempp.h + goo/gtypes.h +splash/CMakeFiles/splash_objs.dir/SplashScreen.cc.o + /home/calvin/src/xpdf-4.04/splash/SplashMath.h + /home/calvin/src/xpdf-4.04/splash/SplashScreen.cc + /home/calvin/src/xpdf-4.04/splash/SplashScreen.h + /home/calvin/src/xpdf-4.04/splash/SplashTypes.h + aconf.h + aconf2.h + goo/FixedPoint.h + goo/gmem.h + goo/gmempp.h + goo/gtypes.h +splash/CMakeFiles/splash_objs.dir/SplashState.cc.o + /home/calvin/src/xpdf-4.04/splash/SplashBitmap.h + /home/calvin/src/xpdf-4.04/splash/SplashClip.h + /home/calvin/src/xpdf-4.04/splash/SplashMath.h + /home/calvin/src/xpdf-4.04/splash/SplashPattern.h + /home/calvin/src/xpdf-4.04/splash/SplashScreen.h + /home/calvin/src/xpdf-4.04/splash/SplashState.cc + /home/calvin/src/xpdf-4.04/splash/SplashState.h + /home/calvin/src/xpdf-4.04/splash/SplashTypes.h + aconf.h + aconf2.h + goo/FixedPoint.h + goo/gmem.h + goo/gmempp.h + goo/gtypes.h +splash/CMakeFiles/splash_objs.dir/SplashXPath.cc.o + /home/calvin/src/xpdf-4.04/splash/SplashMath.h + /home/calvin/src/xpdf-4.04/splash/SplashPath.h + /home/calvin/src/xpdf-4.04/splash/SplashTypes.h + /home/calvin/src/xpdf-4.04/splash/SplashXPath.cc + /home/calvin/src/xpdf-4.04/splash/SplashXPath.h + aconf.h + aconf2.h + goo/FixedPoint.h + goo/gmem.h + goo/gmempp.h + goo/gtypes.h +splash/CMakeFiles/splash_objs.dir/SplashXPathScanner.cc.o + /home/calvin/src/xpdf-4.04/splash/SplashMath.h + /home/calvin/src/xpdf-4.04/splash/SplashTypes.h + /home/calvin/src/xpdf-4.04/splash/SplashXPath.h + /home/calvin/src/xpdf-4.04/splash/SplashXPathScanner.cc + /home/calvin/src/xpdf-4.04/splash/SplashXPathScanner.h + aconf.h + aconf2.h + goo/FixedPoint.h + goo/GList.h + goo/gmem.h + goo/gmempp.h + goo/gtypes.h diff --git a/splash/CMakeFiles/splash_objs.dir/depend.make b/splash/CMakeFiles/splash_objs.dir/depend.make new file mode 100644 index 0000000..a0f85ab --- /dev/null +++ b/splash/CMakeFiles/splash_objs.dir/depend.make @@ -0,0 +1,240 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.18 + +splash/CMakeFiles/splash_objs.dir/Splash.cc.o: splash/Splash.cc +splash/CMakeFiles/splash_objs.dir/Splash.cc.o: splash/Splash.h +splash/CMakeFiles/splash_objs.dir/Splash.cc.o: splash/SplashBitmap.h +splash/CMakeFiles/splash_objs.dir/Splash.cc.o: splash/SplashClip.h +splash/CMakeFiles/splash_objs.dir/Splash.cc.o: splash/SplashErrorCodes.h +splash/CMakeFiles/splash_objs.dir/Splash.cc.o: splash/SplashFont.h +splash/CMakeFiles/splash_objs.dir/Splash.cc.o: splash/SplashGlyphBitmap.h +splash/CMakeFiles/splash_objs.dir/Splash.cc.o: splash/SplashMath.h +splash/CMakeFiles/splash_objs.dir/Splash.cc.o: splash/SplashPath.h +splash/CMakeFiles/splash_objs.dir/Splash.cc.o: splash/SplashPattern.h +splash/CMakeFiles/splash_objs.dir/Splash.cc.o: splash/SplashScreen.h +splash/CMakeFiles/splash_objs.dir/Splash.cc.o: splash/SplashState.h +splash/CMakeFiles/splash_objs.dir/Splash.cc.o: splash/SplashTypes.h +splash/CMakeFiles/splash_objs.dir/Splash.cc.o: splash/SplashXPath.h +splash/CMakeFiles/splash_objs.dir/Splash.cc.o: splash/SplashXPathScanner.h +splash/CMakeFiles/splash_objs.dir/Splash.cc.o: aconf.h +splash/CMakeFiles/splash_objs.dir/Splash.cc.o: aconf2.h +splash/CMakeFiles/splash_objs.dir/Splash.cc.o: goo/FixedPoint.h +splash/CMakeFiles/splash_objs.dir/Splash.cc.o: goo/GString.h +splash/CMakeFiles/splash_objs.dir/Splash.cc.o: goo/gmem.h +splash/CMakeFiles/splash_objs.dir/Splash.cc.o: goo/gmempp.h +splash/CMakeFiles/splash_objs.dir/Splash.cc.o: goo/gtypes.h + +splash/CMakeFiles/splash_objs.dir/SplashBitmap.cc.o: splash/SplashBitmap.cc +splash/CMakeFiles/splash_objs.dir/SplashBitmap.cc.o: splash/SplashBitmap.h +splash/CMakeFiles/splash_objs.dir/SplashBitmap.cc.o: splash/SplashErrorCodes.h +splash/CMakeFiles/splash_objs.dir/SplashBitmap.cc.o: splash/SplashTypes.h +splash/CMakeFiles/splash_objs.dir/SplashBitmap.cc.o: aconf.h +splash/CMakeFiles/splash_objs.dir/SplashBitmap.cc.o: aconf2.h +splash/CMakeFiles/splash_objs.dir/SplashBitmap.cc.o: goo/FixedPoint.h +splash/CMakeFiles/splash_objs.dir/SplashBitmap.cc.o: goo/Trace.h +splash/CMakeFiles/splash_objs.dir/SplashBitmap.cc.o: goo/gfile.h +splash/CMakeFiles/splash_objs.dir/SplashBitmap.cc.o: goo/gmem.h +splash/CMakeFiles/splash_objs.dir/SplashBitmap.cc.o: goo/gmempp.h +splash/CMakeFiles/splash_objs.dir/SplashBitmap.cc.o: goo/gtypes.h + +splash/CMakeFiles/splash_objs.dir/SplashClip.cc.o: splash/SplashClip.cc +splash/CMakeFiles/splash_objs.dir/SplashClip.cc.o: splash/SplashClip.h +splash/CMakeFiles/splash_objs.dir/SplashClip.cc.o: splash/SplashErrorCodes.h +splash/CMakeFiles/splash_objs.dir/SplashClip.cc.o: splash/SplashMath.h +splash/CMakeFiles/splash_objs.dir/SplashClip.cc.o: splash/SplashPath.h +splash/CMakeFiles/splash_objs.dir/SplashClip.cc.o: splash/SplashTypes.h +splash/CMakeFiles/splash_objs.dir/SplashClip.cc.o: splash/SplashXPath.h +splash/CMakeFiles/splash_objs.dir/SplashClip.cc.o: splash/SplashXPathScanner.h +splash/CMakeFiles/splash_objs.dir/SplashClip.cc.o: aconf.h +splash/CMakeFiles/splash_objs.dir/SplashClip.cc.o: aconf2.h +splash/CMakeFiles/splash_objs.dir/SplashClip.cc.o: goo/FixedPoint.h +splash/CMakeFiles/splash_objs.dir/SplashClip.cc.o: goo/gmem.h +splash/CMakeFiles/splash_objs.dir/SplashClip.cc.o: goo/gmempp.h +splash/CMakeFiles/splash_objs.dir/SplashClip.cc.o: goo/gtypes.h + +splash/CMakeFiles/splash_objs.dir/SplashFTFont.cc.o: splash/SplashFTFont.cc +splash/CMakeFiles/splash_objs.dir/SplashFTFont.cc.o: splash/SplashFTFont.h +splash/CMakeFiles/splash_objs.dir/SplashFTFont.cc.o: splash/SplashFTFontEngine.h +splash/CMakeFiles/splash_objs.dir/SplashFTFont.cc.o: splash/SplashFTFontFile.h +splash/CMakeFiles/splash_objs.dir/SplashFTFont.cc.o: splash/SplashFont.h +splash/CMakeFiles/splash_objs.dir/SplashFTFont.cc.o: splash/SplashFontEngine.h +splash/CMakeFiles/splash_objs.dir/SplashFTFont.cc.o: splash/SplashFontFile.h +splash/CMakeFiles/splash_objs.dir/SplashFTFont.cc.o: splash/SplashGlyphBitmap.h +splash/CMakeFiles/splash_objs.dir/SplashFTFont.cc.o: splash/SplashMath.h +splash/CMakeFiles/splash_objs.dir/SplashFTFont.cc.o: splash/SplashPath.h +splash/CMakeFiles/splash_objs.dir/SplashFTFont.cc.o: splash/SplashTypes.h +splash/CMakeFiles/splash_objs.dir/SplashFTFont.cc.o: /usr/include/freetype2/freetype/config/ftheader.h +splash/CMakeFiles/splash_objs.dir/SplashFTFont.cc.o: /usr/include/freetype2/ft2build.h +splash/CMakeFiles/splash_objs.dir/SplashFTFont.cc.o: aconf.h +splash/CMakeFiles/splash_objs.dir/SplashFTFont.cc.o: aconf2.h +splash/CMakeFiles/splash_objs.dir/SplashFTFont.cc.o: goo/FixedPoint.h +splash/CMakeFiles/splash_objs.dir/SplashFTFont.cc.o: goo/GMutex.h +splash/CMakeFiles/splash_objs.dir/SplashFTFont.cc.o: goo/gmem.h +splash/CMakeFiles/splash_objs.dir/SplashFTFont.cc.o: goo/gmempp.h +splash/CMakeFiles/splash_objs.dir/SplashFTFont.cc.o: goo/gtypes.h + +splash/CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.o: splash/SplashFTFontEngine.cc +splash/CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.o: splash/SplashFTFontEngine.h +splash/CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.o: splash/SplashFTFontFile.h +splash/CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.o: splash/SplashFontFile.h +splash/CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.o: splash/SplashTypes.h +splash/CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.o: /usr/include/freetype2/freetype/config/ftheader.h +splash/CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.o: /usr/include/freetype2/ft2build.h +splash/CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.o: aconf.h +splash/CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.o: aconf2.h +splash/CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.o: fofi/FoFiBase.h +splash/CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.o: fofi/FoFiTrueType.h +splash/CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.o: fofi/FoFiType1C.h +splash/CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.o: goo/FixedPoint.h +splash/CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.o: goo/GMutex.h +splash/CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.o: goo/GString.h +splash/CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.o: goo/gfile.h +splash/CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.o: goo/gmem.h +splash/CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.o: goo/gmempp.h +splash/CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.o: goo/gtypes.h + +splash/CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.o: splash/SplashFTFont.h +splash/CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.o: splash/SplashFTFontEngine.h +splash/CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.o: splash/SplashFTFontFile.cc +splash/CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.o: splash/SplashFTFontFile.h +splash/CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.o: splash/SplashFont.h +splash/CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.o: splash/SplashFontFile.h +splash/CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.o: splash/SplashMath.h +splash/CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.o: splash/SplashTypes.h +splash/CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.o: /usr/include/freetype2/freetype/config/ftheader.h +splash/CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.o: /usr/include/freetype2/ft2build.h +splash/CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.o: aconf.h +splash/CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.o: aconf2.h +splash/CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.o: goo/FixedPoint.h +splash/CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.o: goo/GMutex.h +splash/CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.o: goo/GString.h +splash/CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.o: goo/gmem.h +splash/CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.o: goo/gmempp.h +splash/CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.o: goo/gtypes.h + +splash/CMakeFiles/splash_objs.dir/SplashFont.cc.o: splash/SplashFont.cc +splash/CMakeFiles/splash_objs.dir/SplashFont.cc.o: splash/SplashFont.h +splash/CMakeFiles/splash_objs.dir/SplashFont.cc.o: splash/SplashFontFile.h +splash/CMakeFiles/splash_objs.dir/SplashFont.cc.o: splash/SplashGlyphBitmap.h +splash/CMakeFiles/splash_objs.dir/SplashFont.cc.o: splash/SplashMath.h +splash/CMakeFiles/splash_objs.dir/SplashFont.cc.o: splash/SplashTypes.h +splash/CMakeFiles/splash_objs.dir/SplashFont.cc.o: aconf.h +splash/CMakeFiles/splash_objs.dir/SplashFont.cc.o: aconf2.h +splash/CMakeFiles/splash_objs.dir/SplashFont.cc.o: goo/FixedPoint.h +splash/CMakeFiles/splash_objs.dir/SplashFont.cc.o: goo/GMutex.h +splash/CMakeFiles/splash_objs.dir/SplashFont.cc.o: goo/gmem.h +splash/CMakeFiles/splash_objs.dir/SplashFont.cc.o: goo/gmempp.h +splash/CMakeFiles/splash_objs.dir/SplashFont.cc.o: goo/gtypes.h + +splash/CMakeFiles/splash_objs.dir/SplashFontEngine.cc.o: splash/SplashFTFontEngine.h +splash/CMakeFiles/splash_objs.dir/SplashFontEngine.cc.o: splash/SplashFont.h +splash/CMakeFiles/splash_objs.dir/SplashFontEngine.cc.o: splash/SplashFontEngine.cc +splash/CMakeFiles/splash_objs.dir/SplashFontEngine.cc.o: splash/SplashFontEngine.h +splash/CMakeFiles/splash_objs.dir/SplashFontEngine.cc.o: splash/SplashFontFile.h +splash/CMakeFiles/splash_objs.dir/SplashFontEngine.cc.o: splash/SplashFontFileID.h +splash/CMakeFiles/splash_objs.dir/SplashFontEngine.cc.o: splash/SplashMath.h +splash/CMakeFiles/splash_objs.dir/SplashFontEngine.cc.o: splash/SplashTypes.h +splash/CMakeFiles/splash_objs.dir/SplashFontEngine.cc.o: /usr/include/freetype2/freetype/config/ftheader.h +splash/CMakeFiles/splash_objs.dir/SplashFontEngine.cc.o: /usr/include/freetype2/ft2build.h +splash/CMakeFiles/splash_objs.dir/SplashFontEngine.cc.o: aconf.h +splash/CMakeFiles/splash_objs.dir/SplashFontEngine.cc.o: aconf2.h +splash/CMakeFiles/splash_objs.dir/SplashFontEngine.cc.o: goo/FixedPoint.h +splash/CMakeFiles/splash_objs.dir/SplashFontEngine.cc.o: goo/GList.h +splash/CMakeFiles/splash_objs.dir/SplashFontEngine.cc.o: goo/GMutex.h +splash/CMakeFiles/splash_objs.dir/SplashFontEngine.cc.o: goo/GString.h +splash/CMakeFiles/splash_objs.dir/SplashFontEngine.cc.o: goo/gmem.h +splash/CMakeFiles/splash_objs.dir/SplashFontEngine.cc.o: goo/gmempp.h +splash/CMakeFiles/splash_objs.dir/SplashFontEngine.cc.o: goo/gtypes.h + +splash/CMakeFiles/splash_objs.dir/SplashFontFile.cc.o: splash/SplashFontFile.cc +splash/CMakeFiles/splash_objs.dir/SplashFontFile.cc.o: splash/SplashFontFile.h +splash/CMakeFiles/splash_objs.dir/SplashFontFile.cc.o: splash/SplashFontFileID.h +splash/CMakeFiles/splash_objs.dir/SplashFontFile.cc.o: splash/SplashTypes.h +splash/CMakeFiles/splash_objs.dir/SplashFontFile.cc.o: aconf.h +splash/CMakeFiles/splash_objs.dir/SplashFontFile.cc.o: aconf2.h +splash/CMakeFiles/splash_objs.dir/SplashFontFile.cc.o: goo/FixedPoint.h +splash/CMakeFiles/splash_objs.dir/SplashFontFile.cc.o: goo/GMutex.h +splash/CMakeFiles/splash_objs.dir/SplashFontFile.cc.o: goo/GString.h +splash/CMakeFiles/splash_objs.dir/SplashFontFile.cc.o: goo/gmempp.h +splash/CMakeFiles/splash_objs.dir/SplashFontFile.cc.o: goo/gtypes.h + +splash/CMakeFiles/splash_objs.dir/SplashFontFileID.cc.o: splash/SplashFontFileID.cc +splash/CMakeFiles/splash_objs.dir/SplashFontFileID.cc.o: splash/SplashFontFileID.h +splash/CMakeFiles/splash_objs.dir/SplashFontFileID.cc.o: aconf.h +splash/CMakeFiles/splash_objs.dir/SplashFontFileID.cc.o: aconf2.h +splash/CMakeFiles/splash_objs.dir/SplashFontFileID.cc.o: goo/gmempp.h +splash/CMakeFiles/splash_objs.dir/SplashFontFileID.cc.o: goo/gtypes.h + +splash/CMakeFiles/splash_objs.dir/SplashPath.cc.o: splash/SplashErrorCodes.h +splash/CMakeFiles/splash_objs.dir/SplashPath.cc.o: splash/SplashPath.cc +splash/CMakeFiles/splash_objs.dir/SplashPath.cc.o: splash/SplashPath.h +splash/CMakeFiles/splash_objs.dir/SplashPath.cc.o: splash/SplashTypes.h +splash/CMakeFiles/splash_objs.dir/SplashPath.cc.o: aconf.h +splash/CMakeFiles/splash_objs.dir/SplashPath.cc.o: aconf2.h +splash/CMakeFiles/splash_objs.dir/SplashPath.cc.o: goo/FixedPoint.h +splash/CMakeFiles/splash_objs.dir/SplashPath.cc.o: goo/gmem.h +splash/CMakeFiles/splash_objs.dir/SplashPath.cc.o: goo/gmempp.h +splash/CMakeFiles/splash_objs.dir/SplashPath.cc.o: goo/gtypes.h + +splash/CMakeFiles/splash_objs.dir/SplashPattern.cc.o: splash/SplashMath.h +splash/CMakeFiles/splash_objs.dir/SplashPattern.cc.o: splash/SplashPattern.cc +splash/CMakeFiles/splash_objs.dir/SplashPattern.cc.o: splash/SplashPattern.h +splash/CMakeFiles/splash_objs.dir/SplashPattern.cc.o: splash/SplashScreen.h +splash/CMakeFiles/splash_objs.dir/SplashPattern.cc.o: splash/SplashTypes.h +splash/CMakeFiles/splash_objs.dir/SplashPattern.cc.o: aconf.h +splash/CMakeFiles/splash_objs.dir/SplashPattern.cc.o: aconf2.h +splash/CMakeFiles/splash_objs.dir/SplashPattern.cc.o: goo/FixedPoint.h +splash/CMakeFiles/splash_objs.dir/SplashPattern.cc.o: goo/gmempp.h +splash/CMakeFiles/splash_objs.dir/SplashPattern.cc.o: goo/gtypes.h + +splash/CMakeFiles/splash_objs.dir/SplashScreen.cc.o: splash/SplashMath.h +splash/CMakeFiles/splash_objs.dir/SplashScreen.cc.o: splash/SplashScreen.cc +splash/CMakeFiles/splash_objs.dir/SplashScreen.cc.o: splash/SplashScreen.h +splash/CMakeFiles/splash_objs.dir/SplashScreen.cc.o: splash/SplashTypes.h +splash/CMakeFiles/splash_objs.dir/SplashScreen.cc.o: aconf.h +splash/CMakeFiles/splash_objs.dir/SplashScreen.cc.o: aconf2.h +splash/CMakeFiles/splash_objs.dir/SplashScreen.cc.o: goo/FixedPoint.h +splash/CMakeFiles/splash_objs.dir/SplashScreen.cc.o: goo/gmem.h +splash/CMakeFiles/splash_objs.dir/SplashScreen.cc.o: goo/gmempp.h +splash/CMakeFiles/splash_objs.dir/SplashScreen.cc.o: goo/gtypes.h + +splash/CMakeFiles/splash_objs.dir/SplashState.cc.o: splash/SplashBitmap.h +splash/CMakeFiles/splash_objs.dir/SplashState.cc.o: splash/SplashClip.h +splash/CMakeFiles/splash_objs.dir/SplashState.cc.o: splash/SplashMath.h +splash/CMakeFiles/splash_objs.dir/SplashState.cc.o: splash/SplashPattern.h +splash/CMakeFiles/splash_objs.dir/SplashState.cc.o: splash/SplashScreen.h +splash/CMakeFiles/splash_objs.dir/SplashState.cc.o: splash/SplashState.cc +splash/CMakeFiles/splash_objs.dir/SplashState.cc.o: splash/SplashState.h +splash/CMakeFiles/splash_objs.dir/SplashState.cc.o: splash/SplashTypes.h +splash/CMakeFiles/splash_objs.dir/SplashState.cc.o: aconf.h +splash/CMakeFiles/splash_objs.dir/SplashState.cc.o: aconf2.h +splash/CMakeFiles/splash_objs.dir/SplashState.cc.o: goo/FixedPoint.h +splash/CMakeFiles/splash_objs.dir/SplashState.cc.o: goo/gmem.h +splash/CMakeFiles/splash_objs.dir/SplashState.cc.o: goo/gmempp.h +splash/CMakeFiles/splash_objs.dir/SplashState.cc.o: goo/gtypes.h + +splash/CMakeFiles/splash_objs.dir/SplashXPath.cc.o: splash/SplashMath.h +splash/CMakeFiles/splash_objs.dir/SplashXPath.cc.o: splash/SplashPath.h +splash/CMakeFiles/splash_objs.dir/SplashXPath.cc.o: splash/SplashTypes.h +splash/CMakeFiles/splash_objs.dir/SplashXPath.cc.o: splash/SplashXPath.cc +splash/CMakeFiles/splash_objs.dir/SplashXPath.cc.o: splash/SplashXPath.h +splash/CMakeFiles/splash_objs.dir/SplashXPath.cc.o: aconf.h +splash/CMakeFiles/splash_objs.dir/SplashXPath.cc.o: aconf2.h +splash/CMakeFiles/splash_objs.dir/SplashXPath.cc.o: goo/FixedPoint.h +splash/CMakeFiles/splash_objs.dir/SplashXPath.cc.o: goo/gmem.h +splash/CMakeFiles/splash_objs.dir/SplashXPath.cc.o: goo/gmempp.h +splash/CMakeFiles/splash_objs.dir/SplashXPath.cc.o: goo/gtypes.h + +splash/CMakeFiles/splash_objs.dir/SplashXPathScanner.cc.o: splash/SplashMath.h +splash/CMakeFiles/splash_objs.dir/SplashXPathScanner.cc.o: splash/SplashTypes.h +splash/CMakeFiles/splash_objs.dir/SplashXPathScanner.cc.o: splash/SplashXPath.h +splash/CMakeFiles/splash_objs.dir/SplashXPathScanner.cc.o: splash/SplashXPathScanner.cc +splash/CMakeFiles/splash_objs.dir/SplashXPathScanner.cc.o: splash/SplashXPathScanner.h +splash/CMakeFiles/splash_objs.dir/SplashXPathScanner.cc.o: aconf.h +splash/CMakeFiles/splash_objs.dir/SplashXPathScanner.cc.o: aconf2.h +splash/CMakeFiles/splash_objs.dir/SplashXPathScanner.cc.o: goo/FixedPoint.h +splash/CMakeFiles/splash_objs.dir/SplashXPathScanner.cc.o: goo/GList.h +splash/CMakeFiles/splash_objs.dir/SplashXPathScanner.cc.o: goo/gmem.h +splash/CMakeFiles/splash_objs.dir/SplashXPathScanner.cc.o: goo/gmempp.h +splash/CMakeFiles/splash_objs.dir/SplashXPathScanner.cc.o: goo/gtypes.h + diff --git a/splash/CMakeFiles/splash_objs.dir/flags.make b/splash/CMakeFiles/splash_objs.dir/flags.make new file mode 100644 index 0000000..2adb3c6 --- /dev/null +++ b/splash/CMakeFiles/splash_objs.dir/flags.make @@ -0,0 +1,10 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.18 + +# compile CXX with /usr/bin/c++ +CXX_DEFINES = + +CXX_INCLUDES = -I/home/calvin/src/xpdf-4.04 -I/home/calvin/src/xpdf-4.04/goo -I/home/calvin/src/xpdf-4.04/fofi -I/usr/include/freetype2 + +CXX_FLAGS = -fPIC + diff --git a/splash/CMakeFiles/splash_objs.dir/progress.make b/splash/CMakeFiles/splash_objs.dir/progress.make new file mode 100644 index 0000000..3fb0f77 --- /dev/null +++ b/splash/CMakeFiles/splash_objs.dir/progress.make @@ -0,0 +1,17 @@ +CMAKE_PROGRESS_1 = 38 +CMAKE_PROGRESS_2 = 39 +CMAKE_PROGRESS_3 = 40 +CMAKE_PROGRESS_4 = +CMAKE_PROGRESS_5 = 41 +CMAKE_PROGRESS_6 = 42 +CMAKE_PROGRESS_7 = +CMAKE_PROGRESS_8 = 43 +CMAKE_PROGRESS_9 = 44 +CMAKE_PROGRESS_10 = 45 +CMAKE_PROGRESS_11 = +CMAKE_PROGRESS_12 = 46 +CMAKE_PROGRESS_13 = 47 +CMAKE_PROGRESS_14 = 48 +CMAKE_PROGRESS_15 = +CMAKE_PROGRESS_16 = 49 + diff --git a/splash/CMakeLists.txt b/splash/CMakeLists.txt new file mode 100644 index 0000000..4ac14ed --- /dev/null +++ b/splash/CMakeLists.txt @@ -0,0 +1,49 @@ +#======================================================================== +# +# splash/CMakeLists.txt +# +# CMake script for the splash library. +# +# Copyright 2015 Glyph & Cog, LLC +# +#======================================================================== + +if (HAVE_SPLASH) + include_directories("${PROJECT_SOURCE_DIR}") + include_directories("${PROJECT_BINARY_DIR}") + include_directories("${PROJECT_SOURCE_DIR}/goo") + include_directories("${PROJECT_SOURCE_DIR}/fofi") + include_directories("${FREETYPE_INCLUDE_DIRS}") + + if (HAVE_DTYPE4_H) + include_directories("${DTYPE_INCLUDE_DIR}") + set(DTYPE_SRCS + SplashDT4Font.cc SplashDT4FontEngine.cc SplashDT4FontFile.cc) + endif () + + add_library(splash_objs OBJECT + Splash.cc + SplashBitmap.cc + SplashClip.cc + SplashFTFont.cc + SplashFTFontEngine.cc + SplashFTFontFile.cc + SplashFont.cc + SplashFontEngine.cc + SplashFontFile.cc + SplashFontFileID.cc + SplashPath.cc + SplashPattern.cc + SplashScreen.cc + SplashState.cc + SplashXPath.cc + SplashXPathScanner.cc + ${DTYPE_SRCS} + ) + set_property(TARGET splash_objs + PROPERTY POSITION_INDEPENDENT_CODE True) + + add_library(splash + $<TARGET_OBJECTS:splash_objs> + ) +endif () diff --git a/splash/Makefile b/splash/Makefile new file mode 100644 index 0000000..cf5a512 --- /dev/null +++ b/splash/Makefile @@ -0,0 +1,715 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 3.18 + +# Default target executed when no arguments are given to make. +default_target: all + +.PHONY : default_target + +# Allow only one "make -f Makefile2" at a time, but pass parallelism. +.NOTPARALLEL: + + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + + +# Disable VCS-based implicit rules. +% : %,v + + +# Disable VCS-based implicit rules. +% : RCS/% + + +# Disable VCS-based implicit rules. +% : RCS/%,v + + +# Disable VCS-based implicit rules. +% : SCCS/s.% + + +# Disable VCS-based implicit rules. +% : s.% + + +.SUFFIXES: .hpux_make_needs_suffix_list + + +# Command-line flag to silence nested $(MAKE). +$(VERBOSE)MAKESILENT = -s + +#Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: + +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /usr/bin/cmake + +# The command to remove a file. +RM = /usr/bin/cmake -E rm -f + +# Escaping for special characters. +EQUALS = = + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /home/calvin/src/xpdf-4.04 + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /home/calvin/src/xpdf-4.04 + +#============================================================================= +# Targets provided globally by CMake. + +# Special rule for the target install/strip +install/strip: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..." + /usr/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake +.PHONY : install/strip + +# Special rule for the target install/strip +install/strip/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..." + /usr/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake +.PHONY : install/strip/fast + +# Special rule for the target install/local +install/local: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..." + /usr/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake +.PHONY : install/local + +# Special rule for the target install/local +install/local/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..." + /usr/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake +.PHONY : install/local/fast + +# Special rule for the target install +install: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." + /usr/bin/cmake -P cmake_install.cmake +.PHONY : install + +# Special rule for the target install +install/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." + /usr/bin/cmake -P cmake_install.cmake +.PHONY : install/fast + +# Special rule for the target list_install_components +list_install_components: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Available install components are: \"Unspecified\"" +.PHONY : list_install_components + +# Special rule for the target list_install_components +list_install_components/fast: list_install_components + +.PHONY : list_install_components/fast + +# Special rule for the target rebuild_cache +rebuild_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..." + /usr/bin/cmake --regenerate-during-build -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : rebuild_cache + +# Special rule for the target rebuild_cache +rebuild_cache/fast: rebuild_cache + +.PHONY : rebuild_cache/fast + +# Special rule for the target edit_cache +edit_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "No interactive CMake dialog available..." + /usr/bin/cmake -E echo No\ interactive\ CMake\ dialog\ available. +.PHONY : edit_cache + +# Special rule for the target edit_cache +edit_cache/fast: edit_cache + +.PHONY : edit_cache/fast + +# The main all target +all: cmake_check_build_system + cd /home/calvin/src/xpdf-4.04 && $(CMAKE_COMMAND) -E cmake_progress_start /home/calvin/src/xpdf-4.04/CMakeFiles /home/calvin/src/xpdf-4.04/splash//CMakeFiles/progress.marks + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 splash/all + $(CMAKE_COMMAND) -E cmake_progress_start /home/calvin/src/xpdf-4.04/CMakeFiles 0 +.PHONY : all + +# The main clean target +clean: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 splash/clean +.PHONY : clean + +# The main clean target +clean/fast: clean + +.PHONY : clean/fast + +# Prepare targets for installation. +preinstall: all + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 splash/preinstall +.PHONY : preinstall + +# Prepare targets for installation. +preinstall/fast: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 splash/preinstall +.PHONY : preinstall/fast + +# clear depends +depend: + cd /home/calvin/src/xpdf-4.04 && $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 +.PHONY : depend + +# Convenience name for target. +splash/CMakeFiles/splash.dir/rule: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 splash/CMakeFiles/splash.dir/rule +.PHONY : splash/CMakeFiles/splash.dir/rule + +# Convenience name for target. +splash: splash/CMakeFiles/splash.dir/rule + +.PHONY : splash + +# fast build rule for target. +splash/fast: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash.dir/build.make splash/CMakeFiles/splash.dir/build +.PHONY : splash/fast + +# Convenience name for target. +splash/CMakeFiles/splash_objs.dir/rule: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f CMakeFiles/Makefile2 splash/CMakeFiles/splash_objs.dir/rule +.PHONY : splash/CMakeFiles/splash_objs.dir/rule + +# Convenience name for target. +splash_objs: splash/CMakeFiles/splash_objs.dir/rule + +.PHONY : splash_objs + +# fast build rule for target. +splash_objs/fast: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/build +.PHONY : splash_objs/fast + +Splash.o: Splash.cc.o + +.PHONY : Splash.o + +# target to build an object file +Splash.cc.o: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/Splash.cc.o +.PHONY : Splash.cc.o + +Splash.i: Splash.cc.i + +.PHONY : Splash.i + +# target to preprocess a source file +Splash.cc.i: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/Splash.cc.i +.PHONY : Splash.cc.i + +Splash.s: Splash.cc.s + +.PHONY : Splash.s + +# target to generate assembly for a file +Splash.cc.s: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/Splash.cc.s +.PHONY : Splash.cc.s + +SplashBitmap.o: SplashBitmap.cc.o + +.PHONY : SplashBitmap.o + +# target to build an object file +SplashBitmap.cc.o: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashBitmap.cc.o +.PHONY : SplashBitmap.cc.o + +SplashBitmap.i: SplashBitmap.cc.i + +.PHONY : SplashBitmap.i + +# target to preprocess a source file +SplashBitmap.cc.i: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashBitmap.cc.i +.PHONY : SplashBitmap.cc.i + +SplashBitmap.s: SplashBitmap.cc.s + +.PHONY : SplashBitmap.s + +# target to generate assembly for a file +SplashBitmap.cc.s: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashBitmap.cc.s +.PHONY : SplashBitmap.cc.s + +SplashClip.o: SplashClip.cc.o + +.PHONY : SplashClip.o + +# target to build an object file +SplashClip.cc.o: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashClip.cc.o +.PHONY : SplashClip.cc.o + +SplashClip.i: SplashClip.cc.i + +.PHONY : SplashClip.i + +# target to preprocess a source file +SplashClip.cc.i: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashClip.cc.i +.PHONY : SplashClip.cc.i + +SplashClip.s: SplashClip.cc.s + +.PHONY : SplashClip.s + +# target to generate assembly for a file +SplashClip.cc.s: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashClip.cc.s +.PHONY : SplashClip.cc.s + +SplashFTFont.o: SplashFTFont.cc.o + +.PHONY : SplashFTFont.o + +# target to build an object file +SplashFTFont.cc.o: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashFTFont.cc.o +.PHONY : SplashFTFont.cc.o + +SplashFTFont.i: SplashFTFont.cc.i + +.PHONY : SplashFTFont.i + +# target to preprocess a source file +SplashFTFont.cc.i: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashFTFont.cc.i +.PHONY : SplashFTFont.cc.i + +SplashFTFont.s: SplashFTFont.cc.s + +.PHONY : SplashFTFont.s + +# target to generate assembly for a file +SplashFTFont.cc.s: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashFTFont.cc.s +.PHONY : SplashFTFont.cc.s + +SplashFTFontEngine.o: SplashFTFontEngine.cc.o + +.PHONY : SplashFTFontEngine.o + +# target to build an object file +SplashFTFontEngine.cc.o: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.o +.PHONY : SplashFTFontEngine.cc.o + +SplashFTFontEngine.i: SplashFTFontEngine.cc.i + +.PHONY : SplashFTFontEngine.i + +# target to preprocess a source file +SplashFTFontEngine.cc.i: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.i +.PHONY : SplashFTFontEngine.cc.i + +SplashFTFontEngine.s: SplashFTFontEngine.cc.s + +.PHONY : SplashFTFontEngine.s + +# target to generate assembly for a file +SplashFTFontEngine.cc.s: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashFTFontEngine.cc.s +.PHONY : SplashFTFontEngine.cc.s + +SplashFTFontFile.o: SplashFTFontFile.cc.o + +.PHONY : SplashFTFontFile.o + +# target to build an object file +SplashFTFontFile.cc.o: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.o +.PHONY : SplashFTFontFile.cc.o + +SplashFTFontFile.i: SplashFTFontFile.cc.i + +.PHONY : SplashFTFontFile.i + +# target to preprocess a source file +SplashFTFontFile.cc.i: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.i +.PHONY : SplashFTFontFile.cc.i + +SplashFTFontFile.s: SplashFTFontFile.cc.s + +.PHONY : SplashFTFontFile.s + +# target to generate assembly for a file +SplashFTFontFile.cc.s: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashFTFontFile.cc.s +.PHONY : SplashFTFontFile.cc.s + +SplashFont.o: SplashFont.cc.o + +.PHONY : SplashFont.o + +# target to build an object file +SplashFont.cc.o: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashFont.cc.o +.PHONY : SplashFont.cc.o + +SplashFont.i: SplashFont.cc.i + +.PHONY : SplashFont.i + +# target to preprocess a source file +SplashFont.cc.i: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashFont.cc.i +.PHONY : SplashFont.cc.i + +SplashFont.s: SplashFont.cc.s + +.PHONY : SplashFont.s + +# target to generate assembly for a file +SplashFont.cc.s: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashFont.cc.s +.PHONY : SplashFont.cc.s + +SplashFontEngine.o: SplashFontEngine.cc.o + +.PHONY : SplashFontEngine.o + +# target to build an object file +SplashFontEngine.cc.o: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashFontEngine.cc.o +.PHONY : SplashFontEngine.cc.o + +SplashFontEngine.i: SplashFontEngine.cc.i + +.PHONY : SplashFontEngine.i + +# target to preprocess a source file +SplashFontEngine.cc.i: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashFontEngine.cc.i +.PHONY : SplashFontEngine.cc.i + +SplashFontEngine.s: SplashFontEngine.cc.s + +.PHONY : SplashFontEngine.s + +# target to generate assembly for a file +SplashFontEngine.cc.s: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashFontEngine.cc.s +.PHONY : SplashFontEngine.cc.s + +SplashFontFile.o: SplashFontFile.cc.o + +.PHONY : SplashFontFile.o + +# target to build an object file +SplashFontFile.cc.o: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashFontFile.cc.o +.PHONY : SplashFontFile.cc.o + +SplashFontFile.i: SplashFontFile.cc.i + +.PHONY : SplashFontFile.i + +# target to preprocess a source file +SplashFontFile.cc.i: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashFontFile.cc.i +.PHONY : SplashFontFile.cc.i + +SplashFontFile.s: SplashFontFile.cc.s + +.PHONY : SplashFontFile.s + +# target to generate assembly for a file +SplashFontFile.cc.s: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashFontFile.cc.s +.PHONY : SplashFontFile.cc.s + +SplashFontFileID.o: SplashFontFileID.cc.o + +.PHONY : SplashFontFileID.o + +# target to build an object file +SplashFontFileID.cc.o: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashFontFileID.cc.o +.PHONY : SplashFontFileID.cc.o + +SplashFontFileID.i: SplashFontFileID.cc.i + +.PHONY : SplashFontFileID.i + +# target to preprocess a source file +SplashFontFileID.cc.i: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashFontFileID.cc.i +.PHONY : SplashFontFileID.cc.i + +SplashFontFileID.s: SplashFontFileID.cc.s + +.PHONY : SplashFontFileID.s + +# target to generate assembly for a file +SplashFontFileID.cc.s: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashFontFileID.cc.s +.PHONY : SplashFontFileID.cc.s + +SplashPath.o: SplashPath.cc.o + +.PHONY : SplashPath.o + +# target to build an object file +SplashPath.cc.o: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashPath.cc.o +.PHONY : SplashPath.cc.o + +SplashPath.i: SplashPath.cc.i + +.PHONY : SplashPath.i + +# target to preprocess a source file +SplashPath.cc.i: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashPath.cc.i +.PHONY : SplashPath.cc.i + +SplashPath.s: SplashPath.cc.s + +.PHONY : SplashPath.s + +# target to generate assembly for a file +SplashPath.cc.s: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashPath.cc.s +.PHONY : SplashPath.cc.s + +SplashPattern.o: SplashPattern.cc.o + +.PHONY : SplashPattern.o + +# target to build an object file +SplashPattern.cc.o: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashPattern.cc.o +.PHONY : SplashPattern.cc.o + +SplashPattern.i: SplashPattern.cc.i + +.PHONY : SplashPattern.i + +# target to preprocess a source file +SplashPattern.cc.i: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashPattern.cc.i +.PHONY : SplashPattern.cc.i + +SplashPattern.s: SplashPattern.cc.s + +.PHONY : SplashPattern.s + +# target to generate assembly for a file +SplashPattern.cc.s: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashPattern.cc.s +.PHONY : SplashPattern.cc.s + +SplashScreen.o: SplashScreen.cc.o + +.PHONY : SplashScreen.o + +# target to build an object file +SplashScreen.cc.o: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashScreen.cc.o +.PHONY : SplashScreen.cc.o + +SplashScreen.i: SplashScreen.cc.i + +.PHONY : SplashScreen.i + +# target to preprocess a source file +SplashScreen.cc.i: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashScreen.cc.i +.PHONY : SplashScreen.cc.i + +SplashScreen.s: SplashScreen.cc.s + +.PHONY : SplashScreen.s + +# target to generate assembly for a file +SplashScreen.cc.s: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashScreen.cc.s +.PHONY : SplashScreen.cc.s + +SplashState.o: SplashState.cc.o + +.PHONY : SplashState.o + +# target to build an object file +SplashState.cc.o: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashState.cc.o +.PHONY : SplashState.cc.o + +SplashState.i: SplashState.cc.i + +.PHONY : SplashState.i + +# target to preprocess a source file +SplashState.cc.i: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashState.cc.i +.PHONY : SplashState.cc.i + +SplashState.s: SplashState.cc.s + +.PHONY : SplashState.s + +# target to generate assembly for a file +SplashState.cc.s: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashState.cc.s +.PHONY : SplashState.cc.s + +SplashXPath.o: SplashXPath.cc.o + +.PHONY : SplashXPath.o + +# target to build an object file +SplashXPath.cc.o: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashXPath.cc.o +.PHONY : SplashXPath.cc.o + +SplashXPath.i: SplashXPath.cc.i + +.PHONY : SplashXPath.i + +# target to preprocess a source file +SplashXPath.cc.i: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashXPath.cc.i +.PHONY : SplashXPath.cc.i + +SplashXPath.s: SplashXPath.cc.s + +.PHONY : SplashXPath.s + +# target to generate assembly for a file +SplashXPath.cc.s: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashXPath.cc.s +.PHONY : SplashXPath.cc.s + +SplashXPathScanner.o: SplashXPathScanner.cc.o + +.PHONY : SplashXPathScanner.o + +# target to build an object file +SplashXPathScanner.cc.o: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashXPathScanner.cc.o +.PHONY : SplashXPathScanner.cc.o + +SplashXPathScanner.i: SplashXPathScanner.cc.i + +.PHONY : SplashXPathScanner.i + +# target to preprocess a source file +SplashXPathScanner.cc.i: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashXPathScanner.cc.i +.PHONY : SplashXPathScanner.cc.i + +SplashXPathScanner.s: SplashXPathScanner.cc.s + +.PHONY : SplashXPathScanner.s + +# target to generate assembly for a file +SplashXPathScanner.cc.s: + cd /home/calvin/src/xpdf-4.04 && $(MAKE) $(MAKESILENT) -f splash/CMakeFiles/splash_objs.dir/build.make splash/CMakeFiles/splash_objs.dir/SplashXPathScanner.cc.s +.PHONY : SplashXPathScanner.cc.s + +# Help Target +help: + @echo "The following are some of the valid targets for this Makefile:" + @echo "... all (the default if no target is provided)" + @echo "... clean" + @echo "... depend" + @echo "... edit_cache" + @echo "... install" + @echo "... install/local" + @echo "... install/strip" + @echo "... list_install_components" + @echo "... rebuild_cache" + @echo "... splash" + @echo "... splash_objs" + @echo "... Splash.o" + @echo "... Splash.i" + @echo "... Splash.s" + @echo "... SplashBitmap.o" + @echo "... SplashBitmap.i" + @echo "... SplashBitmap.s" + @echo "... SplashClip.o" + @echo "... SplashClip.i" + @echo "... SplashClip.s" + @echo "... SplashFTFont.o" + @echo "... SplashFTFont.i" + @echo "... SplashFTFont.s" + @echo "... SplashFTFontEngine.o" + @echo "... SplashFTFontEngine.i" + @echo "... SplashFTFontEngine.s" + @echo "... SplashFTFontFile.o" + @echo "... SplashFTFontFile.i" + @echo "... SplashFTFontFile.s" + @echo "... SplashFont.o" + @echo "... SplashFont.i" + @echo "... SplashFont.s" + @echo "... SplashFontEngine.o" + @echo "... SplashFontEngine.i" + @echo "... SplashFontEngine.s" + @echo "... SplashFontFile.o" + @echo "... SplashFontFile.i" + @echo "... SplashFontFile.s" + @echo "... SplashFontFileID.o" + @echo "... SplashFontFileID.i" + @echo "... SplashFontFileID.s" + @echo "... SplashPath.o" + @echo "... SplashPath.i" + @echo "... SplashPath.s" + @echo "... SplashPattern.o" + @echo "... SplashPattern.i" + @echo "... SplashPattern.s" + @echo "... SplashScreen.o" + @echo "... SplashScreen.i" + @echo "... SplashScreen.s" + @echo "... SplashState.o" + @echo "... SplashState.i" + @echo "... SplashState.s" + @echo "... SplashXPath.o" + @echo "... SplashXPath.i" + @echo "... SplashXPath.s" + @echo "... SplashXPathScanner.o" + @echo "... SplashXPathScanner.i" + @echo "... SplashXPathScanner.s" +.PHONY : help + + + +#============================================================================= +# Special targets to cleanup operation of make. + +# Special rule to run CMake to check the build system integrity. +# No rule that depends on this can have commands that come from listfiles +# because they might be regenerated. +cmake_check_build_system: + cd /home/calvin/src/xpdf-4.04 && $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 +.PHONY : cmake_check_build_system + diff --git a/splash/Splash.cc b/splash/Splash.cc new file mode 100644 index 0000000..4afe21b --- /dev/null +++ b/splash/Splash.cc @@ -0,0 +1,8521 @@ +//======================================================================== +// +// Splash.cc +// +// Copyright 2003-2020 Glyph & Cog, LLC +// +//======================================================================== + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include <math.h> +#include "gmem.h" +#include "gmempp.h" +#include "GString.h" +#include "SplashErrorCodes.h" +#include "SplashMath.h" +#include "SplashBitmap.h" +#include "SplashState.h" +#include "SplashPath.h" +#include "SplashXPath.h" +#include "SplashXPathScanner.h" +#include "SplashPattern.h" +#include "SplashScreen.h" +#include "SplashFont.h" +#include "SplashGlyphBitmap.h" +#include "Splash.h" + +// the MSVC math.h doesn't define this +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +//------------------------------------------------------------------------ + +// distance of Bezier control point from center for circle approximation +// = (4 * (sqrt(2) - 1) / 3) * r +#define bezierCircle ((SplashCoord)0.55228475) +#define bezierCircle2 ((SplashCoord)(0.5 * 0.55228475)) + +// Divide a 16-bit value (in [0, 255*255]) by 255, returning an 8-bit result. +static inline Guchar div255(int x) { + return (Guchar)((x + (x >> 8) + 0x80) >> 8); +} + +// Clip x to lie in [0, 255]. +static inline Guchar clip255(int x) { + return x < 0 ? 0 : x > 255 ? 255 : (Guchar)x; +} + +// Used by drawImage and fillImageMask to divide the target +// quadrilateral into sections. +struct ImageSection { + int y0, y1; // actual y range + int ia0, ia1; // vertex indices for edge A + int ib0, ib1; // vertex indices for edge B + SplashCoord xa0, ya0, xa1, ya1; // edge A + SplashCoord dxdya; // slope of edge A + SplashCoord xb0, yb0, xb1, yb1; // edge B + SplashCoord dxdyb; // slope of edge B +}; + +//------------------------------------------------------------------------ +// SplashPipe +//------------------------------------------------------------------------ + +#define splashPipeMaxStages 9 + +struct SplashPipe { + // source pattern + SplashPattern *pattern; + + // source alpha and color + Guchar aInput; + SplashColor cSrcVal; + + // source overprint mask + //~ this is a kludge - this pointer should be passed as an arg to the + //~ pipeRun function, but that would require passing in a lot of + //~ null pointers, since it's rarely used + Guint *srcOverprintMaskPtr; + + // special cases and result color + GBool noTransparency; + GBool shapeOnly; + SplashPipeResultColorCtrl resultColorCtrl; + + // non-isolated group correction + // (this is only used when Splash::composite() is called to composite + // a non-isolated group onto the backdrop) + GBool nonIsolatedGroup; + + // the "run" function + void (Splash::*run)(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr); +}; + +SplashPipeResultColorCtrl Splash::pipeResultColorNoAlphaBlend[] = { + splashPipeResultColorNoAlphaBlendMono, + splashPipeResultColorNoAlphaBlendMono, + splashPipeResultColorNoAlphaBlendRGB, + splashPipeResultColorNoAlphaBlendRGB +#if SPLASH_CMYK + , + splashPipeResultColorNoAlphaBlendCMYK +#endif +}; + +SplashPipeResultColorCtrl Splash::pipeResultColorAlphaNoBlend[] = { + splashPipeResultColorAlphaNoBlendMono, + splashPipeResultColorAlphaNoBlendMono, + splashPipeResultColorAlphaNoBlendRGB, + splashPipeResultColorAlphaNoBlendRGB +#if SPLASH_CMYK + , + splashPipeResultColorAlphaNoBlendCMYK +#endif +}; + +SplashPipeResultColorCtrl Splash::pipeResultColorAlphaBlend[] = { + splashPipeResultColorAlphaBlendMono, + splashPipeResultColorAlphaBlendMono, + splashPipeResultColorAlphaBlendRGB, + splashPipeResultColorAlphaBlendRGB +#if SPLASH_CMYK + , + splashPipeResultColorAlphaBlendCMYK +#endif +}; + +//------------------------------------------------------------------------ +// modified region +//------------------------------------------------------------------------ + +void Splash::clearModRegion() { + modXMin = bitmap->width; + modYMin = bitmap->height; + modXMax = -1; + modYMax = -1; +} + +inline void Splash::updateModX(int x) { + if (x < modXMin) { + modXMin = x; + } + if (x > modXMax) { + modXMax = x; + } +} + +inline void Splash::updateModY(int y) { + if (y < modYMin) { + modYMin = y; + } + if (y > modYMax) { + modYMax = y; + } +} + +//------------------------------------------------------------------------ +// pipeline +//------------------------------------------------------------------------ + +inline void Splash::pipeInit(SplashPipe *pipe, SplashPattern *pattern, + Guchar aInput, GBool usesShape, + GBool nonIsolatedGroup, GBool usesSrcOverprint) { + SplashColorMode mode; + + mode = bitmap->mode; + + pipe->pattern = NULL; + + // source color + if (pattern && pattern->isStatic()) { + pattern->getColor(0, 0, pipe->cSrcVal); + pipe->pattern = NULL; + } else { + pipe->pattern = pattern; + } + + // source alpha + pipe->aInput = aInput; + + // source overprint mask + pipe->srcOverprintMaskPtr = NULL; + + // special cases + pipe->noTransparency = aInput == 255 && + !state->softMask && + !usesShape && + !state->inNonIsolatedGroup && + !state->inKnockoutGroup && + !nonIsolatedGroup && + state->overprintMask == 0xffffffff; + pipe->shapeOnly = aInput == 255 && + !state->softMask && + usesShape && + !state->inNonIsolatedGroup && + !state->inKnockoutGroup && + !nonIsolatedGroup && + state->overprintMask == 0xffffffff; + + // result color + if (pipe->noTransparency) { + // the !state->blendFunc case is handled separately in pipeRun + pipe->resultColorCtrl = pipeResultColorNoAlphaBlend[mode]; + } else if (!state->blendFunc) { + pipe->resultColorCtrl = pipeResultColorAlphaNoBlend[mode]; + } else { + pipe->resultColorCtrl = pipeResultColorAlphaBlend[mode]; + } + + // non-isolated group correction + pipe->nonIsolatedGroup = nonIsolatedGroup; + + // select the 'run' function + pipe->run = &Splash::pipeRun; + if (overprintMaskBitmap || usesSrcOverprint) { + // use Splash::pipeRun + } else if (!pipe->pattern && pipe->noTransparency && !state->blendFunc) { + if (mode == splashModeMono1 && !bitmap->alpha) { + pipe->run = &Splash::pipeRunSimpleMono1; + } else if (mode == splashModeMono8 && bitmap->alpha) { + pipe->run = &Splash::pipeRunSimpleMono8; + } else if (mode == splashModeRGB8 && bitmap->alpha) { + pipe->run = &Splash::pipeRunSimpleRGB8; + } else if (mode == splashModeBGR8 && bitmap->alpha) { + pipe->run = &Splash::pipeRunSimpleBGR8; +#if SPLASH_CMYK + } else if (mode == splashModeCMYK8 && bitmap->alpha) { + pipe->run = &Splash::pipeRunSimpleCMYK8; +#endif + } + } else if (!pipe->pattern && pipe->shapeOnly && !state->blendFunc) { + if (mode == splashModeMono1 && !bitmap->alpha) { + pipe->run = &Splash::pipeRunShapeMono1; + } else if (mode == splashModeMono8 && bitmap->alpha) { + pipe->run = &Splash::pipeRunShapeMono8; + } else if (mode == splashModeRGB8 && bitmap->alpha) { + pipe->run = &Splash::pipeRunShapeRGB8; + } else if (mode == splashModeBGR8 && bitmap->alpha) { + pipe->run = &Splash::pipeRunShapeBGR8; +#if SPLASH_CMYK + } else if (mode == splashModeCMYK8 && bitmap->alpha) { + pipe->run = &Splash::pipeRunShapeCMYK8; +#endif + } else if (mode == splashModeMono8 && !bitmap->alpha) { + // this is used when drawing soft-masked images + pipe->run = &Splash::pipeRunShapeNoAlphaMono8; + } + } else if (!pipe->pattern && !pipe->noTransparency && !state->softMask && + usesShape && + !(state->inNonIsolatedGroup && groupBackBitmap->alpha) && + !state->inKnockoutGroup && + !state->blendFunc && !pipe->nonIsolatedGroup) { + if (mode == splashModeMono1 && !bitmap->alpha) { + pipe->run = &Splash::pipeRunAAMono1; + } else if (mode == splashModeMono8 && bitmap->alpha) { + pipe->run = &Splash::pipeRunAAMono8; + } else if (mode == splashModeRGB8 && bitmap->alpha) { + pipe->run = &Splash::pipeRunAARGB8; + } else if (mode == splashModeBGR8 && bitmap->alpha) { + pipe->run = &Splash::pipeRunAABGR8; +#if SPLASH_CMYK + } else if (mode == splashModeCMYK8 && bitmap->alpha) { + pipe->run = &Splash::pipeRunAACMYK8; +#endif + } + } else if (!pipe->pattern && + aInput == 255 && + state->softMask && + usesShape && + !state->inNonIsolatedGroup && + !state->inKnockoutGroup && + !nonIsolatedGroup && + state->overprintMask == 0xffffffff && + !state->blendFunc) { + if (mode == splashModeMono8 && bitmap->alpha) { + pipe->run = &Splash::pipeRunSoftMaskMono8; + } else if (mode == splashModeRGB8 && bitmap->alpha) { + pipe->run = &Splash::pipeRunSoftMaskRGB8; + } else if (mode == splashModeBGR8 && bitmap->alpha) { + pipe->run = &Splash::pipeRunSoftMaskBGR8; +#if SPLASH_CMYK + } else if (mode == splashModeCMYK8 && bitmap->alpha) { + pipe->run = &Splash::pipeRunSoftMaskCMYK8; +#endif + } + } else if (!pipe->pattern && !pipe->noTransparency && !state->softMask && + usesShape && + state->inNonIsolatedGroup && groupBackBitmap->alpha && + !state->inKnockoutGroup && + !state->blendFunc && !pipe->nonIsolatedGroup) { + if (mode == splashModeMono8 && bitmap->alpha) { + pipe->run = &Splash::pipeRunNonIsoMono8; + } else if (mode == splashModeRGB8 && bitmap->alpha) { + pipe->run = &Splash::pipeRunNonIsoRGB8; + } else if (mode == splashModeBGR8 && bitmap->alpha) { + pipe->run = &Splash::pipeRunNonIsoBGR8; +#if SPLASH_CMYK + } else if (mode == splashModeCMYK8 && bitmap->alpha) { + pipe->run = &Splash::pipeRunNonIsoCMYK8; +#endif + } + } +} + +// 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 destColorMask; + Guchar *destAlphaPtr; + SplashColorPtr color0Ptr; + Guchar color0Mask; + Guchar *alpha0Ptr; + SplashColorPtr softMaskPtr; + Guint overprintMask; + Guint *overprintMaskPtr; +#if SPLASH_CMYK + Guchar aPrev; + SplashColor cSrc2, cDest2; +#endif + + if (cSrcPtr && !pipe->pattern) { + cSrcStride = bitmapComps; + } else { + cSrcPtr = pipe->cSrcVal; + cSrcStride = 0; + } + + if (shapePtr) { + shapePtr2 = shapePtr; + shapeStride = 1; + for (; x0 <= x1; ++x0) { + if (*shapePtr2) { + break; + } + cSrcPtr += cSrcStride; + ++shapePtr2; + if (pipe->srcOverprintMaskPtr) { + ++pipe->srcOverprintMaskPtr; + } + } + } else { + shapeVal = 0xff; + shapePtr2 = &shapeVal; + shapeStride = 0; + } + if (x0 > x1) { + return; + } + updateModX(x0); + updateModY(y); + lastX = x0; + + useDestRow(y); + + if (bitmap->mode == splashModeMono1) { + destColorPtr = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)]; + destColorMask = (Guchar)(0x80 >> (x0 & 7)); + } else { + destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * bitmapComps]; + destColorMask = 0; // make gcc happy + } + if (bitmap->alpha) { + destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; + } else { + destAlphaPtr = NULL; + } + if (state->softMask) { + softMaskPtr = &state->softMask->data[y * state->softMask->rowSize + x0]; + } else { + softMaskPtr = NULL; + } + if (state->inKnockoutGroup) { + if (bitmap->mode == splashModeMono1) { + color0Ptr = + &groupBackBitmap->data[(groupBackY + y) * groupBackBitmap->rowSize + + ((groupBackX + x0) >> 3)]; + color0Mask = (Guchar)(0x80 >> ((groupBackX + x0) & 7)); + } else { + color0Ptr = + &groupBackBitmap->data[(groupBackY + y) * groupBackBitmap->rowSize + + (groupBackX + 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)]; + } else { + alpha0Ptr = NULL; + } + if (overprintMaskBitmap) { + overprintMaskPtr = overprintMaskBitmap + y * bitmap->width + x0; + } else { + overprintMaskPtr = NULL; + } + + for (x = x0; x <= x1; ++x) { + + //----- shape + + shape = *shapePtr2; + if (!shape) { + if (bitmap->mode == splashModeMono1) { + destColorPtr += destColorMask & 1; + destColorMask = (Guchar)((destColorMask << 7) | (destColorMask >> 1)); + } else { + destColorPtr += bitmapComps; + } + if (destAlphaPtr) { + ++destAlphaPtr; + } + if (softMaskPtr) { + ++softMaskPtr; + } + if (color0Ptr) { + if (bitmap->mode == splashModeMono1) { + color0Ptr += color0Mask & 1; + color0Mask = (Guchar)((color0Mask << 7) | (color0Mask >> 1)); + } else { + color0Ptr += bitmapComps; + } + } + if (alpha0Ptr) { + ++alpha0Ptr; + } + cSrcPtr += cSrcStride; + shapePtr2 += shapeStride; + if (pipe->srcOverprintMaskPtr) { + ++pipe->srcOverprintMaskPtr; + } + if (overprintMaskPtr) { + ++overprintMaskPtr; + } + continue; + } + lastX = x; + + //----- source color + + // static pattern: handled in pipeInit + // fixed color: handled in pipeInit + + // dynamic pattern + if (pipe->pattern) { + pipe->pattern->getColor(x, y, pipe->cSrcVal); + } + + cResult0 = cResult1 = cResult2 = cResult3 = 0; // make gcc happy + + if (pipe->noTransparency && !state->blendFunc) { + + //----- handle overprint + + if (overprintMaskPtr) { + *overprintMaskPtr++ = 0xffffffff; + } + + //----- result color + + switch (bitmap->mode) { + case splashModeMono1: + case splashModeMono8: + cResult0 = state->grayTransfer[cSrcPtr[0]]; + break; + case splashModeRGB8: + case splashModeBGR8: + cResult0 = state->rgbTransferR[cSrcPtr[0]]; + cResult1 = state->rgbTransferG[cSrcPtr[1]]; + cResult2 = state->rgbTransferB[cSrcPtr[2]]; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + cResult0 = state->cmykTransferC[cSrcPtr[0]]; + cResult1 = state->cmykTransferM[cSrcPtr[1]]; + cResult2 = state->cmykTransferY[cSrcPtr[2]]; + cResult3 = state->cmykTransferK[cSrcPtr[3]]; + break; +#endif + } + aResult = 255; + + } else { // if (noTransparency && !blendFunc) + + //----- read destination pixel + // (or backdrop color, for knockout groups) + + if (color0Ptr) { + + switch (bitmap->mode) { + case splashModeMono1: + cDest[0] = (*color0Ptr & color0Mask) ? 0xff : 0x00; + color0Ptr += color0Mask & 1; + color0Mask = (Guchar)((color0Mask << 7) | (color0Mask >> 1)); + break; + case splashModeMono8: + cDest[0] = *color0Ptr++; + break; + case splashModeRGB8: + cDest[0] = color0Ptr[0]; + cDest[1] = color0Ptr[1]; + cDest[2] = color0Ptr[2]; + color0Ptr += 3; + break; + case splashModeBGR8: + cDest[2] = color0Ptr[0]; + cDest[1] = color0Ptr[1]; + cDest[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]; + color0Ptr += 4; + break; +#endif + } + + } else { + + 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 + } + + } + + if (destAlphaPtr) { + aDest = *destAlphaPtr; + } else { + aDest = 0xff; + } + + //----- read source color; handle overprint + + if (pipe->srcOverprintMaskPtr) { + overprintMask = *pipe->srcOverprintMaskPtr++; + } else { + overprintMask = state->overprintMask; + } + if (overprintMaskPtr) { + *overprintMaskPtr++ |= overprintMask; + } + + switch (bitmap->mode) { + case splashModeMono1: + case splashModeMono8: + cSrc[0] = state->grayTransfer[cSrcPtr[0]]; + break; + case splashModeRGB8: + case splashModeBGR8: + cSrc[0] = state->rgbTransferR[cSrcPtr[0]]; + cSrc[1] = state->rgbTransferG[cSrcPtr[1]]; + cSrc[2] = state->rgbTransferB[cSrcPtr[2]]; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + if (alpha0Ptr) { // non-isolated group + if (color0Ptr) { // non-isolated, knockout group + aPrev = *alpha0Ptr; + } else { // non-isolated, non-knockout group + aPrev = (Guchar)(*alpha0Ptr + aDest - div255(*alpha0Ptr * aDest)); + } + } else { // isolated group + if (color0Ptr) { // isolated, knockout group + aPrev = 0; + } else { // isolated, non-knockout group + aPrev = aDest; + } + } + if (overprintMask & 0x01) { + cSrc[0] = state->cmykTransferC[cSrcPtr[0]]; + } else { + cSrc[0] = div255(aPrev * cDest[0]); + } + if (overprintMask & 0x02) { + cSrc[1] = state->cmykTransferM[cSrcPtr[1]]; + } else { + cSrc[1] = div255(aPrev * cDest[1]); + } + if (overprintMask & 0x04) { + cSrc[2] = state->cmykTransferY[cSrcPtr[2]]; + } else { + cSrc[2] = div255(aPrev * cDest[2]); + } + if (overprintMask & 0x08) { + cSrc[3] = state->cmykTransferK[cSrcPtr[3]]; + } else { + cSrc[3] = div255(aPrev * cDest[3]); + } + break; +#endif + } + + //----- source alpha + + if (softMaskPtr) { + if (shapePtr) { + aSrc = div255(div255(pipe->aInput * *softMaskPtr++) * shape); + } else { + aSrc = div255(pipe->aInput * *softMaskPtr++); + } + } else if (shapePtr) { + aSrc = div255(pipe->aInput * shape); + } else { + aSrc = pipe->aInput; + } + + //----- non-isolated group correction + + if (pipe->nonIsolatedGroup) { + // This path is only used when Splash::composite() is called to + // composite a non-isolated group onto the backdrop. In this + // case, shape 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 + // need to compute the corrected alpha, because the + // destination is is storing group alpha (same computation as + // blitCorrectedAlpha). + if (alpha0Ptr) { + t = *alpha0Ptr; + t = (Guchar)(aDest + t - div255(aDest * t)); + } else { + t = aDest; + } + t = (t * 255) / shape - t; + switch (bitmap->mode) { +#if SPLASH_CMYK + case splashModeCMYK8: + cSrc[3] = clip255(cSrc[3] + ((cSrc[3] - cDest[3]) * t) / 255); +#endif + case splashModeRGB8: + case splashModeBGR8: + cSrc[2] = clip255(cSrc[2] + ((cSrc[2] - cDest[2]) * t) / 255); + cSrc[1] = clip255(cSrc[1] + ((cSrc[1] - cDest[1]) * t) / 255); + case splashModeMono1: + case splashModeMono8: + cSrc[0] = clip255(cSrc[0] + ((cSrc[0] - cDest[0]) * t) / 255); + break; + } + } + + //----- blend function + + if (state->blendFunc) { +#if SPLASH_CMYK + if (bitmap->mode == splashModeCMYK8) { + // convert colors to additive + cSrc2[0] = (Guchar)(0xff - cSrc[0]); + 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); + // convert result back to subtractive + cBlend[0] = (Guchar)(0xff - cBlend[0]); + cBlend[1] = (Guchar)(0xff - cBlend[1]); + cBlend[2] = (Guchar)(0xff - cBlend[2]); + cBlend[3] = (Guchar)(0xff - cBlend[3]); + } else +#endif + (*state->blendFunc)(cSrc, cDest, cBlend, bitmap->mode); + } + + //----- result alpha and non-isolated group element correction + + // 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 + aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest)); + alpha0 = *alpha0Ptr++; + alphaI = (Guchar)(aResult + alpha0 - div255(aResult * alpha0)); + alphaIm1 = (Guchar)(alpha0 + aDest - div255(alpha0 * aDest)); + } + } else { + if (color0Ptr) { + // isolated, knockout + aResult = aSrc; + alphaI = aSrc; + alphaIm1 = 0; + } else { + // isolated, non-knockout + aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest)); + alphaI = aResult; + alphaIm1 = aDest; + } + } + + //----- result color + + switch (pipe->resultColorCtrl) { + + case splashPipeResultColorNoAlphaBlendMono: + cResult0 = div255((255 - aDest) * cSrc[0] + aDest * cBlend[0]); + break; + case splashPipeResultColorNoAlphaBlendRGB: + cResult0 = div255((255 - aDest) * cSrc[0] + aDest * cBlend[0]); + cResult1 = div255((255 - aDest) * cSrc[1] + aDest * cBlend[1]); + cResult2 = div255((255 - aDest) * cSrc[2] + aDest * cBlend[2]); + break; +#if SPLASH_CMYK + case splashPipeResultColorNoAlphaBlendCMYK: + cResult0 = div255((255 - aDest) * cSrc[0] + aDest * cBlend[0]); + cResult1 = div255((255 - aDest) * cSrc[1] + aDest * cBlend[1]); + cResult2 = div255((255 - aDest) * cSrc[2] + aDest * cBlend[2]); + cResult3 = div255((255 - aDest) * cSrc[3] + aDest * cBlend[3]); + break; +#endif + + case splashPipeResultColorAlphaNoBlendMono: + if (alphaI == 0) { + cResult0 = 0; + } else { + cResult0 = (Guchar)(((alphaI - aSrc) * cDest[0] + aSrc * cSrc[0]) + / alphaI); + } + break; + case splashPipeResultColorAlphaNoBlendRGB: + if (alphaI == 0) { + cResult0 = 0; + cResult1 = 0; + cResult2 = 0; + } else { + cResult0 = (Guchar)(((alphaI - aSrc) * cDest[0] + aSrc * cSrc[0]) + / alphaI); + cResult1 = (Guchar)(((alphaI - aSrc) * cDest[1] + aSrc * cSrc[1]) + / alphaI); + cResult2 = (Guchar)(((alphaI - aSrc) * cDest[2] + aSrc * cSrc[2]) + / alphaI); + } + break; +#if SPLASH_CMYK + case splashPipeResultColorAlphaNoBlendCMYK: + if (alphaI == 0) { + cResult0 = 0; + cResult1 = 0; + cResult2 = 0; + cResult3 = 0; + } else { + cResult0 = (Guchar)(((alphaI - aSrc) * cDest[0] + aSrc * cSrc[0]) + / alphaI); + cResult1 = (Guchar)(((alphaI - aSrc) * cDest[1] + aSrc * cSrc[1]) + / alphaI); + cResult2 = (Guchar)(((alphaI - aSrc) * cDest[2] + aSrc * cSrc[2]) + / alphaI); + cResult3 = (Guchar)(((alphaI - aSrc) * cDest[3] + aSrc * cSrc[3]) + / alphaI); + } + break; +#endif + + case splashPipeResultColorAlphaBlendMono: + if (alphaI == 0) { + cResult0 = 0; + } else { + cResult0 = (Guchar)(((alphaI - aSrc) * cDest[0] + + aSrc * ((255 - alphaIm1) * cSrc[0] + + alphaIm1 * cBlend[0]) / 255) + / alphaI); + } + break; + case splashPipeResultColorAlphaBlendRGB: + if (alphaI == 0) { + cResult0 = 0; + cResult1 = 0; + cResult2 = 0; + } else { + cResult0 = (Guchar)(((alphaI - aSrc) * cDest[0] + + aSrc * ((255 - alphaIm1) * cSrc[0] + + alphaIm1 * cBlend[0]) / 255) + / alphaI); + cResult1 = (Guchar)(((alphaI - aSrc) * cDest[1] + + aSrc * ((255 - alphaIm1) * cSrc[1] + + alphaIm1 * cBlend[1]) / 255) + / alphaI); + cResult2 = (Guchar)(((alphaI - aSrc) * cDest[2] + + aSrc * ((255 - alphaIm1) * cSrc[2] + + alphaIm1 * cBlend[2]) / 255) + / alphaI); + } + break; +#if SPLASH_CMYK + case splashPipeResultColorAlphaBlendCMYK: + if (alphaI == 0) { + cResult0 = 0; + cResult1 = 0; + cResult2 = 0; + cResult3 = 0; + } else { + cResult0 = (Guchar)(((alphaI - aSrc) * cDest[0] + + aSrc * ((255 - alphaIm1) * cSrc[0] + + alphaIm1 * cBlend[0]) / 255) + / alphaI); + cResult1 = (Guchar)(((alphaI - aSrc) * cDest[1] + + aSrc * ((255 - alphaIm1) * cSrc[1] + + alphaIm1 * cBlend[1]) / 255) + / alphaI); + cResult2 = (Guchar)(((alphaI - aSrc) * cDest[2] + + aSrc * ((255 - alphaIm1) * cSrc[2] + + alphaIm1 * cBlend[2]) / 255) + / alphaI); + cResult3 = (Guchar)(((alphaI - aSrc) * cDest[3] + + aSrc * ((255 - alphaIm1) * cSrc[3] + + alphaIm1 * cBlend[3]) / 255) + / alphaI); + } + break; +#endif + } + + } // if (noTransparency && !blendFunc) + + //----- write destination pixel + + switch (bitmap->mode) { + case splashModeMono1: + if (state->screen->test(x, y, cResult0)) { + *destColorPtr |= destColorMask; + } else { + *destColorPtr &= (Guchar)~destColorMask; + } + destColorPtr += destColorMask & 1; + destColorMask = (Guchar)((destColorMask << 7) | (destColorMask >> 1)); + break; + case splashModeMono8: + *destColorPtr++ = cResult0; + break; + case splashModeRGB8: + destColorPtr[0] = cResult0; + destColorPtr[1] = cResult1; + destColorPtr[2] = cResult2; + destColorPtr += 3; + break; + case splashModeBGR8: + destColorPtr[0] = cResult2; + destColorPtr[1] = cResult1; + destColorPtr[2] = cResult0; + destColorPtr += 3; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + destColorPtr[0] = cResult0; + destColorPtr[1] = cResult1; + destColorPtr[2] = cResult2; + destColorPtr[3] = cResult3; + destColorPtr += 4; + break; +#endif + } + if (destAlphaPtr) { + *destAlphaPtr++ = aResult; + } + + cSrcPtr += cSrcStride; + shapePtr2 += shapeStride; + } // for (x ...) + + updateModX(lastX); +} + +// special case: +// !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 cResult0; + SplashColorPtr destColorPtr; + Guchar destColorMask; + SplashScreenCursor screenCursor; + int cSrcStride, x; + + if (cSrcPtr) { + cSrcStride = 1; + } else { + cSrcPtr = pipe->cSrcVal; + cSrcStride = 0; + } + if (x0 > x1) { + return; + } + updateModX(x0); + updateModX(x1); + updateModY(y); + + useDestRow(y); + + destColorPtr = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)]; + destColorMask = (Guchar)(0x80 >> (x0 & 7)); + + screenCursor = state->screen->getTestCursor(y); + + for (x = x0; x <= x1; ++x) { + + //----- write destination pixel + cResult0 = state->grayTransfer[cSrcPtr[0]]; + if (state->screen->testWithCursor(screenCursor, x, cResult0)) { + *destColorPtr |= destColorMask; + } else { + *destColorPtr &= (Guchar)~destColorMask; + } + destColorPtr += destColorMask & 1; + destColorMask = (Guchar)((destColorMask << 7) | (destColorMask >> 1)); + + cSrcPtr += cSrcStride; + } +} + +// special case: +// !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) { + SplashColorPtr destColorPtr; + Guchar *destAlphaPtr; + int cSrcStride, x; + + if (cSrcPtr) { + cSrcStride = 1; + } else { + cSrcPtr = pipe->cSrcVal; + cSrcStride = 0; + } + if (x0 > x1) { + return; + } + updateModX(x0); + updateModX(x1); + updateModY(y); + + useDestRow(y); + + destColorPtr = &bitmap->data[y * bitmap->rowSize + x0]; + destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; + + for (x = x0; x <= x1; ++x) { + + //----- write destination pixel + *destColorPtr++ = state->grayTransfer[cSrcPtr[0]]; + *destAlphaPtr++ = 255; + + cSrcPtr += cSrcStride; + } +} + +// special case: +// !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) { + SplashColorPtr destColorPtr; + Guchar *destAlphaPtr; + int cSrcStride, x; + + if (cSrcPtr) { + cSrcStride = 3; + } else { + cSrcPtr = pipe->cSrcVal; + cSrcStride = 0; + } + if (x0 > x1) { + return; + } + updateModX(x0); + updateModX(x1); + updateModY(y); + + useDestRow(y); + + destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0]; + destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; + + for (x = x0; x <= x1; ++x) { + + //----- write destination pixel + destColorPtr[0] = state->rgbTransferR[cSrcPtr[0]]; + destColorPtr[1] = state->rgbTransferG[cSrcPtr[1]]; + destColorPtr[2] = state->rgbTransferB[cSrcPtr[2]]; + destColorPtr += 3; + *destAlphaPtr++ = 255; + + cSrcPtr += cSrcStride; + } +} + +// special case: +// !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) { + SplashColorPtr destColorPtr; + Guchar *destAlphaPtr; + int cSrcStride, x; + + if (cSrcPtr) { + cSrcStride = 3; + } else { + cSrcPtr = pipe->cSrcVal; + cSrcStride = 0; + } + if (x0 > x1) { + return; + } + updateModX(x0); + updateModX(x1); + updateModY(y); + + useDestRow(y); + + destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0]; + destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; + + for (x = x0; x <= x1; ++x) { + + //----- write destination pixel + destColorPtr[0] = state->rgbTransferB[cSrcPtr[2]]; + destColorPtr[1] = state->rgbTransferG[cSrcPtr[1]]; + destColorPtr[2] = state->rgbTransferR[cSrcPtr[0]]; + destColorPtr += 3; + *destAlphaPtr++ = 255; + + cSrcPtr += cSrcStride; + } +} + +#if SPLASH_CMYK +// special case: +// !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) { + SplashColorPtr destColorPtr; + Guchar *destAlphaPtr; + int cSrcStride, x; + + if (cSrcPtr) { + cSrcStride = 4; + } else { + cSrcPtr = pipe->cSrcVal; + cSrcStride = 0; + } + if (x0 > x1) { + return; + } + updateModX(x0); + updateModX(x1); + updateModY(y); + + useDestRow(y); + + destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x0]; + destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; + + for (x = x0; x <= x1; ++x) { + + //----- write destination pixel + destColorPtr[0] = state->cmykTransferC[cSrcPtr[0]]; + destColorPtr[1] = state->cmykTransferM[cSrcPtr[1]]; + destColorPtr[2] = state->cmykTransferY[cSrcPtr[2]]; + destColorPtr[3] = state->cmykTransferK[cSrcPtr[3]]; + destColorPtr += 4; + *destAlphaPtr++ = 255; + + cSrcPtr += cSrcStride; + } +} +#endif + + +// special case: +// !pipe->pattern && pipe->shapeOnly && !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; + SplashColorPtr destColorPtr; + Guchar destColorMask; + SplashScreenCursor screenCursor; + int cSrcStride, x, lastX; + + if (cSrcPtr) { + cSrcStride = 1; + } else { + cSrcPtr = pipe->cSrcVal; + cSrcStride = 0; + } + for (; x0 <= x1; ++x0) { + if (*shapePtr) { + break; + } + cSrcPtr += cSrcStride; + ++shapePtr; + } + if (x0 > x1) { + return; + } + updateModX(x0); + updateModY(y); + lastX = x0; + + useDestRow(y); + + destColorPtr = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)]; + destColorMask = (Guchar)(0x80 >> (x0 & 7)); + + screenCursor = state->screen->getTestCursor(y); + + for (x = x0; x <= x1; ++x) { + + //----- shape + shape = *shapePtr; + if (!shape) { + destColorPtr += destColorMask & 1; + destColorMask = (Guchar)((destColorMask << 7) | (destColorMask >> 1)); + cSrcPtr += cSrcStride; + ++shapePtr; + continue; + } + lastX = x; + + //----- source color + cSrc0 = state->grayTransfer[cSrcPtr[0]]; + + //----- source alpha + aSrc = shape; + + //----- special case for aSrc = 255 + if (aSrc == 255) { + cResult0 = cSrc0; + } else { + + //----- read destination pixel + cDest0 = (*destColorPtr & destColorMask) ? 0xff : 0x00; + + //----- result color + // note: aDest = alphaI = aResult = 0xff + cResult0 = (Guchar)div255((0xff - aSrc) * cDest0 + aSrc * cSrc0); + } + + //----- write destination pixel + if (state->screen->testWithCursor(screenCursor, x, cResult0)) { + *destColorPtr |= destColorMask; + } else { + *destColorPtr &= (Guchar)~destColorMask; + } + destColorPtr += destColorMask & 1; + destColorMask = (Guchar)((destColorMask << 7) | (destColorMask >> 1)); + + cSrcPtr += cSrcStride; + ++shapePtr; + } + + updateModX(lastX); +} + +// special case: +// !pipe->pattern && pipe->shapeOnly && !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; + SplashColorPtr destColorPtr; + Guchar *destAlphaPtr; + int cSrcStride, x, lastX; + + if (cSrcPtr) { + cSrcStride = 1; + } else { + cSrcPtr = pipe->cSrcVal; + cSrcStride = 0; + } + for (; x0 <= x1; ++x0) { + if (*shapePtr) { + break; + } + cSrcPtr += cSrcStride; + ++shapePtr; + } + if (x0 > x1) { + return; + } + updateModX(x0); + updateModY(y); + lastX = x0; + + useDestRow(y); + + destColorPtr = &bitmap->data[y * bitmap->rowSize + x0]; + destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; + + for (x = x0; x <= x1; ++x) { + + //----- shape + shape = *shapePtr; + if (!shape) { + ++destColorPtr; + ++destAlphaPtr; + cSrcPtr += cSrcStride; + ++shapePtr; + continue; + } + lastX = x; + + //----- source color + cSrc0 = state->grayTransfer[cSrcPtr[0]]; + + //----- source alpha + aSrc = shape; + + //----- special case for aSrc = 255 + if (aSrc == 255) { + aResult = 255; + cResult0 = cSrc0; + } else { + + //----- read destination alpha + aDest = *destAlphaPtr; + + //----- special case for aDest = 0 + if (aDest == 0) { + aResult = aSrc; + cResult0 = cSrc0; + } else { + + //----- read destination pixel + cDest0 = *destColorPtr; + + //----- result alpha and non-isolated group element correction + aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest)); + alphaI = aResult; + + //----- result color + cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI); + } + } + + //----- write destination pixel + *destColorPtr++ = cResult0; + *destAlphaPtr++ = aResult; + + cSrcPtr += cSrcStride; + ++shapePtr; + } + + updateModX(lastX); +} + +// special case: +// !pipe->pattern && pipe->shapeOnly && !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 cSrc0, cSrc1, cSrc2; + Guchar cDest0, cDest1, cDest2; + Guchar cResult0, cResult1, cResult2; + SplashColorPtr destColorPtr; + Guchar *destAlphaPtr; + int cSrcStride, x, lastX; + + if (cSrcPtr) { + cSrcStride = 3; + } else { + cSrcPtr = pipe->cSrcVal; + cSrcStride = 0; + } + for (; x0 <= x1; ++x0) { + if (*shapePtr) { + break; + } + cSrcPtr += cSrcStride; + ++shapePtr; + } + if (x0 > x1) { + return; + } + updateModX(x0); + updateModY(y); + lastX = x0; + + useDestRow(y); + + destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0]; + destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; + + for (x = x0; x <= x1; ++x) { + + //----- shape + shape = *shapePtr; + if (!shape) { + destColorPtr += 3; + ++destAlphaPtr; + cSrcPtr += cSrcStride; + ++shapePtr; + continue; + } + lastX = x; + + //----- source color + cSrc0 = state->rgbTransferR[cSrcPtr[0]]; + cSrc1 = state->rgbTransferG[cSrcPtr[1]]; + cSrc2 = state->rgbTransferB[cSrcPtr[2]]; + + //----- source alpha + aSrc = shape; + + //----- special case for aSrc = 255 + if (aSrc == 255) { + aResult = 255; + cResult0 = cSrc0; + cResult1 = cSrc1; + cResult2 = cSrc2; + } else { + + //----- read destination alpha + aDest = *destAlphaPtr; + + //----- special case for aDest = 0 + if (aDest == 0) { + aResult = aSrc; + cResult0 = cSrc0; + cResult1 = cSrc1; + cResult2 = cSrc2; + } else { + + //----- read destination pixel + cDest0 = destColorPtr[0]; + cDest1 = destColorPtr[1]; + cDest2 = destColorPtr[2]; + + //----- result alpha and non-isolated group element correction + aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest)); + alphaI = aResult; + + //----- result color + cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI); + cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI); + cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI); + } + } + + //----- write destination pixel + destColorPtr[0] = cResult0; + destColorPtr[1] = cResult1; + destColorPtr[2] = cResult2; + destColorPtr += 3; + *destAlphaPtr++ = aResult; + + cSrcPtr += cSrcStride; + ++shapePtr; + } + + updateModX(lastX); +} + +// special case: +// !pipe->pattern && pipe->shapeOnly && !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 cSrc0, cSrc1, cSrc2; + Guchar cDest0, cDest1, cDest2; + Guchar cResult0, cResult1, cResult2; + SplashColorPtr destColorPtr; + Guchar *destAlphaPtr; + int cSrcStride, x, lastX; + + if (cSrcPtr) { + cSrcStride = 3; + } else { + cSrcPtr = pipe->cSrcVal; + cSrcStride = 0; + } + for (; x0 <= x1; ++x0) { + if (*shapePtr) { + break; + } + cSrcPtr += cSrcStride; + ++shapePtr; + } + if (x0 > x1) { + return; + } + updateModX(x0); + updateModY(y); + lastX = x0; + + useDestRow(y); + + destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0]; + destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; + + for (x = x0; x <= x1; ++x) { + + //----- shape + shape = *shapePtr; + if (!shape) { + destColorPtr += 3; + ++destAlphaPtr; + cSrcPtr += cSrcStride; + ++shapePtr; + continue; + } + lastX = x; + + //----- source color + cSrc0 = state->rgbTransferR[cSrcPtr[0]]; + cSrc1 = state->rgbTransferG[cSrcPtr[1]]; + cSrc2 = state->rgbTransferB[cSrcPtr[2]]; + + //----- source alpha + aSrc = shape; + + //----- special case for aSrc = 255 + if (aSrc == 255) { + aResult = 255; + cResult0 = cSrc0; + cResult1 = cSrc1; + cResult2 = cSrc2; + } else { + + //----- read destination alpha + aDest = *destAlphaPtr; + + //----- special case for aDest = 0 + if (aDest == 0) { + aResult = aSrc; + cResult0 = cSrc0; + cResult1 = cSrc1; + cResult2 = cSrc2; + } else { + + //----- read destination pixel + cDest0 = destColorPtr[2]; + cDest1 = destColorPtr[1]; + cDest2 = destColorPtr[0]; + + //----- result alpha and non-isolated group element correction + aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest)); + alphaI = aResult; + + //----- result color + cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI); + cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI); + cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI); + } + } + + //----- write destination pixel + destColorPtr[0] = cResult2; + destColorPtr[1] = cResult1; + destColorPtr[2] = cResult0; + destColorPtr += 3; + *destAlphaPtr++ = aResult; + + cSrcPtr += cSrcStride; + ++shapePtr; + } + + updateModX(lastX); +} + +#if SPLASH_CMYK +// special case: +// !pipe->pattern && pipe->shapeOnly && !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 cSrc0, cSrc1, cSrc2, cSrc3; + Guchar cDest0, cDest1, cDest2, cDest3; + Guchar cResult0, cResult1, cResult2, cResult3; + SplashColorPtr destColorPtr; + Guchar *destAlphaPtr; + int cSrcStride, x, lastX; + + if (cSrcPtr) { + cSrcStride = 4; + } else { + cSrcPtr = pipe->cSrcVal; + cSrcStride = 0; + } + for (; x0 <= x1; ++x0) { + if (*shapePtr) { + break; + } + cSrcPtr += cSrcStride; + ++shapePtr; + } + if (x0 > x1) { + return; + } + updateModX(x0); + updateModY(y); + lastX = x0; + + useDestRow(y); + + destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x0]; + destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; + + for (x = x0; x <= x1; ++x) { + + //----- shape + shape = *shapePtr; + if (!shape) { + destColorPtr += 4; + ++destAlphaPtr; + cSrcPtr += cSrcStride; + ++shapePtr; + continue; + } + lastX = x; + + //----- read destination pixel + cDest0 = destColorPtr[0]; + cDest1 = destColorPtr[1]; + cDest2 = destColorPtr[2]; + cDest3 = destColorPtr[3]; + aDest = *destAlphaPtr; + + //----- overprint + cSrc0 = state->cmykTransferC[cSrcPtr[0]]; + cSrc1 = state->cmykTransferM[cSrcPtr[1]]; + cSrc2 = state->cmykTransferY[cSrcPtr[2]]; + cSrc3 = state->cmykTransferK[cSrcPtr[3]]; + + //----- source alpha + aSrc = shape; + + //----- special case for aSrc = 255 + if (aSrc == 255) { + aResult = 255; + cResult0 = cSrc0; + cResult1 = cSrc1; + cResult2 = cSrc2; + cResult3 = cSrc3; + } else { + + //----- special case for aDest = 0 + if (aDest == 0) { + aResult = aSrc; + cResult0 = cSrc0; + cResult1 = cSrc1; + cResult2 = cSrc2; + cResult3 = cSrc3; + } else { + + //----- result alpha and non-isolated group element correction + aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest)); + alphaI = aResult; + + //----- result color + cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI); + cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI); + cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI); + cResult3 = (Guchar)(((alphaI - aSrc) * cDest3 + aSrc * cSrc3) / alphaI); + } + } + + //----- write destination pixel + destColorPtr[0] = cResult0; + destColorPtr[1] = cResult1; + destColorPtr[2] = cResult2; + destColorPtr[3] = cResult3; + destColorPtr += 4; + *destAlphaPtr++ = aResult; + + cSrcPtr += cSrcStride; + ++shapePtr; + } + + updateModX(lastX); +} +#endif + + +// special case: +// !pipe->pattern && pipe->shapeOnly && !state->blendFunc && +// bitmap->mode == splashModeMono8 && !bitmap->alpha +void Splash::pipeRunShapeNoAlphaMono8(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, + SplashColorPtr cSrcPtr) { + Guchar shape, aSrc, cSrc0, cDest0, cResult0; + SplashColorPtr destColorPtr; + int cSrcStride, x, lastX; + + if (cSrcPtr) { + cSrcStride = 1; + } else { + cSrcPtr = pipe->cSrcVal; + cSrcStride = 0; + } + for (; x0 <= x1; ++x0) { + if (*shapePtr) { + break; + } + cSrcPtr += cSrcStride; + ++shapePtr; + } + if (x0 > x1) { + return; + } + updateModX(x0); + updateModY(y); + lastX = x0; + + useDestRow(y); + + destColorPtr = &bitmap->data[y * bitmap->rowSize + x0]; + + for (x = x0; x <= x1; ++x) { + + //----- shape + shape = *shapePtr; + if (!shape) { + ++destColorPtr; + cSrcPtr += cSrcStride; + ++shapePtr; + continue; + } + lastX = x; + + //----- source color + cSrc0 = state->grayTransfer[cSrcPtr[0]]; + + //----- source alpha + aSrc = shape; + + //----- special case for aSrc = 255 + if (aSrc == 255) { + cResult0 = cSrc0; + } else { + + //----- read destination pixel + cDest0 = *destColorPtr; + + //----- result color + cResult0 = div255((255 - aSrc) * cDest0 + aSrc * cSrc0); + } + + //----- write destination pixel + *destColorPtr++ = cResult0; + + cSrcPtr += cSrcStride; + ++shapePtr; + } + + updateModX(lastX); +} + +// special case: +// !pipe->pattern && !pipe->noTransparency && !state->softMask && +// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc && +// !pipe->nonIsolatedGroup && +// 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; + SplashColorPtr destColorPtr; + Guchar destColorMask; + SplashScreenCursor screenCursor; + int cSrcStride, x, lastX; + + if (cSrcPtr) { + cSrcStride = 1; + } else { + cSrcPtr = pipe->cSrcVal; + cSrcStride = 0; + } + for (; x0 <= x1; ++x0) { + if (*shapePtr) { + break; + } + cSrcPtr += cSrcStride; + ++shapePtr; + } + if (x0 > x1) { + return; + } + updateModX(x0); + updateModY(y); + lastX = x0; + + useDestRow(y); + + destColorPtr = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)]; + destColorMask = (Guchar)(0x80 >> (x0 & 7)); + + screenCursor = state->screen->getTestCursor(y); + + for (x = x0; x <= x1; ++x) { + + //----- shape + shape = *shapePtr; + if (!shape) { + destColorPtr += destColorMask & 1; + destColorMask = (Guchar)((destColorMask << 7) | (destColorMask >> 1)); + cSrcPtr += cSrcStride; + ++shapePtr; + continue; + } + lastX = x; + + //----- read destination pixel + cDest0 = (*destColorPtr & destColorMask) ? 0xff : 0x00; + + //----- source color + cSrc0 = state->grayTransfer[cSrcPtr[0]]; + + //----- source alpha + aSrc = div255(pipe->aInput * shape); + + //----- result color + // note: aDest = alphaI = aResult = 0xff + cResult0 = (Guchar)div255((0xff - aSrc) * cDest0 + aSrc * cSrc0); + + //----- write destination pixel + if (state->screen->testWithCursor(screenCursor, x, cResult0)) { + *destColorPtr |= destColorMask; + } else { + *destColorPtr &= (Guchar)~destColorMask; + } + destColorPtr += destColorMask & 1; + destColorMask = (Guchar)((destColorMask << 7) | (destColorMask >> 1)); + + cSrcPtr += cSrcStride; + ++shapePtr; + } + + updateModX(lastX); +} + +// special case: +// !pipe->pattern && !pipe->noTransparency && !state->softMask && +// pipe->usesShape && !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; + SplashColorPtr destColorPtr; + Guchar *destAlphaPtr; + int cSrcStride, x, lastX; + + if (cSrcPtr) { + cSrcStride = 1; + } else { + cSrcPtr = pipe->cSrcVal; + cSrcStride = 0; + } + for (; x0 <= x1; ++x0) { + if (*shapePtr) { + break; + } + cSrcPtr += cSrcStride; + ++shapePtr; + } + if (x0 > x1) { + return; + } + updateModX(x0); + updateModY(y); + lastX = x0; + + useDestRow(y); + + destColorPtr = &bitmap->data[y * bitmap->rowSize + x0]; + destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; + + for (x = x0; x <= x1; ++x) { + + //----- shape + shape = *shapePtr; + if (!shape) { + ++destColorPtr; + ++destAlphaPtr; + cSrcPtr += cSrcStride; + ++shapePtr; + continue; + } + lastX = x; + + //----- read destination pixel + cDest0 = *destColorPtr; + aDest = *destAlphaPtr; + + //----- source color + cSrc0 = state->grayTransfer[cSrcPtr[0]]; + + //----- source alpha + aSrc = div255(pipe->aInput * shape); + + //----- result alpha and non-isolated group element correction + aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest)); + alphaI = aResult; + + //----- result color + if (alphaI == 0) { + cResult0 = 0; + } else { + cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI); + } + + //----- write destination pixel + *destColorPtr++ = cResult0; + *destAlphaPtr++ = aResult; + + cSrcPtr += cSrcStride; + ++shapePtr; + } + + updateModX(lastX); +} + +// special case: +// !pipe->pattern && !pipe->noTransparency && !state->softMask && +// pipe->usesShape && !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 cSrc0, cSrc1, cSrc2; + Guchar cDest0, cDest1, cDest2; + Guchar cResult0, cResult1, cResult2; + SplashColorPtr destColorPtr; + Guchar *destAlphaPtr; + int cSrcStride, x, lastX; + + if (cSrcPtr) { + cSrcStride = 3; + } else { + cSrcPtr = pipe->cSrcVal; + cSrcStride = 0; + } + for (; x0 <= x1; ++x0) { + if (*shapePtr) { + break; + } + cSrcPtr += cSrcStride; + ++shapePtr; + } + if (x0 > x1) { + return; + } + updateModX(x0); + updateModY(y); + lastX = x0; + + useDestRow(y); + + destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0]; + destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; + + for (x = x0; x <= x1; ++x) { + + //----- shape + shape = *shapePtr; + if (!shape) { + destColorPtr += 3; + ++destAlphaPtr; + cSrcPtr += cSrcStride; + ++shapePtr; + continue; + } + lastX = x; + + //----- read destination pixel + cDest0 = destColorPtr[0]; + cDest1 = destColorPtr[1]; + cDest2 = destColorPtr[2]; + aDest = *destAlphaPtr; + + //----- source color + cSrc0 = state->rgbTransferR[cSrcPtr[0]]; + cSrc1 = state->rgbTransferG[cSrcPtr[1]]; + cSrc2 = state->rgbTransferB[cSrcPtr[2]]; + + //----- source alpha + aSrc = div255(pipe->aInput * shape); + + //----- result alpha and non-isolated group element correction + aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest)); + alphaI = aResult; + + //----- result color + if (alphaI == 0) { + cResult0 = 0; + cResult1 = 0; + cResult2 = 0; + } else { + cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI); + cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI); + cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI); + } + + //----- write destination pixel + destColorPtr[0] = cResult0; + destColorPtr[1] = cResult1; + destColorPtr[2] = cResult2; + destColorPtr += 3; + *destAlphaPtr++ = aResult; + + cSrcPtr += cSrcStride; + ++shapePtr; + } + + updateModX(lastX); +} + +// special case: +// !pipe->pattern && !pipe->noTransparency && !state->softMask && +// pipe->usesShape && !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 cSrc0, cSrc1, cSrc2; + Guchar cDest0, cDest1, cDest2; + Guchar cResult0, cResult1, cResult2; + SplashColorPtr destColorPtr; + Guchar *destAlphaPtr; + int cSrcStride, x, lastX; + + if (cSrcPtr) { + cSrcStride = 3; + } else { + cSrcPtr = pipe->cSrcVal; + cSrcStride = 0; + } + for (; x0 <= x1; ++x0) { + if (*shapePtr) { + break; + } + cSrcPtr += cSrcStride; + ++shapePtr; + } + if (x0 > x1) { + return; + } + updateModX(x0); + updateModY(y); + lastX = x0; + + useDestRow(y); + + destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x0]; + destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; + + for (x = x0; x <= x1; ++x) { + + //----- shape + shape = *shapePtr; + if (!shape) { + destColorPtr += 3; + ++destAlphaPtr; + cSrcPtr += cSrcStride; + ++shapePtr; + continue; + } + lastX = x; + + //----- read destination pixel + cDest0 = destColorPtr[2]; + cDest1 = destColorPtr[1]; + cDest2 = destColorPtr[0]; + aDest = *destAlphaPtr; + + //----- source color + cSrc0 = state->rgbTransferR[cSrcPtr[0]]; + cSrc1 = state->rgbTransferG[cSrcPtr[1]]; + cSrc2 = state->rgbTransferB[cSrcPtr[2]]; + + //----- source alpha + aSrc = div255(pipe->aInput * shape); + + //----- result alpha and non-isolated group element correction + aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest)); + alphaI = aResult; + + //----- result color + if (alphaI == 0) { + cResult0 = 0; + cResult1 = 0; + cResult2 = 0; + } else { + cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI); + cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI); + cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI); + } + + //----- write destination pixel + destColorPtr[0] = cResult2; + destColorPtr[1] = cResult1; + destColorPtr[2] = cResult0; + destColorPtr += 3; + *destAlphaPtr++ = aResult; + + cSrcPtr += cSrcStride; + ++shapePtr; + } + + updateModX(lastX); +} + +#if SPLASH_CMYK +// special case: +// !pipe->pattern && !pipe->noTransparency && !state->softMask && +// pipe->usesShape && !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 cSrc0, cSrc1, cSrc2, cSrc3; + Guchar cDest0, cDest1, cDest2, cDest3; + Guchar cResult0, cResult1, cResult2, cResult3; + SplashColorPtr destColorPtr; + Guchar *destAlphaPtr; + int cSrcStride, x, lastX; + + if (cSrcPtr) { + cSrcStride = 4; + } else { + cSrcPtr = pipe->cSrcVal; + cSrcStride = 0; + } + for (; x0 <= x1; ++x0) { + if (*shapePtr) { + break; + } + cSrcPtr += cSrcStride; + ++shapePtr; + } + if (x0 > x1) { + return; + } + updateModX(x0); + updateModY(y); + lastX = x0; + + useDestRow(y); + + destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x0]; + destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; + + for (x = x0; x <= x1; ++x) { + + //----- shape + shape = *shapePtr; + if (!shape) { + destColorPtr += 4; + ++destAlphaPtr; + cSrcPtr += cSrcStride; + ++shapePtr; + continue; + } + lastX = x; + + //----- read destination pixel + cDest0 = destColorPtr[0]; + cDest1 = destColorPtr[1]; + cDest2 = destColorPtr[2]; + cDest3 = destColorPtr[3]; + aDest = *destAlphaPtr; + + //----- overprint + if (state->overprintMask & 1) { + cSrc0 = state->cmykTransferC[cSrcPtr[0]]; + } else { + cSrc0 = div255(aDest * cDest0); + } + if (state->overprintMask & 2) { + cSrc1 = state->cmykTransferM[cSrcPtr[1]]; + } else { + cSrc1 = div255(aDest * cDest1); + } + if (state->overprintMask & 4) { + cSrc2 = state->cmykTransferY[cSrcPtr[2]]; + } else { + cSrc2 = div255(aDest * cDest2); + } + if (state->overprintMask & 8) { + cSrc3 = state->cmykTransferK[cSrcPtr[3]]; + } else { + cSrc3 = div255(aDest * cDest3); + } + + //----- source alpha + aSrc = div255(pipe->aInput * shape); + + //----- result alpha and non-isolated group element correction + aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest)); + alphaI = aResult; + + //----- result color + if (alphaI == 0) { + cResult0 = 0; + cResult1 = 0; + cResult2 = 0; + cResult3 = 0; + } else { + cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI); + cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI); + cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI); + cResult3 = (Guchar)(((alphaI - aSrc) * cDest3 + aSrc * cSrc3) / alphaI); + } + + //----- write destination pixel + destColorPtr[0] = cResult0; + destColorPtr[1] = cResult1; + destColorPtr[2] = cResult2; + destColorPtr[3] = cResult3; + destColorPtr += 4; + *destAlphaPtr++ = aResult; + + cSrcPtr += cSrcStride; + ++shapePtr; + } + + updateModX(lastX); +} +#endif + + +// special case: +// !pipe->pattern && aInput == 255 && state->softMask && usesShape && +// !state->inNonIsolatedGroup && !state->inKnockoutGroup && +// !nonIsolatedGroup && state->overprintMask == 0xffffffff && +// !state->blendFunc && +// bitmap->mode == splashModeMono8 && bitmap->alpha +void Splash::pipeRunSoftMaskMono8(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr) { + Guchar shape, aSrc, aDest, alphaI, aResult; + Guchar cSrc0, cDest0, cResult0; + SplashColorPtr destColorPtr; + Guchar *destAlphaPtr; + SplashColorPtr softMaskPtr; + int cSrcStride, x, lastX; + + if (cSrcPtr) { + cSrcStride = 1; + } else { + cSrcPtr = pipe->cSrcVal; + cSrcStride = 0; + } + for (; x0 <= x1; ++x0) { + if (*shapePtr) { + break; + } + cSrcPtr += cSrcStride; + ++shapePtr; + } + if (x0 > x1) { + return; + } + updateModX(x0); + updateModY(y); + lastX = x0; + + useDestRow(y); + + destColorPtr = &bitmap->data[y * bitmap->rowSize + x0]; + destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; + softMaskPtr = &state->softMask->data[y * state->softMask->rowSize + x0]; + + for (x = x0; x <= x1; ++x) { + + //----- shape + shape = *shapePtr; + if (!shape) { + ++destColorPtr; + ++destAlphaPtr; + ++softMaskPtr; + cSrcPtr += cSrcStride; + ++shapePtr; + continue; + } + lastX = x; + + //----- read source color + cSrc0 = state->grayTransfer[cSrcPtr[0]]; + + //----- source alpha + aSrc = div255(*softMaskPtr++ * shape); + + //----- special case for aSrc = 255 + if (aSrc == 255) { + aResult = 255; + cResult0 = cSrc0; + } else { + + //----- read destination alpha + aDest = *destAlphaPtr; + + //----- special case for aDest = 0 + if (aDest == 0) { + aResult = aSrc; + cResult0 = cSrc0; + } else { + + //----- read destination pixel + cDest0 = destColorPtr[0]; + + //----- result alpha and non-isolated group element correction + aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest)); + alphaI = aResult; + + //----- result color + cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI); + } + } + + //----- write destination pixel + destColorPtr[0] = cResult0; + ++destColorPtr; + *destAlphaPtr++ = aResult; + + cSrcPtr += cSrcStride; + ++shapePtr; + } + + updateModX(lastX); +} + +// special case: +// !pipe->pattern && aInput == 255 && state->softMask && usesShape && +// !state->inNonIsolatedGroup && !state->inKnockoutGroup && +// !nonIsolatedGroup && state->overprintMask == 0xffffffff && +// !state->blendFunc && +// bitmap->mode == splashModeRGB8 && bitmap->alpha +void Splash::pipeRunSoftMaskRGB8(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr) { + Guchar shape, aSrc, aDest, alphaI, aResult; + Guchar cSrc0, cSrc1, cSrc2; + Guchar cDest0, cDest1, cDest2; + Guchar cResult0, cResult1, cResult2; + SplashColorPtr destColorPtr; + Guchar *destAlphaPtr; + SplashColorPtr softMaskPtr; + int cSrcStride, x, lastX; + + if (cSrcPtr) { + cSrcStride = 3; + } else { + cSrcPtr = pipe->cSrcVal; + cSrcStride = 0; + } + for (; x0 <= x1; ++x0) { + if (*shapePtr) { + break; + } + cSrcPtr += cSrcStride; + ++shapePtr; + } + if (x0 > x1) { + return; + } + updateModX(x0); + updateModY(y); + lastX = x0; + + useDestRow(y); + + destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * 3]; + destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; + softMaskPtr = &state->softMask->data[y * state->softMask->rowSize + x0]; + + for (x = x0; x <= x1; ++x) { + + //----- shape + shape = *shapePtr; + if (!shape) { + destColorPtr += 3; + ++destAlphaPtr; + ++softMaskPtr; + cSrcPtr += cSrcStride; + ++shapePtr; + continue; + } + lastX = x; + + //----- read source color + cSrc0 = state->rgbTransferR[cSrcPtr[0]]; + cSrc1 = state->rgbTransferG[cSrcPtr[1]]; + cSrc2 = state->rgbTransferB[cSrcPtr[2]]; + + //----- source alpha + aSrc = div255(*softMaskPtr++ * shape); + + //----- special case for aSrc = 255 + if (aSrc == 255) { + aResult = 255; + cResult0 = cSrc0; + cResult1 = cSrc1; + cResult2 = cSrc2; + } else { + + //----- read destination alpha + aDest = *destAlphaPtr; + + //----- special case for aDest = 0 + if (aDest == 0) { + aResult = aSrc; + cResult0 = cSrc0; + cResult1 = cSrc1; + cResult2 = cSrc2; + } else { + + //----- read destination pixel + cDest0 = destColorPtr[0]; + cDest1 = destColorPtr[1]; + cDest2 = destColorPtr[2]; + + //----- result alpha and non-isolated group element correction + aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest)); + alphaI = aResult; + + //----- result color + cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI); + cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI); + cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI); + } + } + + //----- write destination pixel + destColorPtr[0] = cResult0; + destColorPtr[1] = cResult1; + destColorPtr[2] = cResult2; + destColorPtr += 3; + *destAlphaPtr++ = aResult; + + cSrcPtr += cSrcStride; + ++shapePtr; + } + + updateModX(lastX); +} + +// special case: +// !pipe->pattern && aInput == 255 && state->softMask && usesShape && +// !state->inNonIsolatedGroup && !state->inKnockoutGroup && +// !nonIsolatedGroup && state->overprintMask == 0xffffffff && +// !state->blendFunc && +// bitmap->mode == splashModeBGR8 && bitmap->alpha +void Splash::pipeRunSoftMaskBGR8(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr) { + Guchar shape, aSrc, aDest, alphaI, aResult; + Guchar cSrc0, cSrc1, cSrc2; + Guchar cDest0, cDest1, cDest2; + Guchar cResult0, cResult1, cResult2; + SplashColorPtr destColorPtr; + Guchar *destAlphaPtr; + SplashColorPtr softMaskPtr; + int cSrcStride, x, lastX; + + if (cSrcPtr) { + cSrcStride = 3; + } else { + cSrcPtr = pipe->cSrcVal; + cSrcStride = 0; + } + for (; x0 <= x1; ++x0) { + if (*shapePtr) { + break; + } + cSrcPtr += cSrcStride; + ++shapePtr; + } + if (x0 > x1) { + return; + } + updateModX(x0); + updateModY(y); + lastX = x0; + + useDestRow(y); + + destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * 3]; + destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; + softMaskPtr = &state->softMask->data[y * state->softMask->rowSize + x0]; + + for (x = x0; x <= x1; ++x) { + + //----- shape + shape = *shapePtr; + if (!shape) { + destColorPtr += 3; + ++destAlphaPtr; + ++softMaskPtr; + cSrcPtr += cSrcStride; + ++shapePtr; + continue; + } + lastX = x; + + //----- read source color + cSrc0 = state->rgbTransferR[cSrcPtr[0]]; + cSrc1 = state->rgbTransferG[cSrcPtr[1]]; + cSrc2 = state->rgbTransferB[cSrcPtr[2]]; + + //----- source alpha + aSrc = div255(*softMaskPtr++ * shape); + + //----- special case for aSrc = 255 + if (aSrc == 255) { + aResult = 255; + cResult0 = cSrc0; + cResult1 = cSrc1; + cResult2 = cSrc2; + } else { + + //----- read destination alpha + aDest = *destAlphaPtr; + + //----- special case for aDest = 0 + if (aDest == 0) { + aResult = aSrc; + cResult0 = cSrc0; + cResult1 = cSrc1; + cResult2 = cSrc2; + } else { + + //----- read destination pixel + cDest0 = destColorPtr[2]; + cDest1 = destColorPtr[1]; + cDest2 = destColorPtr[0]; + + //----- result alpha and non-isolated group element correction + aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest)); + alphaI = aResult; + + //----- result color + cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI); + cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI); + cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI); + } + } + + //----- write destination pixel + destColorPtr[2] = cResult0; + destColorPtr[1] = cResult1; + destColorPtr[0] = cResult2; + destColorPtr += 3; + *destAlphaPtr++ = aResult; + + cSrcPtr += cSrcStride; + ++shapePtr; + } + + updateModX(lastX); +} + +#if SPLASH_CMYK +// special case: +// !pipe->pattern && aInput == 255 && state->softMask && usesShape && +// !state->inNonIsolatedGroup && !state->inKnockoutGroup && +// !nonIsolatedGroup && state->overprintMask == 0xffffffff && +// !state->blendFunc && +// bitmap->mode == splashModeCMYK8 && bitmap->alpha +void Splash::pipeRunSoftMaskCMYK8(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr) { + Guchar shape, aSrc, aDest, alphaI, aResult; + Guchar cSrc0, cSrc1, cSrc2, cSrc3; + Guchar cDest0, cDest1, cDest2, cDest3; + Guchar cResult0, cResult1, cResult2, cResult3; + SplashColorPtr destColorPtr; + Guchar *destAlphaPtr; + SplashColorPtr softMaskPtr; + int cSrcStride, x, lastX; + + if (cSrcPtr) { + cSrcStride = 4; + } else { + cSrcPtr = pipe->cSrcVal; + cSrcStride = 0; + } + for (; x0 <= x1; ++x0) { + if (*shapePtr) { + break; + } + cSrcPtr += cSrcStride; + ++shapePtr; + } + if (x0 > x1) { + return; + } + updateModX(x0); + updateModY(y); + lastX = x0; + + useDestRow(y); + + destColorPtr = &bitmap->data[y * bitmap->rowSize + x0 * 4]; + destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; + softMaskPtr = &state->softMask->data[y * state->softMask->rowSize + x0]; + + for (x = x0; x <= x1; ++x) { + + //----- shape + shape = *shapePtr; + if (!shape) { + destColorPtr += 4; + ++destAlphaPtr; + ++softMaskPtr; + cSrcPtr += cSrcStride; + ++shapePtr; + continue; + } + lastX = x; + + //----- read destination pixel + cDest0 = destColorPtr[0]; + cDest1 = destColorPtr[1]; + cDest2 = destColorPtr[2]; + cDest3 = destColorPtr[3]; + + //----- read destination alpha + aDest = *destAlphaPtr; + + //----- overprint + cSrc0 = state->cmykTransferC[cSrcPtr[0]]; + cSrc1 = state->cmykTransferM[cSrcPtr[1]]; + cSrc2 = state->cmykTransferY[cSrcPtr[2]]; + cSrc3 = state->cmykTransferK[cSrcPtr[3]]; + + //----- source alpha + aSrc = div255(*softMaskPtr++ * shape); + + //----- special case for aSrc = 255 + if (aSrc == 255) { + aResult = 255; + cResult0 = cSrc0; + cResult1 = cSrc1; + cResult2 = cSrc2; + cResult3 = cSrc3; + } else { + + //----- special case for aDest = 0 + if (aDest == 0) { + aResult = aSrc; + cResult0 = cSrc0; + cResult1 = cSrc1; + cResult2 = cSrc2; + cResult3 = cSrc3; + } else { + + //----- result alpha and non-isolated group element correction + aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest)); + alphaI = aResult; + + //----- result color + cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI); + cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI); + cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI); + cResult3 = (Guchar)(((alphaI - aSrc) * cDest3 + aSrc * cSrc3) / alphaI); + } + } + + //----- write destination pixel + destColorPtr[0] = cResult0; + destColorPtr[1] = cResult1; + destColorPtr[2] = cResult2; + destColorPtr[3] = cResult3; + destColorPtr += 4; + *destAlphaPtr++ = aResult; + + cSrcPtr += cSrcStride; + ++shapePtr; + } + + updateModX(lastX); +} +#endif + + +void Splash::pipeRunNonIsoMono8(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr) { + Guchar shape, aSrc, aDest, alphaI, alpha0, aResult; + Guchar cSrc0, cDest0, cResult0; + SplashColorPtr destColorPtr; + Guchar *destAlphaPtr; + Guchar *alpha0Ptr; + int cSrcStride, x, lastX; + + if (cSrcPtr) { + cSrcStride = 1; + } else { + cSrcPtr = pipe->cSrcVal; + cSrcStride = 0; + } + for (; x0 <= x1; ++x0) { + if (*shapePtr) { + break; + } + cSrcPtr += cSrcStride; + ++shapePtr; + } + if (x0 > x1) { + return; + } + updateModX(x0); + updateModY(y); + lastX = x0; + + useDestRow(y); + + destColorPtr = &bitmap->data[y * bitmap->rowSize + x0]; + destAlphaPtr = &bitmap->alpha[y * bitmap->alphaRowSize + x0]; + alpha0Ptr = &groupBackBitmap->alpha[(groupBackY + y) + * groupBackBitmap->alphaRowSize + + (groupBackX + x0)]; + + for (x = x0; x <= x1; ++x) { + + //----- shape + shape = *shapePtr; + if (!shape) { + destColorPtr += 1; + ++destAlphaPtr; + ++alpha0Ptr; + cSrcPtr += cSrcStride; + ++shapePtr; + continue; + } + lastX = x; + + //----- read destination pixel + cDest0 = destColorPtr[0]; + aDest = *destAlphaPtr; + + //----- source color + cSrc0 = state->grayTransfer[cSrcPtr[0]]; + + //----- source alpha + aSrc = div255(pipe->aInput * shape); + + //----- result alpha and non-isolated group element correction + aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest)); + alpha0 = *alpha0Ptr++; + alphaI = (Guchar)(aResult + alpha0 - div255(aResult * alpha0)); + + //----- result color + if (alphaI == 0) { + cResult0 = 0; + } else { + cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI); + } + + //----- write destination pixel + *destColorPtr++ = cResult0; + *destAlphaPtr++ = aResult; + + cSrcPtr += cSrcStride; + ++shapePtr; + } // for (x ...) + + updateModX(lastX); +} + +void Splash::pipeRunNonIsoRGB8(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr) { + Guchar shape, aSrc, aDest, alphaI, alpha0, aResult; + Guchar cSrc0, cSrc1, cSrc2; + Guchar cDest0, cDest1, cDest2; + Guchar cResult0, cResult1, cResult2; + SplashColorPtr destColorPtr; + Guchar *destAlphaPtr; + Guchar *alpha0Ptr; + int cSrcStride, x, lastX; + + if (cSrcPtr) { + cSrcStride = 3; + } else { + cSrcPtr = pipe->cSrcVal; + cSrcStride = 0; + } + for (; x0 <= x1; ++x0) { + if (*shapePtr) { + break; + } + cSrcPtr += cSrcStride; + ++shapePtr; + } + if (x0 > x1) { + return; + } + updateModX(x0); + updateModY(y); + lastX = x0; + + useDestRow(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)]; + + for (x = x0; x <= x1; ++x) { + + //----- shape + shape = *shapePtr; + if (!shape) { + destColorPtr += 3; + ++destAlphaPtr; + ++alpha0Ptr; + cSrcPtr += cSrcStride; + ++shapePtr; + continue; + } + lastX = x; + + //----- read destination pixel + cDest0 = destColorPtr[0]; + cDest1 = destColorPtr[1]; + cDest2 = destColorPtr[2]; + aDest = *destAlphaPtr; + + //----- source color + cSrc0 = state->rgbTransferR[cSrcPtr[0]]; + cSrc1 = state->rgbTransferG[cSrcPtr[1]]; + cSrc2 = state->rgbTransferB[cSrcPtr[2]]; + + //----- source alpha + aSrc = div255(pipe->aInput * shape); + + //----- result alpha and non-isolated group element correction + aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest)); + alpha0 = *alpha0Ptr++; + alphaI = (Guchar)(aResult + alpha0 - div255(aResult * alpha0)); + + //----- result color + if (alphaI == 0) { + cResult0 = 0; + cResult1 = 0; + cResult2 = 0; + } else { + cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI); + cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI); + cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI); + } + + //----- write destination pixel + destColorPtr[0] = cResult0; + destColorPtr[1] = cResult1; + destColorPtr[2] = cResult2; + destColorPtr += 3; + *destAlphaPtr++ = aResult; + + cSrcPtr += cSrcStride; + ++shapePtr; + } // for (x ...) + + updateModX(lastX); +} + +void Splash::pipeRunNonIsoBGR8(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr) { + Guchar shape, aSrc, aDest, alphaI, alpha0, aResult; + Guchar cSrc0, cSrc1, cSrc2; + Guchar cDest0, cDest1, cDest2; + Guchar cResult0, cResult1, cResult2; + SplashColorPtr destColorPtr; + Guchar *destAlphaPtr; + Guchar *alpha0Ptr; + int cSrcStride, x, lastX; + + if (cSrcPtr) { + cSrcStride = 3; + } else { + cSrcPtr = pipe->cSrcVal; + cSrcStride = 0; + } + for (; x0 <= x1; ++x0) { + if (*shapePtr) { + break; + } + cSrcPtr += cSrcStride; + ++shapePtr; + } + if (x0 > x1) { + return; + } + updateModX(x0); + updateModY(y); + lastX = x0; + + useDestRow(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)]; + + for (x = x0; x <= x1; ++x) { + + //----- shape + shape = *shapePtr; + if (!shape) { + destColorPtr += 3; + ++destAlphaPtr; + ++alpha0Ptr; + cSrcPtr += cSrcStride; + ++shapePtr; + continue; + } + lastX = x; + + //----- read destination pixel + cDest0 = destColorPtr[2]; + cDest1 = destColorPtr[1]; + cDest2 = destColorPtr[0]; + aDest = *destAlphaPtr; + + //----- source color + cSrc0 = state->rgbTransferR[cSrcPtr[0]]; + cSrc1 = state->rgbTransferG[cSrcPtr[1]]; + cSrc2 = state->rgbTransferB[cSrcPtr[2]]; + + //----- source alpha + aSrc = div255(pipe->aInput * shape); + + //----- result alpha and non-isolated group element correction + aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest)); + alpha0 = *alpha0Ptr++; + alphaI = (Guchar)(aResult + alpha0 - div255(aResult * alpha0)); + + //----- result color + if (alphaI == 0) { + cResult0 = 0; + cResult1 = 0; + cResult2 = 0; + } else { + cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI); + cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI); + cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI); + } + + //----- write destination pixel + destColorPtr[0] = cResult2; + destColorPtr[1] = cResult1; + destColorPtr[2] = cResult0; + destColorPtr += 3; + *destAlphaPtr++ = aResult; + + cSrcPtr += cSrcStride; + ++shapePtr; + } // for (x ...) + + updateModX(lastX); +} + +#if SPLASH_CMYK +void Splash::pipeRunNonIsoCMYK8(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr) { + Guchar shape, aSrc, aDest, alphaI, alpha0, aResult, aPrev; + Guchar cSrc0, cSrc1, cSrc2, cSrc3; + Guchar cDest0, cDest1, cDest2, cDest3; + Guchar cResult0, cResult1, cResult2, cResult3; + SplashColorPtr destColorPtr; + Guchar *destAlphaPtr; + Guchar *alpha0Ptr; + int cSrcStride, x, lastX; + + if (cSrcPtr) { + cSrcStride = 4; + } else { + cSrcPtr = pipe->cSrcVal; + cSrcStride = 0; + } + for (; x0 <= x1; ++x0) { + if (*shapePtr) { + break; + } + cSrcPtr += cSrcStride; + ++shapePtr; + } + if (x0 > x1) { + return; + } + updateModX(x0); + updateModY(y); + lastX = x0; + + useDestRow(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)]; + + for (x = x0; x <= x1; ++x) { + + //----- shape + shape = *shapePtr; + if (!shape) { + destColorPtr += 4; + ++destAlphaPtr; + ++alpha0Ptr; + cSrcPtr += cSrcStride; + ++shapePtr; + continue; + } + lastX = x; + + //----- read destination pixel + cDest0 = destColorPtr[0]; + cDest1 = destColorPtr[1]; + cDest2 = destColorPtr[2]; + cDest3 = destColorPtr[3]; + aDest = *destAlphaPtr; + + //----- overprint + aPrev = (Guchar)(*alpha0Ptr + aDest - div255(*alpha0Ptr * aDest)); + if (state->overprintMask & 0x01) { + cSrc0 = state->cmykTransferC[cSrcPtr[0]]; + } else { + cSrc0 = div255(aPrev * cDest0); + } + if (state->overprintMask & 0x02) { + cSrc1 = state->cmykTransferM[cSrcPtr[1]]; + } else { + cSrc1 = div255(aPrev * cDest1); + } + if (state->overprintMask & 0x04) { + cSrc2 = state->cmykTransferY[cSrcPtr[2]]; + } else { + cSrc2 = div255(aPrev * cDest2); + } + if (state->overprintMask & 0x08) { + cSrc3 = state->cmykTransferK[cSrcPtr[3]]; + } else { + cSrc3 = div255(aPrev * cDest3); + } + + //----- source alpha + aSrc = div255(pipe->aInput * shape); + + //----- result alpha and non-isolated group element correction + aResult = (Guchar)(aSrc + aDest - div255(aSrc * aDest)); + alpha0 = *alpha0Ptr++; + alphaI = (Guchar)(aResult + alpha0 - div255(aResult * alpha0)); + + //----- result color + if (alphaI == 0) { + cResult0 = 0; + cResult1 = 0; + cResult2 = 0; + cResult3 = 0; + } else { + cResult0 = (Guchar)(((alphaI - aSrc) * cDest0 + aSrc * cSrc0) / alphaI); + cResult1 = (Guchar)(((alphaI - aSrc) * cDest1 + aSrc * cSrc1) / alphaI); + cResult2 = (Guchar)(((alphaI - aSrc) * cDest2 + aSrc * cSrc2) / alphaI); + cResult3 = (Guchar)(((alphaI - aSrc) * cDest3 + aSrc * cSrc3) / alphaI); + } + + //----- write destination pixel + destColorPtr[0] = cResult0; + destColorPtr[1] = cResult1; + destColorPtr[2] = cResult2; + destColorPtr[3] = cResult3; + destColorPtr += 4; + *destAlphaPtr++ = aResult; + + cSrcPtr += cSrcStride; + ++shapePtr; + } // for (x ...) + + updateModX(lastX); +} +#endif + + +void Splash::useDestRow(int y) { + int y0, y1, yy; + + if (groupDestInitMode == splashGroupDestPreInit) { + return; + } + if (groupDestInitYMin > groupDestInitYMax) { + y0 = y1 = y; + groupDestInitYMin = groupDestInitYMax = y; + } else if (y < groupDestInitYMin) { + y0 = y; + y1 = groupDestInitYMin - 1; + groupDestInitYMin = y; + } else if (y > groupDestInitYMax) { + y0 = groupDestInitYMax + 1; + y1 = y; + groupDestInitYMax = y; + } else { + return; + } + for (yy = y0; yy <= y1; ++yy) { + if (groupDestInitMode == splashGroupDestInitZero) { + // same as clear(color=0, alpha=0) + memset(bitmap->data + bitmap->rowSize * yy, 0, + bitmap->rowSize < 0 ? -bitmap->rowSize : bitmap->rowSize); + if (bitmap->alpha) { + memset(bitmap->alpha + bitmap->alphaRowSize * yy, 0, + bitmap->alphaRowSize); + } + } else { // (groupDestInitMode == splashGroupDestInitCopy) + // same as blitTransparent + copyGroupBackdropRow(yy); + } + } +} + +void Splash::copyGroupBackdropRow(int y) { + SplashColorPtr p, q; + Guchar mask, srcMask; + int x; + + if (groupBackBitmap->mode != bitmap->mode) { + return; + } + + if (bitmap->mode == splashModeMono1) { + p = &bitmap->data[y * bitmap->rowSize]; + mask = (Guchar)0x80; + q = &groupBackBitmap->data[(groupBackY + y) * groupBackBitmap->rowSize + + (groupBackX >> 3)]; + srcMask = (Guchar)(0x80 >> (groupBackX & 7)); + for (x = 0; x < bitmap->width; ++x) { + if (*q & srcMask) { + *p |= mask; + } else { + *p &= (Guchar)~mask; + } + if (!(mask = (Guchar)(mask >> 1))) { + mask = 0x80; + ++p; + } + if (!(srcMask = (Guchar)(srcMask >> 1))) { + srcMask = 0x80; + ++q; + } + } + } else { + p = &bitmap->data[y * bitmap->rowSize]; + q = &groupBackBitmap->data[(groupBackY + y) * groupBackBitmap->rowSize + + bitmapComps * groupBackX]; + memcpy(p, q, bitmapComps * bitmap->width); + } + + if (bitmap->alpha) { + memset(&bitmap->alpha[y * bitmap->alphaRowSize], 0, bitmap->width); + } +} + +//------------------------------------------------------------------------ + +// Transform a point from user space to device space. +inline void Splash::transform(SplashCoord *matrix, + SplashCoord xi, SplashCoord yi, + SplashCoord *xo, SplashCoord *yo) { + // [ m[0] m[1] 0 ] + // [xo yo 1] = [xi yi 1] * [ m[2] m[3] 0 ] + // [ m[4] m[5] 1 ] + *xo = xi * matrix[0] + yi * matrix[2] + matrix[4]; + *yo = xi * matrix[1] + yi * matrix[3] + matrix[5]; +} + +//------------------------------------------------------------------------ +// SplashImageCache +//------------------------------------------------------------------------ + +SplashImageCache::SplashImageCache() { + tag = NULL; + width = 0; + height = 0; + mode = splashModeRGB8; + alpha = gFalse; + interpolate = gFalse; + colorData = NULL; + alphaData = NULL; + refCount = 1; +} + +SplashImageCache::~SplashImageCache() { + if (tag) { + delete tag; + } + gfree(colorData); + gfree(alphaData); +} + +GBool SplashImageCache::match(GString *aTag, int aWidth, int aHeight, + SplashColorMode aMode, GBool aAlpha, + GBool aInterpolate) { + return aTag && tag && !aTag->cmp(tag) && + aWidth == width && aHeight == height && + aMode == mode && aAlpha == alpha && + aInterpolate == interpolate; +} + +void SplashImageCache::reset(GString *aTag, int aWidth, int aHeight, + SplashColorMode aMode, GBool aAlpha, + GBool aInterpolate) { + if (tag) { + delete tag; + } + if (aTag) { + tag = aTag->copy(); + } else { + tag = NULL; + } + width = aWidth; + height = aHeight; + mode = aMode; + alpha = aAlpha; + interpolate = aInterpolate; + gfree(colorData); + colorData = NULL; + gfree(alphaData); + alphaData = NULL; +} + +void SplashImageCache::incRefCount() { + ++refCount; +} + +void SplashImageCache::decRefCount() { + --refCount; + if (refCount == 0) { + delete this; + } +} + +//------------------------------------------------------------------------ +// ImageScaler +//------------------------------------------------------------------------ + +// Abstract base class. +class ImageScaler { +public: + + ImageScaler() {} + virtual ~ImageScaler() {} + + // Compute the next line of the scaled image. This can be called up + // to [scaledHeight] times. + virtual void nextLine() = 0; + + // Retrieve the color and alpha data generated by the most recent + // call to nextLine(). + virtual Guchar *colorData() = 0; + virtual Guchar *alphaData() = 0; +}; + +//------------------------------------------------------------------------ +// BasicImageScaler +//------------------------------------------------------------------------ + +// The actual image scaler. +class BasicImageScaler: public ImageScaler { +public: + + BasicImageScaler(SplashImageSource aSrc, void *aSrcData, + int aSrcWidth, int aSrcHeight, int aNComps, GBool aHasAlpha, + int aScaledWidth, int aScaledHeight, GBool aInterpolate); + virtual ~BasicImageScaler(); + virtual void nextLine(); + virtual Guchar *colorData() { return colorLine; } + virtual Guchar *alphaData() { return alphaLine; } + +protected: + + void vertDownscaleHorizDownscale(); + void vertDownscaleHorizUpscaleNoInterp(); + void vertDownscaleHorizUpscaleInterp(); + void vertUpscaleHorizDownscaleNoInterp(); + void vertUpscaleHorizDownscaleInterp(); + void vertUpscaleHorizUpscaleNoInterp(); + void vertUpscaleHorizUpscaleInterp(); + + // source image data function + SplashImageSource src; + void *srcData; + + // source image size + int srcWidth; + int srcHeight; + + // scaled image size + int scaledWidth; + int scaledHeight; + + // number of color and alpha components + int nComps; + GBool hasAlpha; + + // params/state for vertical scaling + int yp, yq; + int yt, yn; + int ySrcCur, yScaledCur; + SplashCoord yInvScale; + + // params for horizontal scaling + int xp, xq; + SplashCoord xInvScale; + + // scaling function + void (BasicImageScaler::*scalingFunc)(); + + // temporary buffers for vertical scaling + Guchar *colorTmpBuf0; + Guchar *colorTmpBuf1; + Guchar *colorTmpBuf2; + Guchar *alphaTmpBuf0; + Guchar *alphaTmpBuf1; + Guchar *alphaTmpBuf2; + Guint *colorAccBuf; + Guint *alphaAccBuf; + + // output of horizontal scaling + Guchar *colorLine; + Guchar *alphaLine; +}; + +BasicImageScaler::BasicImageScaler(SplashImageSource aSrc, void *aSrcData, + int aSrcWidth, int aSrcHeight, + int aNComps, GBool aHasAlpha, + int aScaledWidth, int aScaledHeight, + GBool aInterpolate) { + colorTmpBuf0 = NULL; + colorTmpBuf1 = NULL; + colorTmpBuf2 = NULL; + alphaTmpBuf0 = NULL; + alphaTmpBuf1 = NULL; + alphaTmpBuf2 = NULL; + colorAccBuf = NULL; + alphaAccBuf = NULL; + colorLine = NULL; + alphaLine = NULL; + + src = aSrc; + srcData = aSrcData; + srcWidth = aSrcWidth; + srcHeight = aSrcHeight; + scaledWidth = aScaledWidth; + scaledHeight = aScaledHeight; + nComps = aNComps; + hasAlpha = aHasAlpha; + + // select scaling function; allocate buffers + if (scaledHeight <= srcHeight) { + // vertical downscaling + yp = srcHeight / scaledHeight; + yq = srcHeight % scaledHeight; + yt = 0; + colorTmpBuf0 = (Guchar *)gmallocn(srcWidth, nComps); + colorAccBuf = (Guint *)gmallocn(srcWidth, nComps * (int)sizeof(Guint)); + if (hasAlpha) { + alphaTmpBuf0 = (Guchar *)gmalloc(srcWidth); + alphaAccBuf = (Guint *)gmallocn(srcWidth, sizeof(Guint)); + } + if (scaledWidth <= srcWidth) { + scalingFunc = &BasicImageScaler::vertDownscaleHorizDownscale; + } else { + if (aInterpolate) { + scalingFunc = &BasicImageScaler::vertDownscaleHorizUpscaleInterp; + } else { + scalingFunc = &BasicImageScaler::vertDownscaleHorizUpscaleNoInterp; + } + } + } else { + // vertical upscaling + yp = scaledHeight / srcHeight; + yq = scaledHeight % srcHeight; + yt = 0; + yn = 0; + if (aInterpolate) { + yInvScale = (SplashCoord)srcHeight / (SplashCoord)scaledHeight; + colorTmpBuf0 = (Guchar *)gmallocn(srcWidth, nComps); + colorTmpBuf1 = (Guchar *)gmallocn(srcWidth, nComps); + if (hasAlpha) { + alphaTmpBuf0 = (Guchar *)gmalloc(srcWidth); + alphaTmpBuf1 = (Guchar *)gmalloc(srcWidth); + } + ySrcCur = 0; + yScaledCur = 0; + if (scaledWidth <= srcWidth) { + scalingFunc = &BasicImageScaler::vertUpscaleHorizDownscaleInterp; + } else { + colorTmpBuf2 = (Guchar *)gmallocn(srcWidth, nComps); + if (hasAlpha) { + alphaTmpBuf2 = (Guchar *)gmalloc(srcWidth); + } + scalingFunc = &BasicImageScaler::vertUpscaleHorizUpscaleInterp; + } + } else { + colorTmpBuf0 = (Guchar *)gmallocn(srcWidth, nComps); + if (hasAlpha) { + alphaTmpBuf0 = (Guchar *)gmalloc(srcWidth); + } + if (scaledWidth <= srcWidth) { + scalingFunc = &BasicImageScaler::vertUpscaleHorizDownscaleNoInterp; + } else { + scalingFunc = &BasicImageScaler::vertUpscaleHorizUpscaleNoInterp; + } + } + } + if (scaledWidth <= srcWidth) { + xp = srcWidth / scaledWidth; + xq = srcWidth % scaledWidth; + } else { + xp = scaledWidth / srcWidth; + xq = scaledWidth % srcWidth; + if (aInterpolate) { + xInvScale = (SplashCoord)srcWidth / (SplashCoord)scaledWidth; + } + } + colorLine = (Guchar *)gmallocn(scaledWidth, nComps); + if (hasAlpha) { + alphaLine = (Guchar *)gmalloc(scaledWidth); + } +} + +BasicImageScaler::~BasicImageScaler() { + gfree(colorTmpBuf0); + gfree(colorTmpBuf1); + gfree(colorTmpBuf2); + gfree(alphaTmpBuf0); + gfree(alphaTmpBuf1); + gfree(alphaTmpBuf2); + gfree(colorAccBuf); + gfree(alphaAccBuf); + gfree(colorLine); + gfree(alphaLine); +} + +void BasicImageScaler::nextLine() { + (this->*scalingFunc)(); +} + +void BasicImageScaler::vertDownscaleHorizDownscale() { + //--- vert downscale + int yStep = yp; + yt += yq; + if (yt >= scaledHeight) { + yt -= scaledHeight; + ++yStep; + } + memset(colorAccBuf, 0, (srcWidth * nComps) * sizeof(Guint)); + if (hasAlpha) { + memset(alphaAccBuf, 0, srcWidth * sizeof(Guint)); + } + int nRowComps = srcWidth * nComps; + for (int i = 0; i < yStep; ++i) { + (*src)(srcData, colorTmpBuf0, alphaTmpBuf0); + for (int j = 0; j < nRowComps; ++j) { + colorAccBuf[j] += colorTmpBuf0[j]; + } + if (hasAlpha) { + for (int j = 0; j < srcWidth; ++j) { + alphaAccBuf[j] += alphaTmpBuf0[j]; + } + } + } + + //--- horiz downscale + int colorAcc[splashMaxColorComps]; + int xt = 0; + int unscaledColorIdx = 0; + int unscaledAlphaIdx = 0; + int scaledColorIdx = 0; + + for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) { + int xStep = xp; + xt += xq; + if (xt >= scaledWidth) { + xt -= scaledWidth; + ++xStep; + } + + for (int j = 0; j < nComps; ++j) { + colorAcc[j] = 0; + } + for (int i = 0; i < xStep; ++i) { + for (int j = 0; j < nComps; ++j) { + colorAcc[j] += colorAccBuf[unscaledColorIdx + j]; + } + unscaledColorIdx += nComps; + } + int nPixels = yStep * xStep; + for (int j = 0; j < nComps; ++j) { + colorLine[scaledColorIdx + j] = (Guchar)(colorAcc[j] / nPixels); + } + scaledColorIdx += nComps; + + if (hasAlpha) { + int alphaAcc = 0; + for (int i = 0; i < xStep; ++i) { + alphaAcc += alphaAccBuf[unscaledAlphaIdx]; + ++unscaledAlphaIdx; + } + alphaLine[scaledIdx] = (Guchar)(alphaAcc / nPixels); + } + } +} + +void BasicImageScaler::vertDownscaleHorizUpscaleNoInterp() { + //--- vert downscale + int yStep = yp; + yt += yq; + if (yt >= scaledHeight) { + yt -= scaledHeight; + ++yStep; + } + memset(colorAccBuf, 0, (srcWidth * nComps) * sizeof(Guint)); + if (hasAlpha) { + memset(alphaAccBuf, 0, srcWidth * sizeof(Guint)); + } + int nRowComps = srcWidth * nComps; + for (int i = 0; i < yStep; ++i) { + (*src)(srcData, colorTmpBuf0, alphaTmpBuf0); + for (int j = 0; j < nRowComps; ++j) { + colorAccBuf[j] += colorTmpBuf0[j]; + } + if (hasAlpha) { + for (int j = 0; j < srcWidth; ++j) { + alphaAccBuf[j] += alphaTmpBuf0[j]; + } + } + } + + //--- horiz upscale + Guchar colorBuf[splashMaxColorComps]; + int xt = 0; + int scaledColorIdx = 0; + int srcColorIdx = 0; + int scaledAlphaIdx = 0; + for (int srcIdx = 0; srcIdx < srcWidth; ++srcIdx) { + int xStep = xp; + xt += xq; + if (xt >= srcWidth) { + xt -= srcWidth; + ++xStep; + } + for (int j = 0; j < nComps; ++j) { + colorBuf[j] = (Guchar)(colorAccBuf[srcColorIdx + j] / yStep); + } + srcColorIdx += nComps; + for (int i = 0; i < xStep; ++i) { + for (int j = 0; j < nComps; ++j) { + colorLine[scaledColorIdx + j] = colorBuf[j]; + } + scaledColorIdx += nComps; + } + if (hasAlpha) { + Guchar alphaBuf = (Guchar)(alphaAccBuf[srcIdx] / yStep); + for (int i = 0; i < xStep; ++i) { + alphaLine[scaledAlphaIdx] = alphaBuf; + ++scaledAlphaIdx; + } + } + } +} + +void BasicImageScaler::vertDownscaleHorizUpscaleInterp() { + //--- vert downscale + int yStep = yp; + yt += yq; + if (yt >= scaledHeight) { + yt -= scaledHeight; + ++yStep; + } + memset(colorAccBuf, 0, (srcWidth * nComps) * sizeof(Guint)); + if (hasAlpha) { + memset(alphaAccBuf, 0, srcWidth * sizeof(Guint)); + } + int nRowComps = srcWidth * nComps; + for (int i = 0; i < yStep; ++i) { + (*src)(srcData, colorTmpBuf0, alphaTmpBuf0); + for (int j = 0; j < nRowComps; ++j) { + colorAccBuf[j] += colorTmpBuf0[j]; + } + if (hasAlpha) { + for (int j = 0; j < srcWidth; ++j) { + alphaAccBuf[j] += alphaTmpBuf0[j]; + } + } + } + for (int j = 0; j < srcWidth * nComps; ++j) { + colorAccBuf[j] /= yStep; + } + if (hasAlpha) { + for (int j = 0; j < srcWidth; ++j) { + alphaAccBuf[j] /= yStep; + } + } + + //--- horiz upscale + int scaledColorIdx = 0; + for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) { + SplashCoord xs = ((SplashCoord)scaledIdx + 0.5) * xInvScale; + int x0 = splashFloor(xs - 0.5); + int x1 = x0 + 1; + SplashCoord s0 = (SplashCoord)x1 + 0.5 - xs; + SplashCoord s1 = (SplashCoord)1 - s0; + if (x0 < 0) { + x0 = 0; + } + if (x1 >= srcWidth) { + x1 = srcWidth - 1; + } + for (int j = 0; j < nComps; ++j) { + colorLine[scaledColorIdx + j] = + (Guchar)(int)(s0 * colorAccBuf[x0 * nComps + j] + + s1 * colorAccBuf[x1 * nComps + j]); + } + scaledColorIdx += nComps; + if (hasAlpha) { + alphaLine[scaledIdx] = (Guchar)(int)(s0 * alphaAccBuf[x0] + + s1 * alphaAccBuf[x1]); + } + } +} + +void BasicImageScaler::vertUpscaleHorizDownscaleNoInterp() { + //--- vert upscale + if (yn == 0) { + yn = yp; + yt += yq; + if (yt >= srcHeight) { + yt -= srcHeight; + ++yn; + } + (*src)(srcData, colorTmpBuf0, alphaTmpBuf0); + } + --yn; + + //--- horiz downscale + int colorAcc[splashMaxColorComps]; + int xt = 0; + int unscaledColorIdx = 0; + int unscaledAlphaIdx = 0; + int scaledColorIdx = 0; + for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) { + int xStep = xp; + xt += xq; + if (xt >= scaledWidth) { + xt -= scaledWidth; + ++xStep; + } + + for (int j = 0; j < nComps; ++j) { + colorAcc[j] = 0; + } + for (int i = 0; i < xStep; ++i) { + for (int j = 0; j < nComps; ++j) { + colorAcc[j] += colorTmpBuf0[unscaledColorIdx + j]; + } + unscaledColorIdx += nComps; + } + for (int j = 0; j < nComps; ++j) { + colorLine[scaledColorIdx + j] = (Guchar)(colorAcc[j] / xStep); + } + scaledColorIdx += nComps; + + if (hasAlpha) { + int alphaAcc = 0; + for (int i = 0; i < xStep; ++i) { + alphaAcc += alphaTmpBuf0[unscaledAlphaIdx]; + ++unscaledAlphaIdx; + } + alphaLine[scaledIdx] = (Guchar)(alphaAcc / xStep); + } + } +} + +void BasicImageScaler::vertUpscaleHorizDownscaleInterp() { + //--- vert upscale + if (ySrcCur == 0) { + (*src)(srcData, colorTmpBuf0, alphaTmpBuf0); + (*src)(srcData, colorTmpBuf1, alphaTmpBuf1); + ySrcCur = 1; + } + SplashCoord ys = ((SplashCoord)yScaledCur + 0.5) * yInvScale; + int y0 = splashFloor(ys - 0.5); + int y1 = y0 + 1; + SplashCoord vs0 = (SplashCoord)y1 + 0.5 - ys; + SplashCoord vs1 = (SplashCoord)1 - vs0; + if (y1 > ySrcCur && ySrcCur < srcHeight - 1) { + Guchar *t = colorTmpBuf0; + colorTmpBuf0 = colorTmpBuf1; + colorTmpBuf1 = t; + if (hasAlpha) { + t = alphaTmpBuf0; + alphaTmpBuf0 = alphaTmpBuf1; + alphaTmpBuf1 = t; + } + (*src)(srcData, colorTmpBuf1, alphaTmpBuf1); + ++ySrcCur; + } + Guchar *color0 = colorTmpBuf0; + Guchar *color1 = colorTmpBuf1; + Guchar *alpha0 = alphaTmpBuf0; + Guchar *alpha1 = alphaTmpBuf1; + if (y0 < 0) { + y0 = 0; + color1 = color0; + alpha1 = alpha0; + } + if (y1 >= srcHeight) { + y1 = srcHeight - 1; + color0 = color1; + alpha0 = alpha1; + } + ++yScaledCur; + + //--- horiz downscale + int colorAcc[splashMaxColorComps]; + int xt = 0; + int unscaledColorIdx = 0; + int unscaledAlphaIdx = 0; + int scaledColorIdx = 0; + for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) { + int xStep = xp; + xt += xq; + if (xt >= scaledWidth) { + xt -= scaledWidth; + ++xStep; + } + + for (int j = 0; j < nComps; ++j) { + colorAcc[j] = 0; + } + for (int i = 0; i < xStep; ++i) { + for (int j = 0; j < nComps; ++j) { + colorAcc[j] += (int)(vs0 * (int)color0[unscaledColorIdx + j] + + vs1 * (int)color1[unscaledColorIdx + j]); + } + unscaledColorIdx += nComps; + } + for (int j = 0; j < nComps; ++j) { + colorLine[scaledColorIdx + j] = (Guchar)(colorAcc[j] / xStep); + } + scaledColorIdx += nComps; + + if (hasAlpha) { + int alphaAcc = 0; + for (int i = 0; i < xStep; ++i) { + alphaAcc += (int)(vs0 * (int)alpha0[unscaledAlphaIdx] + + vs1 * (int)alpha1[unscaledAlphaIdx]); + ++unscaledAlphaIdx; + } + alphaLine[scaledIdx] = (Guchar)(alphaAcc / xStep); + } + } +} + +void BasicImageScaler::vertUpscaleHorizUpscaleNoInterp() { + //--- vert upscale + if (yn == 0) { + yn = yp; + yt += yq; + if (yt >= srcHeight) { + yt -= srcHeight; + ++yn; + } + (*src)(srcData, colorTmpBuf0, alphaTmpBuf0); + } + --yn; + + //--- horiz upscale + int xt = 0; + int scaledColorIdx = 0; + int srcColorIdx = 0; + int scaledAlphaIdx = 0; + for (int srcIdx = 0; srcIdx < srcWidth; ++srcIdx) { + int xStep = xp; + xt += xq; + if (xt >= srcWidth) { + xt -= srcWidth; + ++xStep; + } + for (int i = 0; i < xStep; ++i) { + for (int j = 0; j < nComps; ++j) { + colorLine[scaledColorIdx + j] = colorTmpBuf0[srcColorIdx + j]; + } + scaledColorIdx += nComps; + } + srcColorIdx += nComps; + if (hasAlpha) { + Guchar alphaBuf = alphaTmpBuf0[srcIdx]; + for (int i = 0; i < xStep; ++i) { + alphaLine[scaledAlphaIdx] = alphaBuf; + ++scaledAlphaIdx; + } + } + } +} + +void BasicImageScaler::vertUpscaleHorizUpscaleInterp() { + //--- vert upscale + if (ySrcCur == 0) { + (*src)(srcData, colorTmpBuf0, alphaTmpBuf0); + (*src)(srcData, colorTmpBuf1, alphaTmpBuf1); + ySrcCur = 1; + } + SplashCoord ys = ((SplashCoord)yScaledCur + 0.5) * yInvScale; + int y0 = splashFloor(ys - 0.5); + int y1 = y0 + 1; + SplashCoord vs0 = (SplashCoord)y1 + 0.5 - ys; + SplashCoord vs1 = (SplashCoord)1 - vs0; + if (y1 > ySrcCur && ySrcCur < srcHeight - 1) { + Guchar *t = colorTmpBuf0; + colorTmpBuf0 = colorTmpBuf1; + colorTmpBuf1 = t; + if (hasAlpha) { + t = alphaTmpBuf0; + alphaTmpBuf0 = alphaTmpBuf1; + alphaTmpBuf1 = t; + } + (*src)(srcData, colorTmpBuf1, alphaTmpBuf1); + ++ySrcCur; + } + Guchar *color0 = colorTmpBuf0; + Guchar *color1 = colorTmpBuf1; + Guchar *alpha0 = alphaTmpBuf0; + Guchar *alpha1 = alphaTmpBuf1; + if (y0 < 0) { + y0 = 0; + color1 = color0; + alpha1 = alpha0; + } + if (y1 >= srcHeight) { + y1 = srcHeight - 1; + color0 = color1; + alpha0 = alpha1; + } + ++yScaledCur; + for (int srcIdx = 0; srcIdx < srcWidth * nComps; ++srcIdx) { + colorTmpBuf2[srcIdx] = (Guchar)(int)(vs0 * (int)color0[srcIdx] + + vs1 * (int)color1[srcIdx]); + } + if (hasAlpha) { + for (int srcIdx = 0; srcIdx < srcWidth; ++srcIdx) { + alphaTmpBuf2[srcIdx] = (Guchar)(int)(vs0 * (int)alpha0[srcIdx] + + vs1 * (int)alpha1[srcIdx]); + } + } + + //--- horiz upscale + int scaledColorIdx = 0; + for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) { + SplashCoord xs = ((SplashCoord)scaledIdx + 0.5) * xInvScale; + int x0 = splashFloor(xs - 0.5); + int x1 = x0 + 1; + SplashCoord hs0 = (SplashCoord)x1 + 0.5 - xs; + SplashCoord hs1 = (SplashCoord)1 - hs0; + if (x0 < 0) { + x0 = 0; + } + if (x1 >= srcWidth) { + x1 = srcWidth - 1; + } + for (int j = 0; j < nComps; ++j) { + colorLine[scaledColorIdx + j] = + (Guchar)(int)(hs0 * (int)colorTmpBuf2[x0 * nComps + j] + + hs1 * (int)colorTmpBuf2[x1 * nComps + j]); + } + scaledColorIdx += nComps; + if (hasAlpha) { + alphaLine[scaledIdx] = (Guchar)(int)(hs0 * (int)alphaTmpBuf2[x0] + + hs1 * (int)alphaTmpBuf2[x1]); + } + } +} + +//------------------------------------------------------------------------ +// SavingImageScaler +//------------------------------------------------------------------------ + +// Wrapper around BasicImageScaler that saves the scaled image for use +// by ReplayImageScaler. +class SavingImageScaler: public BasicImageScaler { +public: + + SavingImageScaler(SplashImageSource aSrc, void *aSrcData, + int aSrcWidth, int aSrcHeight, int aNComps, GBool aHasAlpha, + int aScaledWidth, int aScaledHeight, GBool aInterpolate, + Guchar *aColorCache, Guchar *aAlphaCache); + virtual void nextLine(); + +private: + + Guchar *colorPtr; + Guchar *alphaPtr; +}; + +SavingImageScaler::SavingImageScaler(SplashImageSource aSrc, void *aSrcData, + int aSrcWidth, int aSrcHeight, + int aNComps, GBool aHasAlpha, + int aScaledWidth, int aScaledHeight, + GBool aInterpolate, + Guchar *aColorCache, Guchar *aAlphaCache): + BasicImageScaler(aSrc, aSrcData, aSrcWidth, aSrcHeight, aNComps, aHasAlpha, + aScaledWidth, aScaledHeight, aInterpolate) +{ + colorPtr = aColorCache; + alphaPtr = aAlphaCache; +} + +void SavingImageScaler::nextLine() { + BasicImageScaler::nextLine(); + memcpy(colorPtr, colorData(), scaledWidth * nComps); + colorPtr += scaledWidth * nComps; + if (hasAlpha) { + memcpy(alphaPtr, alphaData(), scaledWidth); + alphaPtr += scaledWidth; + } +} + +//------------------------------------------------------------------------ +// ReplayImageScaler +//------------------------------------------------------------------------ + +// "Replay" a scaled image saved by SavingImageScaler. +class ReplayImageScaler: public ImageScaler { +public: + + ReplayImageScaler(int aNComps, GBool aHasAlpha, + int aScaledWidth, + Guchar *aColorCache, Guchar *aAlphaCache); + virtual void nextLine(); + virtual Guchar *colorData() { return colorLine; } + virtual Guchar *alphaData() { return alphaLine; } + +private: + + int nComps; + GBool hasAlpha; + int scaledWidth; + Guchar *colorPtr; + Guchar *alphaPtr; + Guchar *colorLine; + Guchar *alphaLine; +}; + +ReplayImageScaler::ReplayImageScaler(int aNComps, GBool aHasAlpha, + int aScaledWidth, + Guchar *aColorCache, Guchar *aAlphaCache) { + nComps = aNComps; + hasAlpha = aHasAlpha; + scaledWidth = aScaledWidth; + colorPtr = aColorCache; + alphaPtr = aAlphaCache; + colorLine = NULL; + alphaLine = NULL; +} + +void ReplayImageScaler::nextLine() { + colorLine = colorPtr; + alphaLine = alphaPtr; + colorPtr += scaledWidth * nComps; + if (hasAlpha) { + alphaPtr += scaledWidth; + } +} + +//------------------------------------------------------------------------ +// ImageMaskScaler +//------------------------------------------------------------------------ + +class ImageMaskScaler { +public: + + // Set up a MaskScaler to scale from [srcWidth]x[srcHeight] to + // [scaledWidth]x[scaledHeight]. The [interpolate] flag controls + // filtering on upsampling, and the [antialias] flag controls + // filtering on downsampling. + ImageMaskScaler(SplashImageMaskSource aSrc, void *aSrcData, + int aSrcWidth, int aSrcHeight, + int aScaledWidth, int aScaledHeight, + GBool aInterpolate, GBool aAntialias); + + ~ImageMaskScaler(); + + // Compute the next line of the scaled image mask. This can be + // called up to [scaledHeight] times. + void nextLine(); + + // Retrieve the data generated by the most recent call to + // nextLine(). + Guchar *data() { return line; } + +private: + + void vertDownscaleHorizDownscale(); + void vertDownscaleHorizDownscaleThresh(); + void vertDownscaleHorizUpscaleNoInterp(); + void vertDownscaleHorizUpscaleInterp(); + void vertDownscaleHorizUpscaleThresh(); + void vertUpscaleHorizDownscaleNoInterp(); + void vertUpscaleHorizDownscaleInterp(); + void vertUpscaleHorizDownscaleThresh(); + void vertUpscaleHorizUpscaleNoInterp(); + void vertUpscaleHorizUpscaleInterp(); + + // source image data function + SplashImageMaskSource src; + void *srcData; + + // source image size + int srcWidth; + int srcHeight; + + // scaled image size + int scaledWidth; + int scaledHeight; + + // params/state for vertical scaling + int yp, yq; + int yt, yn; + int ySrcCur, yScaledCur; + SplashCoord yInvScale; + + // params for horizontal scaling + int xp, xq; + SplashCoord xInvScale; + + // vertical and horizontal scaling functions + void (ImageMaskScaler::*scalingFunc)(); + + // temporary buffers for vertical scaling + Guchar *tmpBuf0; + Guchar *tmpBuf1; + Guchar *tmpBuf2; + Guint *accBuf; + + // output of horizontal scaling + Guchar *line; +}; + +ImageMaskScaler::ImageMaskScaler(SplashImageMaskSource aSrc, void *aSrcData, + int aSrcWidth, int aSrcHeight, + int aScaledWidth, int aScaledHeight, + GBool aInterpolate, GBool aAntialias) { + tmpBuf0 = NULL; + tmpBuf1 = NULL; + tmpBuf2 = NULL; + accBuf = NULL; + line = NULL; + + src = aSrc; + srcData = aSrcData; + srcWidth = aSrcWidth; + srcHeight = aSrcHeight; + scaledWidth = aScaledWidth; + scaledHeight = aScaledHeight; + + // select scaling function; allocate buffers + if (scaledHeight <= srcHeight) { + // vertical downscaling + yp = srcHeight / scaledHeight; + yq = srcHeight % scaledHeight; + yt = 0; + tmpBuf0 = (Guchar *)gmalloc(srcWidth); + accBuf = (Guint *)gmallocn(srcWidth, sizeof(Guint)); + if (scaledWidth <= srcWidth) { + if (!aAntialias) { + scalingFunc = &ImageMaskScaler::vertDownscaleHorizDownscaleThresh; + } else { + scalingFunc = &ImageMaskScaler::vertDownscaleHorizDownscale; + } + } else { + if (!aAntialias) { + scalingFunc = &ImageMaskScaler::vertDownscaleHorizUpscaleThresh; + } else if (aInterpolate) { + scalingFunc = &ImageMaskScaler::vertDownscaleHorizUpscaleInterp; + } else { + scalingFunc = &ImageMaskScaler::vertDownscaleHorizUpscaleNoInterp; + } + } + } else { + // vertical upscaling + yp = scaledHeight / srcHeight; + yq = scaledHeight % srcHeight; + yt = 0; + yn = 0; + if (!aAntialias) { + tmpBuf0 = (Guchar *)gmalloc(srcWidth); + if (scaledWidth <= srcWidth) { + scalingFunc = &ImageMaskScaler::vertUpscaleHorizDownscaleThresh; + } else { + scalingFunc = &ImageMaskScaler::vertUpscaleHorizUpscaleNoInterp; + } + } else if (aInterpolate) { + yInvScale = (SplashCoord)srcHeight / (SplashCoord)scaledHeight; + tmpBuf0 = (Guchar *)gmalloc(srcWidth); + tmpBuf1 = (Guchar *)gmalloc(srcWidth); + ySrcCur = 0; + yScaledCur = 0; + if (scaledWidth <= srcWidth) { + scalingFunc = &ImageMaskScaler::vertUpscaleHorizDownscaleInterp; + } else { + tmpBuf2 = (Guchar *)gmalloc(srcWidth); + scalingFunc = &ImageMaskScaler::vertUpscaleHorizUpscaleInterp; + } + } else { + tmpBuf0 = (Guchar *)gmalloc(srcWidth); + if (scaledWidth <= srcWidth) { + scalingFunc = &ImageMaskScaler::vertUpscaleHorizDownscaleNoInterp; + } else { + scalingFunc = &ImageMaskScaler::vertUpscaleHorizUpscaleNoInterp; + } + } + } + if (scaledWidth <= srcWidth) { + xp = srcWidth / scaledWidth; + xq = srcWidth % scaledWidth; + } else { + xp = scaledWidth / srcWidth; + xq = scaledWidth % srcWidth; + if (aInterpolate) { + xInvScale = (SplashCoord)srcWidth / (SplashCoord)scaledWidth; + } + } + line = (Guchar *)gmalloc(scaledWidth); +} + +ImageMaskScaler::~ImageMaskScaler() { + gfree(tmpBuf0); + gfree(tmpBuf1); + gfree(tmpBuf2); + gfree(accBuf); + gfree(line); +} + +void ImageMaskScaler::nextLine() { + (this->*scalingFunc)(); +} + +void ImageMaskScaler::vertDownscaleHorizDownscale() { + //--- vert downscale + int yStep = yp; + yt += yq; + if (yt >= scaledHeight) { + yt -= scaledHeight; + ++yStep; + } + memset(accBuf, 0, srcWidth * sizeof(Guint)); + for (int i = 0; i < yStep; ++i) { + (*src)(srcData, tmpBuf0); + for (int j = 0; j < srcWidth; ++j) { + accBuf[j] += tmpBuf0[j]; + } + } + + //--- horiz downscale + int acc; + int xt = 0; + int unscaledIdx = 0; + for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) { + int xStep = xp; + xt += xq; + if (xt >= scaledWidth) { + xt -= scaledWidth; + ++xStep; + } + + acc = 0; + for (int i = 0; i < xStep; ++i) { + acc += accBuf[unscaledIdx]; + ++unscaledIdx; + } + line[scaledIdx] = (Guchar)((255 * acc) / (xStep * yStep)); + } +} + +void ImageMaskScaler::vertDownscaleHorizDownscaleThresh() { + //--- vert downscale + int yStep = yp; + yt += yq; + if (yt >= scaledHeight) { + yt -= scaledHeight; + ++yStep; + } + memset(accBuf, 0, srcWidth * sizeof(Guint)); + for (int i = 0; i < yStep; ++i) { + (*src)(srcData, tmpBuf0); + for (int j = 0; j < srcWidth; ++j) { + accBuf[j] += tmpBuf0[j]; + } + } + + //--- horiz downscale + int acc; + int xt = 0; + int unscaledIdx = 0; + for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) { + int xStep = xp; + xt += xq; + if (xt >= scaledWidth) { + xt -= scaledWidth; + ++xStep; + } + + acc = 0; + for (int i = 0; i < xStep; ++i) { + acc += accBuf[unscaledIdx]; + ++unscaledIdx; + } + line[scaledIdx] = acc > ((xStep * yStep) >> 1) ? (Guchar)255 : (Guchar)0; + } +} + +void ImageMaskScaler::vertDownscaleHorizUpscaleNoInterp() { + //--- vert downscale + int yStep = yp; + yt += yq; + if (yt >= scaledHeight) { + yt -= scaledHeight; + ++yStep; + } + memset(accBuf, 0, srcWidth * sizeof(Guint)); + for (int i = 0; i < yStep; ++i) { + (*src)(srcData, tmpBuf0); + for (int j = 0; j < srcWidth; ++j) { + accBuf[j] += tmpBuf0[j]; + } + } + + //--- horiz upscale + int xt = 0; + int scaledIdx = 0; + for (int srcIdx = 0; srcIdx < srcWidth; ++srcIdx) { + int xStep = xp; + xt += xq; + if (xt >= srcWidth) { + xt -= srcWidth; + ++xStep; + } + Guchar buf = (Guchar)((255 * accBuf[srcIdx]) / yStep); + for (int i = 0; i < xStep; ++i) { + line[scaledIdx] = buf; + ++scaledIdx; + } + } +} + +void ImageMaskScaler::vertDownscaleHorizUpscaleInterp() { + //--- vert downscale + int yStep = yp; + yt += yq; + if (yt >= scaledHeight) { + yt -= scaledHeight; + ++yStep; + } + memset(accBuf, 0, srcWidth * sizeof(Guint)); + for (int i = 0; i < yStep; ++i) { + (*src)(srcData, tmpBuf0); + for (int j = 0; j < srcWidth; ++j) { + accBuf[j] += tmpBuf0[j]; + } + } + for (int j = 0; j < srcWidth; ++j) { + accBuf[j] = (255 * accBuf[j]) / yStep; + } + + //--- horiz upscale + for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) { + SplashCoord xs = ((SplashCoord)scaledIdx + 0.5) * xInvScale; + int x0 = splashFloor(xs - 0.5); + int x1 = x0 + 1; + SplashCoord s0 = (SplashCoord)x1 + 0.5 - xs; + SplashCoord s1 = (SplashCoord)1 - s0; + if (x0 < 0) { + x0 = 0; + } + if (x1 >= srcWidth) { + x1 = srcWidth - 1; + } + line[scaledIdx] = (Guchar)(int)(s0 * accBuf[x0] + s1 * accBuf[x1]); + } +} + +void ImageMaskScaler::vertDownscaleHorizUpscaleThresh() { + //--- vert downscale + int yStep = yp; + yt += yq; + if (yt >= scaledHeight) { + yt -= scaledHeight; + ++yStep; + } + memset(accBuf, 0, srcWidth * sizeof(Guint)); + for (int i = 0; i < yStep; ++i) { + (*src)(srcData, tmpBuf0); + for (int j = 0; j < srcWidth; ++j) { + accBuf[j] += tmpBuf0[j]; + } + } + + //--- horiz upscale + int xt = 0; + int scaledIdx = 0; + for (int srcIdx = 0; srcIdx < srcWidth; ++srcIdx) { + int xStep = xp; + xt += xq; + if (xt >= srcWidth) { + xt -= srcWidth; + ++xStep; + } + Guchar buf = accBuf[srcIdx] > (Guint)(yStep >> 1) ? (Guchar)255 : (Guchar)0; + for (int i = 0; i < xStep; ++i) { + line[scaledIdx] = buf; + ++scaledIdx; + } + } +} + +void ImageMaskScaler::vertUpscaleHorizDownscaleNoInterp() { + //--- vert upscale + if (yn == 0) { + yn = yp; + yt += yq; + if (yt >= srcHeight) { + yt -= srcHeight; + ++yn; + } + (*src)(srcData, tmpBuf0); + } + --yn; + + //--- horiz downscale + int acc; + int xt = 0; + int unscaledIdx = 0; + for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) { + int xStep = xp; + xt += xq; + if (xt >= scaledWidth) { + xt -= scaledWidth; + ++xStep; + } + + acc = 0; + for (int i = 0; i < xStep; ++i) { + acc += tmpBuf0[unscaledIdx]; + ++unscaledIdx; + } + line[scaledIdx] = (Guchar)((255 * acc) / xStep); + } +} + +void ImageMaskScaler::vertUpscaleHorizDownscaleInterp() { + //--- vert upscale + if (ySrcCur == 0) { + (*src)(srcData, tmpBuf0); + (*src)(srcData, tmpBuf1); + ySrcCur = 1; + } + SplashCoord ys = ((SplashCoord)yScaledCur + 0.5) * yInvScale; + int y0 = splashFloor(ys - 0.5); + int y1 = y0 + 1; + SplashCoord vs0 = (SplashCoord)y1 + 0.5 - ys; + SplashCoord vs1 = (SplashCoord)1 - vs0; + if (y1 > ySrcCur && ySrcCur < srcHeight - 1) { + Guchar *t = tmpBuf0; + tmpBuf0 = tmpBuf1; + tmpBuf1 = t; + (*src)(srcData, tmpBuf1); + ++ySrcCur; + } + Guchar *mask0 = tmpBuf0; + Guchar *mask1 = tmpBuf1; + if (y0 < 0) { + y0 = 0; + mask1 = mask0; + } + if (y1 >= srcHeight) { + y1 = srcHeight - 1; + mask0 = mask1; + } + ++yScaledCur; + + //--- horiz downscale + int acc; + int xt = 0; + int unscaledIdx = 0; + for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) { + int xStep = xp; + xt += xq; + if (xt >= scaledWidth) { + xt -= scaledWidth; + ++xStep; + } + + acc = 0; + for (int i = 0; i < xStep; ++i) { + acc += (int)(vs0 * (int)mask0[unscaledIdx] + + vs1 * (int)mask1[unscaledIdx]); + ++unscaledIdx; + } + line[scaledIdx] = (Guchar)((255 * acc) / xStep); + } +} + +void ImageMaskScaler::vertUpscaleHorizDownscaleThresh() { + //--- vert upscale + if (yn == 0) { + yn = yp; + yt += yq; + if (yt >= srcHeight) { + yt -= srcHeight; + ++yn; + } + (*src)(srcData, tmpBuf0); + } + --yn; + + //--- horiz downscale + int acc; + int xt = 0; + int unscaledIdx = 0; + for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) { + int xStep = xp; + xt += xq; + if (xt >= scaledWidth) { + xt -= scaledWidth; + ++xStep; + } + + acc = 0; + for (int i = 0; i < xStep; ++i) { + acc += tmpBuf0[unscaledIdx]; + ++unscaledIdx; + } + line[scaledIdx] = acc > (xStep >> 1) ? (Guchar)255 : (Guchar)0; + } +} + +void ImageMaskScaler::vertUpscaleHorizUpscaleNoInterp() { + //--- vert upscale + if (yn == 0) { + yn = yp; + yt += yq; + if (yt >= srcHeight) { + yt -= srcHeight; + ++yn; + } + (*src)(srcData, tmpBuf0); + } + --yn; + + //--- horiz upscale + int xt = 0; + int scaledIdx = 0; + for (int srcIdx = 0; srcIdx < srcWidth; ++srcIdx) { + int xStep = xp; + xt += xq; + if (xt >= srcWidth) { + xt -= srcWidth; + ++xStep; + } + Guchar buf = (Guchar)(255 * tmpBuf0[srcIdx]); + for (int i = 0; i < xStep; ++i) { + line[scaledIdx] = buf; + ++scaledIdx; + } + } +} + +void ImageMaskScaler::vertUpscaleHorizUpscaleInterp() { + //--- vert upscale + if (ySrcCur == 0) { + (*src)(srcData, tmpBuf0); + (*src)(srcData, tmpBuf1); + ySrcCur = 1; + } + SplashCoord ys = ((SplashCoord)yScaledCur + 0.5) * yInvScale; + int y0 = splashFloor(ys - 0.5); + int y1 = y0 + 1; + SplashCoord vs0 = (SplashCoord)255 * ((SplashCoord)y1 + 0.5 - ys); + SplashCoord vs1 = (SplashCoord)255 - vs0; + if (y1 > ySrcCur && ySrcCur < srcHeight - 1) { + Guchar *t = tmpBuf0; + tmpBuf0 = tmpBuf1; + tmpBuf1 = t; + (*src)(srcData, tmpBuf1); + ++ySrcCur; + } + Guchar *mask0 = tmpBuf0; + Guchar *mask1 = tmpBuf1; + if (y0 < 0) { + y0 = 0; + mask1 = mask0; + } + if (y1 >= srcHeight) { + y1 = srcHeight - 1; + mask0 = mask1; + } + ++yScaledCur; + for (int srcIdx = 0; srcIdx < srcWidth; ++srcIdx) { + tmpBuf2[srcIdx] = (Guchar)(int)(vs0 * (int)mask0[srcIdx] + + vs1 * (int)mask1[srcIdx]); + } + + //--- horiz upscale + for (int scaledIdx = 0; scaledIdx < scaledWidth; ++scaledIdx) { + SplashCoord xs = ((SplashCoord)scaledIdx + 0.5) * xInvScale; + int x0 = splashFloor(xs - 0.5); + int x1 = x0 + 1; + SplashCoord hs0 = (SplashCoord)x1 + 0.5 - xs; + SplashCoord hs1 = (SplashCoord)1 - hs0; + if (x0 < 0) { + x0 = 0; + } + if (x1 >= srcWidth) { + x1 = srcWidth - 1; + } + line[scaledIdx] = (Guchar)(int)(hs0 * (int)tmpBuf2[x0] + + hs1 * (int)tmpBuf2[x1]); + } +} + +//------------------------------------------------------------------------ +// Splash +//------------------------------------------------------------------------ + +Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA, + SplashImageCache *imageCacheA, + SplashScreenParams *screenParams) { + bitmap = bitmapA; + bitmapComps = splashColorModeNComps[bitmap->mode]; + vectorAntialias = vectorAntialiasA; + inShading = gFalse; + state = new SplashState(bitmap->width, bitmap->height, vectorAntialias, + screenParams); + scanBuf = (Guchar *)gmalloc(bitmap->width); + if (bitmap->mode == splashModeMono1) { + scanBuf2 = (Guchar *)gmalloc(bitmap->width); + } else { + scanBuf2 = NULL; + } + groupBackBitmap = NULL; + groupDestInitMode = splashGroupDestPreInit; + overprintMaskBitmap = NULL; + minLineWidth = 0; + clearModRegion(); + debugMode = gFalse; + + if (imageCacheA) { + imageCache = imageCacheA; + imageCache->incRefCount(); + } else { + imageCache = new SplashImageCache(); + } +} + +Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA, + SplashImageCache *imageCacheA, SplashScreen *screenA) { + bitmap = bitmapA; + bitmapComps = splashColorModeNComps[bitmap->mode]; + vectorAntialias = vectorAntialiasA; + inShading = gFalse; + state = new SplashState(bitmap->width, bitmap->height, vectorAntialias, + screenA); + scanBuf = (Guchar *)gmalloc(bitmap->width); + if (bitmap->mode == splashModeMono1) { + scanBuf2 = (Guchar *)gmalloc(bitmap->width); + } else { + scanBuf2 = NULL; + } + groupBackBitmap = NULL; + groupDestInitMode = splashGroupDestPreInit; + overprintMaskBitmap = NULL; + minLineWidth = 0; + clearModRegion(); + debugMode = gFalse; + + if (imageCacheA) { + imageCache = imageCacheA; + imageCache->incRefCount(); + } else { + imageCache = new SplashImageCache(); + } +} + +Splash::~Splash() { + imageCache->decRefCount(); + + while (state->next) { + restoreState(); + } + delete state; + gfree(scanBuf); + gfree(scanBuf2); +} + +//------------------------------------------------------------------------ +// state read +//------------------------------------------------------------------------ + +SplashCoord *Splash::getMatrix() { + return state->matrix; +} + +SplashPattern *Splash::getStrokePattern() { + return state->strokePattern; +} + +SplashPattern *Splash::getFillPattern() { + return state->fillPattern; +} + +SplashScreen *Splash::getScreen() { + return state->screen; +} + +SplashBlendFunc Splash::getBlendFunc() { + return state->blendFunc; +} + +SplashCoord Splash::getStrokeAlpha() { + return state->strokeAlpha; +} + +SplashCoord Splash::getFillAlpha() { + return state->fillAlpha; +} + +SplashCoord Splash::getLineWidth() { + return state->lineWidth; +} + +int Splash::getLineCap() { + return state->lineCap; +} + +int Splash::getLineJoin() { + return state->lineJoin; +} + +SplashCoord Splash::getMiterLimit() { + return state->miterLimit; +} + +SplashCoord Splash::getFlatness() { + return state->flatness; +} + +SplashCoord *Splash::getLineDash() { + return state->lineDash; +} + +int Splash::getLineDashLength() { + return state->lineDashLength; +} + +SplashCoord Splash::getLineDashPhase() { + return state->lineDashPhase; +} + +SplashStrokeAdjustMode Splash::getStrokeAdjust() { + return state->strokeAdjust; +} + +SplashClip *Splash::getClip() { + return state->clip; +} + +SplashBitmap *Splash::getSoftMask() { + return state->softMask; +} + +GBool Splash::getInNonIsolatedGroup() { + return state->inNonIsolatedGroup; +} + +GBool Splash::getInKnockoutGroup() { + return state->inKnockoutGroup; +} + +//------------------------------------------------------------------------ +// state write +//------------------------------------------------------------------------ + +void Splash::setMatrix(SplashCoord *matrix) { + memcpy(state->matrix, matrix, 6 * sizeof(SplashCoord)); +} + +void Splash::setStrokePattern(SplashPattern *strokePattern) { + state->setStrokePattern(strokePattern); +} + +void Splash::setFillPattern(SplashPattern *fillPattern) { + state->setFillPattern(fillPattern); +} + +void Splash::setScreen(SplashScreen *screen) { + state->setScreen(screen); +} + +void Splash::setBlendFunc(SplashBlendFunc func) { + state->blendFunc = func; +} + +void Splash::setStrokeAlpha(SplashCoord alpha) { + state->strokeAlpha = alpha; +} + +void Splash::setFillAlpha(SplashCoord alpha) { + state->fillAlpha = alpha; +} + +void Splash::setLineWidth(SplashCoord lineWidth) { + state->lineWidth = lineWidth; +} + +void Splash::setLineCap(int lineCap) { + if (lineCap >= 0 && lineCap <= 2) { + state->lineCap = lineCap; + } else { + state->lineCap = 0; + } +} + +void Splash::setLineJoin(int lineJoin) { + if (lineJoin >= 0 && lineJoin <= 2) { + state->lineJoin = lineJoin; + } else { + state->lineJoin = 0; + } +} + +void Splash::setMiterLimit(SplashCoord miterLimit) { + state->miterLimit = miterLimit; +} + +void Splash::setFlatness(SplashCoord flatness) { + if (flatness < 1) { + state->flatness = 1; + } else { + state->flatness = flatness; + } +} + +void Splash::setLineDash(SplashCoord *lineDash, int lineDashLength, + SplashCoord lineDashPhase) { + state->setLineDash(lineDash, lineDashLength, lineDashPhase); +} + +void Splash::setStrokeAdjust(SplashStrokeAdjustMode strokeAdjust) { + state->strokeAdjust = strokeAdjust; +} + +void Splash::clipResetToRect(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1) { + state->clipResetToRect(x0, y0, x1, y1); +} + +SplashError Splash::clipToRect(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1) { + return state->clipToRect(x0, y0, x1, y1); +} + +SplashError Splash::clipToPath(SplashPath *path, GBool eo) { + return state->clipToPath(path, eo); +} + +void Splash::setSoftMask(SplashBitmap *softMask, GBool deleteBitmap) { + state->setSoftMask(softMask, deleteBitmap); +} + +void Splash::setInTransparencyGroup(SplashBitmap *groupBackBitmapA, + int groupBackXA, int groupBackYA, + SplashGroupDestInitMode groupDestInitModeA, + GBool nonIsolated, GBool knockout) { + groupBackBitmap = groupBackBitmapA; + groupBackX = groupBackXA; + groupBackY = groupBackYA; + groupDestInitMode = groupDestInitModeA; + groupDestInitYMin = 1; + groupDestInitYMax = 0; + state->inNonIsolatedGroup = nonIsolated; + state->inKnockoutGroup = knockout; +} + +void Splash::forceDeferredInit(int y, int h) { + useDestRow(y); + useDestRow(y + h - 1); +} + +// Check that alpha is 0 in the specified rectangle. +// NB: This doesn't work correctly in a non-isolated group, because +// the rasterizer temporarily stores alpha_g instead of alpha. +GBool Splash::checkTransparentRect(int x, int y, int w, int h) { + if (state->inNonIsolatedGroup) { + return gFalse; + } + + + if (!bitmap->alpha) { + return gFalse; + } + int yy0, yy1; + if (groupDestInitMode == splashGroupDestPreInit) { + 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) { + for (int xx = 0; xx < w; ++xx) { + if (alphaP[xx] != 0) { + return gFalse; + } + } + alphaP += bitmap->getAlphaRowSize(); + } + return gTrue; +} + +void Splash::setTransfer(Guchar *red, Guchar *green, Guchar *blue, + Guchar *gray) { + state->setTransfer(red, green, blue, gray); +} + +void Splash::setOverprintMask(Guint overprintMask) { + state->overprintMask = overprintMask; +} + + +void Splash::setEnablePathSimplification(GBool en) { + state->enablePathSimplification = en; +} + +//------------------------------------------------------------------------ +// state save/restore +//------------------------------------------------------------------------ + +void Splash::saveState() { + SplashState *newState; + + newState = state->copy(); + newState->next = state; + state = newState; +} + +SplashError Splash::restoreState() { + SplashState *oldState; + + if (!state->next) { + return splashErrNoSave; + } + oldState = state; + state = state->next; + delete oldState; + return splashOk; +} + +//------------------------------------------------------------------------ +// drawing operations +//------------------------------------------------------------------------ + +void Splash::clear(SplashColorPtr color, Guchar alpha) { + SplashColorPtr row, p; + Guchar mono; + int x, y; + + switch (bitmap->mode) { + case splashModeMono1: + mono = (color[0] & 0x80) ? 0xff : 0x00; + if (bitmap->rowSize < 0) { + memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), + mono, -bitmap->rowSize * bitmap->height); + } else { + memset(bitmap->data, mono, bitmap->rowSize * bitmap->height); + } + break; + case splashModeMono8: + if (bitmap->rowSize < 0) { + memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), + color[0], -bitmap->rowSize * bitmap->height); + } else { + memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height); + } + break; + case splashModeRGB8: + if (color[0] == color[1] && color[1] == color[2]) { + if (bitmap->rowSize < 0) { + memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), + color[0], -bitmap->rowSize * bitmap->height); + } else { + memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height); + } + } else { + row = bitmap->data; + for (y = 0; y < bitmap->height; ++y) { + p = row; + for (x = 0; x < bitmap->width; ++x) { + *p++ = color[0]; + *p++ = color[1]; + *p++ = color[2]; + } + row += bitmap->rowSize; + } + } + break; + case splashModeBGR8: + if (color[0] == color[1] && color[1] == color[2]) { + if (bitmap->rowSize < 0) { + memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), + color[0], -bitmap->rowSize * bitmap->height); + } else { + memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height); + } + } else { + row = bitmap->data; + for (y = 0; y < bitmap->height; ++y) { + p = row; + for (x = 0; x < bitmap->width; ++x) { + *p++ = color[2]; + *p++ = color[1]; + *p++ = color[0]; + } + row += bitmap->rowSize; + } + } + break; +#if SPLASH_CMYK + case splashModeCMYK8: + if (color[0] == color[1] && color[1] == color[2] && color[2] == color[3]) { + if (bitmap->rowSize < 0) { + memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), + color[0], -bitmap->rowSize * bitmap->height); + } else { + memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height); + } + } else { + row = bitmap->data; + for (y = 0; y < bitmap->height; ++y) { + p = row; + for (x = 0; x < bitmap->width; ++x) { + *p++ = color[0]; + *p++ = color[1]; + *p++ = color[2]; + *p++ = color[3]; + } + row += bitmap->rowSize; + } + } + break; +#endif + } + + if (bitmap->alpha) { + memset(bitmap->alpha, alpha, bitmap->alphaRowSize * bitmap->height); + } + + updateModX(0); + updateModY(0); + updateModX(bitmap->width - 1); + updateModY(bitmap->height - 1); +} + +SplashError Splash::stroke(SplashPath *path) { + SplashPath *path2, *dPath; + SplashCoord t0, t1, t2, t3, w, w2, lineDashMax, lineDashTotal; + int lineCap, lineJoin, i; + + if (debugMode) { + printf("stroke [dash:%d] [width:%.2f]:\n", + state->lineDashLength, (double)state->lineWidth); + dumpPath(path); + } + opClipRes = splashClipAllOutside; + if (path->length == 0) { + return splashErrEmptyPath; + } + path2 = flattenPath(path, state->matrix, state->flatness); + + // Compute an approximation of the transformed line width. + // Given a CTM of [m0 m1], + // [m2 m3] + // if |m0|*|m3| >= |m1|*|m2| then use min{|m0|,|m3|}, else + // use min{|m1|,|m2|}. + // This handles the common cases -- [s 0 ] and [0 s] -- + // [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; + } + w2 = w * state->lineWidth; + + // construct the dashed path + if (state->lineDashLength > 0) { + + // check the maximum transformed dash element length (using the + // same approximation as for line width) -- if it's less than 0.1 + // 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] + lineDashTotal = 0; + lineDashMax = 0; + for (i = 0; i < state->lineDashLength; ++i) { + lineDashTotal += state->lineDash[i]; + if (state->lineDash[i] > lineDashMax) { + lineDashMax = state->lineDash[i]; + } + } + // Acrobat simply draws nothing if the dash array is [0] + if (lineDashTotal == 0) { + delete path2; + return splashOk; + } + if (w * lineDashMax > 0.1) { + + dPath = makeDashedPath(path2); + delete path2; + path2 = dPath; + if (path2->length == 0) { + delete path2; + return splashErrEmptyPath; + } + } + } + + // round caps on narrow lines look bad, and can't be + // stroke-adjusted, so use projecting caps instead (but we can't do + // this if there are zero-length dashes or segments, because those + // turn into round dots) + lineCap = state->lineCap; + lineJoin = state->lineJoin; + if (state->strokeAdjust == splashStrokeAdjustCAD && + w2 < 3.5) { + if (lineCap == splashLineCapRound && + !state->lineDashContainsZeroLengthDashes() && + !path->containsZeroLengthSubpaths()) { + lineCap = splashLineCapProjecting; + } + if (lineJoin == splashLineJoinRound) { + lineJoin = splashLineJoinBevel; + } + } + + // if there is a min line width set, and the transformed line width + // is smaller, use the min line width + if (w > 0 && w2 < minLineWidth) { + strokeWide(path2, minLineWidth / w, splashLineCapButt, splashLineJoinBevel); + } else if (bitmap->mode == splashModeMono1 || !vectorAntialias) { + // in monochrome mode or if antialiasing is disabled, use 0-width + // lines for any transformed line width <= 1 -- lines less than 1 + // pixel wide look too fat without antialiasing + if (w2 < 1.001) { + strokeNarrow(path2); + } else { + strokeWide(path2, state->lineWidth, lineCap, lineJoin); + } + } else { + // in gray and color modes, only use 0-width lines if the line + // width is explicitly set to 0 + if (state->lineWidth == 0) { + strokeNarrow(path2); + } else { + strokeWide(path2, state->lineWidth, lineCap, lineJoin); + } + } + + delete path2; + return splashOk; +} + +void Splash::strokeNarrow(SplashPath *path) { + SplashPipe pipe; + SplashXPath *xPath; + SplashXPathSeg *seg; + int x0, x1, y0, y1, xa, xb, y; + SplashCoord dxdy; + SplashClipResult clipRes; + int nClipRes[3]; + int i; + + nClipRes[0] = nClipRes[1] = nClipRes[2] = 0; + + xPath = new SplashXPath(path, state->matrix, state->flatness, gFalse, + state->enablePathSimplification, + state->strokeAdjust); + + pipeInit(&pipe, state->strokePattern, + (Guchar)splashRound(state->strokeAlpha * 255), + gTrue, gFalse); + + for (i = 0, seg = xPath->segs; i < xPath->length; ++i, ++seg) { + if (seg->y0 <= seg->y1) { + y0 = splashFloor(seg->y0); + y1 = splashFloor(seg->y1); + x0 = splashFloor(seg->x0); + x1 = splashFloor(seg->x1); + } else { + y0 = splashFloor(seg->y1); + y1 = splashFloor(seg->y0); + x0 = splashFloor(seg->x1); + x1 = splashFloor(seg->x0); + } + if ((clipRes = state->clip->testRect(x0 <= x1 ? x0 : x1, y0, + x0 <= x1 ? x1 : x0, y1, + state->strokeAdjust)) + != splashClipAllOutside) { + if (y0 == y1) { + if (x0 <= x1) { + drawStrokeSpan(&pipe, x0, x1, y0, clipRes == splashClipAllInside); + } else { + drawStrokeSpan(&pipe, x1, x0, y0, clipRes == splashClipAllInside); + } + } else { + dxdy = seg->dxdy; + y = state->clip->getYMinI(state->strokeAdjust); + if (y0 < y) { + y0 = y; + x0 = splashFloor(seg->x0 + ((SplashCoord)y0 - seg->y0) * dxdy); + } + y = state->clip->getYMaxI(state->strokeAdjust); + if (y1 > y) { + y1 = y; + x1 = splashFloor(seg->x0 + ((SplashCoord)y1 - seg->y0) * dxdy); + } + if (x0 <= x1) { + xa = x0; + for (y = y0; y <= y1; ++y) { + if (y < y1) { + xb = splashFloor(seg->x0 + + ((SplashCoord)y + 1 - seg->y0) * dxdy); + } else { + xb = x1 + 1; + } + if (xa == xb) { + drawStrokeSpan(&pipe, xa, xa, y, clipRes == splashClipAllInside); + } else { + drawStrokeSpan(&pipe, xa, xb - 1, y, + clipRes == splashClipAllInside); + } + xa = xb; + } + } else { + xa = x0; + for (y = y0; y <= y1; ++y) { + if (y < y1) { + xb = splashFloor(seg->x0 + + ((SplashCoord)y + 1 - seg->y0) * dxdy); + } else { + xb = x1 - 1; + } + if (xa == xb) { + drawStrokeSpan(&pipe, xa, xa, y, clipRes == splashClipAllInside); + } else { + drawStrokeSpan(&pipe, xb + 1, xa, y, + clipRes == splashClipAllInside); + } + xa = xb; + } + } + } + } + ++nClipRes[clipRes]; + } + if (nClipRes[splashClipPartial] || + (nClipRes[splashClipAllInside] && nClipRes[splashClipAllOutside])) { + opClipRes = splashClipPartial; + } else if (nClipRes[splashClipAllInside]) { + opClipRes = splashClipAllInside; + } else { + opClipRes = splashClipAllOutside; + } + + delete xPath; +} + +void Splash::drawStrokeSpan(SplashPipe *pipe, int x0, int x1, int y, + GBool noClip) { + int x; + + x = state->clip->getXMinI(state->strokeAdjust); + if (x > x0) { + x0 = x; + } + x = state->clip->getXMaxI(state->strokeAdjust); + if (x < x1) { + x1 = x; + } + if (x0 > x1) { + return; + } + for (x = x0; x <= x1; ++x) { + scanBuf[x] = 0xff; + } + if (!noClip) { + if (!state->clip->clipSpanBinary(scanBuf, y, x0, x1, state->strokeAdjust)) { + return; + } + } + (this->*pipe->run)(pipe, x0, x1, y, scanBuf + x0, NULL); +} + +void Splash::strokeWide(SplashPath *path, SplashCoord w, + int lineCap, int lineJoin) { + SplashPath *path2; + + path2 = makeStrokePath(path, w, lineCap, lineJoin, gFalse); + fillWithPattern(path2, gFalse, state->strokePattern, state->strokeAlpha); + delete path2; +} + +SplashPath *Splash::flattenPath(SplashPath *path, SplashCoord *matrix, + SplashCoord flatness) { + SplashPath *fPath; + SplashCoord flatness2; + Guchar flag; + int i; + + fPath = new SplashPath(); +#if USE_FIXEDPOINT + flatness2 = flatness; +#else + flatness2 = flatness * flatness; +#endif + i = 0; + while (i < path->length) { + flag = path->flags[i]; + if (flag & splashPathFirst) { + fPath->moveTo(path->pts[i].x, path->pts[i].y); + ++i; + } else { + if (flag & splashPathCurve) { + flattenCurve(path->pts[i-1].x, path->pts[i-1].y, + path->pts[i ].x, path->pts[i ].y, + path->pts[i+1].x, path->pts[i+1].y, + path->pts[i+2].x, path->pts[i+2].y, + matrix, flatness2, fPath); + i += 3; + } else { + fPath->lineTo(path->pts[i].x, path->pts[i].y); + ++i; + } + if (path->flags[i-1] & splashPathClosed) { + fPath->close(); + } + } + } + return fPath; +} + +void Splash::flattenCurve(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1, + SplashCoord x2, SplashCoord y2, + SplashCoord x3, SplashCoord y3, + SplashCoord *matrix, SplashCoord flatness2, + SplashPath *fPath) { + SplashCoord cx[splashMaxCurveSplits + 1][3]; + SplashCoord cy[splashMaxCurveSplits + 1][3]; + int cNext[splashMaxCurveSplits + 1]; + SplashCoord xl0, xl1, xl2, xr0, xr1, xr2, xr3, xx1, xx2, xh; + SplashCoord yl0, yl1, yl2, yr0, yr1, yr2, yr3, yy1, yy2, yh; + SplashCoord dx, dy, mx, my, tx, ty, d1, d2; + int p1, p2, p3; + + // initial segment + p1 = 0; + p2 = splashMaxCurveSplits; + cx[p1][0] = x0; cy[p1][0] = y0; + cx[p1][1] = x1; cy[p1][1] = y1; + cx[p1][2] = x2; cy[p1][2] = y2; + cx[p2][0] = x3; cy[p2][0] = y3; + cNext[p1] = p2; + + while (p1 < splashMaxCurveSplits) { + + // get the next segment + xl0 = cx[p1][0]; yl0 = cy[p1][0]; + xx1 = cx[p1][1]; yy1 = cy[p1][1]; + xx2 = cx[p1][2]; yy2 = cy[p1][2]; + p2 = cNext[p1]; + xr3 = cx[p2][0]; yr3 = cy[p2][0]; + + // compute the distances (in device space) from the control points + // to the midpoint of the straight line (this is a bit of a hack, + // but it's much faster than computing the actual distances to the + // line) + transform(matrix, (xl0 + xr3) * 0.5, (yl0 + yr3) * 0.5, &mx, &my); + transform(matrix, xx1, yy1, &tx, &ty); +#if USE_FIXEDPOINT + d1 = splashDist(tx, ty, mx, my); +#else + dx = tx - mx; + dy = ty - my; + d1 = dx*dx + dy*dy; +#endif + transform(matrix, xx2, yy2, &tx, &ty); +#if USE_FIXEDPOINT + d2 = splashDist(tx, ty, mx, my); +#else + dx = tx - mx; + dy = ty - my; + d2 = dx*dx + dy*dy; +#endif + + // if the curve is flat enough, or no more subdivisions are + // allowed, add the straight line segment + if (p2 - p1 == 1 || (d1 <= flatness2 && d2 <= flatness2)) { + fPath->lineTo(xr3, yr3); + p1 = p2; + + // otherwise, subdivide the curve + } else { + xl1 = splashAvg(xl0, xx1); + yl1 = splashAvg(yl0, yy1); + xh = splashAvg(xx1, xx2); + yh = splashAvg(yy1, yy2); + xl2 = splashAvg(xl1, xh); + yl2 = splashAvg(yl1, yh); + xr2 = splashAvg(xx2, xr3); + yr2 = splashAvg(yy2, yr3); + xr1 = splashAvg(xh, xr2); + yr1 = splashAvg(yh, yr2); + xr0 = splashAvg(xl2, xr1); + yr0 = splashAvg(yl2, yr1); + // add the new subdivision points + p3 = (p1 + p2) / 2; + cx[p1][1] = xl1; cy[p1][1] = yl1; + cx[p1][2] = xl2; cy[p1][2] = yl2; + cNext[p1] = p3; + cx[p3][0] = xr0; cy[p3][0] = yr0; + cx[p3][1] = xr1; cy[p3][1] = yr1; + cx[p3][2] = xr2; cy[p3][2] = yr2; + cNext[p3] = p2; + } + } +} + +SplashPath *Splash::makeDashedPath(SplashPath *path) { + SplashPath *dPath; + SplashCoord lineDashTotal; + SplashCoord lineDashStartPhase, lineDashDist, segLen; + SplashCoord x0, y0, x1, y1, xa, ya; + GBool lineDashStartOn, lineDashEndOn, lineDashOn, newPath; + int lineDashStartIdx, lineDashIdx, subpathStart, nDashes; + int i, j, k; + + lineDashTotal = 0; + for (i = 0; i < state->lineDashLength; ++i) { + lineDashTotal += state->lineDash[i]; + } + // Acrobat simply draws nothing if the dash array is [0] + if (lineDashTotal == 0) { + return new SplashPath(); + } + lineDashStartPhase = state->lineDashPhase; + 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; + lineDashStartIdx = 0; + if (lineDashStartPhase > 0) { + while (lineDashStartPhase >= state->lineDash[lineDashStartIdx]) { + lineDashStartOn = !lineDashStartOn; + lineDashStartPhase -= state->lineDash[lineDashStartIdx]; + if (++lineDashStartIdx == state->lineDashLength) { + lineDashStartIdx = 0; + } + } + } + + dPath = new SplashPath(); + + // process each subpath + i = 0; + while (i < path->length) { + + // find the end of the subpath + for (j = i; + j < path->length - 1 && !(path->flags[j] & splashPathLast); + ++j) ; + + // initialize the dash parameters + lineDashOn = lineDashStartOn; + lineDashEndOn = lineDashStartOn; + lineDashIdx = lineDashStartIdx; + lineDashDist = state->lineDash[lineDashIdx] - lineDashStartPhase; + subpathStart = dPath->length; + nDashes = 0; + + // process each segment of the subpath + newPath = gTrue; + for (k = i; k < j; ++k) { + + // grab the segment + x0 = path->pts[k].x; + y0 = path->pts[k].y; + x1 = path->pts[k+1].x; + y1 = path->pts[k+1].y; + segLen = splashDist(x0, y0, x1, y1); + + // process the segment + while (segLen > 0) { + + // Special case for zero-length dash segments: draw a very + // short -- but not zero-length -- segment. This ensures that + // we get the correct behavior with butt and projecting line + // caps. The PS/PDF specs imply that zero-length segments are + // not drawn unless the line cap is round, but Acrobat and + // Ghostscript both draw very short segments (for butt caps) + // and squares (for projecting caps). + if (lineDashDist == 0) { + if (lineDashOn) { + if (newPath) { + dPath->moveTo(x0, y0); + newPath = gFalse; + ++nDashes; + } + xa = x0 + ((SplashCoord)0.001 / segLen) * (x1 - x0); + ya = y0 + ((SplashCoord)0.001 / segLen) * (y1 - y0); + dPath->lineTo(xa, ya); + } + + } else if (lineDashDist >= segLen) { + if (lineDashOn) { + if (newPath) { + dPath->moveTo(x0, y0); + newPath = gFalse; + ++nDashes; + } + dPath->lineTo(x1, y1); + } + lineDashDist -= segLen; + segLen = 0; + + } else { + xa = x0 + (lineDashDist / segLen) * (x1 - x0); + ya = y0 + (lineDashDist / segLen) * (y1 - y0); + if (lineDashOn) { + if (newPath) { + dPath->moveTo(x0, y0); + newPath = gFalse; + ++nDashes; + } + dPath->lineTo(xa, ya); + } + x0 = xa; + y0 = ya; + segLen -= lineDashDist; + lineDashDist = 0; + } + + lineDashEndOn = lineDashOn; + + // get the next entry in the dash array + if (lineDashDist <= 0) { + lineDashOn = !lineDashOn; + if (++lineDashIdx == state->lineDashLength) { + lineDashIdx = 0; + } + lineDashDist = state->lineDash[lineDashIdx]; + newPath = gTrue; + } + } + } + + // in a closed subpath, where the dash pattern is "on" at both the + // start and end of the subpath, we need to merge the start and + // end to get a proper line join + if ((path->flags[j] & splashPathClosed) && + lineDashStartOn && + lineDashEndOn) { + if (nDashes == 1) { + dPath->close(); + } else if (nDashes > 1) { + k = subpathStart; + do { + ++k; + dPath->lineTo(dPath->pts[k].x, dPath->pts[k].y); + } while (!(dPath->flags[k] & splashPathLast)); + ++k; + memmove(&dPath->pts[subpathStart], &dPath->pts[k], + (dPath->length - k) * sizeof(SplashPathPoint)); + memmove(&dPath->flags[subpathStart], &dPath->flags[k], + (dPath->length - k) * sizeof(Guchar)); + dPath->length -= k - subpathStart; + dPath->curSubpath -= k - subpathStart; + } + } + + i = j + 1; + } + + return dPath; +} + +SplashError Splash::fill(SplashPath *path, GBool eo) { + if (debugMode) { + printf("fill [eo:%d]:\n", eo); + dumpPath(path); + } + return fillWithPattern(path, eo, state->fillPattern, state->fillAlpha); +} + +SplashError Splash::fillWithPattern(SplashPath *path, GBool eo, + SplashPattern *pattern, + SplashCoord alpha) { + SplashPipe pipe; + SplashPath *path2; + SplashXPath *xPath; + SplashXPathScanner *scanner; + 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); + if (path2 != path) { + delete path2; + } + xMin = xPath->getXMin(); + yMin = xPath->getYMin(); + xMax = xPath->getXMax(); + yMax = xPath->getYMax(); + if (xMin > xMax || yMin > yMax) { + delete xPath; + return splashOk; + } + scanner = new SplashXPathScanner(xPath, eo, yMin, yMax); + + // check clipping + if ((clipRes = state->clip->testRect(xMin, yMin, xMax, yMax, + state->strokeAdjust)) + != splashClipAllOutside) { + + if ((t = state->clip->getXMinI(state->strokeAdjust)) > xMin) { + xMin = t; + } + if ((t = state->clip->getXMaxI(state->strokeAdjust)) < xMax) { + xMax = t; + } + if ((t = state->clip->getYMinI(state->strokeAdjust)) > yMin) { + yMin = t; + } + if ((t = state->clip->getYMaxI(state->strokeAdjust)) < yMax) { + yMax = t; + } + if (xMin > xMax || yMin > yMax) { + delete scanner; + delete xPath; + return splashOk; + } + + pipeInit(&pipe, pattern, (Guchar)splashRound(alpha * 255), + gTrue, gFalse); + + // draw the spans + if (vectorAntialias && !inShading) { + for (y = yMin; y <= yMax; ++y) { + scanner->getSpan(scanBuf, y, xMin, xMax, &xMin2, &xMax2); + if (xMin2 <= xMax2) { + if (clipRes != splashClipAllInside) { + state->clip->clipSpan(scanBuf, y, xMin2, xMax2, + state->strokeAdjust); + } + (this->*pipe.run)(&pipe, xMin2, xMax2, y, scanBuf + xMin2, NULL); + } + } + } else { + for (y = yMin; y <= yMax; ++y) { + scanner->getSpanBinary(scanBuf, y, xMin, xMax, &xMin2, &xMax2); + if (xMin2 <= xMax2) { + if (clipRes != splashClipAllInside) { + state->clip->clipSpanBinary(scanBuf, y, xMin2, xMax2, + state->strokeAdjust); + } + (this->*pipe.run)(&pipe, xMin2, xMax2, y, scanBuf + xMin2, NULL); + } + } + } + } + opClipRes = clipRes; + + delete scanner; + delete xPath; + return splashOk; +} + +// Applies various tweaks to a fill path: +// (1) add stroke adjust hints to a filled rectangle +// (2) applies a minimum width to a zero-width filled rectangle (so +// stroke adjustment works correctly +// (3) convert a degenerate fill ('moveto lineto fill' and 'moveto +// lineto closepath fill') to a minimum-width filled rectangle +// +// These tweaks only apply to paths with a single subpath. +// +// Returns either the unchanged input path or a new path (in which +// case the returned path must be deleted by the caller). +SplashPath *Splash::tweakFillPath(SplashPath *path) { + SplashPath *path2; + SplashCoord xx0, yy0, xx1, yy1, dx, dy, d, wx, wy, w; + int n; + + if (state->strokeAdjust == splashStrokeAdjustOff || path->hints) { + return path; + } + + n = path->getLength(); + if (!((n == 2) || + (n == 3 && + path->flags[1] == 0) || + (n == 4 && + path->flags[1] == 0 && + path->flags[2] == 0) || + (n == 5 && + path->flags[1] == 0 && + path->flags[2] == 0 && + path->flags[3] == 0))) { + return path; + } + + path2 = path; + + // degenerate fill (2 or 3 points) or rectangle of (nearly) zero + // width --> replace with a min-width rectangle and hint + if (n == 2 || + (n == 3 && (path->flags[0] & splashPathClosed)) || + (n == 3 && (splashAbs(path->pts[0].x - path->pts[2].x) < 0.001 && + splashAbs(path->pts[0].y - path->pts[2].y) < 0.001)) || + ((n == 4 || + (n == 5 && (path->flags[0] & splashPathClosed))) && + ((splashAbs(path->pts[0].x - path->pts[1].x) < 0.001 && + splashAbs(path->pts[0].y - path->pts[1].y) < 0.001 && + splashAbs(path->pts[2].x - path->pts[3].x) < 0.001 && + splashAbs(path->pts[2].y - path->pts[3].y) < 0.001) || + (splashAbs(path->pts[0].x - path->pts[3].x) < 0.001 && + splashAbs(path->pts[0].y - path->pts[3].y) < 0.001 && + splashAbs(path->pts[1].x - path->pts[2].x) < 0.001 && + splashAbs(path->pts[1].y - path->pts[2].y) < 0.001)))) { + wx = state->matrix[0] + state->matrix[2]; + wy = state->matrix[1] + state->matrix[3]; + w = splashSqrt(wx*wx + wy*wy); + if (w < 0.001) { + w = 0; + } else { + // min width is 0.1 -- this constant is minWidth * sqrt(2) + w = (SplashCoord)0.1414 / w; + } + xx0 = path->pts[0].x; + yy0 = path->pts[0].y; + if (n <= 3) { + xx1 = path->pts[1].x; + yy1 = path->pts[1].y; + } else { + xx1 = path->pts[2].x; + yy1 = path->pts[2].y; + } + dx = xx1 - xx0; + dy = yy1 - yy0; + d = splashSqrt(dx * dx + dy * dy); + if (d < 0.001) { + d = 0; + } else { + d = w / d; + } + dx *= d; + dy *= d; + path2 = new SplashPath(); + path2->moveTo(xx0 + dy, yy0 - dx); + path2->lineTo(xx1 + dy, yy1 - dx); + path2->lineTo(xx1 - dy, yy1 + dx); + path2->lineTo(xx0 - dy, yy0 + dx); + path2->close(gTrue); + path2->addStrokeAdjustHint(0, 2, 0, 4); + path2->addStrokeAdjustHint(1, 3, 0, 4); + + // unclosed rectangle --> close and hint + } else if (n == 4 && !(path->flags[0] & splashPathClosed)) { + path2->close(gTrue); + path2->addStrokeAdjustHint(0, 2, 0, 4); + path2->addStrokeAdjustHint(1, 3, 0, 4); + + // closed rectangle --> hint + } else if (n == 5 && (path->flags[0] & splashPathClosed)) { + path2->addStrokeAdjustHint(0, 2, 0, 4); + path2->addStrokeAdjustHint(1, 3, 0, 4); + } + + return path2; +} + +GBool Splash::pathAllOutside(SplashPath *path) { + SplashCoord xMin1, yMin1, xMax1, yMax1; + SplashCoord xMin2, yMin2, xMax2, yMax2; + SplashCoord x, y; + int xMinI, yMinI, xMaxI, yMaxI; + int i; + + xMin1 = xMax1 = path->pts[0].x; + yMin1 = yMax1 = path->pts[0].y; + for (i = 1; i < path->length; ++i) { + if (path->pts[i].x < xMin1) { + xMin1 = path->pts[i].x; + } else if (path->pts[i].x > xMax1) { + xMax1 = path->pts[i].x; + } + if (path->pts[i].y < yMin1) { + yMin1 = path->pts[i].y; + } else if (path->pts[i].y > yMax1) { + yMax1 = path->pts[i].y; + } + } + + transform(state->matrix, xMin1, yMin1, &x, &y); + xMin2 = xMax2 = x; + yMin2 = yMax2 = y; + transform(state->matrix, xMin1, yMax1, &x, &y); + if (x < xMin2) { + xMin2 = x; + } else if (x > xMax2) { + xMax2 = x; + } + if (y < yMin2) { + yMin2 = y; + } else if (y > yMax2) { + yMax2 = y; + } + transform(state->matrix, xMax1, yMin1, &x, &y); + if (x < xMin2) { + xMin2 = x; + } else if (x > xMax2) { + xMax2 = x; + } + if (y < yMin2) { + yMin2 = y; + } else if (y > yMax2) { + yMax2 = y; + } + transform(state->matrix, xMax1, yMax1, &x, &y); + if (x < xMin2) { + xMin2 = x; + } else if (x > xMax2) { + xMax2 = x; + } + if (y < yMin2) { + yMin2 = y; + } else if (y > yMax2) { + yMax2 = y; + } + // 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; +} + +SplashError Splash::fillChar(SplashCoord x, SplashCoord y, + int 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", + (double)x, (double)y, c, c, c); + } + transform(state->matrix, x, y, &xt, &yt); + x0 = splashFloor(xt); + xFrac = splashFloor((xt - x0) * splashFontFraction); + y0 = splashFloor(yt); + yFrac = splashFloor((yt - y0) * splashFontFraction); + if (!font->getGlyph(c, xFrac, yFrac, &glyph)) { + return splashErrNoGlyph; + } + err = fillGlyph2(x0, y0, &glyph); + if (glyph.freeData) { + gfree(glyph.data); + } + return err; +} + +SplashError Splash::fillGlyph(SplashCoord x, SplashCoord y, + SplashGlyphBitmap *glyph) { + SplashCoord xt, yt; + int x0, y0; + + transform(state->matrix, x, y, &xt, &yt); + x0 = splashFloor(xt); + y0 = splashFloor(yt); + return fillGlyph2(x0, y0, glyph); +} + +SplashError Splash::fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph) { + SplashPipe pipe; + SplashClipResult clipRes; + Guchar alpha; + Guchar *p; + int xMin, yMin, xMax, yMax; + int x, y, xg, yg, xx, t; + + xg = x0 - glyph->x; + yg = y0 - glyph->y; + xMin = xg; + xMax = xg + glyph->w - 1; + yMin = yg; + yMax = yg + glyph->h - 1; + if ((clipRes = state->clip->testRect(xMin, yMin, xMax, yMax, + state->strokeAdjust)) + != splashClipAllOutside) { + pipeInit(&pipe, state->fillPattern, + (Guchar)splashRound(state->fillAlpha * 255), + 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); + } + } else { + p = glyph->data; + for (y = yMin; y <= yMax; ++y) { + for (x = xMin; x <= xMax; x += 8) { + alpha = *p++; + for (xx = 0; xx < 8 && x + xx <= xMax; ++xx) { + scanBuf[x + xx] = (alpha & 0x80) ? 0xff : 0x00; + alpha = (Guchar)(alpha << 1); + } + } + (this->*pipe.run)(&pipe, xMin, xMax, y, scanBuf + xMin, NULL); + } + } + } else { + if ((t = state->clip->getXMinI(state->strokeAdjust)) > xMin) { + xMin = t; + } + if ((t = state->clip->getXMaxI(state->strokeAdjust)) < xMax) { + xMax = t; + } + if ((t = state->clip->getYMinI(state->strokeAdjust)) > yMin) { + yMin = t; + } + if ((t = state->clip->getYMaxI(state->strokeAdjust)) < yMax) { + yMax = t; + } + if (xMin <= xMax && yMin <= yMax) { + if (glyph->aa) { + for (y = yMin; y <= yMax; ++y) { + p = glyph->data + (y - yg) * glyph->w + (xMin - xg); + 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); + } + } else { + for (y = yMin; y <= yMax; ++y) { + p = glyph->data + (y - yg) * ((glyph->w + 7) >> 3) + + ((xMin - xg) >> 3); + alpha = *p++; + xx = (xMin - xg) & 7; + alpha = (Guchar)(alpha << xx); + for (x = xMin; xx < 8 && x <= xMax; ++x, ++xx) { + scanBuf[x] = (alpha & 0x80) ? 255 : 0; + alpha = (Guchar)(alpha << 1); + } + for (; x <= xMax; x += 8) { + alpha = *p++; + for (xx = 0; xx < 8 && x + xx <= xMax; ++xx) { + scanBuf[x + xx] = (alpha & 0x80) ? 255 : 0; + alpha = (Guchar)(alpha << 1); + } + } + state->clip->clipSpanBinary(scanBuf, y, xMin, xMax, + state->strokeAdjust); + (this->*pipe.run)(&pipe, xMin, xMax, y, scanBuf + xMin, NULL); + } + } + } + } + } + opClipRes = clipRes; + + return splashOk; +} + +void Splash::getImageBounds(SplashCoord xyMin, SplashCoord xyMax, + int *xyMinI, int *xyMaxI) { + if (state->strokeAdjust == splashStrokeAdjustOff) { + // make sure the coords fit in 32-bit ints +#if USE_FIXEDPOINT + if (xyMin < -32767) { + xyMin = -32767; + } else if (xyMin > 32767) { + xyMin = 32767; + } + if (xyMax < -32767) { + xyMax = -32767; + } else if (xyMax > 32767) { + xyMax = 32767; + } +#else + if (xyMin < -1e9) { + xyMin = -1e9; + } else if (xyMin > 1e9) { + xyMin = 1e9; + } + if (xyMax < -1e9) { + xyMax = -1e9; + } else if (xyMax > 1e9) { + xyMax = 1e9; + } +#endif + *xyMinI = splashFloor(xyMin); + *xyMaxI = splashFloor(xyMax); + if (*xyMaxI <= *xyMinI) { + *xyMaxI = *xyMinI + 1; + } + } else { + splashStrokeAdjust(xyMin, xyMax, xyMinI, xyMaxI, state->strokeAdjust); + } +} + +struct SplashDrawImageMaskRowData { + SplashPipe pipe; +}; + +// The glyphMode flag is not currently used, but may be useful if the +// stroke adjustment behavior is changed. +SplashError Splash::fillImageMask(GString *imageTag, + SplashImageMaskSource src, void *srcData, + int w, int h, SplashCoord *mat, + GBool glyphMode, GBool interpolate, + GBool antialias) { + if (debugMode) { + printf("fillImageMask: w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n", + w, h, (double)mat[0], (double)mat[1], (double)mat[2], + (double)mat[3], (double)mat[4], (double)mat[5]); + } + + //--- check for singular matrix + if (!splashCheckDet(mat[0], mat[1], mat[2], mat[3], 0.000001)) { + return splashErrSingularMatrix; + } + + //--- compute image bbox, check clipping + GBool flipsOnly = splashAbs(mat[1]) <= 0.0001 && splashAbs(mat[2]) <= 0.0001; + GBool rot90Only = splashAbs(mat[0]) <= 0.0001 && splashAbs(mat[3]) <= 0.0001; + GBool horizFlip = gFalse; + GBool vertFlip = gFalse; + int xMin, yMin, xMax, yMax; + if (flipsOnly) { + horizFlip = mat[0] < 0; + vertFlip = mat[3] < 0; + if (horizFlip) { + getImageBounds(mat[0] + mat[4], mat[4], &xMin, &xMax); + } else { + getImageBounds(mat[4], mat[0] + mat[4], &xMin, &xMax); + } + if (vertFlip) { + getImageBounds(mat[3] + mat[5], mat[5], &yMin, &yMax); + } else { + getImageBounds(mat[5], mat[3] + mat[5], &yMin, &yMax); + } + } else if (rot90Only) { + horizFlip = mat[2] < 0; + vertFlip = mat[1] < 0; + if (horizFlip) { + getImageBounds(mat[2] + mat[4], mat[4], &xMin, &xMax); + } else { + getImageBounds(mat[4], mat[2] + mat[4], &xMin, &xMax); + } + if (vertFlip) { + getImageBounds(mat[1] + mat[5], mat[5], &yMin, &yMax); + } else { + getImageBounds(mat[5], mat[1] + mat[5], &yMin, &yMax); + } + } else { + int xx = splashRound(mat[4]); // (0,0) + int yy = splashRound(mat[5]); + xMin = xMax = xx; + yMin = yMax = yy; + xx = splashRound(mat[0] + mat[4]); // (1,0) + yy = splashRound(mat[1] + mat[5]); + if (xx < xMin) { + xMin = xx; + } else if (xx > xMax) { + xMax = xx; + } + if (yy < yMin) { + yMin = yy; + } else if (yy > yMax) { + yMax = yy; + } + xx = splashRound(mat[2] + mat[4]); // (0,1) + yy = splashRound(mat[3] + mat[5]); + if (xx < xMin) { + xMin = xx; + } else if (xx > xMax) { + xMax = xx; + } + if (yy < yMin) { + yMin = yy; + } else if (yy > yMax) { + yMax = yy; + } + xx = splashRound(mat[0] + mat[2] + mat[4]); // (1,1) + yy = splashRound(mat[1] + mat[3] + mat[5]); + if (xx < xMin) { + xMin = xx; + } else if (xx > xMax) { + xMax = xx; + } + if (yy < yMin) { + yMin = yy; + } else if (yy > yMax) { + yMax = yy; + } + if (xMax <= xMin) { + xMax = xMin + 1; + } + if (yMax <= yMin) { + yMax = yMin + 1; + } + } + SplashClipResult clipRes = + state->clip->testRect(xMin, yMin, xMax - 1, yMax - 1, + state->strokeAdjust); + // If the scaled mask is much wider and/or taller than the clip + // region, we use the "arbitrary" scaling path, to avoid a + // potentially very slow loop in the flips-only path (which scans + // the full width and height of the scaled mask, regardless of the + // clip region). + int clipW = state->clip->getXMaxI(state->strokeAdjust) + - state->clip->getXMinI(state->strokeAdjust); + int clipH = state->clip->getYMaxI(state->strokeAdjust) + - state->clip->getYMinI(state->strokeAdjust); + GBool veryLarge = ((xMax - xMin) / 8 > clipW && xMax - xMin > 1000) || + ((yMax - yMin) / 8 > clipH && yMax - yMin > 1000); + + //--- set up the SplashDrawImageMaskRowData object and the pipes + SplashDrawImageMaskRowData dd; + pipeInit(&dd.pipe, state->fillPattern, + (Guchar)splashRound(state->fillAlpha * 255), + gTrue, gFalse); + + //--- choose the drawRow function + SplashDrawImageMaskRowFunc drawRowFunc; + if (clipRes == splashClipAllInside) { + drawRowFunc = &Splash::drawImageMaskRowNoClip; + } else { + if (antialias) { + drawRowFunc = &Splash::drawImageMaskRowClipAA; + } else { + drawRowFunc = &Splash::drawImageMaskRowClipNoAA; + } + } + + //--- 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); + } + 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 { // top-down + for (int y = 0; y < scaledHeight; ++y) { + scaler.nextLine(); + (this->*drawRowFunc)(&dd, scaler.data(), + xMin, yMin + y, scaledWidth); + } + } + } + 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; + } + + // 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) * 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; + } + } + (this->*drawRowFunc)(&dd, tmpLine, xMin, yMin + y, scaledHeight); + } + + gfree(tmpLine); + gfree(scaledMask); + } + + //--- arbitrary transform + } else { + // estimate of size of scaled image + int scaledWidth = splashRound(splashSqrt(mat[0] * mat[0] + + mat[1] * mat[1])); + int scaledHeight = splashRound(splashSqrt(mat[2] * mat[2] + + mat[3] * mat[3])); + if (scaledWidth < 1) { + scaledWidth = 1; + } + if (scaledHeight < 1) { + scaledHeight = 1; + } + GBool downscaling = gTrue; + if (veryLarge || (scaledWidth >= w && scaledHeight >= h)) { + downscaling = gFalse; + scaledWidth = w; + scaledHeight = h; + } + + // compute mapping from device space to scaled image space + SplashCoord mat1[6]; + mat1[0] = mat[0] / scaledWidth; + mat1[1] = mat[1] / scaledWidth; + mat1[2] = mat[2] / scaledHeight; + mat1[3] = mat[3] / scaledHeight; + mat1[4] = mat[4]; + mat1[5] = mat[5]; + SplashCoord det = mat1[0] * mat1[3] - mat1[1] * mat1[2]; + if (splashAbs(det) < 1e-6) { + // this should be caught by the singular matrix check in drawImage + return splashErrSingularMatrix; + } + SplashCoord invMat[6]; + invMat[0] = mat1[3] / det; + invMat[1] = -mat1[1] / det; + invMat[2] = -mat1[2] / det; + invMat[3] = mat1[0] / det; + // the extra "+ 0.5 * (...)" terms are here because the + // drawImageArbitrary(No)Interp functions multiply by pixel + // centers, (x + 0.5, y + 0.5) + invMat[4] = (mat1[2] * mat1[5] - mat1[3] * mat1[4]) / det + + (invMat[0] + invMat[2]) * 0.5; + invMat[5] = (mat1[1] * mat1[4] - mat1[0] * mat1[5]) / det + + (invMat[1] + invMat[3]) * 0.5; + + // if downscaling: store the downscaled image mask + // if upscaling: store the unscaled image mask + Guchar *scaledMask = (Guchar *)gmallocn(scaledHeight, scaledWidth); + if (downscaling) { + ImageMaskScaler scaler(src, srcData, w, h, + scaledWidth, scaledHeight, interpolate, antialias); + Guchar *ptr = scaledMask; + for (int y = 0; y < scaledHeight; ++y) { + scaler.nextLine(); + memcpy(ptr, scaler.data(), scaledWidth); + ptr += scaledWidth; + } + } else { + Guchar *ptr = scaledMask; + for (int y = 0; y < scaledHeight; ++y) { + (*src)(srcData, ptr); + for (int x = 0; x < scaledWidth; ++x) { + *ptr = (Guchar)(*ptr * 255); + ++ptr; + } + } + } + + // draw it + if (interpolate && antialias) { + drawImageMaskArbitraryInterp(scaledMask, + &dd, drawRowFunc, invMat, + scaledWidth, scaledHeight, + xMin, yMin, xMax, yMax); + } else { + drawImageMaskArbitraryNoInterp(scaledMask, + &dd, drawRowFunc, invMat, + scaledWidth, scaledHeight, + xMin, yMin, xMax, yMax); + } + + // free the downscaled/unscaled image + gfree(scaledMask); + } + + return splashOk; +} + +void Splash::drawImageMaskArbitraryNoInterp( + Guchar *scaledMask, + SplashDrawImageMaskRowData *dd, + SplashDrawImageMaskRowFunc drawRowFunc, + SplashCoord *invMat, + int scaledWidth, int scaledHeight, + int xMin, int yMin, int xMax, int yMax) { + int tt = state->clip->getXMinI(state->strokeAdjust); + if (tt > xMin) { + xMin = tt; + } + tt = state->clip->getXMaxI(state->strokeAdjust) + 1; + if (tt < xMax) { + xMax = tt; + } + tt = state->clip->getYMinI(state->strokeAdjust); + if (tt > yMin) { + yMin = tt; + } + tt = state->clip->getYMaxI(state->strokeAdjust) + 1; + if (tt < yMax) { + yMax = tt; + } + if (xMax <= xMin || yMax <= yMin) { + return; + } + + Guchar *buf = (Guchar *)gmalloc(xMax - xMin); + + for (int y = yMin; y < yMax; ++y) { + int rowMin = xMax; + int rowMax = 0; + for (int x = xMin; x < xMax; ++x) { + // note: invMat includes a "+0.5" factor so that this is really + // a multiply by (x+0.5, y+0.5) + int xx = splashFloor((SplashCoord)x * invMat[0] + + (SplashCoord)y * invMat[2] + invMat[4]); + int yy = splashFloor((SplashCoord)x * invMat[1] + + (SplashCoord)y * invMat[3] + invMat[5]); + if (xx >= 0 && xx < scaledWidth && + yy >= 0 && yy < scaledHeight) { + Guchar *p = scaledMask + (yy * scaledWidth + xx); + Guchar *q = buf + (x - xMin); + *q = *p; + if (x < rowMin) { + rowMin = x; + } + rowMax = x + 1; + } + } + if (rowMin < rowMax) { + (this->*drawRowFunc)(dd, buf + (rowMin - xMin), + rowMin, y, rowMax - rowMin); + } + } + + gfree(buf); +} + +void Splash::drawImageMaskArbitraryInterp( + Guchar *scaledMask, + SplashDrawImageMaskRowData *dd, + SplashDrawImageMaskRowFunc drawRowFunc, + SplashCoord *invMat, + int scaledWidth, int scaledHeight, + int xMin, int yMin, int xMax, int yMax) { + int tt = state->clip->getXMinI(state->strokeAdjust); + if (tt > xMin) { + xMin = tt; + } + tt = state->clip->getXMaxI(state->strokeAdjust) + 1; + if (tt < xMax) { + xMax = tt; + } + tt = state->clip->getYMinI(state->strokeAdjust); + if (tt > yMin) { + yMin = tt; + } + tt = state->clip->getYMaxI(state->strokeAdjust) + 1; + if (tt < yMax) { + yMax = tt; + } + if (xMax <= xMin || yMax <= yMin) { + return; + } + + Guchar *buf = (Guchar *)gmalloc(xMax - xMin); + + for (int y = yMin; y < yMax; ++y) { + int rowMin = xMax; + int rowMax = 0; + for (int x = xMin; x < xMax; ++x) { + // note: invMat includes a "+0.5" factor so that this is really + // a multiply by (x+0.5, y+0.5) + SplashCoord xs = (SplashCoord)x * invMat[0] + + (SplashCoord)y * invMat[2] + invMat[4]; + SplashCoord ys = (SplashCoord)x * invMat[1] + + (SplashCoord)y * invMat[3] + invMat[5]; + int x0 = splashFloor(xs - 0.5); + int x1 = x0 + 1; + int y0 = splashFloor(ys - 0.5); + int y1 = y0 + 1; + if (x1 >= 0 && x0 < scaledWidth && y1 >= 0 && y0 < scaledHeight) { + SplashCoord sx0 = (SplashCoord)x1 + 0.5 - xs; + SplashCoord sx1 = (SplashCoord)1 - sx0; + SplashCoord sy0 = (SplashCoord)y1 + 0.5 - ys; + SplashCoord sy1 = (SplashCoord)1 - sy0; + if (x0 < 0) { + x0 = 0; + } + if (x1 >= scaledWidth) { + x1 = scaledWidth - 1; + } + if (y0 < 0) { + y0 = 0; + } + if (y1 >= scaledHeight) { + y1 = scaledHeight - 1; + } + Guchar *p00 = scaledMask + (y0 * scaledWidth + x0); + Guchar *p10 = scaledMask + (y0 * scaledWidth + x1); + Guchar *p01 = scaledMask + (y1 * scaledWidth + x0); + Guchar *p11 = scaledMask + (y1 * scaledWidth + x1); + Guchar *q = buf + (x - xMin); + *q = (Guchar)(int)(sx0 * (sy0 * (int)*p00 + sy1 * (int)*p01) + + sx1 * (sy0 * (int)*p10 + sy1 * (int)*p11)); + if (x < rowMin) { + rowMin = x; + } + rowMax = x + 1; + } + } + if (rowMin < rowMax) { + (this->*drawRowFunc)(dd, buf + (rowMin - xMin), + rowMin, y, rowMax - rowMin); + } + } + + gfree(buf); +} + +void Splash::mirrorImageMaskRow(Guchar *maskIn, Guchar *maskOut, int width) { + Guchar *p, *q; + + p = maskIn; + q = maskOut + (width - 1); + for (int i = 0; i < width; ++i) { + *q = *p; + ++p; + --q; + } +} + +void Splash::drawImageMaskRowNoClip(SplashDrawImageMaskRowData *data, + Guchar *maskData, + int x, int y, int width) { + (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y, maskData, NULL); +} + +void Splash::drawImageMaskRowClipNoAA(SplashDrawImageMaskRowData *data, + Guchar *maskData, + int x, int y, int width) { + if (y < 0 || y >= bitmap->height) { + return; + } + if (x < 0) { + maskData -= x; + width += x; + x = 0; + } + if (x + width > bitmap->width) { + width = bitmap->width - x; + } + if (width <= 0) { + return; + } + memcpy(scanBuf + x, maskData, width); + state->clip->clipSpanBinary(scanBuf, y, x, x + width - 1, + state->strokeAdjust); + (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y, + scanBuf + x, NULL); +} + +void Splash::drawImageMaskRowClipAA(SplashDrawImageMaskRowData *data, + Guchar *maskData, + int x, int y, int width) { + if (y < 0 || y >= bitmap->height) { + return; + } + if (x < 0) { + maskData -= x; + width += x; + x = 0; + } + if (x + width > bitmap->width) { + width = bitmap->width - x; + } + if (width <= 0) { + return; + } + memcpy(scanBuf + x, maskData, width); + state->clip->clipSpan(scanBuf, y, x, x + width - 1, state->strokeAdjust); + (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y, + scanBuf + x, NULL); +} + +struct SplashDrawImageRowData { + int nComps; + GBool srcAlpha; + SplashPipe pipe; +}; + +SplashError Splash::drawImage(GString *imageTag, + SplashImageSource src, void *srcData, + SplashColorMode srcMode, GBool srcAlpha, + int w, int h, SplashCoord *mat, + GBool interpolate) { + if (debugMode) { + printf("drawImage: srcMode=%d srcAlpha=%d w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n", + srcMode, srcAlpha, w, h, (double)mat[0], (double)mat[1], (double)mat[2], + (double)mat[3], (double)mat[4], (double)mat[5]); + } + + //--- check color modes + GBool ok = gFalse; + int nComps = 0; + switch (bitmap->mode) { + case splashModeMono1: + case splashModeMono8: + ok = srcMode == splashModeMono8; + nComps = 1; + break; + case splashModeRGB8: + case splashModeBGR8: + ok = srcMode == splashModeRGB8; + nComps = 3; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + ok = srcMode == splashModeCMYK8; + nComps = 4; + break; +#endif + default: + ok = gFalse; + break; + } + if (!ok) { + return splashErrModeMismatch; + } + + //--- check for singular matrix + if (!splashCheckDet(mat[0], mat[1], mat[2], mat[3], 0.000001)) { + return splashErrSingularMatrix; + } + + //--- compute image bbox, check clipping + GBool flipsOnly = splashAbs(mat[1]) <= 0.0001 && splashAbs(mat[2]) <= 0.0001; + GBool rot90Only = splashAbs(mat[0]) <= 0.0001 && splashAbs(mat[3]) <= 0.0001; + GBool horizFlip = gFalse; + GBool vertFlip = gFalse; + int xMin, yMin, xMax, yMax; + if (flipsOnly) { + horizFlip = mat[0] < 0; + vertFlip = mat[3] < 0; + if (horizFlip) { + getImageBounds(mat[0] + mat[4], mat[4], &xMin, &xMax); + } else { + getImageBounds(mat[4], mat[0] + mat[4], &xMin, &xMax); + } + if (vertFlip) { + getImageBounds(mat[3] + mat[5], mat[5], &yMin, &yMax); + } else { + getImageBounds(mat[5], mat[3] + mat[5], &yMin, &yMax); + } + } else if (rot90Only) { + horizFlip = mat[2] < 0; + vertFlip = mat[1] < 0; + if (horizFlip) { + getImageBounds(mat[2] + mat[4], mat[4], &xMin, &xMax); + } else { + getImageBounds(mat[4], mat[2] + mat[4], &xMin, &xMax); + } + if (vertFlip) { + getImageBounds(mat[1] + mat[5], mat[5], &yMin, &yMax); + } else { + getImageBounds(mat[5], mat[1] + mat[5], &yMin, &yMax); + } + } else { + int xx = splashRound(mat[4]); // (0,0) + int yy = splashRound(mat[5]); + xMin = xMax = xx; + yMin = yMax = yy; + xx = splashRound(mat[0] + mat[4]); // (1,0) + yy = splashRound(mat[1] + mat[5]); + if (xx < xMin) { + xMin = xx; + } else if (xx > xMax) { + xMax = xx; + } + if (yy < yMin) { + yMin = yy; + } else if (yy > yMax) { + yMax = yy; + } + xx = splashRound(mat[2] + mat[4]); // (0,1) + yy = splashRound(mat[3] + mat[5]); + if (xx < xMin) { + xMin = xx; + } else if (xx > xMax) { + xMax = xx; + } + if (yy < yMin) { + yMin = yy; + } else if (yy > yMax) { + yMax = yy; + } + xx = splashRound(mat[0] + mat[2] + mat[4]); // (1,1) + yy = splashRound(mat[1] + mat[3] + mat[5]); + if (xx < xMin) { + xMin = xx; + } else if (xx > xMax) { + xMax = xx; + } + if (yy < yMin) { + yMin = yy; + } else if (yy > yMax) { + yMax = yy; + } + if (xMax <= xMin) { + xMax = xMin + 1; + } + if (yMax <= yMin) { + yMax = yMin + 1; + } + } + SplashClipResult clipRes = + state->clip->testRect(xMin, yMin, xMax - 1, yMax - 1, + state->strokeAdjust); + // If the scaled image is much wider and/or taller than the clip + // region, we use the arbitrary transform path, to avoid a + // potentially very slow loop in the flips-only path (which scans + // the full width and height of the scaled image, regardless of the + // clip region). + int clipW = state->clip->getXMaxI(state->strokeAdjust) + - state->clip->getXMinI(state->strokeAdjust); + int clipH = state->clip->getYMaxI(state->strokeAdjust) + - state->clip->getYMinI(state->strokeAdjust); + GBool veryLarge = ((xMax - xMin) / 8 > clipW && xMax - xMin > 1000) || + ((yMax - yMin) / 8 > clipH && yMax - yMin > 1000); + + //--- set up the SplashDrawImageRowData object and the pipes + SplashDrawImageRowData dd; + dd.nComps = nComps; + dd.srcAlpha = srcAlpha; + pipeInit(&dd.pipe, NULL, + (Guchar)splashRound(state->fillAlpha * 255), + clipRes != splashClipAllInside || srcAlpha, + gFalse); + + //--- choose the drawRow function + SplashDrawImageRowFunc drawRowFunc; + if (clipRes == splashClipAllInside) { + if (srcAlpha) { + drawRowFunc = &Splash::drawImageRowNoClipAlpha; + } else { + drawRowFunc = &Splash::drawImageRowNoClipNoAlpha; + } + } else { + if (srcAlpha) { + if (vectorAntialias) { + drawRowFunc = &Splash::drawImageRowClipAlphaAA; + } else { + drawRowFunc = &Splash::drawImageRowClipAlphaNoAA; + } + } else { + if (vectorAntialias) { + drawRowFunc = &Splash::drawImageRowClipNoAlphaAA; + } else { + drawRowFunc = &Splash::drawImageRowClipNoAlphaNoAA; + } + } + } + + //--- 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); + } + } + 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 { // 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; + } + + //--- 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); + } + 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) * 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 (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]; + } + ptr += scaledWidth * nComps; + } + if (srcAlpha) { + q = tmpAlphaLine; + for (int x = 0; x < scaledHeight; ++x) { + *q++ = *alphaPtr; + alphaPtr += scaledWidth; + } + } + } + (this->*drawRowFunc)(&dd, tmpLine, tmpAlphaLine, + xMin, yMin + y, scaledHeight); + } + + gfree(tmpLine); + gfree(tmpAlphaLine); + if (freeScaledImage) { + gfree(scaledColor); + gfree(scaledAlpha); + } + } + + //--- arbitrary transform + } else { + // estimate of size of scaled image + int scaledWidth = splashRound(splashSqrt(mat[0] * mat[0] + + mat[1] * mat[1])); + int scaledHeight = splashRound(splashSqrt(mat[2] * mat[2] + + mat[3] * mat[3])); + if (scaledWidth < 1) { + scaledWidth = 1; + } + if (scaledHeight < 1) { + scaledHeight = 1; + } + if (veryLarge || (scaledWidth >= w && scaledHeight >= h)) { + scaledWidth = w; + scaledHeight = h; + } + + // compute mapping from device space to scaled image space + SplashCoord mat1[6]; + mat1[0] = mat[0] / scaledWidth; + mat1[1] = mat[1] / scaledWidth; + mat1[2] = mat[2] / scaledHeight; + mat1[3] = mat[3] / scaledHeight; + mat1[4] = mat[4]; + mat1[5] = mat[5]; + SplashCoord det = mat1[0] * mat1[3] - mat1[1] * mat1[2]; + if (splashAbs(det) < 1e-6) { + // this should be caught by the singular matrix check in drawImage + return splashErrSingularMatrix; + } + SplashCoord invMat[6]; + invMat[0] = mat1[3] / det; + invMat[1] = -mat1[1] / det; + invMat[2] = -mat1[2] / det; + invMat[3] = mat1[0] / det; + // the extra "+ 0.5 * (...)" terms are here because the + // drawImageArbitrary(No)Interp functions multiply by pixel + // centers, (x + 0.5, y + 0.5) + invMat[4] = (mat1[2] * mat1[5] - mat1[3] * mat1[4]) / det + + (invMat[0] + invMat[2]) * 0.5; + invMat[5] = (mat1[1] * mat1[4] - mat1[0] * mat1[5]) / det + + (invMat[1] + invMat[3]) * 0.5; + + Guchar *scaledColor, *scaledAlpha; + GBool freeScaledImage; + getScaledImage(imageTag, src, srcData, w, h, nComps, + scaledWidth, scaledHeight, srcMode, srcAlpha, interpolate, + &scaledColor, &scaledAlpha, &freeScaledImage); + + // draw it + if (interpolate) { + drawImageArbitraryInterp(scaledColor, scaledAlpha, + &dd, drawRowFunc, invMat, + scaledWidth, scaledHeight, + xMin, yMin, xMax, yMax, + nComps, srcAlpha); + } else { + drawImageArbitraryNoInterp(scaledColor, scaledAlpha, + &dd, drawRowFunc, invMat, + scaledWidth, scaledHeight, + xMin, yMin, xMax, yMax, + nComps, srcAlpha); + } + + // free the downscaled/unscaled image + if (freeScaledImage) { + gfree(scaledColor); + gfree(scaledAlpha); + } + } + + return splashOk; +} + +ImageScaler *Splash::getImageScaler(GString *imageTag, + SplashImageSource src, void *srcData, + int w, int h, int nComps, + int scaledWidth, int scaledHeight, + SplashColorMode srcMode, + GBool srcAlpha, GBool interpolate) { + // Notes: + // + // * If the scaled image is more than 8 Mpixels, we don't cache it. + // + // * Caching is done on the third consecutive use (second + // consecutive reuse) of an image; this avoids overhead on the + // common case of single-use images. + + if (scaledWidth < 8000000 / scaledHeight && + imageCache->match(imageTag, scaledWidth, scaledHeight, + srcMode, srcAlpha, interpolate)) { + if (imageCache->colorData) { + return new ReplayImageScaler(nComps, srcAlpha, scaledWidth, + imageCache->colorData, + imageCache->alphaData); + } else { + int lineSize; + if (scaledWidth < INT_MAX / nComps) { + lineSize = scaledWidth * nComps; + } else { + lineSize = -1; + } + imageCache->colorData = (Guchar *)gmallocn(scaledHeight, lineSize); + if (srcAlpha) { + imageCache->alphaData = (Guchar *)gmallocn(scaledHeight, scaledWidth); + } + return new SavingImageScaler(src, srcData, + w, h, nComps, srcAlpha, + scaledWidth, scaledHeight, + interpolate, + imageCache->colorData, + imageCache->alphaData); + } + } else { + imageCache->reset(imageTag, scaledWidth, scaledHeight, + srcMode, srcAlpha, interpolate); + return new BasicImageScaler(src, srcData, + w, h, nComps, srcAlpha, + scaledWidth, scaledHeight, + interpolate); + } +} + +void Splash::getScaledImage(GString *imageTag, + SplashImageSource src, void *srcData, + int w, int h, int nComps, + int scaledWidth, int scaledHeight, + SplashColorMode srcMode, + GBool srcAlpha, GBool interpolate, + Guchar **scaledColor, Guchar **scaledAlpha, + GBool *freeScaledImage) { + // Notes: + // + // * If the scaled image is more than 8 Mpixels, we don't cache it. + // + // * This buffers the whole image anyway, so there's no reason to + // skip caching on the first reuse. + + if (scaledWidth >= 8000000 / scaledHeight) { + int lineSize; + if (scaledWidth < INT_MAX / nComps) { + lineSize = scaledWidth * nComps; + } else { + lineSize = -1; + } + *scaledColor = (Guchar *)gmallocn(scaledHeight, lineSize); + if (srcAlpha) { + *scaledAlpha = (Guchar *)gmallocn(scaledHeight, scaledWidth); + } else { + *scaledAlpha = NULL; + } + *freeScaledImage = gTrue; + if (scaledWidth == w && scaledHeight == h) { + Guchar *colorPtr = *scaledColor; + Guchar *alphaPtr = *scaledAlpha; + for (int y = 0; y < scaledHeight; ++y) { + (*src)(srcData, colorPtr, alphaPtr); + colorPtr += scaledWidth * nComps; + if (srcAlpha) { + alphaPtr += scaledWidth; + } + } + } else { + BasicImageScaler scaler(src, srcData, w, h, nComps, srcAlpha, + scaledWidth, scaledHeight, interpolate); + Guchar *colorPtr = *scaledColor; + Guchar *alphaPtr = *scaledAlpha; + for (int y = 0; y < scaledHeight; ++y) { + scaler.nextLine(); + memcpy(colorPtr, scaler.colorData(), scaledWidth * nComps); + colorPtr += scaledWidth * nComps; + if (srcAlpha) { + memcpy(alphaPtr, scaler.alphaData(), scaledWidth); + alphaPtr += scaledWidth; + } + } + } + } else { + if (!imageCache->match(imageTag, scaledWidth, scaledHeight, + srcMode, srcAlpha, interpolate) || + !imageCache->colorData) { + imageCache->reset(imageTag, scaledWidth, scaledHeight, + srcMode, srcAlpha, interpolate); + int lineSize; + if (scaledWidth < INT_MAX / nComps) { + lineSize = scaledWidth * nComps; + } else { + lineSize = -1; + } + imageCache->colorData = (Guchar *)gmallocn(scaledHeight, lineSize); + if (srcAlpha) { + imageCache->alphaData = (Guchar *)gmallocn(scaledHeight, scaledWidth); + } + if (scaledWidth == w && scaledHeight == h) { + Guchar *colorPtr = imageCache->colorData; + Guchar *alphaPtr = imageCache->alphaData; + for (int y = 0; y < scaledHeight; ++y) { + (*src)(srcData, colorPtr, alphaPtr); + colorPtr += scaledWidth * nComps; + if (srcAlpha) { + alphaPtr += scaledWidth; + } + } + } else { + SavingImageScaler scaler(src, srcData, w, h, nComps, srcAlpha, + scaledWidth, scaledHeight, interpolate, + imageCache->colorData, imageCache->alphaData); + Guchar *colorPtr = imageCache->colorData; + Guchar *alphaPtr = imageCache->alphaData; + for (int y = 0; y < scaledHeight; ++y) { + scaler.nextLine(); + memcpy(colorPtr, scaler.colorData(), scaledWidth * nComps); + colorPtr += scaledWidth * nComps; + if (srcAlpha) { + memcpy(alphaPtr, scaler.alphaData(), scaledWidth); + alphaPtr += scaledWidth; + } + } + } + } + *scaledColor = imageCache->colorData; + *scaledAlpha = imageCache->alphaData; + *freeScaledImage = gFalse; + } +} + +void Splash::drawImageArbitraryNoInterp(Guchar *scaledColor, + Guchar *scaledAlpha, + SplashDrawImageRowData *dd, + SplashDrawImageRowFunc drawRowFunc, + SplashCoord *invMat, + int scaledWidth, int scaledHeight, + int xMin, int yMin, int xMax, int yMax, + int nComps, GBool srcAlpha) { + int tt = state->clip->getXMinI(state->strokeAdjust); + if (tt > xMin) { + xMin = tt; + } + tt = state->clip->getXMaxI(state->strokeAdjust) + 1; + if (tt < xMax) { + xMax = tt; + } + tt = state->clip->getYMinI(state->strokeAdjust); + if (tt > yMin) { + yMin = tt; + } + tt = state->clip->getYMaxI(state->strokeAdjust) + 1; + if (tt < yMax) { + yMax = tt; + } + if (xMax <= xMin || yMax <= yMin) { + return; + } + + Guchar *colorBuf = (Guchar *)gmallocn(xMax - xMin, nComps); + Guchar *alphaBuf = NULL; + if (srcAlpha) { + alphaBuf = (Guchar *)gmalloc(xMax - xMin); + } + + for (int y = yMin; y < yMax; ++y) { + int rowMin = xMax; + int rowMax = 0; + for (int x = xMin; x < xMax; ++x) { + // note: invMat includes a "+0.5" factor so that this is really + // a multiply by (x+0.5, y+0.5) + int xx = splashFloor((SplashCoord)x * invMat[0] + + (SplashCoord)y * invMat[2] + invMat[4]); + int yy = splashFloor((SplashCoord)x * invMat[1] + + (SplashCoord)y * invMat[3] + invMat[5]); + if (xx >= 0 && xx < scaledWidth && + yy >= 0 && yy < scaledHeight) { + Guchar *p = scaledColor + (yy * scaledWidth + xx) * nComps; + Guchar *q = colorBuf + (x - xMin) * nComps; + for (int i = 0; i < nComps; ++i) { + *q++ = *p++; + } + if (srcAlpha) { + alphaBuf[x - xMin] = scaledAlpha[yy * scaledWidth + xx]; + } + if (x < rowMin) { + rowMin = x; + } + rowMax = x + 1; + } + } + if (rowMin < rowMax) { + (this->*drawRowFunc)(dd, + colorBuf + (rowMin - xMin) * nComps, + alphaBuf + (rowMin - xMin), + rowMin, y, rowMax - rowMin); + } + } + + gfree(colorBuf); + gfree(alphaBuf); +} + +void Splash::drawImageArbitraryInterp(Guchar *scaledColor, Guchar *scaledAlpha, + SplashDrawImageRowData *dd, + SplashDrawImageRowFunc drawRowFunc, + SplashCoord *invMat, + int scaledWidth, int scaledHeight, + int xMin, int yMin, int xMax, int yMax, + int nComps, GBool srcAlpha) { + int tt = state->clip->getXMinI(state->strokeAdjust); + if (tt > xMin) { + xMin = tt; + } + tt = state->clip->getXMaxI(state->strokeAdjust) + 1; + if (tt < xMax) { + xMax = tt; + } + tt = state->clip->getYMinI(state->strokeAdjust); + if (tt > yMin) { + yMin = tt; + } + tt = state->clip->getYMaxI(state->strokeAdjust) + 1; + if (tt < yMax) { + yMax = tt; + } + if (xMax <= xMin || yMax <= yMin) { + return; + } + + Guchar *colorBuf = (Guchar *)gmallocn(xMax - xMin, nComps); + Guchar *alphaBuf = NULL; + if (srcAlpha) { + alphaBuf = (Guchar *)gmalloc(xMax - xMin); + } + + for (int y = yMin; y < yMax; ++y) { + int rowMin = xMax; + int rowMax = 0; + for (int x = xMin; x < xMax; ++x) { + // note: invMat includes a "+0.5" factor so that this is really + // a multiply by (x+0.5, y+0.5) + SplashCoord xs = (SplashCoord)x * invMat[0] + + (SplashCoord)y * invMat[2] + invMat[4]; + SplashCoord ys = (SplashCoord)x * invMat[1] + + (SplashCoord)y * invMat[3] + invMat[5]; + int x0 = splashFloor(xs - 0.5); + int x1 = x0 + 1; + int y0 = splashFloor(ys - 0.5); + int y1 = y0 + 1; + if (x1 >= 0 && x0 < scaledWidth && y1 >= 0 && y0 < scaledHeight) { + SplashCoord sx0 = (SplashCoord)x1 + 0.5 - xs; + SplashCoord sx1 = (SplashCoord)1 - sx0; + SplashCoord sy0 = (SplashCoord)y1 + 0.5 - ys; + SplashCoord sy1 = (SplashCoord)1 - sy0; + if (x0 < 0) { + x0 = 0; + } + if (x1 >= scaledWidth) { + x1 = scaledWidth - 1; + } + if (y0 < 0) { + y0 = 0; + } + if (y1 >= scaledHeight) { + y1 = scaledHeight - 1; + } + Guchar *p00 = scaledColor + (y0 * scaledWidth + x0) * nComps; + Guchar *p10 = scaledColor + (y0 * scaledWidth + x1) * nComps; + Guchar *p01 = scaledColor + (y1 * scaledWidth + x0) * nComps; + Guchar *p11 = scaledColor + (y1 * scaledWidth + x1) * nComps; + Guchar *q = colorBuf + (x - xMin) * nComps; + for (int i = 0; i < nComps; ++i) { + *q++ = (Guchar)(int)(sx0 * (sy0 * (int)*p00++ + sy1 * (int)*p01++) + + sx1 * (sy0 * (int)*p10++ + sy1 * (int)*p11++)); + } + if (srcAlpha) { + p00 = scaledAlpha + (y0 * scaledWidth + x0); + p10 = scaledAlpha + (y0 * scaledWidth + x1); + p01 = scaledAlpha + (y1 * scaledWidth + x0); + p11 = scaledAlpha + (y1 * scaledWidth + x1); + q = alphaBuf + (x - xMin); + *q = (Guchar)(int)(sx0 * (sy0 * (int)*p00 + sy1 * (int)*p01) + + sx1 * (sy0 * (int)*p10 + sy1 * (int)*p11)); + } + if (x < rowMin) { + rowMin = x; + } + rowMax = x + 1; + } + } + if (rowMin < rowMax) { + (this->*drawRowFunc)(dd, + colorBuf + (rowMin - xMin) * nComps, + alphaBuf + (rowMin - xMin), + rowMin, y, rowMax - rowMin); + } + } + + gfree(colorBuf); + gfree(alphaBuf); +} + +void Splash::mirrorImageRow(Guchar *colorIn, Guchar *alphaIn, + Guchar *colorOut, Guchar *alphaOut, + int width, int nComps, GBool srcAlpha) { + Guchar *p, *q; + + p = colorIn; + q = colorOut + (width - 1) * nComps; + for (int i = 0; i < width; ++i) { + for (int j = 0; j < nComps; ++j) { + q[j] = p[j]; + } + p += nComps; + q -= nComps; + } + + if (srcAlpha) { + p = alphaIn; + q = alphaOut + (width - 1); + for (int i = 0; i < width; ++i) { + *q = *p; + ++p; + --q; + } + } +} + +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); +} + +void Splash::drawImageRowNoClipAlpha(SplashDrawImageRowData *data, + Guchar *colorData, Guchar *alphaData, + int x, int y, int width) { + (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y, + alphaData, colorData); +} + +void Splash::drawImageRowClipNoAlphaNoAA(SplashDrawImageRowData *data, + Guchar *colorData, + Guchar *alphaData, + int x, int y, int width) { + if (y < 0 || y >= bitmap->height) { + return; + } + if (x < 0) { + colorData -= x * data->nComps; + width += x; + x = 0; + } + if (x + width > bitmap->width) { + width = bitmap->width - x; + } + if (width <= 0) { + return; + } + memset(scanBuf + x, 0xff, width); + state->clip->clipSpanBinary(scanBuf, y, x, x + width - 1, + state->strokeAdjust); + (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y, + scanBuf + x, colorData); +} + +void Splash::drawImageRowClipNoAlphaAA(SplashDrawImageRowData *data, + Guchar *colorData, + Guchar *alphaData, + int x, int y, int width) { + if (y < 0 || y >= bitmap->height) { + return; + } + if (x < 0) { + colorData -= x * data->nComps; + width += x; + x = 0; + } + if (x + width > bitmap->width) { + width = bitmap->width - x; + } + if (width <= 0) { + return; + } + memset(scanBuf + x, 0xff, width); + state->clip->clipSpan(scanBuf, y, x, x + width - 1, state->strokeAdjust); + (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y, + scanBuf + x, colorData); +} + +void Splash::drawImageRowClipAlphaNoAA(SplashDrawImageRowData *data, + Guchar *colorData, + Guchar *alphaData, + int x, int y, int width) { + if (y < 0 || y >= bitmap->height) { + return; + } + if (x < 0) { + colorData -= x * data->nComps; + alphaData -= x; + width += x; + x = 0; + } + if (x + width > bitmap->width) { + width = bitmap->width - x; + } + if (width <= 0) { + return; + } + memcpy(scanBuf + x, alphaData, width); + state->clip->clipSpanBinary(scanBuf, y, x, x + width - 1, + state->strokeAdjust); + (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y, + scanBuf + x, colorData); +} + +void Splash::drawImageRowClipAlphaAA(SplashDrawImageRowData *data, + Guchar *colorData, + Guchar *alphaData, + int x, int y, int width) { + if (y < 0 || y >= bitmap->height) { + return; + } + if (x < 0) { + colorData -= x * data->nComps; + alphaData -= x; + width += x; + x = 0; + } + if (x + width > bitmap->width) { + width = bitmap->width - x; + } + if (width <= 0) { + return; + } + memcpy(scanBuf + x, alphaData, width); + state->clip->clipSpan(scanBuf, y, x, x + width - 1, state->strokeAdjust); + (this->*data->pipe.run)(&data->pipe, x, x + width - 1, y, + scanBuf + x, colorData); +} + +SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc, + int xDest, int yDest, int w, int h, + GBool noClip, GBool nonIsolated) { + SplashPipe pipe; + Guchar *mono1Ptr, *lineBuf, *linePtr; + Guchar mono1Mask, b; + int x0, x1, x, y0, y1, y, t; + + if (!(src->mode == bitmap->mode || + (src->mode == splashModeMono8 && bitmap->mode == splashModeMono1) || + (src->mode == splashModeRGB8 && bitmap->mode == splashModeBGR8))) { + return splashErrModeMismatch; + } + + pipeInit(&pipe, NULL, + (Guchar)splashRound(state->fillAlpha * 255), + !noClip || src->alpha != NULL, nonIsolated); + 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) { + 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 uses shape instead of alpha, which isn't technically + // correct, but works out the same + (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y, + src->alpha + + (ySrc + y) * src->alphaRowSize + xSrc, + scanBuf); + } + } else { + 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, + NULL, + scanBuf); + } + } + } else { + x0 = xDest; + if ((t = state->clip->getXMinI(state->strokeAdjust)) > x0) { + x0 = t; + } + x1 = xDest + w; + if ((t = state->clip->getXMaxI(state->strokeAdjust) + 1) < x1) { + x1 = t; + } + y0 = yDest; + if ((t = state->clip->getYMinI(state->strokeAdjust)) > y0) { + y0 = t; + } + y1 = yDest + h; + if ((t = state->clip->getYMaxI(state->strokeAdjust) + 1) < y1) { + y1 = t; + } + if (x0 < x1 && y0 < y1) { + if (src->alpha) { + for (y = y0; y < y1; ++y) { + 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 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, + scanBuf + x0); + } + } else { + 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)); + } + memset(scanBuf2 + x0, 0xff, x1 - x0); + if (!state->clip->clipSpanBinary(scanBuf2, y, x0, x1 - 1, + state->strokeAdjust)) { + continue; + } + (this->*pipe.run)(&pipe, x0, x1 - 1, y, + scanBuf2 + x0, + scanBuf + x0); + } + } + } + } + + } else if (src->mode == splashModeBGR8) { + // in BGR8 mode, pipeRun expects the source to be in RGB8 format, + // so we need to swap bytes + lineBuf = (Guchar *)gmallocn(w, 3); + if (noClip) { + if (src->alpha) { + 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 uses shape instead of alpha, which isn't technically + // correct, but works out the same + (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y, + src->alpha + + (ySrc + y) * src->alphaRowSize + xSrc, + lineBuf); + } + } else { + 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, + NULL, lineBuf); + } + } + } else { + x0 = xDest; + if ((t = state->clip->getXMinI(state->strokeAdjust)) > x0) { + x0 = t; + } + x1 = xDest + w; + if ((t = state->clip->getXMaxI(state->strokeAdjust) + 1) < x1) { + x1 = t; + } + y0 = yDest; + if ((t = state->clip->getYMinI(state->strokeAdjust)) > y0) { + y0 = t; + } + y1 = yDest + h; + if ((t = state->clip->getYMaxI(state->strokeAdjust) + 1) < y1) { + y1 = t; + } + if (x0 < x1 && y0 < y1) { + if (src->alpha) { + for (y = y0; y < y1; ++y) { + memcpy(scanBuf + x0, + src->alpha + (ySrc + y - yDest) * src->alphaRowSize + + (xSrc + x0 - xDest), + x1 - x0); + state->clip->clipSpan(scanBuf, y, x0, x1 - 1, state->strokeAdjust); + 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, lineBuf); + } + } else { + for (y = y0; y < y1; ++y) { + memset(scanBuf + x0, 0xff, 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->*pipe.run)(&pipe, x0, x1 - 1, yDest + y, + scanBuf + x0, + src->data + + (ySrc + y - yDest) * src->rowSize + + (xSrc + x0 - xDest) * bitmapComps); + } + } + } + } + gfree(lineBuf); + + } else { // src->mode not mono1 or BGR8 + if (noClip) { + if (src->alpha) { + 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, + 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, + src->data + (ySrc + y) * src->rowSize + + xSrc * bitmapComps); + } + } + } else { + x0 = xDest; + if ((t = state->clip->getXMinI(state->strokeAdjust)) > x0) { + x0 = t; + } + x1 = xDest + w; + if ((t = state->clip->getXMaxI(state->strokeAdjust) + 1) < x1) { + x1 = t; + } + y0 = yDest; + if ((t = state->clip->getYMinI(state->strokeAdjust)) > y0) { + y0 = t; + } + y1 = yDest + h; + if ((t = state->clip->getYMaxI(state->strokeAdjust) + 1) < y1) { + y1 = t; + } + if (x0 < x1 && y0 < y1) { + if (src->alpha) { + for (y = y0; y < y1; ++y) { + memcpy(scanBuf + x0, + src->alpha + (ySrc + y - yDest) * src->alphaRowSize + + (xSrc + x0 - xDest), + x1 - x0); + state->clip->clipSpan(scanBuf, y, x0, x1 - 1, state->strokeAdjust); + // this uses shape instead of alpha, which isn't technically + // correct, but works out the same + (this->*pipe.run)(&pipe, x0, x1 - 1, y, + scanBuf + x0, + src->data + + (ySrc + y - yDest) * src->rowSize + + (xSrc + x0 - xDest) * bitmapComps); + } + } else { + for (y = y0; y < y1; ++y) { + memset(scanBuf + x0, 0xff, x1 - x0); + state->clip->clipSpan(scanBuf, y, x0, x1 - 1, state->strokeAdjust); + (this->*pipe.run)(&pipe, x0, x1 - 1, yDest + y, + scanBuf + x0, + src->data + + (ySrc + y - yDest) * src->rowSize + + (xSrc + x0 - xDest) * bitmapComps); + } + } + } + } + } + + return splashOk; +} + +SplashError Splash::compositeWithOverprint(SplashBitmap *src, + Guint *srcOverprintMaskBitmap, + int xSrc, int ySrc, + int xDest, int yDest, int w, int h, + GBool noClip, GBool nonIsolated) { + SplashPipe pipe; + int x0, x1, y0, y1, y, t; + + if (!(src->mode == bitmap->mode || + (src->mode == splashModeMono8 && bitmap->mode == splashModeMono1) || + (src->mode == splashModeRGB8 && bitmap->mode == splashModeBGR8))) { + return splashErrModeMismatch; + } + + pipeInit(&pipe, NULL, + (Guchar)splashRound(state->fillAlpha * 255), + !noClip || src->alpha != NULL, nonIsolated, gTrue); + + if (noClip) { + if (src->alpha) { + for (y = 0; y < h; ++y) { + pipe.srcOverprintMaskPtr = srcOverprintMaskBitmap + y * w + xSrc; + // this uses shape instead of alpha, which isn't technically + // correct, but works out the same + (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y, + src->alpha + + (ySrc + y) * src->alphaRowSize + xSrc, + src->data + (ySrc + y) * src->rowSize + + xSrc * bitmapComps); + } + } else { + for (y = 0; y < h; ++y) { + pipe.srcOverprintMaskPtr = srcOverprintMaskBitmap + y * w + xSrc; + (this->*pipe.run)(&pipe, xDest, xDest + w - 1, yDest + y, + NULL, + src->data + (ySrc + y) * src->rowSize + + xSrc * bitmapComps); + } + } + } else { + x0 = xDest; + if ((t = state->clip->getXMinI(state->strokeAdjust)) > x0) { + x0 = t; + } + x1 = xDest + w; + if ((t = state->clip->getXMaxI(state->strokeAdjust) + 1) < x1) { + x1 = t; + } + y0 = yDest; + if ((t = state->clip->getYMinI(state->strokeAdjust)) > y0) { + y0 = t; + } + y1 = yDest + h; + if ((t = state->clip->getYMaxI(state->strokeAdjust) + 1) < y1) { + y1 = t; + } + if (x0 < x1 && y0 < y1) { + if (src->alpha) { + for (y = y0; y < y1; ++y) { + memcpy(scanBuf + x0, + src->alpha + (ySrc + y - yDest) * src->alphaRowSize + + (xSrc + x0 - xDest), + x1 - x0); + state->clip->clipSpan(scanBuf, y, x0, x1 - 1, state->strokeAdjust); + pipe.srcOverprintMaskPtr = srcOverprintMaskBitmap + + (ySrc + y - yDest) * w + + (xSrc + x0 - xDest); + // this uses shape instead of alpha, which isn't technically + // correct, but works out the same + (this->*pipe.run)(&pipe, x0, x1 - 1, y, + scanBuf + x0, + src->data + + (ySrc + y - yDest) * src->rowSize + + (xSrc + x0 - xDest) * bitmapComps); + } + } else { + for (y = y0; y < y1; ++y) { + memset(scanBuf + x0, 0xff, x1 - x0); + state->clip->clipSpan(scanBuf, y, x0, x1 - 1, state->strokeAdjust); + pipe.srcOverprintMaskPtr = srcOverprintMaskBitmap + + (ySrc + y - yDest) * w + + (xSrc + x0 - xDest); + (this->*pipe.run)(&pipe, x0, x1 - 1, y, + scanBuf + x0, + src->data + + (ySrc + y - yDest) * src->rowSize + + (xSrc + x0 - xDest) * bitmapComps); + } + } + } + } + + return splashOk; +} + +void Splash::compositeBackground(SplashColorPtr color) { + SplashColorPtr p; + Guchar *q; + Guchar alpha, alpha1, c, color0, color1, color2, mask; +#if SPLASH_CMYK + Guchar color3; +#endif + int x, y; + + switch (bitmap->mode) { + case splashModeMono1: + color0 = color[0]; + for (y = 0; y < bitmap->height; ++y) { + p = &bitmap->data[y * bitmap->rowSize]; + q = &bitmap->alpha[y * bitmap->alphaRowSize]; + mask = 0x80; + for (x = 0; x < bitmap->width; ++x) { + alpha = *q++; + if (alpha == 0) { + if (color0 & 0x80) { + *p |= mask; + } else { + *p &= (Guchar)~mask; + } + } else if (alpha != 255) { + alpha1 = (Guchar)(255 - alpha); + c = (*p & mask) ? 0xff : 0x00; + c = div255(alpha1 * color0 + alpha * c); + if (c & 0x80) { + *p |= mask; + } else { + *p &= (Guchar)~mask; + } + } + if (!(mask = (Guchar)(mask >> 1))) { + mask = 0x80; + ++p; + } + } + } + break; + case splashModeMono8: + color0 = color[0]; + for (y = 0; y < bitmap->height; ++y) { + p = &bitmap->data[y * bitmap->rowSize]; + q = &bitmap->alpha[y * bitmap->alphaRowSize]; + for (x = 0; x < bitmap->width; ++x) { + alpha = *q++; + if (alpha == 0) { + p[0] = color0; + } else if (alpha != 255) { + alpha1 = (Guchar)(255 - alpha); + p[0] = div255(alpha1 * color0 + alpha * p[0]); + } + ++p; + } + } + break; + case splashModeRGB8: + case splashModeBGR8: + color0 = color[0]; + color1 = color[1]; + color2 = color[2]; + for (y = 0; y < bitmap->height; ++y) { + p = &bitmap->data[y * bitmap->rowSize]; + q = &bitmap->alpha[y * bitmap->alphaRowSize]; + for (x = 0; x < bitmap->width; ++x) { + alpha = *q++; + if (alpha == 0) { + p[0] = color0; + p[1] = color1; + p[2] = color2; + } else if (alpha != 255) { + alpha1 = (Guchar)(255 - alpha); + p[0] = div255(alpha1 * color0 + alpha * p[0]); + p[1] = div255(alpha1 * color1 + alpha * p[1]); + p[2] = div255(alpha1 * color2 + alpha * p[2]); + } + p += 3; + } + } + break; +#if SPLASH_CMYK + case splashModeCMYK8: + color0 = color[0]; + color1 = color[1]; + color2 = color[2]; + color3 = color[3]; + for (y = 0; y < bitmap->height; ++y) { + p = &bitmap->data[y * bitmap->rowSize]; + q = &bitmap->alpha[y * bitmap->alphaRowSize]; + for (x = 0; x < bitmap->width; ++x) { + alpha = *q++; + if (alpha == 0) { + p[0] = color0; + p[1] = color1; + p[2] = color2; + p[3] = color3; + } else if (alpha != 255) { + alpha1 = (Guchar)(255 - alpha); + p[0] = div255(alpha1 * color0 + alpha * p[0]); + p[1] = div255(alpha1 * color1 + alpha * p[1]); + p[2] = div255(alpha1 * color2 + alpha * p[2]); + p[3] = div255(alpha1 * color3 + alpha * p[3]); + } + p += 4; + } + } + break; +#endif + } + 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) { + SplashPath *pathIn, *dashPath, *pathOut; + SplashCoord d, dx, dy, wdx, wdy, dxNext, dyNext, wdxNext, wdyNext; + SplashCoord crossprod, dotprod, miter, m; + SplashCoord angle, angleNext, dAngle, xc, yc; + SplashCoord dxJoin, dyJoin, dJoin, kappa; + SplashCoord cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4; + GBool first, last, closed; + int subpathStart0, subpathStart1, seg, i0, i1, j0, j1, k0, k1; + int left0, left1, left2, right0, right1, right2, join0, join1, join2; + int leftFirst, rightFirst, firstPt; + + pathOut = new SplashPath(); + + if (path->length == 0) { + return pathOut; + } + + if (flatten) { + pathIn = flattenPath(path, state->matrix, state->flatness); + if (state->lineDashLength > 0) { + dashPath = makeDashedPath(pathIn); + delete pathIn; + pathIn = dashPath; + if (pathIn->length == 0) { + delete pathIn; + return pathOut; + } + } + } else { + pathIn = path; + } + + subpathStart0 = subpathStart1 = 0; // make gcc happy + seg = 0; // make gcc happy + closed = gFalse; // make gcc happy + left0 = left1 = right0 = right1 = join0 = join1 = 0; // make gcc happy + leftFirst = rightFirst = firstPt = 0; // make gcc happy + + i0 = 0; + for (i1 = i0; + !(pathIn->flags[i1] & splashPathLast) && + i1 + 1 < pathIn->length && + pathIn->pts[i1+1].x == pathIn->pts[i1].x && + pathIn->pts[i1+1].y == pathIn->pts[i1].y; + ++i1) ; + + while (i1 < pathIn->length) { + if ((first = pathIn->flags[i0] & splashPathFirst)) { + subpathStart0 = i0; + subpathStart1 = i1; + seg = 0; + closed = pathIn->flags[i0] & splashPathClosed; + } + j0 = i1 + 1; + if (j0 < pathIn->length) { + for (j1 = j0; + !(pathIn->flags[j1] & splashPathLast) && + j1 + 1 < pathIn->length && + pathIn->pts[j1+1].x == pathIn->pts[j1].x && + pathIn->pts[j1+1].y == pathIn->pts[j1].y; + ++j1) ; + } else { + j1 = j0; + } + if (pathIn->flags[i1] & splashPathLast) { + if (first && lineCap == splashLineCapRound) { + // special case: zero-length subpath with round line caps --> + // draw a circle + pathOut->moveTo(pathIn->pts[i0].x + (SplashCoord)0.5 * w, + pathIn->pts[i0].y); + pathOut->curveTo(pathIn->pts[i0].x + (SplashCoord)0.5 * w, + pathIn->pts[i0].y + bezierCircle2 * w, + pathIn->pts[i0].x + bezierCircle2 * w, + pathIn->pts[i0].y + (SplashCoord)0.5 * w, + pathIn->pts[i0].x, + pathIn->pts[i0].y + (SplashCoord)0.5 * w); + pathOut->curveTo(pathIn->pts[i0].x - bezierCircle2 * w, + pathIn->pts[i0].y + (SplashCoord)0.5 * w, + pathIn->pts[i0].x - (SplashCoord)0.5 * w, + pathIn->pts[i0].y + bezierCircle2 * w, + pathIn->pts[i0].x - (SplashCoord)0.5 * w, + pathIn->pts[i0].y); + pathOut->curveTo(pathIn->pts[i0].x - (SplashCoord)0.5 * w, + pathIn->pts[i0].y - bezierCircle2 * w, + pathIn->pts[i0].x - bezierCircle2 * w, + pathIn->pts[i0].y - (SplashCoord)0.5 * w, + pathIn->pts[i0].x, + pathIn->pts[i0].y - (SplashCoord)0.5 * w); + pathOut->curveTo(pathIn->pts[i0].x + bezierCircle2 * w, + pathIn->pts[i0].y - (SplashCoord)0.5 * w, + pathIn->pts[i0].x + (SplashCoord)0.5 * w, + pathIn->pts[i0].y - bezierCircle2 * w, + pathIn->pts[i0].x + (SplashCoord)0.5 * w, + pathIn->pts[i0].y); + pathOut->close(); + } + i0 = j0; + i1 = j1; + continue; + } + last = pathIn->flags[j1] & splashPathLast; + if (last) { + k0 = subpathStart1 + 1; + } else { + k0 = j1 + 1; + } + for (k1 = k0; + !(pathIn->flags[k1] & splashPathLast) && + k1 + 1 < pathIn->length && + pathIn->pts[k1+1].x == pathIn->pts[k1].x && + pathIn->pts[k1+1].y == pathIn->pts[k1].y; + ++k1) ; + + // compute the deltas for segment (i1, j0) +#if USE_FIXEDPOINT + // the 1/d value can be small, which introduces significant + // inaccuracies in fixed point mode + d = splashDist(pathIn->pts[i1].x, pathIn->pts[i1].y, + pathIn->pts[j0].x, pathIn->pts[j0].y); + dx = (pathIn->pts[j0].x - pathIn->pts[i1].x) / d; + dy = (pathIn->pts[j0].y - pathIn->pts[i1].y) / d; +#else + d = (SplashCoord)1 / splashDist(pathIn->pts[i1].x, pathIn->pts[i1].y, + pathIn->pts[j0].x, pathIn->pts[j0].y); + dx = d * (pathIn->pts[j0].x - pathIn->pts[i1].x); + dy = d * (pathIn->pts[j0].y - pathIn->pts[i1].y); +#endif + wdx = (SplashCoord)0.5 * w * dx; + wdy = (SplashCoord)0.5 * w * dy; + + // draw the start cap + if (i0 == subpathStart0) { + firstPt = pathOut->length; + } + if (first && !closed) { + switch (lineCap) { + case splashLineCapButt: + pathOut->moveTo(pathIn->pts[i0].x - wdy, pathIn->pts[i0].y + wdx); + pathOut->lineTo(pathIn->pts[i0].x + wdy, pathIn->pts[i0].y - wdx); + break; + case splashLineCapRound: + pathOut->moveTo(pathIn->pts[i0].x - wdy, pathIn->pts[i0].y + wdx); + pathOut->curveTo(pathIn->pts[i0].x - wdy - bezierCircle * wdx, + pathIn->pts[i0].y + wdx - bezierCircle * wdy, + pathIn->pts[i0].x - wdx - bezierCircle * wdy, + pathIn->pts[i0].y - wdy + bezierCircle * wdx, + pathIn->pts[i0].x - wdx, + pathIn->pts[i0].y - wdy); + pathOut->curveTo(pathIn->pts[i0].x - wdx + bezierCircle * wdy, + pathIn->pts[i0].y - wdy - bezierCircle * wdx, + pathIn->pts[i0].x + wdy - bezierCircle * wdx, + pathIn->pts[i0].y - wdx - bezierCircle * wdy, + pathIn->pts[i0].x + wdy, + pathIn->pts[i0].y - wdx); + break; + case splashLineCapProjecting: + pathOut->moveTo(pathIn->pts[i0].x - wdx - wdy, + pathIn->pts[i0].y + wdx - wdy); + pathOut->lineTo(pathIn->pts[i0].x - wdx + wdy, + pathIn->pts[i0].y - wdx - wdy); + break; + } + } else { + pathOut->moveTo(pathIn->pts[i0].x - wdy, pathIn->pts[i0].y + wdx); + pathOut->lineTo(pathIn->pts[i0].x + wdy, pathIn->pts[i0].y - wdx); + } + + // draw the left side of the segment rectangle and the end cap + left2 = pathOut->length - 1; + if (last && !closed) { + switch (lineCap) { + case splashLineCapButt: + pathOut->lineTo(pathIn->pts[j0].x + wdy, pathIn->pts[j0].y - wdx); + pathOut->lineTo(pathIn->pts[j0].x - wdy, pathIn->pts[j0].y + wdx); + break; + case splashLineCapRound: + pathOut->lineTo(pathIn->pts[j0].x + wdy, pathIn->pts[j0].y - wdx); + pathOut->curveTo(pathIn->pts[j0].x + wdy + bezierCircle * wdx, + pathIn->pts[j0].y - wdx + bezierCircle * wdy, + pathIn->pts[j0].x + wdx + bezierCircle * wdy, + pathIn->pts[j0].y + wdy - bezierCircle * wdx, + pathIn->pts[j0].x + wdx, + pathIn->pts[j0].y + wdy); + pathOut->curveTo(pathIn->pts[j0].x + wdx - bezierCircle * wdy, + pathIn->pts[j0].y + wdy + bezierCircle * wdx, + pathIn->pts[j0].x - wdy + bezierCircle * wdx, + pathIn->pts[j0].y + wdx + bezierCircle * wdy, + pathIn->pts[j0].x - wdy, + pathIn->pts[j0].y + wdx); + break; + case splashLineCapProjecting: + pathOut->lineTo(pathIn->pts[j0].x + wdy + wdx, + pathIn->pts[j0].y - wdx + wdy); + pathOut->lineTo(pathIn->pts[j0].x - wdy + wdx, + pathIn->pts[j0].y + wdx + wdy); + break; + } + } else { + pathOut->lineTo(pathIn->pts[j0].x + wdy, pathIn->pts[j0].y - wdx); + pathOut->lineTo(pathIn->pts[j0].x - wdy, pathIn->pts[j0].y + wdx); + } + + // draw the right side of the segment rectangle + // (NB: if stroke adjustment is enabled, the closepath operation MUST + // add a segment because this segment is used for a hint) + right2 = pathOut->length - 1; + pathOut->close(state->strokeAdjust != splashStrokeAdjustOff); + + // draw the join + join2 = pathOut->length; + if (!last || closed) { + + // compute the deltas for segment (j1, k0) +#if USE_FIXEDPOINT + // the 1/d value can be small, which introduces significant + // inaccuracies in fixed point mode + d = splashDist(pathIn->pts[j1].x, pathIn->pts[j1].y, + pathIn->pts[k0].x, pathIn->pts[k0].y); + dxNext = (pathIn->pts[k0].x - pathIn->pts[j1].x) / d; + dyNext = (pathIn->pts[k0].y - pathIn->pts[j1].y) / d; +#else + d = (SplashCoord)1 / splashDist(pathIn->pts[j1].x, pathIn->pts[j1].y, + pathIn->pts[k0].x, pathIn->pts[k0].y); + dxNext = d * (pathIn->pts[k0].x - pathIn->pts[j1].x); + dyNext = d * (pathIn->pts[k0].y - pathIn->pts[j1].y); +#endif + wdxNext = (SplashCoord)0.5 * w * dxNext; + wdyNext = (SplashCoord)0.5 * w * dyNext; + + // compute the join parameters + crossprod = dx * dyNext - dy * dxNext; + dotprod = -(dx * dxNext + dy * dyNext); + if (dotprod > 0.9999) { + // avoid a divide-by-zero -- set miter to something arbitrary + // such that sqrt(miter) will exceed miterLimit (and m is never + // used in that situation) + // (note: the comparison value (0.9999) has to be less than + // 1-epsilon, where epsilon is the smallest value + // representable in the fixed point format) + miter = (state->miterLimit + 1) * (state->miterLimit + 1); + m = 0; + } else { + miter = (SplashCoord)2 / ((SplashCoord)1 - dotprod); + if (miter < 1) { + // this can happen because of floating point inaccuracies + miter = 1; + } + m = splashSqrt(miter - 1); + } + + // round join + if (lineJoin == splashLineJoinRound) { + // join angle < 180 + if (crossprod < 0) { + angle = atan2((double)dx, (double)-dy); + angleNext = atan2((double)dxNext, (double)-dyNext); + if (angle < angleNext) { + angle += 2 * M_PI; + } + dAngle = (angle - angleNext) / M_PI; + if (dAngle < 0.501) { + // span angle is <= 90 degrees -> draw a single arc + kappa = dAngle * bezierCircle * w; + cx1 = pathIn->pts[j0].x - wdy + kappa * dx; + cy1 = pathIn->pts[j0].y + wdx + kappa * dy; + cx2 = pathIn->pts[j0].x - wdyNext - kappa * dxNext; + cy2 = pathIn->pts[j0].y + wdxNext - kappa * dyNext; + pathOut->moveTo(pathIn->pts[j0].x, pathIn->pts[j0].y); + pathOut->lineTo(pathIn->pts[j0].x - wdyNext, + pathIn->pts[j0].y + wdxNext); + pathOut->curveTo(cx2, cy2, cx1, cy1, + pathIn->pts[j0].x - wdy, + pathIn->pts[j0].y + wdx); + } else { + // span angle is > 90 degrees -> split into two arcs + dJoin = splashDist(-wdy, wdx, -wdyNext, wdxNext); + if (dJoin > 0) { + dxJoin = (-wdyNext + wdy) / dJoin; + dyJoin = (wdxNext - wdx) / dJoin; + xc = pathIn->pts[j0].x + + (SplashCoord)0.5 * w + * cos((double)((SplashCoord)0.5 * (angle + angleNext))); + yc = pathIn->pts[j0].y + + (SplashCoord)0.5 * w + * sin((double)((SplashCoord)0.5 * (angle + angleNext))); + kappa = dAngle * bezierCircle2 * w; + cx1 = pathIn->pts[j0].x - wdy + kappa * dx; + cy1 = pathIn->pts[j0].y + wdx + kappa * dy; + cx2 = xc - kappa * dxJoin; + cy2 = yc - kappa * dyJoin; + cx3 = xc + kappa * dxJoin; + cy3 = yc + kappa * dyJoin; + cx4 = pathIn->pts[j0].x - wdyNext - kappa * dxNext; + cy4 = pathIn->pts[j0].y + wdxNext - kappa * dyNext; + pathOut->moveTo(pathIn->pts[j0].x, pathIn->pts[j0].y); + pathOut->lineTo(pathIn->pts[j0].x - wdyNext, + pathIn->pts[j0].y + wdxNext); + pathOut->curveTo(cx4, cy4, cx3, cy3, xc, yc); + pathOut->curveTo(cx2, cy2, cx1, cy1, + pathIn->pts[j0].x - wdy, + pathIn->pts[j0].y + wdx); + } + } + + // join angle >= 180 + } else { + angle = atan2((double)-dx, (double)dy); + angleNext = atan2((double)-dxNext, (double)dyNext); + if (angleNext < angle) { + angleNext += 2 * M_PI; + } + dAngle = (angleNext - angle) / M_PI; + if (dAngle < 0.501) { + // span angle is <= 90 degrees -> draw a single arc + kappa = dAngle * bezierCircle * w; + cx1 = pathIn->pts[j0].x + wdy + kappa * dx; + cy1 = pathIn->pts[j0].y - wdx + kappa * dy; + cx2 = pathIn->pts[j0].x + wdyNext - kappa * dxNext; + cy2 = pathIn->pts[j0].y - wdxNext - kappa * dyNext; + pathOut->moveTo(pathIn->pts[j0].x, pathIn->pts[j0].y); + pathOut->lineTo(pathIn->pts[j0].x + wdy, + pathIn->pts[j0].y - wdx); + pathOut->curveTo(cx1, cy1, cx2, cy2, + pathIn->pts[j0].x + wdyNext, + pathIn->pts[j0].y - wdxNext); + } else { + // span angle is > 90 degrees -> split into two arcs + dJoin = splashDist(wdy, -wdx, wdyNext, -wdxNext); + if (dJoin > 0) { + dxJoin = (wdyNext - wdy) / dJoin; + dyJoin = (-wdxNext + wdx) / dJoin; + xc = pathIn->pts[j0].x + + (SplashCoord)0.5 * w + * cos((double)((SplashCoord)0.5 * (angle + angleNext))); + yc = pathIn->pts[j0].y + + (SplashCoord)0.5 * w + * sin((double)((SplashCoord)0.5 * (angle + angleNext))); + kappa = dAngle * bezierCircle2 * w; + cx1 = pathIn->pts[j0].x + wdy + kappa * dx; + cy1 = pathIn->pts[j0].y - wdx + kappa * dy; + cx2 = xc - kappa * dxJoin; + cy2 = yc - kappa * dyJoin; + cx3 = xc + kappa * dxJoin; + cy3 = yc + kappa * dyJoin; + cx4 = pathIn->pts[j0].x + wdyNext - kappa * dxNext; + cy4 = pathIn->pts[j0].y - wdxNext - kappa * dyNext; + pathOut->moveTo(pathIn->pts[j0].x, pathIn->pts[j0].y); + pathOut->lineTo(pathIn->pts[j0].x + wdy, + pathIn->pts[j0].y - wdx); + pathOut->curveTo(cx1, cy1, cx2, cy2, xc, yc); + pathOut->curveTo(cx3, cy3, cx4, cy4, + pathIn->pts[j0].x + wdyNext, + pathIn->pts[j0].y - wdxNext); + } + } + } + + } else { + pathOut->moveTo(pathIn->pts[j0].x, pathIn->pts[j0].y); + + // join angle < 180 + if (crossprod < 0) { + pathOut->lineTo(pathIn->pts[j0].x - wdyNext, + pathIn->pts[j0].y + wdxNext); + // miter join inside limit + if (lineJoin == splashLineJoinMiter && + splashSqrt(miter) <= state->miterLimit) { + pathOut->lineTo(pathIn->pts[j0].x - wdy + wdx * m, + pathIn->pts[j0].y + wdx + wdy * m); + pathOut->lineTo(pathIn->pts[j0].x - wdy, + pathIn->pts[j0].y + wdx); + // bevel join or miter join outside limit + } else { + pathOut->lineTo(pathIn->pts[j0].x - wdy, + pathIn->pts[j0].y + wdx); + } + + // join angle >= 180 + } else { + pathOut->lineTo(pathIn->pts[j0].x + wdy, + pathIn->pts[j0].y - wdx); + // miter join inside limit + if (lineJoin == splashLineJoinMiter && + splashSqrt(miter) <= state->miterLimit) { + pathOut->lineTo(pathIn->pts[j0].x + wdy + wdx * m, + pathIn->pts[j0].y - wdx + wdy * m); + pathOut->lineTo(pathIn->pts[j0].x + wdyNext, + pathIn->pts[j0].y - wdxNext); + // bevel join or miter join outside limit + } else { + pathOut->lineTo(pathIn->pts[j0].x + wdyNext, + pathIn->pts[j0].y - wdxNext); + } + } + } + + pathOut->close(); + } + + // add stroke adjustment hints + if (state->strokeAdjust != splashStrokeAdjustOff) { + + // subpath with one segment + if (seg == 0 && last) { + switch (lineCap) { + case splashLineCapButt: + pathOut->addStrokeAdjustHint(firstPt, left2 + 1, + firstPt, pathOut->length - 1); + break; + case splashLineCapProjecting: + pathOut->addStrokeAdjustHint(firstPt, left2 + 1, + firstPt, pathOut->length - 1, gTrue); + break; + case splashLineCapRound: + break; + } + pathOut->addStrokeAdjustHint(left2, right2, + firstPt, pathOut->length - 1); + } else { + + // start of subpath + if (seg == 1) { + + // start cap + if (!closed) { + switch (lineCap) { + case splashLineCapButt: + pathOut->addStrokeAdjustHint(firstPt, left1 + 1, + firstPt, firstPt + 1); + pathOut->addStrokeAdjustHint(firstPt, left1 + 1, + right1 + 1, right1 + 1); + break; + case splashLineCapProjecting: + pathOut->addStrokeAdjustHint(firstPt, left1 + 1, + firstPt, firstPt + 1, gTrue); + pathOut->addStrokeAdjustHint(firstPt, left1 + 1, + right1 + 1, right1 + 1, gTrue); + break; + case splashLineCapRound: + break; + } + } + + // first segment + pathOut->addStrokeAdjustHint(left1, right1, firstPt, left2); + pathOut->addStrokeAdjustHint(left1, right1, right2 + 1, right2 + 1); + } + + // middle of subpath + if (seg > 1) { + pathOut->addStrokeAdjustHint(left1, right1, left0 + 1, right0); + pathOut->addStrokeAdjustHint(left1, right1, join0, left2); + pathOut->addStrokeAdjustHint(left1, right1, right2 + 1, right2 + 1); + } + + // end of subpath + if (last) { + + if (closed) { + // first segment + pathOut->addStrokeAdjustHint(leftFirst, rightFirst, + left2 + 1, right2); + pathOut->addStrokeAdjustHint(leftFirst, rightFirst, + join2, pathOut->length - 1); + + // last segment + pathOut->addStrokeAdjustHint(left2, right2, + left1 + 1, right1); + pathOut->addStrokeAdjustHint(left2, right2, + join1, pathOut->length - 1); + pathOut->addStrokeAdjustHint(left2, right2, + leftFirst - 1, leftFirst); + pathOut->addStrokeAdjustHint(left2, right2, + rightFirst + 1, rightFirst + 1); + + } else { + + // last segment + pathOut->addStrokeAdjustHint(left2, right2, + left1 + 1, right1); + pathOut->addStrokeAdjustHint(left2, right2, + join1, pathOut->length - 1); + + // end cap + switch (lineCap) { + case splashLineCapButt: + pathOut->addStrokeAdjustHint(left2 - 1, left2 + 1, + left2 + 1, left2 + 2); + break; + case splashLineCapProjecting: + pathOut->addStrokeAdjustHint(left2 - 1, left2 + 1, + left2 + 1, left2 + 2, gTrue); + break; + case splashLineCapRound: + break; + } + } + } + } + + left0 = left1; + left1 = left2; + right0 = right1; + right1 = right2; + join0 = join1; + join1 = join2; + if (seg == 0) { + leftFirst = left2; + rightFirst = right2; + } + } + + i0 = j0; + i1 = j1; + ++seg; + } + + if (pathIn != path) { + delete pathIn; + } + + return pathOut; +} + +SplashClipResult Splash::limitRectToClipRect(int *xMin, int *yMin, + int *xMax, int *yMax) { + int t; + + if ((t = state->clip->getXMinI(state->strokeAdjust)) > *xMin) { + *xMin = t; + } + if ((t = state->clip->getXMaxI(state->strokeAdjust) + 1) < *xMax) { + *xMax = t; + } + if ((t = state->clip->getYMinI(state->strokeAdjust)) > *yMin) { + *yMin = t; + } + if ((t = state->clip->getYMaxI(state->strokeAdjust) + 1) < *yMax) { + *yMax = t; + } + if (*xMin >= *xMax || *yMin >= *yMax) { + return splashClipAllOutside; + } + return state->clip->testRect(*xMin, *yMin, *xMax - 1, *yMax - 1, + state->strokeAdjust); +} + +void Splash::dumpPath(SplashPath *path) { + int i; + + for (i = 0; i < path->length; ++i) { + printf(" %3d: x=%8.2f y=%8.2f%s%s%s%s\n", + i, (double)path->pts[i].x, (double)path->pts[i].y, + (path->flags[i] & splashPathFirst) ? " first" : "", + (path->flags[i] & splashPathLast) ? " last" : "", + (path->flags[i] & splashPathClosed) ? " closed" : "", + (path->flags[i] & splashPathCurve) ? " curve" : ""); + } + if (path->hintsLength == 0) { + printf(" no hints\n"); + } else { + for (i = 0; i < path->hintsLength; ++i) { + printf(" hint %3d: ctrl0=%d ctrl1=%d pts=%d..%d\n", + i, path->hints[i].ctrl0, path->hints[i].ctrl1, + path->hints[i].firstPt, path->hints[i].lastPt); + } + } +} + +void Splash::dumpXPath(SplashXPath *path) { + int i; + + for (i = 0; i < path->length; ++i) { + printf(" %4d: x0=%8.2f y0=%8.2f x1=%8.2f y1=%8.2f count=%d\n", + i, (double)path->segs[i].x0, (double)path->segs[i].y0, + (double)path->segs[i].x1, (double)path->segs[i].y1, + path->segs[i].count); + } +} + diff --git a/splash/Splash.h b/splash/Splash.h new file mode 100644 index 0000000..9622b07 --- /dev/null +++ b/splash/Splash.h @@ -0,0 +1,537 @@ +//======================================================================== +// +// Splash.h +// +// Copyright 2003-2013 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef SPLASH_H +#define SPLASH_H + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" +#include "SplashClip.h" + +class GString; +class Splash; +class SplashBitmap; +struct SplashGlyphBitmap; +class SplashState; +class SplashPattern; +class SplashScreen; +class SplashPath; +class SplashXPath; +class SplashFont; +struct SplashPipe; +struct SplashDrawImageMaskRowData; +class ImageScaler; +typedef void (Splash::*SplashDrawImageMaskRowFunc)( + SplashDrawImageMaskRowData *data, + Guchar *maskData, + int x, int y, int width); +struct SplashDrawImageRowData; +typedef void (Splash::*SplashDrawImageRowFunc)(SplashDrawImageRowData *data, + Guchar *colorData, + Guchar *alphaData, + int x, int y, int width); + +//------------------------------------------------------------------------ + +// Retrieves the next line of pixels in an image mask. Normally, +// fills in *<line> and returns true. If the image stream is +// exhausted, returns false. +typedef GBool (*SplashImageMaskSource)(void *data, Guchar *pixel); + +// Retrieves the next line of pixels in an image. Normally, fills in +// *<line> and returns true. If the image stream is exhausted, +// returns false. +typedef GBool (*SplashImageSource)(void *data, SplashColorPtr colorLine, + Guchar *alphaLine); + + +//------------------------------------------------------------------------ + +enum SplashPipeResultColorCtrl { + splashPipeResultColorNoAlphaBlendMono, + splashPipeResultColorNoAlphaBlendRGB, +#if SPLASH_CMYK + splashPipeResultColorNoAlphaBlendCMYK, +#endif + splashPipeResultColorAlphaNoBlendMono, + splashPipeResultColorAlphaNoBlendRGB, +#if SPLASH_CMYK + splashPipeResultColorAlphaNoBlendCMYK, +#endif + splashPipeResultColorAlphaBlendMono, + splashPipeResultColorAlphaBlendRGB +#if SPLASH_CMYK + , + splashPipeResultColorAlphaBlendCMYK +#endif +}; + +//------------------------------------------------------------------------ + +// Transparency group destination bitmap initialization control. +enum SplashGroupDestInitMode { + splashGroupDestPreInit, // dest is already initialized + splashGroupDestInitZero, // initialize to zero (isolated group) + splashGroupDestInitCopy // copy backdrop (non-isolated group) +}; + +//------------------------------------------------------------------------ +// SplashImageCache +//------------------------------------------------------------------------ + +// This holds a cached image, and is shared by multiple Splash objects +// in the same thread. +class SplashImageCache { +public: + + SplashImageCache(); + ~SplashImageCache(); + GBool match(GString *aTag, int aWidth, int aHeight, + SplashColorMode aMode, GBool aAlpha, + GBool aInterpolate); + void reset(GString *aTag, int aWidth, int aHeight, + SplashColorMode aMode, GBool aAlpha, + GBool aInterpolate); + void incRefCount(); + void decRefCount(); + + GString *tag; + int width; + int height; + SplashColorMode mode; + GBool alpha; + GBool interpolate; + Guchar *colorData; + Guchar *alphaData; + + int refCount; +}; + +//------------------------------------------------------------------------ +// Splash +//------------------------------------------------------------------------ + +class Splash { +public: + + // Create a new rasterizer object. + Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA, + SplashImageCache *imageCacheA, + SplashScreenParams *screenParams = NULL); + Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA, + SplashImageCache *imageCacheA, SplashScreen *screenA); + + ~Splash(); + + //----- state read + + SplashCoord *getMatrix(); + SplashPattern *getStrokePattern(); + SplashPattern *getFillPattern(); + SplashScreen *getScreen(); + SplashBlendFunc getBlendFunc(); + SplashCoord getStrokeAlpha(); + SplashCoord getFillAlpha(); + SplashCoord getLineWidth(); + int getLineCap(); + int getLineJoin(); + SplashCoord getMiterLimit(); + SplashCoord getFlatness(); + SplashCoord *getLineDash(); + int getLineDashLength(); + SplashCoord getLineDashPhase(); + SplashStrokeAdjustMode getStrokeAdjust(); + SplashClip *getClip(); + SplashBitmap *getSoftMask(); + GBool getInNonIsolatedGroup(); + GBool getInKnockoutGroup(); + + //----- state write + + void setMatrix(SplashCoord *matrix); + void setStrokePattern(SplashPattern *strokeColor); + void setFillPattern(SplashPattern *fillColor); + void setScreen(SplashScreen *screen); + void setBlendFunc(SplashBlendFunc func); + void setStrokeAlpha(SplashCoord alpha); + void setFillAlpha(SplashCoord alpha); + void setLineWidth(SplashCoord lineWidth); + void setLineCap(int lineCap); + void setLineJoin(int lineJoin); + void setMiterLimit(SplashCoord miterLimit); + void setFlatness(SplashCoord flatness); + // the <lineDash> array will be copied + void setLineDash(SplashCoord *lineDash, int lineDashLength, + SplashCoord lineDashPhase); + void setStrokeAdjust(SplashStrokeAdjustMode strokeAdjust); + // NB: uses transformed coordinates. + void clipResetToRect(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1); + // NB: uses transformed coordinates. + SplashError clipToRect(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1); + // NB: uses untransformed coordinates. + SplashError clipToPath(SplashPath *path, GBool eo); + void setSoftMask(SplashBitmap *softMask, GBool deleteBitmap = gTrue); + void setInTransparencyGroup(SplashBitmap *groupBackBitmapA, + int groupBackXA, int groupBackYA, + SplashGroupDestInitMode groupDestInitModeA, + GBool nonIsolated, GBool knockout); + void forceDeferredInit(int y, int h); + GBool checkTransparentRect(int x, int y, int w, int h); + void setTransfer(Guchar *red, Guchar *green, Guchar *blue, Guchar *gray); + void setOverprintMask(Guint overprintMask); + void setEnablePathSimplification(GBool en); + + //----- state save/restore + + void saveState(); + SplashError restoreState(); + + //----- drawing operations + + // Fill the bitmap with <color>. This is not subject to clipping. + void clear(SplashColorPtr color, Guchar alpha = 0x00); + + // Stroke a path using the current stroke pattern. + SplashError stroke(SplashPath *path); + + // Fill a path using the current fill pattern. + SplashError fill(SplashPath *path, GBool eo); + + // Draw a character, using the current fill pattern. + SplashError fillChar(SplashCoord x, SplashCoord y, int c, SplashFont *font); + + // Draw a glyph, using the current fill pattern. This function does + // not free any data, i.e., it ignores glyph->freeData. + SplashError fillGlyph(SplashCoord x, SplashCoord y, + SplashGlyphBitmap *glyph); + + // Draws an image mask using the fill color. This will read <h> + // lines of <w> pixels from <src>, starting with the top line. "1" + // pixels will be drawn with the current fill color; "0" pixels are + // transparent. The matrix: + // [ mat[0] mat[1] 0 ] + // [ mat[2] mat[3] 0 ] + // [ mat[4] mat[5] 1 ] + // maps a unit square to the desired destination for the image, in + // PostScript style: + // [x' y' 1] = [x y 1] * mat + // Note that the Splash y axis points downward, and the image source + // is assumed to produce pixels in raster order, starting from the + // top line. If [interpolate] is false, no filtering is done when + // upsampling. If [antialias] is false, no filtering is done when + // upsampling (overriding the [interpolate] flag), and threshold + // filtering is done when downsampling. + SplashError fillImageMask(GString *imageTag, + SplashImageMaskSource src, void *srcData, + int w, int h, SplashCoord *mat, + GBool glyphMode, GBool interpolate, + GBool antialias); + + // Draw an image. This will read <h> lines of <w> pixels from + // <src>, starting with the top line. These pixels are assumed to + // be in the source mode, <srcMode>. If <srcAlpha> is true, the + // alpha values returned by <src> are used; otherwise they are + // ignored. The following combinations of source and target modes + // are supported: + // source target + // ------ ------ + // Mono8 Mono1 -- with dithering + // Mono8 Mono8 + // RGB8 RGB8 + // BGR8 RGB8 + // CMYK8 CMYK8 + // The matrix behaves as for fillImageMask. + SplashError drawImage(GString *imageTag, + SplashImageSource src, void *srcData, + SplashColorMode srcMode, GBool srcAlpha, + int w, int h, SplashCoord *mat, + GBool interpolate); + + // Composite a rectangular region from <src> onto this Splash + // object. + SplashError composite(SplashBitmap *src, int xSrc, int ySrc, + int xDest, int yDest, int w, int h, + GBool noClip, GBool nonIsolated); + + // Composite a rectangular region from <src> onto this Splash + // object, using <srcOverprintMaskBitmap> as the overprint mask per + // pixel. This is only supported for CMYK and DeviceN bitmaps. + SplashError compositeWithOverprint(SplashBitmap *src, + Guint *srcOverprintMaskBitmap, + int xSrc, int ySrc, + int xDest, int yDest, int w, int h, + GBool noClip, GBool nonIsolated); + + // Composite this Splash object onto a background color. The + // background alpha is assumed to be 1. + void compositeBackground(SplashColorPtr color); + + // Copy a rectangular region from <src> onto the bitmap belonging to + // this Splash object. The destination alpha values are all set to + // zero. + SplashError blitTransparent(SplashBitmap *src, int xSrc, int ySrc, + int xDest, int yDest, int w, int h); + + // Copy a rectangular region from the bitmap belonging to this + // Splash object to <dest>. 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 + // the line width <w>. All other stroke parameters are taken from + // the current state. If <flatten> is true, this function will + // first flatten the path and handle the linedash. + SplashPath *makeStrokePath(SplashPath *path, SplashCoord w, + int lineCap, int lineJoin, + GBool flatten = gTrue); + + // Reduce the size of a rectangle as much as possible by moving any + // edges that are completely outside the clip region. Returns the + // clipping status of the resulting rectangle. + SplashClipResult limitRectToClipRect(int *xMin, int *yMin, + int *xMax, int *yMax); + + // Return the associated bitmap. + SplashBitmap *getBitmap() { return bitmap; } + + // Enable writing the per-pixel overprint mask to a separate bitmap. + void setOverprintMaskBitmap(Guint *overprintMaskBitmapA) + { overprintMaskBitmap = overprintMaskBitmapA; } + + // Set the minimum line width. + void setMinLineWidth(SplashCoord w) { minLineWidth = w; } + + // Get a bounding box which includes all modifications since the + // last call to clearModRegion. + void getModRegion(int *xMin, int *yMin, int *xMax, int *yMax) + { *xMin = modXMin; *yMin = modYMin; *xMax = modXMax; *yMax = modYMax; } + + // Clear the modified region bounding box. + void clearModRegion(); + + // Get clipping status for the last drawing operation subject to + // clipping. + SplashClipResult getClipRes() { return opClipRes; } + + // Toggle debug mode on or off. + void setDebugMode(GBool debugModeA) { debugMode = debugModeA; } + + 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); + void pipeRun(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr); + void pipeRunSimpleMono1(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr); + void pipeRunSimpleMono8(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr); + void pipeRunSimpleRGB8(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr); + void pipeRunSimpleBGR8(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr); +#if SPLASH_CMYK + void pipeRunSimpleCMYK8(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr); +#endif + void pipeRunShapeMono1(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr); + void pipeRunShapeMono8(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr); + void pipeRunShapeRGB8(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr); + void pipeRunShapeBGR8(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr); +#if SPLASH_CMYK + void pipeRunShapeCMYK8(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr); +#endif + void pipeRunShapeNoAlphaMono8(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr); + void pipeRunAAMono1(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr); + void pipeRunAAMono8(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr); + void pipeRunAARGB8(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr); + void pipeRunAABGR8(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr); +#if SPLASH_CMYK + void pipeRunAACMYK8(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr); +#endif + void pipeRunSoftMaskMono8(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr); + void pipeRunSoftMaskRGB8(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr); + void pipeRunSoftMaskBGR8(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr); +#if SPLASH_CMYK + void pipeRunSoftMaskCMYK8(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr); +#endif + void pipeRunNonIsoMono8(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr); + void pipeRunNonIsoRGB8(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr); + void pipeRunNonIsoBGR8(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr); +#if SPLASH_CMYK + void pipeRunNonIsoCMYK8(SplashPipe *pipe, int x0, int x1, int y, + Guchar *shapePtr, SplashColorPtr cSrcPtr); +#endif + void useDestRow(int y); + void copyGroupBackdropRow(int y); + void transform(SplashCoord *matrix, SplashCoord xi, SplashCoord yi, + SplashCoord *xo, SplashCoord *yo); + void updateModX(int x); + void updateModY(int y); + void strokeNarrow(SplashPath *path); + void drawStrokeSpan(SplashPipe *pipe, int x0, int x1, int y, GBool noClip); + void strokeWide(SplashPath *path, SplashCoord w, + int lineCap, int lineJoin); + SplashPath *flattenPath(SplashPath *path, SplashCoord *matrix, + SplashCoord flatness); + void flattenCurve(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1, + SplashCoord x2, SplashCoord y2, + SplashCoord x3, SplashCoord y3, + SplashCoord *matrix, SplashCoord flatness2, + SplashPath *fPath); + SplashPath *makeDashedPath(SplashPath *xPath); + SplashError fillWithPattern(SplashPath *path, GBool eo, + SplashPattern *pattern, SplashCoord alpha); + SplashPath *tweakFillPath(SplashPath *path); + GBool pathAllOutside(SplashPath *path); + SplashError fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph); + void getImageBounds(SplashCoord xyMin, SplashCoord xyMax, + int *xyMinI, int *xyMaxI); + void drawImageMaskArbitraryNoInterp(Guchar *scaledMask, + SplashDrawImageMaskRowData *dd, + SplashDrawImageMaskRowFunc drawRowFunc, + SplashCoord *invMat, + int scaledWidth, int scaledHeight, + int xMin, int yMin, int xMax, int yMax); + void drawImageMaskArbitraryInterp(Guchar *scaledMask, + SplashDrawImageMaskRowData *dd, + SplashDrawImageMaskRowFunc drawRowFunc, + SplashCoord *invMat, + int scaledWidth, int scaledHeight, + int xMin, int yMin, int xMax, int yMax); + void mirrorImageMaskRow(Guchar *maskIn, Guchar *maskOut, int width); + void drawImageMaskRowNoClip(SplashDrawImageMaskRowData *data, + Guchar *maskData, + int x, int y, int width); + void drawImageMaskRowClipNoAA(SplashDrawImageMaskRowData *data, + Guchar *maskData, + int x, int y, int width); + void drawImageMaskRowClipAA(SplashDrawImageMaskRowData *data, + Guchar *maskData, + int x, int y, int width); + ImageScaler *getImageScaler(GString *imageTag, + SplashImageSource src, void *srcData, + int w, int h, int nComps, + int scaledWidth, int scaledHeight, + SplashColorMode srcMode, + GBool srcAlpha, GBool interpolate); + void getScaledImage(GString *imageTag, + SplashImageSource src, void *srcData, + int w, int h, int nComps, + int scaledWidth, int scaledHeight, + SplashColorMode srcMode, + GBool srcAlpha, GBool interpolate, + Guchar **scaledColor, Guchar **scaledAlpha, + GBool *freeScaledImage); + void drawImageArbitraryNoInterp(Guchar *scaledColor, Guchar *scaledAlpha, + SplashDrawImageRowData *dd, + SplashDrawImageRowFunc drawRowFunc, + SplashCoord *invMat, + int scaledWidth, int scaledHeight, + int xMin, int yMin, int xMax, int yMax, + int nComps, GBool srcAlpha); + void drawImageArbitraryInterp(Guchar *scaledColor, Guchar *scaledAlpha, + SplashDrawImageRowData *dd, + SplashDrawImageRowFunc drawRowFunc, + SplashCoord *invMat, + int scaledWidth, int scaledHeight, + int xMin, int yMin, int xMax, int yMax, + int nComps, GBool srcAlpha); + void mirrorImageRow(Guchar *colorIn, Guchar *alphaIn, + Guchar *colorOut, Guchar *alphaOut, + int width, int nComps, GBool srcAlpha); + void drawImageRowNoClipNoAlpha(SplashDrawImageRowData *data, + Guchar *colorData, Guchar *alphaData, + int x, int y, int width); + void drawImageRowNoClipAlpha(SplashDrawImageRowData *data, + Guchar *colorData, Guchar *alphaData, + int x, int y, int width); + void drawImageRowClipNoAlphaNoAA(SplashDrawImageRowData *data, + Guchar *colorData, + Guchar *alphaData, + int x, int y, int width); + void drawImageRowClipNoAlphaAA(SplashDrawImageRowData *data, + Guchar *colorData, + Guchar *alphaData, + int x, int y, int width); + void drawImageRowClipAlphaNoAA(SplashDrawImageRowData *data, + Guchar *colorData, + Guchar *alphaData, + int x, int y, int width); + void drawImageRowClipAlphaAA(SplashDrawImageRowData *data, + Guchar *colorData, + Guchar *alphaData, + int x, int y, int width); + void dumpPath(SplashPath *path); + void dumpXPath(SplashXPath *path); + + + static SplashPipeResultColorCtrl pipeResultColorNoAlphaBlend[]; + static SplashPipeResultColorCtrl pipeResultColorAlphaNoBlend[]; + static SplashPipeResultColorCtrl pipeResultColorAlphaBlend[]; + static int pipeNonIsoGroupCorrection[]; + + SplashBitmap *bitmap; + int bitmapComps; + 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; + Guint *overprintMaskBitmap; + SplashCoord minLineWidth; + int modXMin, modYMin, modXMax, modYMax; + SplashClipResult opClipRes; + GBool vectorAntialias; + GBool inShading; + GBool debugMode; + + SplashImageCache *imageCache; +}; + +#endif diff --git a/splash/SplashBitmap.cc b/splash/SplashBitmap.cc new file mode 100644 index 0000000..db341d7 --- /dev/null +++ b/splash/SplashBitmap.cc @@ -0,0 +1,288 @@ +//======================================================================== +// +// SplashBitmap.cc +// +// Copyright 2003-2013 Glyph & Cog, LLC +// +//======================================================================== + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <stdio.h> +#include <limits.h> +#include "gmem.h" +#include "gmempp.h" +#include "gfile.h" +#include "Trace.h" +#include "SplashErrorCodes.h" +#include "SplashBitmap.h" + +//------------------------------------------------------------------------ +// SplashBitmap +//------------------------------------------------------------------------ + +SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPad, + SplashColorMode modeA, GBool alphaA, + GBool topDown, SplashBitmap *parentA) { + // NB: this code checks that rowSize fits in a signed 32-bit + // integer, because some code (outside this class) makes that + // assumption + width = widthA; + height = heightA; + mode = modeA; + switch (mode) { + case splashModeMono1: + if (width <= 0) { + gMemError("invalid bitmap width"); + } + rowSize = (width + 7) >> 3; + break; + case splashModeMono8: + if (width <= 0) { + gMemError("invalid bitmap width"); + } + rowSize = width; + break; + case splashModeRGB8: + case splashModeBGR8: + if (width <= 0 || width > INT_MAX / 3) { + gMemError("invalid bitmap width"); + } + rowSize = (SplashBitmapRowSize)width * 3; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + if (width <= 0 || width > INT_MAX / 4) { + gMemError("invalid bitmap width"); + } + rowSize = (SplashBitmapRowSize)width * 4; + break; +#endif + } + rowSize += rowPad - 1; + rowSize -= rowSize % rowPad; + + traceAlloc(this, "alloc bitmap: %d x %d x %d %s -> %lld bytes", + width, height, splashColorModeNComps[mode], + alphaA ? "with alpha" : "without alpha", + height * rowSize + (alphaA ? height * width : 0)); + + parent = parentA; + oldData = NULL; + oldAlpha = NULL; + 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"); + } 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; + rowSize = -rowSize; + } + if (alphaA) { + alphaRowSize = width; + if (parent && parent->oldAlpha && + parent->oldAlphaRowSize == alphaRowSize && + parent->oldHeight == height) { + alpha = parent->oldAlpha; + parent->oldAlpha = NULL; + } else { + alpha = (Guchar *)gmallocn64(height, alphaRowSize); + } + } else { + alphaRowSize = 0; + alpha = NULL; + } +} + +SplashBitmap::~SplashBitmap() { + traceFree(this, "free bitmap"); + if (data && rowSize < 0) { + 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; + } else { + gfree(data); + gfree(alpha); + } + gfree(oldData); + gfree(oldAlpha); +} + +SplashError SplashBitmap::writePNMFile(char *fileName) { + FILE *f; + SplashError err; + + if (!(f = openFile(fileName, "wb"))) { + return splashErrOpenFile; + } + err = writePNMFile(f); + fclose(f); + return err; +} + +SplashError SplashBitmap::writePNMFile(FILE *f) { + SplashColorPtr row, p; + int x, y; + + switch (mode) { + + case splashModeMono1: + fprintf(f, "P4\n%d %d\n", width, height); + row = data; + for (y = 0; y < height; ++y) { + p = row; + for (x = 0; x < width; x += 8) { + fputc(*p ^ 0xff, f); + ++p; + } + row += rowSize; + } + break; + + case splashModeMono8: + fprintf(f, "P5\n%d %d\n255\n", width, height); + row = data; + for (y = 0; y < height; ++y) { + fwrite(row, 1, width, f); + row += rowSize; + } + break; + + case splashModeRGB8: + fprintf(f, "P6\n%d %d\n255\n", width, height); + row = data; + for (y = 0; y < height; ++y) { + fwrite(row, 1, 3 * width, f); + row += rowSize; + } + break; + + case splashModeBGR8: + fprintf(f, "P6\n%d %d\n255\n", width, height); + row = data; + for (y = 0; y < height; ++y) { + p = row; + for (x = 0; x < width; ++x) { + fputc(splashBGR8R(p), f); + fputc(splashBGR8G(p), f); + fputc(splashBGR8B(p), f); + p += 3; + } + row += rowSize; + } + break; + +#if SPLASH_CMYK + case splashModeCMYK8: + fprintf(f, "P7\n"); + fprintf(f, "WIDTH %d\n", width); + fprintf(f, "HEIGHT %d\n", height); + fprintf(f, "DEPTH 4\n"); + fprintf(f, "MAXVAL 255\n"); + fprintf(f, "TUPLTYPE CMYK\n"); + fprintf(f, "ENDHDR\n"); + row = data; + for (y = 0; y < height; ++y) { + fwrite(row, 1, 4 * width, f); + row += rowSize; + } + break; +#endif + + } + + return splashOk; +} + +SplashError SplashBitmap::writeAlphaPGMFile(char *fileName) { + FILE *f; + + if (!alpha) { + return splashErrModeMismatch; + } + if (!(f = openFile(fileName, "wb"))) { + return splashErrOpenFile; + } + fprintf(f, "P5\n%d %d\n255\n", width, height); + fwrite(alpha, 1, width * height, f); + fclose(f); + return splashOk; +} + + +void SplashBitmap::getPixel(int x, int y, SplashColorPtr pixel) { + SplashColorPtr p; + + if (y < 0 || y >= height || x < 0 || x >= width) { + return; + } + switch (mode) { + case splashModeMono1: + p = &data[y * rowSize + (x >> 3)]; + pixel[0] = (p[0] & (0x80 >> (x & 7))) ? 0xff : 0x00; + break; + case splashModeMono8: + p = &data[y * rowSize + x]; + pixel[0] = p[0]; + break; + case splashModeRGB8: + p = &data[y * rowSize + 3 * x]; + pixel[0] = p[0]; + pixel[1] = p[1]; + pixel[2] = p[2]; + break; + case splashModeBGR8: + p = &data[y * rowSize + 3 * x]; + pixel[0] = p[2]; + pixel[1] = p[1]; + pixel[2] = p[0]; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + p = &data[y * rowSize + 4 * x]; + pixel[0] = p[0]; + pixel[1] = p[1]; + pixel[2] = p[2]; + pixel[3] = p[3]; + break; +#endif + } +} + +Guchar SplashBitmap::getAlpha(int x, int y) { + return alpha[y * (size_t)width + x]; +} + +SplashColorPtr SplashBitmap::takeData() { + SplashColorPtr data2; + + data2 = data; + data = NULL; + return data2; +} + diff --git a/splash/SplashBitmap.h b/splash/SplashBitmap.h new file mode 100644 index 0000000..54975a3 --- /dev/null +++ b/splash/SplashBitmap.h @@ -0,0 +1,98 @@ +//======================================================================== +// +// SplashBitmap.h +// +// Copyright 2003-2013 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef SPLASHBITMAP_H +#define SPLASHBITMAP_H + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include <stdio.h> +#include <limits.h> +// older compilers won't define SIZE_MAX in stdint.h without this +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS 1 +#endif +#include <stdint.h> +#include "SplashTypes.h" + +//------------------------------------------------------------------------ + +// ssize_t isn't well-defined, so define our own +#if SIZE_MAX == UINT_MAX + typedef int SplashBitmapRowSize; +# define SplashBitmapRowSizeMax INT_MAX +#else + typedef long long SplashBitmapRowSize; +# define SplashBitmapRowSizeMax LLONG_MAX +#endif + +//------------------------------------------------------------------------ +// SplashBitmap +//------------------------------------------------------------------------ + +class SplashBitmap { +public: + + // Create a new bitmap. It will have <widthA> x <heightA> pixels in + // color mode <modeA>. Rows will be padded out to a multiple of + // <rowPad> bytes. If <topDown> is false, the bitmap will be stored + // upside-down, i.e., with the last row first in memory. + SplashBitmap(int widthA, int heightA, int rowPad, + SplashColorMode modeA, GBool alphaA, + GBool topDown, SplashBitmap *parentA); + + ~SplashBitmap(); + + int getWidth() { return width; } + int getHeight() { return height; } + SplashBitmapRowSize getRowSize() { return rowSize; } + size_t getAlphaRowSize() { return alphaRowSize; } + SplashColorMode getMode() { return mode; } + SplashColorPtr getDataPtr() { return data; } + Guchar *getAlphaPtr() { return alpha; } + + SplashError writePNMFile(char *fileName); + SplashError writePNMFile(FILE *f); + SplashError writeAlphaPGMFile(char *fileName); + + void getPixel(int x, int y, SplashColorPtr pixel); + Guchar getAlpha(int x, int y); + + // Caller takes ownership of the bitmap data. The SplashBitmap + // object is no longer valid -- the next call should be to the + // destructor. + SplashColorPtr takeData(); + +private: + + int width, height; // size of bitmap + SplashBitmapRowSize rowSize; // size of one row of data, in bytes + // - negative for bottom-up bitmaps + size_t alphaRowSize; // size of one row of alpha, in bytes + SplashColorMode mode; // color mode + SplashColorPtr data; // pointer to row zero of the color data + Guchar *alpha; // pointer to row zero of the alpha data + // (always top-down) + + // save the last-allocated (large) bitmap data and reuse if possible + SplashBitmap *parent; + SplashColorPtr oldData; + Guchar *oldAlpha; + SplashBitmapRowSize oldRowSize; + size_t oldAlphaRowSize; + int oldHeight; + + friend class Splash; +}; + + +#endif diff --git a/splash/SplashClip.cc b/splash/SplashClip.cc new file mode 100644 index 0000000..bf7b802 --- /dev/null +++ b/splash/SplashClip.cc @@ -0,0 +1,521 @@ +//======================================================================== +// +// SplashClip.cc +// +// Copyright 2003-2013 Glyph & Cog, LLC +// +//======================================================================== + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <stdlib.h> +#include <string.h> +#include "gmem.h" +#include "gmempp.h" +#include "SplashErrorCodes.h" +#include "SplashPath.h" +#include "SplashXPath.h" +#include "SplashXPathScanner.h" +#include "SplashClip.h" + +//------------------------------------------------------------------------ + +// Compute x * y / 255, where x and y are in [0, 255]. +static inline Guchar mul255(Guchar x, Guchar y) { + int z; + + z = (int)x * (int)y; + return (Guchar)((z + (z >> 8) + 0x80) >> 8); +} + +//------------------------------------------------------------------------ +// SplashClip +//------------------------------------------------------------------------ + +SplashClip::SplashClip(int hardXMinA, int hardYMinA, + int hardXMaxA, int hardYMaxA) { + int w; + + hardXMin = hardXMinA; + hardYMin = hardYMinA; + hardXMax = hardXMaxA; + hardYMax = hardYMaxA; + xMin = hardXMin; + yMin = hardYMin; + xMax = hardXMax; + yMax = hardYMax; + intBoundsValid = gFalse; + paths = NULL; + eo = NULL; + scanners = NULL; + length = size = 0; + isSimple = gTrue; + prev = NULL; + if ((w = hardXMax + 1) <= 0) { + w = 1; + } + buf = (Guchar *)gmalloc(w); +} + +SplashClip::SplashClip(SplashClip *clip) { + int w; + + hardXMin = clip->hardXMin; + hardYMin = clip->hardYMin; + hardXMax = clip->hardXMax; + hardYMax = clip->hardYMax; + xMin = clip->xMin; + yMin = clip->yMin; + xMax = clip->xMax; + yMax = clip->yMax; + xMinI = clip->xMinI; + yMinI = clip->yMinI; + xMaxI = clip->xMaxI; + yMaxI = clip->yMaxI; + intBoundsValid = clip->intBoundsValid; + intBoundsStrokeAdjust = clip->intBoundsStrokeAdjust; + paths = NULL; + eo = NULL; + scanners = NULL; + length = size = 0; + isSimple = clip->isSimple; + prev = clip; + if ((w = splashCeil(xMax)) <= 0) { + w = 1; + } + buf = (Guchar *)gmalloc(w); +} + +SplashClip::~SplashClip() { + int i; + + for (i = 0; i < length; ++i) { + delete scanners[i]; + delete paths[i]; + } + gfree(paths); + gfree(eo); + gfree(scanners); + gfree(buf); +} + +void SplashClip::grow(int nPaths) { + if (length + nPaths > size) { + if (size == 0) { + size = 32; + } + while (size < length + nPaths) { + size *= 2; + } + paths = (SplashXPath **)greallocn(paths, size, sizeof(SplashXPath *)); + eo = (Guchar *)greallocn(eo, size, sizeof(Guchar)); + scanners = (SplashXPathScanner **) + greallocn(scanners, size, sizeof(SplashXPathScanner *)); + } +} + +void SplashClip::resetToRect(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1) { + int w, i; + + for (i = 0; i < length; ++i) { + delete paths[i]; + delete scanners[i]; + } + gfree(paths); + gfree(eo); + gfree(scanners); + gfree(buf); + paths = NULL; + eo = NULL; + scanners = NULL; + length = size = 0; + isSimple = gTrue; + prev = NULL; + + if (x0 < x1) { + xMin = x0; + xMax = x1; + } else { + xMin = x1; + xMax = x0; + } + if (y0 < y1) { + yMin = y0; + yMax = y1; + } else { + yMin = y1; + yMax = y0; + } + intBoundsValid = gFalse; + if ((w = splashCeil(xMax)) <= 0) { + w = 1; + } + buf = (Guchar *)gmalloc(w); +} + +SplashError SplashClip::clipToRect(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1) { + if (x0 < x1) { + if (x0 > xMin) { + xMin = x0; + intBoundsValid = gFalse; + } + if (x1 < xMax) { + xMax = x1; + intBoundsValid = gFalse; + } + } else { + if (x1 > xMin) { + xMin = x1; + intBoundsValid = gFalse; + } + if (x0 < xMax) { + xMax = x0; + intBoundsValid = gFalse; + } + } + if (y0 < y1) { + if (y0 > yMin) { + yMin = y0; + intBoundsValid = gFalse; + } + if (y1 < yMax) { + yMax = y1; + intBoundsValid = gFalse; + } + } else { + if (y1 > yMin) { + yMin = y1; + intBoundsValid = gFalse; + } + if (y0 < yMax) { + yMax = y0; + intBoundsValid = gFalse; + } + } + return splashOk; +} + +SplashError SplashClip::clipToPath(SplashPath *path, SplashCoord *matrix, + SplashCoord flatness, GBool eoA, + GBool enablePathSimplification, + SplashStrokeAdjustMode strokeAdjust) { + SplashXPath *xPath; + SplashCoord t; + + xPath = new SplashXPath(path, matrix, flatness, gTrue, + enablePathSimplification, + strokeAdjust); + + // check for an empty path + if (xPath->length == 0) { + xMin = yMin = 1; + xMax = yMax = 0; + intBoundsValid = gFalse; + delete xPath; + return splashOk; + } + + // check for a rectangle + if (xPath->isRect) { + clipToRect(xPath->rectX0, xPath->rectY0, xPath->rectX1, xPath->rectY1); + delete xPath; + return splashOk; + } + + grow(1); + paths[length] = xPath; + eo[length] = (Guchar)eoA; + if ((t = xPath->getXMin()) > xMin) { + xMin = t; + } + if ((t = xPath->getYMin()) > yMin) { + yMin = t; + } + if ((t = xPath->getXMax() + 1) < xMax) { + xMax = t; + } + if ((t = xPath->getYMax() + 1) < yMax) { + yMax = t; + } + intBoundsValid = gFalse; + scanners[length] = new SplashXPathScanner(xPath, eoA, splashFloor(yMin), + splashCeil(yMax) - 1); + ++length; + isSimple = gFalse; + + return splashOk; +} + +SplashClipResult SplashClip::testRect(int rectXMin, int rectYMin, + int rectXMax, int rectYMax, + SplashStrokeAdjustMode strokeAdjust) { + // In general, this function tests the rectangle: + // x = [rectXMin, rectXMax + 1) (note: coords are ints) + // y = [rectYMin, rectYMax + 1) + // against the clipping region: + // x = [xMin, xMax) (note: coords are fp) + // y = [yMin, yMax) + + if (strokeAdjust != splashStrokeAdjustOff && isSimple) { + // special case for stroke adjustment with a simple clipping + // rectangle -- the clipping region is: + // x = [xMinI, xMaxI + 1) + // y = [yMinI, yMaxI + 1) + updateIntBounds(strokeAdjust); + if (xMinI > xMaxI || yMinI > yMaxI) { + return splashClipAllOutside; + } + if (rectXMax + 1 <= xMinI || + rectXMin >= xMaxI + 1 || + rectYMax + 1 <= yMinI || + rectYMin >= yMaxI + 1) { + return splashClipAllOutside; + } + if (rectXMin >= xMinI && + rectXMax <= xMaxI && + rectYMin >= yMinI && + rectYMax <= yMaxI) { + return splashClipAllInside; + } + } else { + if (xMin >= xMax || yMin >= yMax) { + return splashClipAllOutside; + } + if ((SplashCoord)(rectXMax + 1) <= xMin || + (SplashCoord)rectXMin >= xMax || + (SplashCoord)(rectYMax + 1) <= yMin || + (SplashCoord)rectYMin >= yMax) { + return splashClipAllOutside; + } + if (isSimple && + (SplashCoord)rectXMin >= xMin && + (SplashCoord)(rectXMax + 1) <= xMax && + (SplashCoord)rectYMin >= yMin && + (SplashCoord)(rectYMax + 1) <= yMax) { + return splashClipAllInside; + } + } + return splashClipPartial; +} + +void SplashClip::clipSpan(Guchar *line, int y, int x0, int x1, + SplashStrokeAdjustMode strokeAdjust) { + SplashClip *clip; + SplashCoord d; + int x0a, x1a, x0b, x1b, x, i; + + updateIntBounds(strokeAdjust); + + //--- clip to the integer rectangle + + if (y < yMinI || y > yMaxI || + x1 < xMinI || x0 > xMaxI) { + memset(line + x0, 0, x1 - x0 + 1); + return; + } + + if (x0 > xMinI) { + x0a = x0; + } else { + x0a = xMinI; + memset(line + x0, 0, x0a - x0); + } + + if (x1 < xMaxI) { + x1a = x1; + } else { + x1a = xMaxI; + memset(line + x1a + 1, 0, x1 - x1a); + } + + if (x0a > x1a) { + return; + } + + //--- clip to the floating point rectangle + // (if stroke adjustment is disabled) + + if (strokeAdjust == splashStrokeAdjustOff) { + + // clip left edge (xMin) + if (x0a == xMinI) { + d = (SplashCoord)(xMinI + 1) - xMin; + line[x0a] = (Guchar)(int)((SplashCoord)line[x0a] * d); + } + + // clip right edge (xMax) + if (x1a == xMaxI) { + d = xMax - (SplashCoord)xMaxI; + line[x1a] = (Guchar)(int)((SplashCoord)line[x1a] * d); + } + + // clip top edge (yMin) + if (y == yMinI) { + d = (SplashCoord)(yMinI + 1) - yMin; + for (x = x0a; x <= x1a; ++x) { + line[x] = (Guchar)(int)((SplashCoord)line[x] * d); + } + } + + // clip bottom edge (yMax) + if (y == yMaxI) { + d = yMax - (SplashCoord)yMaxI; + for (x = x0a; x <= x1a; ++x) { + line[x] = (Guchar)(int)((SplashCoord)line[x] * d); + } + } + } + + if (isSimple) { + return; + } + + //--- clip to the paths + + for (clip = this; clip; clip = clip->prev) { + for (i = 0; i < clip->length; ++i) { + clip->scanners[i]->getSpan(buf, y, x0a, x1a, &x0b, &x1b); + if (x0a < x0b) { + memset(line + x0a, 0, x0b - x0a); + } + for (x = x0b; x <= x1b; ++x) { + line[x] = mul255(line[x], buf[x]); + } + if (x1b < x1a) { + memset(line + x1b + 1, 0, x1a - x1b); + } + } + } +} + +GBool SplashClip::clipSpanBinary(Guchar *line, int y, int x0, int x1, + SplashStrokeAdjustMode strokeAdjust) { + SplashClip *clip; + int x0a, x1a, x0b, x1b, x, i; + Guchar any; + + updateIntBounds(strokeAdjust); + + if (y < yMinI || y > yMaxI || + x1 < xMinI || x0 > xMaxI) { + if (x0 <= x1) { + memset(line + x0, 0, x1 - x0 + 1); + } + return gFalse; + } + + if (x0 > xMinI) { + x0a = x0; + } else { + x0a = xMinI; + memset(line + x0, 0, x0a - x0); + } + + if (x1 < xMaxI) { + x1a = x1; + } else { + x1a = xMaxI; + memset(line + x1a + 1, 0, x1 - x1a); + } + + if (x0a > x1a) { + return gFalse; + } + + if (isSimple) { + for (x = x0a; x <= x1a; ++x) { + if (line[x]) { + return gTrue; + } + } + return gFalse; + } + + any = 0; + for (clip = this; clip; clip = clip->prev) { + for (i = 0; i < clip->length; ++i) { + clip->scanners[i]->getSpanBinary(buf, y, x0a, x1a, &x0b, &x1b); + if (x0a < x0b) { + memset(line + x0a, 0, x0b - x0a); + } + for (x = x0b; x <= x1b; ++x) { + line[x] &= buf[x]; + any |= line[x]; + } + if (x1b < x1a) { + memset(line + x1b + 1, 0, x1a - x1b); + } + } + } + + return any != 0; +} + +int SplashClip::getXMinI(SplashStrokeAdjustMode strokeAdjust) { + updateIntBounds(strokeAdjust); + return xMinI; +} + +int SplashClip::getXMaxI(SplashStrokeAdjustMode strokeAdjust) { + updateIntBounds(strokeAdjust); + return xMaxI; +} + +int SplashClip::getYMinI(SplashStrokeAdjustMode strokeAdjust) { + updateIntBounds(strokeAdjust); + return yMinI; +} + +int SplashClip::getYMaxI(SplashStrokeAdjustMode strokeAdjust) { + updateIntBounds(strokeAdjust); + return yMaxI; +} + +int SplashClip::getNumPaths() { + SplashClip *clip; + int n; + + n = 0; + for (clip = this; clip; clip = clip->prev) { + n += clip->length; + } + return n; +} + +void SplashClip::updateIntBounds(SplashStrokeAdjustMode strokeAdjust) { + if (intBoundsValid && strokeAdjust == intBoundsStrokeAdjust) { + return; + } + if (strokeAdjust != splashStrokeAdjustOff && isSimple) { + splashStrokeAdjust(xMin, xMax, &xMinI, &xMaxI, strokeAdjust); + splashStrokeAdjust(yMin, yMax, &yMinI, &yMaxI, strokeAdjust); + } else { + xMinI = splashFloor(xMin); + yMinI = splashFloor(yMin); + xMaxI = splashCeil(xMax); + yMaxI = splashCeil(yMax); + } + if (xMinI < hardXMin) { + xMinI = hardXMin; + } + if (yMinI < hardYMin) { + yMinI = hardYMin; + } + if (xMaxI > hardXMax) { + xMaxI = hardXMax; + } + if (yMaxI > hardYMax) { + yMaxI = hardYMax; + } + // the clipping code uses [xMinI, xMaxI] instead of [xMinI, xMaxI) + --xMaxI; + --yMaxI; + intBoundsValid = gTrue; + intBoundsStrokeAdjust = strokeAdjust; +} diff --git a/splash/SplashClip.h b/splash/SplashClip.h new file mode 100644 index 0000000..fb86ed8 --- /dev/null +++ b/splash/SplashClip.h @@ -0,0 +1,130 @@ +//======================================================================== +// +// SplashClip.h +// +// Copyright 2003-2013 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef SPLASHCLIP_H +#define SPLASHCLIP_H + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" +#include "SplashMath.h" + +class SplashPath; +class SplashXPath; +class SplashXPathScanner; +class SplashBitmap; + +//------------------------------------------------------------------------ + +enum SplashClipResult { + splashClipAllInside, + splashClipAllOutside, + splashClipPartial +}; + +//------------------------------------------------------------------------ +// SplashClip +//------------------------------------------------------------------------ + +class SplashClip { +public: + + // Create a clip, for the given rectangle. + SplashClip(int hardXMinA, int hardYMinA, + int hardXMaxA, int hardYMaxA); + + // Copy a clip. + SplashClip *copy() { return new SplashClip(this); } + + ~SplashClip(); + + // Reset the clip to a rectangle. + void resetToRect(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1); + + // Intersect the clip with a rectangle. + SplashError clipToRect(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1); + + // Interesect the clip with <path>. + SplashError clipToPath(SplashPath *path, SplashCoord *matrix, + SplashCoord flatness, GBool eoA, + GBool enablePathSimplification, + SplashStrokeAdjustMode strokeAdjust); + + // Tests a rectangle against the clipping region. Returns one of: + // - splashClipAllInside if the entire rectangle is inside the + // clipping region, i.e., all pixels in the rectangle are + // visible + // - splashClipAllOutside if the entire rectangle is outside the + // clipping region, i.e., all the pixels in the rectangle are + // clipped + // - splashClipPartial if the rectangle is part inside and part + // outside the clipping region + SplashClipResult testRect(int rectXMin, int rectYMin, + int rectXMax, int rectYMax, + SplashStrokeAdjustMode strokeAdjust); + + // Clip a scan line. Modifies line[] by multiplying with clipping + // shape values for one scan line: ([x0, x1], y). + void clipSpan(Guchar *line, int y, int x0, int x1, + SplashStrokeAdjustMode strokeAdjust); + + // Like clipSpan(), but uses the values 0 and 255 only. + // Returns true if there are any non-zero values in the result + // (i.e., returns false if the entire line is clipped out). + GBool clipSpanBinary(Guchar *line, int y, int x0, int x1, + SplashStrokeAdjustMode strokeAdjust); + + // Get the rectangle part of the clip region. + SplashCoord getXMin() { return xMin; } + SplashCoord getXMax() { return xMax; } + SplashCoord getYMin() { return yMin; } + SplashCoord getYMax() { return yMax; } + + // Get the rectangle part of the clip region, in integer coordinates. + int getXMinI(SplashStrokeAdjustMode strokeAdjust); + int getXMaxI(SplashStrokeAdjustMode strokeAdjust); + int getYMinI(SplashStrokeAdjustMode strokeAdjust); + int getYMaxI(SplashStrokeAdjustMode strokeAdjust); + + // Get the number of arbitrary paths used by the clip region. + int getNumPaths(); + +private: + + SplashClip(SplashClip *clip); + void grow(int nPaths); + void updateIntBounds(SplashStrokeAdjustMode strokeAdjust); + + int hardXMin, hardYMin, // coordinates cannot fall outside of + 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) + + int xMinI, yMinI, xMaxI, yMaxI; + GBool intBoundsValid; // true if xMinI, etc. are valid + GBool intBoundsStrokeAdjust; // value of strokeAdjust used to compute + // xMinI, etc. + + SplashXPath **paths; + Guchar *eo; + SplashXPathScanner **scanners; + int length, size; + GBool isSimple; + SplashClip *prev; + Guchar *buf; +}; + +#endif diff --git a/splash/SplashErrorCodes.h b/splash/SplashErrorCodes.h new file mode 100644 index 0000000..ebe6091 --- /dev/null +++ b/splash/SplashErrorCodes.h @@ -0,0 +1,34 @@ +//======================================================================== +// +// SplashErrorCodes.h +// +// Copyright 2003-2013 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef SPLASHERRORCODES_H +#define SPLASHERRORCODES_H + +#include <aconf.h> + +//------------------------------------------------------------------------ + +#define splashOk 0 // no error + +#define splashErrNoCurPt 1 // no current point + +#define splashErrEmptyPath 2 // zero points in path + +#define splashErrBogusPath 3 // only one point in subpath + +#define splashErrNoSave 4 // state stack is empty + +#define splashErrOpenFile 5 // couldn't open file + +#define splashErrNoGlyph 6 // couldn't get the requested glyph + +#define splashErrModeMismatch 7 // invalid combination of color modes + +#define splashErrSingularMatrix 8 // matrix is singular + +#endif diff --git a/splash/SplashFTFont.cc b/splash/SplashFTFont.cc new file mode 100644 index 0000000..9148144 --- /dev/null +++ b/splash/SplashFTFont.cc @@ -0,0 +1,460 @@ +//======================================================================== +// +// SplashFTFont.cc +// +// Copyright 2003-2013 Glyph & Cog, LLC +// +//======================================================================== + +#include <aconf.h> + +#if HAVE_FREETYPE_H + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <ft2build.h> +#include FT_OUTLINE_H +#include FT_SIZES_H +#include FT_GLYPH_H +#include "gmem.h" +#include "gmempp.h" +#include "SplashMath.h" +#include "SplashGlyphBitmap.h" +#include "SplashPath.h" +#include "SplashFontEngine.h" +#include "SplashFTFontEngine.h" +#include "SplashFTFontFile.h" +#include "SplashFTFont.h" + +//------------------------------------------------------------------------ + +static int glyphPathMoveTo(const FT_Vector *pt, void *path); +static int glyphPathLineTo(const FT_Vector *pt, void *path); +static int glyphPathConicTo(const FT_Vector *ctrl, const FT_Vector *pt, + void *path); +static int glyphPathCubicTo(const FT_Vector *ctrl1, const FT_Vector *ctrl2, + const FT_Vector *pt, void *path); + +//------------------------------------------------------------------------ +// SplashFTFont +//------------------------------------------------------------------------ + +SplashFTFont::SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA, + SplashCoord *textMatA): + SplashFont(fontFileA, matA, textMatA, fontFileA->engine->aa) +{ + FT_Face face; + int size, div; + int x, y; +#if USE_FIXEDPOINT + SplashCoord scale; +#endif + + face = fontFileA->face; + if (FT_New_Size(face, &sizeObj)) { + return; + } + face->size = sizeObj; + size = splashRound(splashDist(0, 0, mat[2], mat[3])); + if (size < 1) { + size = 1; + } + if (FT_Set_Pixel_Sizes(face, 0, size)) { + return; + } + // if the textMat values are too small, FreeType's fixed point + // arithmetic doesn't work so well + textScale = splashDist(0, 0, textMat[2], textMat[3]) / size; + // avoid problems with singular (or close-to-singular) matrices + if (textScale < 0.00001) { + textScale = 0.00001; + } + + div = face->bbox.xMax > 20000 ? 65536 : 1; + +#if USE_FIXEDPOINT + scale = (SplashCoord)1 / (SplashCoord)face->units_per_EM; + + // transform the four corners of the font bounding box -- the min + // and max values form the bounding box of the transformed font + x = (int)(mat[0] * (scale * (face->bbox.xMin / div)) + + mat[2] * (scale * (face->bbox.yMin / div))); + xMin = xMax = x; + y = (int)(mat[1] * (scale * (face->bbox.xMin / div)) + + mat[3] * (scale * (face->bbox.yMin / div))); + yMin = yMax = y; + x = (int)(mat[0] * (scale * (face->bbox.xMin / div)) + + mat[2] * (scale * (face->bbox.yMax / div))); + if (x < xMin) { + xMin = x; + } else if (x > xMax) { + xMax = x; + } + y = (int)(mat[1] * (scale * (face->bbox.xMin / div)) + + mat[3] * (scale * (face->bbox.yMax / div))); + if (y < yMin) { + yMin = y; + } else if (y > yMax) { + yMax = y; + } + x = (int)(mat[0] * (scale * (face->bbox.xMax / div)) + + mat[2] * (scale * (face->bbox.yMin / div))); + if (x < xMin) { + xMin = x; + } else if (x > xMax) { + xMax = x; + } + y = (int)(mat[1] * (scale * (face->bbox.xMax / div)) + + mat[3] * (scale * (face->bbox.yMin / div))); + if (y < yMin) { + yMin = y; + } else if (y > yMax) { + yMax = y; + } + x = (int)(mat[0] * (scale * (face->bbox.xMax / div)) + + mat[2] * (scale * (face->bbox.yMax / div))); + if (x < xMin) { + xMin = x; + } else if (x > xMax) { + xMax = x; + } + y = (int)(mat[1] * (scale * (face->bbox.xMax / div)) + + mat[3] * (scale * (face->bbox.yMax / div))); + if (y < yMin) { + yMin = y; + } else if (y > yMax) { + yMax = y; + } +#else // USE_FIXEDPOINT + // transform the four corners of the font bounding box -- the min + // and max values form the bounding box of the transformed font + x = (int)((mat[0] * (SplashCoord)face->bbox.xMin + + mat[2] * (SplashCoord)face->bbox.yMin) / + (div * face->units_per_EM)); + xMin = xMax = x; + y = (int)((mat[1] * (SplashCoord)face->bbox.xMin + + mat[3] * (SplashCoord)face->bbox.yMin) / + (div * face->units_per_EM)); + yMin = yMax = y; + x = (int)((mat[0] * (SplashCoord)face->bbox.xMin + + mat[2] * (SplashCoord)face->bbox.yMax) / + (div * face->units_per_EM)); + if (x < xMin) { + xMin = x; + } else if (x > xMax) { + xMax = x; + } + y = (int)((mat[1] * (SplashCoord)face->bbox.xMin + + mat[3] * (SplashCoord)face->bbox.yMax) / + (div * face->units_per_EM)); + if (y < yMin) { + yMin = y; + } else if (y > yMax) { + yMax = y; + } + x = (int)((mat[0] * (SplashCoord)face->bbox.xMax + + mat[2] * (SplashCoord)face->bbox.yMin) / + (div * face->units_per_EM)); + if (x < xMin) { + xMin = x; + } else if (x > xMax) { + xMax = x; + } + y = (int)((mat[1] * (SplashCoord)face->bbox.xMax + + mat[3] * (SplashCoord)face->bbox.yMin) / + (div * face->units_per_EM)); + if (y < yMin) { + yMin = y; + } else if (y > yMax) { + yMax = y; + } + x = (int)((mat[0] * (SplashCoord)face->bbox.xMax + + mat[2] * (SplashCoord)face->bbox.yMax) / + (div * face->units_per_EM)); + if (x < xMin) { + xMin = x; + } else if (x > xMax) { + xMax = x; + } + y = (int)((mat[1] * (SplashCoord)face->bbox.xMax + + mat[3] * (SplashCoord)face->bbox.yMax) / + (div * face->units_per_EM)); + if (y < yMin) { + yMin = y; + } else if (y > yMax) { + yMax = y; + } +#endif // USE_FIXEDPOINT + // This is a kludge: some buggy PDF generators embed fonts with + // zero bounding boxes. + if (xMax == xMin) { + xMin = 0; + xMax = size; + } + if (yMax == yMin) { + yMin = 0; + yMax = (int)((SplashCoord)1.2 * size); + } + + // compute the transform matrix +#if USE_FIXEDPOINT + matrix.xx = (FT_Fixed)((mat[0] / size).get16Dot16()); + matrix.yx = (FT_Fixed)((mat[1] / size).get16Dot16()); + matrix.xy = (FT_Fixed)((mat[2] / size).get16Dot16()); + matrix.yy = (FT_Fixed)((mat[3] / size).get16Dot16()); + textMatrix.xx = (FT_Fixed)((textMat[0] / (textScale * size)).get16Dot16()); + textMatrix.yx = (FT_Fixed)((textMat[1] / (textScale * size)).get16Dot16()); + textMatrix.xy = (FT_Fixed)((textMat[2] / (textScale * size)).get16Dot16()); + textMatrix.yy = (FT_Fixed)((textMat[3] / (textScale * size)).get16Dot16()); +#else + matrix.xx = (FT_Fixed)((mat[0] / size) * 65536); + matrix.yx = (FT_Fixed)((mat[1] / size) * 65536); + matrix.xy = (FT_Fixed)((mat[2] / size) * 65536); + matrix.yy = (FT_Fixed)((mat[3] / size) * 65536); + textMatrix.xx = (FT_Fixed)((textMat[0] / (textScale * size)) * 65536); + textMatrix.yx = (FT_Fixed)((textMat[1] / (textScale * size)) * 65536); + textMatrix.xy = (FT_Fixed)((textMat[2] / (textScale * size)) * 65536); + textMatrix.yy = (FT_Fixed)((textMat[3] / (textScale * size)) * 65536); +#endif +} + +SplashFTFont::~SplashFTFont() { +} + +GBool SplashFTFont::getGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap) { + return SplashFont::getGlyph(c, xFrac, 0, bitmap); +} + +GBool SplashFTFont::makeGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap) { + SplashFTFontFile *ff; + FT_Vector offset; + FT_GlyphSlot slot; + int gid; + FT_Int32 flags; + int rowSize; + Guchar *p, *q; + int i; + + ff = (SplashFTFontFile *)fontFile; + + ff->face->size = sizeObj; + offset.x = (FT_Pos)(int)((SplashCoord)xFrac * splashFontFractionMul * 64); + offset.y = 0; + FT_Set_Transform(ff->face, &matrix, &offset); + slot = ff->face->glyph; + + if (ff->codeToGID && c < ff->codeToGIDLen) { + gid = ff->codeToGID[c]; + } else { + gid = c; + } + if (ff->fontType == splashFontTrueType && gid < 0) { + // skip the TrueType notdef glyph + return gFalse; + } + + // Set up the load flags: + // * disable bitmaps because they look ugly when scaled, rotated, + // etc. + // * disable autohinting because it can fail badly with font subsets + // that use invalid glyph names (the FreeType autohinter depends + // on the glyph name to figure out how to autohint the glyph) + // * but enable light autohinting for Type 1 fonts because regular + // hinting looks pretty bad, and the invalid glyph name issue + // seems to be very rare (Type 1 fonts are mostly used for + // substitution, in which case the full font is being used, which + // means we have the glyph names) + // This also sets the "pedantic" flag, running the FreeType hinter + // in paranoid mode. If that triggers any errors, we disable + // hinting below. + flags = FT_LOAD_NO_BITMAP | FT_LOAD_PEDANTIC; + if (ff->engine->flags & splashFTNoHinting) { + flags |= FT_LOAD_NO_HINTING; + } else if (ff->fontType == splashFontType1) { + flags |= FT_LOAD_TARGET_LIGHT; + } else { + flags |= FT_LOAD_NO_AUTOHINT; + } + if (FT_Load_Glyph(ff->face, (FT_UInt)gid, flags)) { + // fonts with broken hinting instructions can cause errors here; + // try again with no hinting (this is probably only relevant for + // TrueType fonts) + flags = FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING; + if (FT_Load_Glyph(ff->face, (FT_UInt)gid, flags)) { + return gFalse; + } + } + if (FT_Render_Glyph(slot, aa ? FT_RENDER_MODE_NORMAL + : FT_RENDER_MODE_MONO)) { + return gFalse; + } + if (slot->bitmap.width == 0 || slot->bitmap.rows == 0) { + // this can happen if (a) the glyph is really tiny or (b) the + // metrics in the TrueType file are broken + return gFalse; + } + + bitmap->x = -slot->bitmap_left; + bitmap->y = slot->bitmap_top; + bitmap->w = slot->bitmap.width; + bitmap->h = slot->bitmap.rows; + bitmap->aa = aa; + if (aa) { + rowSize = bitmap->w; + } else { + rowSize = (bitmap->w + 7) >> 3; + } + bitmap->data = (Guchar *)gmallocn(bitmap->h, rowSize); + bitmap->freeData = gTrue; + for (i = 0, p = bitmap->data, q = slot->bitmap.buffer; + i < bitmap->h; + ++i, p += rowSize, q += slot->bitmap.pitch) { + memcpy(p, q, rowSize); + } + + return gTrue; +} + +struct SplashFTFontPath { + SplashPath *path; + SplashCoord textScale; + GBool needClose; +}; + +SplashPath *SplashFTFont::getGlyphPath(int c) { + static FT_Outline_Funcs outlineFuncs = { +#if FREETYPE_MINOR <= 1 + (int (*)(FT_Vector *, void *))&glyphPathMoveTo, + (int (*)(FT_Vector *, void *))&glyphPathLineTo, + (int (*)(FT_Vector *, FT_Vector *, void *))&glyphPathConicTo, + (int (*)(FT_Vector *, FT_Vector *, FT_Vector *, void *))&glyphPathCubicTo, +#else + &glyphPathMoveTo, + &glyphPathLineTo, + &glyphPathConicTo, + &glyphPathCubicTo, +#endif + 0, 0 + }; + SplashFTFontFile *ff; + SplashFTFontPath path; + FT_GlyphSlot slot; + int gid; + FT_Glyph glyph; + + ff = (SplashFTFontFile *)fontFile; + ff->face->size = sizeObj; + FT_Set_Transform(ff->face, &textMatrix, NULL); + slot = ff->face->glyph; + if (ff->codeToGID && c < ff->codeToGIDLen) { + gid = ff->codeToGID[c]; + } else { + gid = c; + } + if (ff->fontType == splashFontTrueType && gid < 0) { + // skip the TrueType notdef glyph + return NULL; + } + if (FT_Load_Glyph(ff->face, (FT_UInt)gid, FT_LOAD_NO_BITMAP)) { + // fonts with broken hinting instructions can cause errors here; + // try again with no hinting (this is probably only relevant for + // TrueType fonts) + if (FT_Load_Glyph(ff->face, (FT_UInt)gid, + FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING)) { + return NULL; + } + } + if (FT_Get_Glyph(slot, &glyph)) { + return NULL; + } + path.path = new SplashPath(); + path.textScale = textScale; + path.needClose = gFalse; + FT_Outline_Decompose(&((FT_OutlineGlyph)glyph)->outline, + &outlineFuncs, &path); + if (path.needClose) { + path.path->close(); + } + FT_Done_Glyph(glyph); + return path.path; +} + +static int glyphPathMoveTo(const FT_Vector *pt, void *path) { + SplashFTFontPath *p = (SplashFTFontPath *)path; + + if (p->needClose) { + p->path->close(); + p->needClose = gFalse; + } + p->path->moveTo((SplashCoord)pt->x * p->textScale / 64.0, + (SplashCoord)pt->y * p->textScale / 64.0); + return 0; +} + +static int glyphPathLineTo(const FT_Vector *pt, void *path) { + SplashFTFontPath *p = (SplashFTFontPath *)path; + + p->path->lineTo((SplashCoord)pt->x * p->textScale / 64.0, + (SplashCoord)pt->y * p->textScale / 64.0); + p->needClose = gTrue; + return 0; +} + +static int glyphPathConicTo(const FT_Vector *ctrl, const FT_Vector *pt, + void *path) { + SplashFTFontPath *p = (SplashFTFontPath *)path; + SplashCoord x0, y0, x1, y1, x2, y2, x3, y3, xc, yc; + + if (!p->path->getCurPt(&x0, &y0)) { + return 0; + } + xc = (SplashCoord)ctrl->x * p->textScale / 64.0; + yc = (SplashCoord)ctrl->y * p->textScale / 64.0; + x3 = (SplashCoord)pt->x * p->textScale / 64.0; + y3 = (SplashCoord)pt->y * p->textScale / 64.0; + + // A second-order Bezier curve is defined by two endpoints, p0 and + // p3, and one control point, pc: + // + // p(t) = (1-t)^2*p0 + t*(1-t)*pc + t^2*p3 + // + // A third-order Bezier curve is defined by the same two endpoints, + // p0 and p3, and two control points, p1 and p2: + // + // p(t) = (1-t)^3*p0 + 3t*(1-t)^2*p1 + 3t^2*(1-t)*p2 + t^3*p3 + // + // Applying some algebra, we can convert a second-order curve to a + // third-order curve: + // + // p1 = (1/3) * (p0 + 2pc) + // p2 = (1/3) * (2pc + p3) + + x1 = (SplashCoord)(1.0 / 3.0) * (x0 + (SplashCoord)2 * xc); + y1 = (SplashCoord)(1.0 / 3.0) * (y0 + (SplashCoord)2 * yc); + x2 = (SplashCoord)(1.0 / 3.0) * ((SplashCoord)2 * xc + x3); + y2 = (SplashCoord)(1.0 / 3.0) * ((SplashCoord)2 * yc + y3); + + p->path->curveTo(x1, y1, x2, y2, x3, y3); + p->needClose = gTrue; + return 0; +} + +static int glyphPathCubicTo(const FT_Vector *ctrl1, const FT_Vector *ctrl2, + const FT_Vector *pt, void *path) { + SplashFTFontPath *p = (SplashFTFontPath *)path; + + p->path->curveTo((SplashCoord)ctrl1->x * p->textScale / 64.0, + (SplashCoord)ctrl1->y * p->textScale / 64.0, + (SplashCoord)ctrl2->x * p->textScale / 64.0, + (SplashCoord)ctrl2->y * p->textScale / 64.0, + (SplashCoord)pt->x * p->textScale / 64.0, + (SplashCoord)pt->y * p->textScale / 64.0); + p->needClose = gTrue; + return 0; +} + +#endif // HAVE_FREETYPE_H diff --git a/splash/SplashFTFont.h b/splash/SplashFTFont.h new file mode 100644 index 0000000..ac08b00 --- /dev/null +++ b/splash/SplashFTFont.h @@ -0,0 +1,60 @@ +//======================================================================== +// +// SplashFTFont.h +// +// Copyright 2003-2013 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef SPLASHFTFONT_H +#define SPLASHFTFONT_H + +#include <aconf.h> + +#if HAVE_FREETYPE_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include <ft2build.h> +#include FT_FREETYPE_H +#include "SplashFont.h" + +class SplashFTFontFile; + +//------------------------------------------------------------------------ +// SplashFTFont +//------------------------------------------------------------------------ + +class SplashFTFont: public SplashFont { +public: + + SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA, + SplashCoord *textMatA); + + virtual ~SplashFTFont(); + + // Munge xFrac and yFrac before calling SplashFont::getGlyph. + virtual GBool getGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap); + + // Rasterize a glyph. The <xFrac> and <yFrac> values are the same + // as described for getGlyph. + virtual GBool makeGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap); + + // Return the path for a glyph. + virtual SplashPath *getGlyphPath(int c); + +private: + + FT_Size sizeObj; + FT_Matrix matrix; + FT_Matrix textMatrix; + SplashCoord textScale; +}; + +#endif // HAVE_FREETYPE_H + +#endif diff --git a/splash/SplashFTFontEngine.cc b/splash/SplashFTFontEngine.cc new file mode 100644 index 0000000..3393954 --- /dev/null +++ b/splash/SplashFTFontEngine.cc @@ -0,0 +1,392 @@ +//======================================================================== +// +// SplashFTFontEngine.cc +// +// Copyright 2003-2013 Glyph & Cog, LLC +// +//======================================================================== + +#include <aconf.h> + +#if HAVE_FREETYPE_H + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <stdio.h> +#ifndef _WIN32 +# include <unistd.h> +#endif +#include "gmem.h" +#include "gmempp.h" +#include "GString.h" +#include "gfile.h" +#include "FoFiTrueType.h" +#include "FoFiType1C.h" +#include "SplashFTFontFile.h" +#include "SplashFTFontEngine.h" +#include FT_MODULE_H +#ifdef FT_CFF_DRIVER_H +# include FT_CFF_DRIVER_H +#endif + +#ifdef VMS +#if (__VMS_VER < 70000000) +extern "C" int unlink(char *filename); +#endif +#endif + +//------------------------------------------------------------------------ + +static void fileWrite(void *stream, const char *data, int len) { + fwrite(data, 1, len, (FILE *)stream); +} + +#if LOAD_FONTS_FROM_MEM +static void gstringWrite(void *stream, const char *data, int len) { + ((GString *)stream)->append(data, len); +} +#endif + +//------------------------------------------------------------------------ +// SplashFTFontEngine +//------------------------------------------------------------------------ + +SplashFTFontEngine::SplashFTFontEngine(GBool aaA, Guint flagsA, + FT_Library libA) { + FT_Int major, minor, patch; + + aa = aaA; + flags = flagsA; + lib = libA; + + // as of FT 2.1.8, CID fonts are indexed by CID instead of GID + FT_Library_Version(lib, &major, &minor, &patch); + useCIDs = major > 2 || + (major == 2 && (minor > 1 || (minor == 1 && patch > 7))); +} + +SplashFTFontEngine *SplashFTFontEngine::init(GBool aaA, Guint flagsA) { + FT_Library libA; + + if (FT_Init_FreeType(&libA)) { + return NULL; + } + return new SplashFTFontEngine(aaA, flagsA, libA); +} + +SplashFTFontEngine::~SplashFTFontEngine() { + FT_Done_FreeType(lib); +} + +SplashFontFile *SplashFTFontEngine::loadType1Font(SplashFontFileID *idA, +#if LOAD_FONTS_FROM_MEM + GString *fontBuf, +#else + char *fileName, + GBool deleteFile, +#endif + const char **enc) { + return SplashFTFontFile::loadType1Font(this, idA, splashFontType1, +#if LOAD_FONTS_FROM_MEM + fontBuf, +#else + fileName, deleteFile, +#endif + enc); +} + +SplashFontFile *SplashFTFontEngine::loadType1CFont(SplashFontFileID *idA, +#if LOAD_FONTS_FROM_MEM + GString *fontBuf, +#else + char *fileName, + GBool deleteFile, +#endif + const char **enc) { + return SplashFTFontFile::loadType1Font(this, idA, splashFontType1C, +#if LOAD_FONTS_FROM_MEM + fontBuf, +#else + fileName, deleteFile, +#endif + enc); +} + +SplashFontFile *SplashFTFontEngine::loadOpenTypeT1CFont(SplashFontFileID *idA, +#if LOAD_FONTS_FROM_MEM + GString *fontBuf, +#else + char *fileName, + GBool deleteFile, +#endif + const char **enc) { + FoFiTrueType *ff; +#if LOAD_FONTS_FROM_MEM + GString *fontBuf2; +#else + GString *tmpFileName; + FILE *tmpFile; +#endif + SplashFontFile *ret; + +#if LOAD_FONTS_FROM_MEM + if (!(ff = FoFiTrueType::make(fontBuf->getCString(), fontBuf->getLength(), + 0, gTrue))) { +#else + if (!(ff = FoFiTrueType::load(fileName, 0, gTrue))) { +#endif + return NULL; + } + if (ff->isHeadlessCFF()) { +#if LOAD_FONTS_FROM_MEM + fontBuf2 = new GString(); + ff->convertToType1(NULL, enc, gFalse, &gstringWrite, fontBuf2); + delete ff; + ret = SplashFTFontFile::loadType1Font(this, idA, splashFontType1, + fontBuf2, enc); + if (ret) { + delete fontBuf; + } else { + delete fontBuf2; + } +#else + tmpFileName = NULL; + if (!openTempFile(&tmpFileName, &tmpFile, "wb", NULL)) { + delete ff; + return NULL; + } + ff->convertToType1(NULL, enc, gFalse, &fileWrite, tmpFile); + delete ff; + fclose(tmpFile); + ret = SplashFTFontFile::loadType1Font(this, idA, splashFontType1, + tmpFileName->getCString(), + gTrue, enc); + if (ret) { + if (deleteFile) { + unlink(fileName); + } + } else { + unlink(tmpFileName->getCString()); + } + delete tmpFileName; +#endif + } else { + delete ff; + ret = SplashFTFontFile::loadType1Font(this, idA, splashFontOpenTypeT1C, +#if LOAD_FONTS_FROM_MEM + fontBuf, +#else + fileName, deleteFile, +#endif + enc); + } + return ret; +} + +SplashFontFile *SplashFTFontEngine::loadCIDFont(SplashFontFileID *idA, +#if LOAD_FONTS_FROM_MEM + GString *fontBuf, +#else + char *fileName, + GBool deleteFile, +#endif + int *codeToGID, + int codeToGIDLen) { + FoFiType1C *ff; + int *cidToGIDMap; + int nCIDs; + SplashFontFile *ret; + + // check for a CFF font + if (codeToGID) { + cidToGIDMap = NULL; + nCIDs = 0; + } else if (useCIDs) { + cidToGIDMap = NULL; + nCIDs = 0; +#if LOAD_FONTS_FROM_MEM + } else if ((ff = FoFiType1C::make(fontBuf->getCString(), + fontBuf->getLength()))) { +#else + } else if ((ff = FoFiType1C::load(fileName))) { +#endif + cidToGIDMap = ff->getCIDToGIDMap(&nCIDs); + delete ff; + } else { + cidToGIDMap = NULL; + nCIDs = 0; + } + ret = SplashFTFontFile::loadCIDFont(this, idA, splashFontCID, +#if LOAD_FONTS_FROM_MEM + fontBuf, +#else + fileName, deleteFile, +#endif + codeToGID ? codeToGID : cidToGIDMap, + codeToGID ? codeToGIDLen : nCIDs); + if (!ret) { + gfree(cidToGIDMap); + } + return ret; +} + +SplashFontFile *SplashFTFontEngine::loadOpenTypeCFFFont(SplashFontFileID *idA, +#if LOAD_FONTS_FROM_MEM + GString *fontBuf, +#else + char *fileName, + GBool deleteFile, +#endif + int *codeToGID, + int codeToGIDLen) { + FoFiTrueType *ff; +#if LOAD_FONTS_FROM_MEM + GString *fontBuf2; +#else + GString *tmpFileName; + FILE *tmpFile; +#endif + char *cffStart; + int cffLength; + int *cidToGIDMap; + int nCIDs; + SplashFontFile *ret; + +#if LOAD_FONTS_FROM_MEM + if (!(ff = FoFiTrueType::make(fontBuf->getCString(), fontBuf->getLength(), + 0, gTrue))) { +#else + if (!(ff = FoFiTrueType::load(fileName, 0, gTrue))) { +#endif + return NULL; + } + cidToGIDMap = NULL; + nCIDs = 0; + if (ff->isHeadlessCFF()) { + if (!ff->getCFFBlock(&cffStart, &cffLength)) { + return NULL; + } +#if LOAD_FONTS_FROM_MEM + fontBuf2 = new GString(cffStart, cffLength); + if (!useCIDs) { + cidToGIDMap = ff->getCIDToGIDMap(&nCIDs); + } + ret = SplashFTFontFile::loadCIDFont(this, idA, splashFontOpenTypeCFF, + fontBuf2, cidToGIDMap, nCIDs); + if (ret) { + delete fontBuf; + } else { + delete fontBuf2; + } +#else + tmpFileName = NULL; + if (!openTempFile(&tmpFileName, &tmpFile, "wb", NULL)) { + delete ff; + return NULL; + } + fwrite(cffStart, 1, cffLength, tmpFile); + fclose(tmpFile); + if (!useCIDs) { + cidToGIDMap = ff->getCIDToGIDMap(&nCIDs); + } + ret = SplashFTFontFile::loadCIDFont(this, idA, splashFontOpenTypeCFF, + tmpFileName->getCString(), gTrue, + cidToGIDMap, nCIDs); + if (ret) { + if (deleteFile) { + unlink(fileName); + } + } else { + unlink(tmpFileName->getCString()); + } + delete tmpFileName; +#endif + } else { + if (!codeToGID && !useCIDs && ff->isOpenTypeCFF()) { + cidToGIDMap = ff->getCIDToGIDMap(&nCIDs); + } + ret = SplashFTFontFile::loadCIDFont(this, idA, splashFontOpenTypeCFF, +#if LOAD_FONTS_FROM_MEM + fontBuf, +#else + fileName, deleteFile, +#endif + codeToGID ? codeToGID : cidToGIDMap, + codeToGID ? codeToGIDLen : nCIDs); + } + delete ff; + if (!ret) { + gfree(cidToGIDMap); + } + return ret; +} + +SplashFontFile *SplashFTFontEngine::loadTrueTypeFont(SplashFontFileID *idA, +#if LOAD_FONTS_FROM_MEM + GString *fontBuf, +#else + char *fileName, + GBool deleteFile, +#endif + int fontNum, + int *codeToGID, + int codeToGIDLen) { + FoFiTrueType *ff; +#if LOAD_FONTS_FROM_MEM + GString *fontBuf2; +#else + GString *tmpFileName; + FILE *tmpFile; +#endif + SplashFontFile *ret; + +#if LOAD_FONTS_FROM_MEM + if (!(ff = FoFiTrueType::make(fontBuf->getCString(), fontBuf->getLength(), + fontNum))) { +#else + if (!(ff = FoFiTrueType::load(fileName, fontNum))) { +#endif + return NULL; + } +#if LOAD_FONTS_FROM_MEM + fontBuf2 = new GString; + ff->writeTTF(&gstringWrite, fontBuf2); +#else + tmpFileName = NULL; + if (!openTempFile(&tmpFileName, &tmpFile, "wb", NULL)) { + delete ff; + return NULL; + } + ff->writeTTF(&fileWrite, tmpFile); + fclose(tmpFile); +#endif + delete ff; + ret = SplashFTFontFile::loadTrueTypeFont(this, idA, splashFontTrueType, +#if LOAD_FONTS_FROM_MEM + fontBuf2, +#else + tmpFileName->getCString(), gTrue, +#endif + 0, codeToGID, codeToGIDLen); +#if LOAD_FONTS_FROM_MEM + if (ret) { + delete fontBuf; + } else { + delete fontBuf2; + } +#else + if (ret) { + if (deleteFile) { + unlink(fileName); + } + } else { + unlink(tmpFileName->getCString()); + } + delete tmpFileName; +#endif + return ret; +} + +#endif // HAVE_FREETYPE_H diff --git a/splash/SplashFTFontEngine.h b/splash/SplashFTFontEngine.h new file mode 100644 index 0000000..24db3c6 --- /dev/null +++ b/splash/SplashFTFontEngine.h @@ -0,0 +1,99 @@ +//======================================================================== +// +// SplashFTFontEngine.h +// +// Copyright 2003-2013 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef SPLASHFTFONTENGINE_H +#define SPLASHFTFONTENGINE_H + +#include <aconf.h> + +#if HAVE_FREETYPE_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include <ft2build.h> +#include FT_FREETYPE_H +#include "gtypes.h" +class GString; + +class SplashFontFile; +class SplashFontFileID; + +//------------------------------------------------------------------------ +// SplashFTFontEngine +//------------------------------------------------------------------------ + +class SplashFTFontEngine { +public: + + static SplashFTFontEngine *init(GBool aaA, Guint flagsA); + + ~SplashFTFontEngine(); + + // Load fonts. + SplashFontFile *loadType1Font(SplashFontFileID *idA, +#if LOAD_FONTS_FROM_MEM + GString *fontBuf, +#else + char *fileName, GBool deleteFile, +#endif + const char **enc); + SplashFontFile *loadType1CFont(SplashFontFileID *idA, +#if LOAD_FONTS_FROM_MEM + GString *fontBuf, +#else + char *fileName, GBool deleteFile, +#endif + const char **enc); + SplashFontFile *loadOpenTypeT1CFont(SplashFontFileID *idA, +#if LOAD_FONTS_FROM_MEM + GString *fontBuf, +#else + char *fileName, GBool deleteFile, +#endif + const char **enc); + SplashFontFile *loadCIDFont(SplashFontFileID *idA, +#if LOAD_FONTS_FROM_MEM + GString *fontBuf, +#else + char *fileName, GBool deleteFile, +#endif + int *codeToGID, int codeToGIDLen); + SplashFontFile *loadOpenTypeCFFFont(SplashFontFileID *idA, +#if LOAD_FONTS_FROM_MEM + GString *fontBuf, +#else + char *fileName, GBool deleteFile, +#endif + int *codeToGID, int codeToGIDLen); + SplashFontFile *loadTrueTypeFont(SplashFontFileID *idA, +#if LOAD_FONTS_FROM_MEM + GString *fontBuf, +#else + char *fileName, GBool deleteFile, +#endif + int fontNum, + int *codeToGID, int codeToGIDLen); + +private: + + SplashFTFontEngine(GBool aaA, Guint flagsA, FT_Library libA); + + GBool aa; + Guint flags; + FT_Library lib; + GBool useCIDs; + + friend class SplashFTFontFile; + friend class SplashFTFont; +}; + +#endif // HAVE_FREETYPE_H + +#endif diff --git a/splash/SplashFTFontFile.cc b/splash/SplashFTFontFile.cc new file mode 100644 index 0000000..b5fd02a --- /dev/null +++ b/splash/SplashFTFontFile.cc @@ -0,0 +1,171 @@ +//======================================================================== +// +// SplashFTFontFile.cc +// +// Copyright 2003-2013 Glyph & Cog, LLC +// +//======================================================================== + +#include <aconf.h> + +#if HAVE_FREETYPE_H + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include "gmem.h" +#include "gmempp.h" +#include "GString.h" +#include "SplashFTFontEngine.h" +#include "SplashFTFont.h" +#include "SplashFTFontFile.h" + +//------------------------------------------------------------------------ +// SplashFTFontFile +//------------------------------------------------------------------------ + +SplashFontFile *SplashFTFontFile::loadType1Font(SplashFTFontEngine *engineA, + SplashFontFileID *idA, + SplashFontType fontTypeA, +#if LOAD_FONTS_FROM_MEM + GString *fontBufA, +#else + char *fileNameA, + GBool deleteFileA, +#endif + const char **encA) { + FT_Face faceA; + int *codeToGIDA; + const char *name; + int i; + +#if LOAD_FONTS_FROM_MEM + if (FT_New_Memory_Face(engineA->lib, (FT_Byte *)fontBufA->getCString(), + fontBufA->getLength(), 0, &faceA)) { +#else + if (FT_New_Face(engineA->lib, fileNameA, 0, &faceA)) { +#endif + return NULL; + } + codeToGIDA = (int *)gmallocn(256, sizeof(int)); + for (i = 0; i < 256; ++i) { + codeToGIDA[i] = 0; + if ((name = encA[i])) { + codeToGIDA[i] = (int)FT_Get_Name_Index(faceA, (char *)name); + } + } + + return new SplashFTFontFile(engineA, idA, fontTypeA, +#if LOAD_FONTS_FROM_MEM + fontBufA, +#else + fileNameA, deleteFileA, +#endif + faceA, codeToGIDA, 256); +} + +SplashFontFile *SplashFTFontFile::loadCIDFont(SplashFTFontEngine *engineA, + SplashFontFileID *idA, + SplashFontType fontTypeA, +#if LOAD_FONTS_FROM_MEM + GString *fontBufA, +#else + char *fileNameA, + GBool deleteFileA, +#endif + int *codeToGIDA, + int codeToGIDLenA) { + FT_Face faceA; + +#if LOAD_FONTS_FROM_MEM + if (FT_New_Memory_Face(engineA->lib, (FT_Byte *)fontBufA->getCString(), + fontBufA->getLength(), 0, &faceA)) { +#else + if (FT_New_Face(engineA->lib, fileNameA, 0, &faceA)) { +#endif + return NULL; + } + + return new SplashFTFontFile(engineA, idA, fontTypeA, +#if LOAD_FONTS_FROM_MEM + fontBufA, +#else + fileNameA, deleteFileA, +#endif + faceA, codeToGIDA, codeToGIDLenA); +} + +SplashFontFile *SplashFTFontFile::loadTrueTypeFont(SplashFTFontEngine *engineA, + SplashFontFileID *idA, + SplashFontType fontTypeA, +#if LOAD_FONTS_FROM_MEM + GString *fontBufA, +#else + char *fileNameA, + GBool deleteFileA, +#endif + int fontNum, + int *codeToGIDA, + int codeToGIDLenA) { + FT_Face faceA; + +#if LOAD_FONTS_FROM_MEM + if (FT_New_Memory_Face(engineA->lib, (FT_Byte *)fontBufA->getCString(), + fontBufA->getLength(), fontNum, &faceA)) { +#else + if (FT_New_Face(engineA->lib, fileNameA, fontNum, &faceA)) { +#endif + return NULL; + } + + return new SplashFTFontFile(engineA, idA, fontTypeA, +#if LOAD_FONTS_FROM_MEM + fontBufA, +#else + fileNameA, deleteFileA, +#endif + faceA, codeToGIDA, codeToGIDLenA); +} + +SplashFTFontFile::SplashFTFontFile(SplashFTFontEngine *engineA, + SplashFontFileID *idA, + SplashFontType fontTypeA, +#if LOAD_FONTS_FROM_MEM + GString *fontBufA, +#else + char *fileNameA, GBool deleteFileA, +#endif + FT_Face faceA, + int *codeToGIDA, int codeToGIDLenA): +#if LOAD_FONTS_FROM_MEM + SplashFontFile(idA, fontTypeA, fontBufA) +#else + SplashFontFile(idA, fontTypeA, fileNameA, deleteFileA) +#endif +{ + engine = engineA; + face = faceA; + codeToGID = codeToGIDA; + codeToGIDLen = codeToGIDLenA; +} + +SplashFTFontFile::~SplashFTFontFile() { + if (face) { + FT_Done_Face(face); + } + if (codeToGID) { + gfree(codeToGID); + } +} + +SplashFont *SplashFTFontFile::makeFont(SplashCoord *mat, + SplashCoord *textMat) { + SplashFont *font; + + font = new SplashFTFont(this, mat, textMat); + font->initCache(); + return font; +} + +#endif // HAVE_FREETYPE_H diff --git a/splash/SplashFTFontFile.h b/splash/SplashFTFontFile.h new file mode 100644 index 0000000..3a6b9b7 --- /dev/null +++ b/splash/SplashFTFontFile.h @@ -0,0 +1,95 @@ +//======================================================================== +// +// SplashFTFontFile.h +// +// Copyright 2003-2013 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef SPLASHFTFONTFILE_H +#define SPLASHFTFONTFILE_H + +#include <aconf.h> + +#if HAVE_FREETYPE_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include <ft2build.h> +#include FT_FREETYPE_H +#include "SplashFontFile.h" + +class SplashFontFileID; +class SplashFTFontEngine; + +//------------------------------------------------------------------------ +// SplashFTFontFile +//------------------------------------------------------------------------ + +class SplashFTFontFile: public SplashFontFile { +public: + + static SplashFontFile *loadType1Font(SplashFTFontEngine *engineA, + SplashFontFileID *idA, + SplashFontType fontTypeA, +#if LOAD_FONTS_FROM_MEM + GString *fontBufA, +#else + char *fileNameA, GBool deleteFileA, +#endif + const char **encA); + static SplashFontFile *loadCIDFont(SplashFTFontEngine *engineA, + SplashFontFileID *idA, + SplashFontType fontTypeA, +#if LOAD_FONTS_FROM_MEM + GString *fontBufA, +#else + char *fileNameA, GBool deleteFileA, +#endif + int *codeToGIDA, int codeToGIDLenA); + static SplashFontFile *loadTrueTypeFont(SplashFTFontEngine *engineA, + SplashFontFileID *idA, + SplashFontType fontTypeA, +#if LOAD_FONTS_FROM_MEM + GString *fontBufA, +#else + char *fileNameA, + GBool deleteFileA, +#endif + int fontNum, + int *codeToGIDA, + int codeToGIDLenA); + + virtual ~SplashFTFontFile(); + + // Create a new SplashFTFont, i.e., a scaled instance of this font + // file. + virtual SplashFont *makeFont(SplashCoord *mat, + SplashCoord *textMat); + +private: + + SplashFTFontFile(SplashFTFontEngine *engineA, + SplashFontFileID *idA, + SplashFontType fontTypeA, +#if LOAD_FONTS_FROM_MEM + GString *fontBufA, +#else + char *fileNameA, GBool deleteFileA, +#endif + FT_Face faceA, + int *codeToGIDA, int codeToGIDLenA); + + SplashFTFontEngine *engine; + FT_Face face; + int *codeToGID; + int codeToGIDLen; + + friend class SplashFTFont; +}; + +#endif // HAVE_FREETYPE_H + +#endif diff --git a/splash/SplashFont.cc b/splash/SplashFont.cc new file mode 100644 index 0000000..2fcd83d --- /dev/null +++ b/splash/SplashFont.cc @@ -0,0 +1,195 @@ +//======================================================================== +// +// SplashFont.cc +// +// Copyright 2003-2013 Glyph & Cog, LLC +// +//======================================================================== + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <string.h> +#include "gmem.h" +#include "gmempp.h" +#include "SplashMath.h" +#include "SplashGlyphBitmap.h" +#include "SplashFontFile.h" +#include "SplashFont.h" + +//------------------------------------------------------------------------ + +// font cache size parameters +#define splashFontCacheAssoc 8 +#define splashFontCacheMaxSets 8 +#define splashFontCacheSize (128*1024) + +//------------------------------------------------------------------------ + +struct SplashFontCacheTag { + int c; + short xFrac, yFrac; // x and y fractions + int mru; // valid bit (0x80000000) and MRU index + int x, y, w, h; // offset and size of glyph +}; + +//------------------------------------------------------------------------ +// SplashFont +//------------------------------------------------------------------------ + +SplashFont::SplashFont(SplashFontFile *fontFileA, SplashCoord *matA, + SplashCoord *textMatA, GBool aaA) { + fontFile = fontFileA; + fontFile->incRefCnt(); + mat[0] = matA[0]; + mat[1] = matA[1]; + mat[2] = matA[2]; + mat[3] = matA[3]; + textMat[0] = textMatA[0]; + textMat[1] = textMatA[1]; + textMat[2] = textMatA[2]; + textMat[3] = textMatA[3]; + aa = aaA; + + cache = NULL; + cacheTags = NULL; + + xMin = yMin = xMax = yMax = 0; +} + +void SplashFont::initCache() { + int i; + + // this should be (max - min + 1), but we add some padding to + // deal with rounding errors + glyphW = xMax - xMin + 3; + glyphH = yMax - yMin + 3; + if (glyphW > 1000 || glyphH > 1000) { + // if the glyphs are too large, don't cache them -- setting the + // cache bitmap size to something tiny will cause getGlyph() to + // fall back to the uncached case + glyphW = glyphH = 0; + glyphSize = 0; + cacheSets = 0; + cacheAssoc = 0; + return; + } + if (aa) { + glyphSize = glyphW * glyphH; + } else { + glyphSize = ((glyphW + 7) >> 3) * glyphH; + } + + // set up the glyph pixmap cache + cacheAssoc = splashFontCacheAssoc; + for (cacheSets = splashFontCacheMaxSets; + cacheSets > 1 && + glyphSize > splashFontCacheSize / (cacheSets * cacheAssoc); + cacheSets >>= 1) ; + cache = (Guchar *)gmallocn(cacheSets * cacheAssoc, glyphSize); + cacheTags = (SplashFontCacheTag *)gmallocn(cacheSets * cacheAssoc, + sizeof(SplashFontCacheTag)); + for (i = 0; i < cacheSets * cacheAssoc; ++i) { + cacheTags[i].mru = i & (cacheAssoc - 1); + } +} + +SplashFont::~SplashFont() { + fontFile->decRefCnt(); + if (cache) { + gfree(cache); + } + if (cacheTags) { + gfree(cacheTags); + } +} + +GBool SplashFont::getGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap) { + SplashGlyphBitmap bitmap2; + int size; + Guchar *p; + int i, j, k; + + // no fractional coordinates for large glyphs or non-anti-aliased + // glyphs + if (!aa || glyphH > 50) { + xFrac = yFrac = 0; + } + + // check the cache + if (cache) { + i = (c & (cacheSets - 1)) * cacheAssoc; + for (j = 0; j < cacheAssoc; ++j) { + if ((cacheTags[i+j].mru & 0x80000000) && + cacheTags[i+j].c == c && + (int)cacheTags[i+j].xFrac == xFrac && + (int)cacheTags[i+j].yFrac == yFrac) { + bitmap->x = cacheTags[i+j].x; + bitmap->y = cacheTags[i+j].y; + bitmap->w = cacheTags[i+j].w; + bitmap->h = cacheTags[i+j].h; + for (k = 0; k < cacheAssoc; ++k) { + if (k != j && + (cacheTags[i+k].mru & 0x7fffffff) < + (cacheTags[i+j].mru & 0x7fffffff)) { + ++cacheTags[i+k].mru; + } + } + cacheTags[i+j].mru = 0x80000000; + bitmap->aa = aa; + bitmap->data = cache + (i+j) * glyphSize; + bitmap->freeData = gFalse; + return gTrue; + } + } + } else { + i = 0; // make gcc happy + } + + // generate the glyph bitmap + if (!makeGlyph(c, xFrac, yFrac, &bitmap2)) { + return gFalse; + } + + // if the glyph doesn't fit in the bounding box, return a temporary + // uncached bitmap + if (!cache || bitmap2.w > glyphW || bitmap2.h > glyphH) { + *bitmap = bitmap2; + return gTrue; + } + + // insert glyph pixmap in cache + if (aa) { + size = bitmap2.w * bitmap2.h; + } else { + size = ((bitmap2.w + 7) >> 3) * bitmap2.h; + } + p = NULL; // make gcc happy + for (j = 0; j < cacheAssoc; ++j) { + if ((cacheTags[i+j].mru & 0x7fffffff) == cacheAssoc - 1) { + cacheTags[i+j].mru = 0x80000000; + cacheTags[i+j].c = c; + cacheTags[i+j].xFrac = (short)xFrac; + cacheTags[i+j].yFrac = (short)yFrac; + cacheTags[i+j].x = bitmap2.x; + cacheTags[i+j].y = bitmap2.y; + cacheTags[i+j].w = bitmap2.w; + cacheTags[i+j].h = bitmap2.h; + p = cache + (i+j) * glyphSize; + memcpy(p, bitmap2.data, size); + } else { + ++cacheTags[i+j].mru; + } + } + *bitmap = bitmap2; + bitmap->data = p; + bitmap->freeData = gFalse; + if (bitmap2.freeData) { + gfree(bitmap2.data); + } + return gTrue; +} diff --git a/splash/SplashFont.h b/splash/SplashFont.h new file mode 100644 index 0000000..2bb9654 --- /dev/null +++ b/splash/SplashFont.h @@ -0,0 +1,111 @@ +//======================================================================== +// +// SplashFont.h +// +// Copyright 2003-2013 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef SPLASHFONT_H +#define SPLASHFONT_H + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "SplashTypes.h" +#include "SplashMath.h" + +struct SplashGlyphBitmap; +struct SplashFontCacheTag; +class SplashFontFile; +class SplashPath; + +//------------------------------------------------------------------------ + +// Fractional positioning uses this many bits to the right of the +// decimal points. +#define splashFontFractionBits 2 +#define splashFontFraction (1 << splashFontFractionBits) +#define splashFontFractionMul \ + ((SplashCoord)1 / (SplashCoord)splashFontFraction) + +//------------------------------------------------------------------------ +// SplashFont +//------------------------------------------------------------------------ + +class SplashFont { +public: + + SplashFont(SplashFontFile *fontFileA, SplashCoord *matA, + SplashCoord *textMatA, GBool aaA); + + // This must be called after the constructor, so that the subclass + // constructor has a chance to compute the bbox. + void initCache(); + + virtual ~SplashFont(); + + SplashFontFile *getFontFile() { return fontFile; } + + // Return true if <this> matches the specified font file and matrix. + GBool matches(SplashFontFile *fontFileA, SplashCoord *matA, + SplashCoord *textMatA) { + return fontFileA == fontFile && + splashAbs(matA[0] - mat[0]) < 0.0001 && + splashAbs(matA[1] - mat[1]) < 0.0001 && + splashAbs(matA[2] - mat[2]) < 0.0001 && + splashAbs(matA[3] - mat[3]) < 0.0001 && + splashAbs(textMatA[0] - textMat[0]) < 0.0001 && + splashAbs(textMatA[1] - textMat[1]) < 0.0001 && + splashAbs(textMatA[2] - textMat[2]) < 0.0001 && + splashAbs(textMatA[3] - textMat[3]) < 0.0001; + } + + // Get a glyph - this does a cache lookup first, and if not found, + // creates a new bitmap and adds it to the cache. The <xFrac> and + // <yFrac> values are splashFontFractionBits bits each, representing + // the numerators of fractions in [0, 1), where the denominator is + // splashFontFraction = 1 << splashFontFractionBits. Subclasses + // should override this to zero out xFrac and/or yFrac if they don't + // support fractional coordinates. + virtual GBool getGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap); + + // Rasterize a glyph. The <xFrac> and <yFrac> values are the same + // as described for getGlyph. + virtual GBool makeGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap) = 0; + + // Return the path for a glyph. + virtual SplashPath *getGlyphPath(int c) = 0; + + // Return the font transform matrix. + SplashCoord *getMatrix() { return mat; } + + // Return the glyph bounding box. + void getBBox(int *xMinA, int *yMinA, int *xMaxA, int *yMaxA) + { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; } + +protected: + + SplashFontFile *fontFile; + SplashCoord mat[4]; // font transform matrix + // (text space -> device space) + SplashCoord textMat[4]; // text transform matrix + // (text space -> user space) + GBool aa; // anti-aliasing + int xMin, yMin, xMax, yMax; // glyph bounding box + Guchar *cache; // glyph bitmap cache + SplashFontCacheTag * // cache tags + cacheTags; + int glyphW, glyphH; // size of glyph bitmaps + int glyphSize; // size of glyph bitmaps, in bytes + int cacheSets; // number of sets in cache + int cacheAssoc; // cache associativity (glyphs per set) +}; + +#endif diff --git a/splash/SplashFontEngine.cc b/splash/SplashFontEngine.cc new file mode 100644 index 0000000..81afe0c --- /dev/null +++ b/splash/SplashFontEngine.cc @@ -0,0 +1,409 @@ +//======================================================================== +// +// SplashFontEngine.cc +// +// Copyright 2003-2013 Glyph & Cog, LLC +// +//======================================================================== + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <stdlib.h> +#include <stdio.h> +#ifndef _WIN32 +# include <unistd.h> +#endif +#include "gmem.h" +#include "gmempp.h" +#include "GString.h" +#include "GList.h" +#include "SplashMath.h" +#include "SplashFTFontEngine.h" +#include "SplashFontFile.h" +#include "SplashFontFileID.h" +#include "SplashFont.h" +#include "SplashFontEngine.h" + +#ifdef VMS +#if (__VMS_VER < 70000000) +extern "C" int unlink(char *filename); +#endif +#endif + +//------------------------------------------------------------------------ +// SplashFontEngine +//------------------------------------------------------------------------ + +SplashFontEngine::SplashFontEngine( +#if HAVE_FREETYPE_H + GBool enableFreeType, + Guint freeTypeFlags, +#endif + GBool aa) { + int i; + + for (i = 0; i < splashFontCacheSize; ++i) { + fontCache[i] = NULL; + } + badFontFiles = new GList(); + +#if HAVE_FREETYPE_H + if (enableFreeType) { + ftEngine = SplashFTFontEngine::init(aa, freeTypeFlags); + } else { + ftEngine = NULL; + } +#endif +} + +SplashFontEngine::~SplashFontEngine() { + int i; + + for (i = 0; i < splashFontCacheSize; ++i) { + if (fontCache[i]) { + delete fontCache[i]; + } + } + deleteGList(badFontFiles, SplashFontFileID); + +#if HAVE_FREETYPE_H + if (ftEngine) { + delete ftEngine; + } +#endif +} + +SplashFontFile *SplashFontEngine::getFontFile(SplashFontFileID *id) { + SplashFontFile *fontFile; + int i; + + for (i = 0; i < splashFontCacheSize; ++i) { + if (fontCache[i]) { + fontFile = fontCache[i]->getFontFile(); + if (fontFile && fontFile->getID()->matches(id)) { + return fontFile; + } + } + } + return NULL; +} + +GBool SplashFontEngine::checkForBadFontFile(SplashFontFileID *id) { + for (int i = 0; i < badFontFiles->getLength(); ++i) { + if (((SplashFontFileID *)badFontFiles->get(i))->matches(id)) { + return gTrue; + } + } + return gFalse; +} + +SplashFontFile *SplashFontEngine::loadType1Font(SplashFontFileID *idA, +#if LOAD_FONTS_FROM_MEM + GString *fontBuf, +#else + char *fileName, + GBool deleteFile, +#endif + const char **enc) { + SplashFontFile *fontFile; + + fontFile = NULL; +#if HAVE_FREETYPE_H + if (!fontFile && ftEngine) { + fontFile = ftEngine->loadType1Font(idA, +#if LOAD_FONTS_FROM_MEM + fontBuf, +#else + fileName, deleteFile, +#endif + enc); + } +#endif + +#if !LOAD_FONTS_FROM_MEM && !defined(_WIN32) && !defined(__ANDROID__) + // delete the (temporary) font file -- with Unix hard link + // semantics, this will remove the last link; otherwise it will + // return an error, leaving the file to be deleted later (if + // loadXYZFont failed, the file will always be deleted) + if (deleteFile) { + unlink(fontFile ? fontFile->fileName->getCString() : fileName); + } +#endif + + if (!fontFile) { + badFontFiles->append(idA); + } + + return fontFile; +} + +SplashFontFile *SplashFontEngine::loadType1CFont(SplashFontFileID *idA, +#if LOAD_FONTS_FROM_MEM + GString *fontBuf, +#else + char *fileName, + GBool deleteFile, +#endif + int *codeToGID, + const char **enc) { + SplashFontFile *fontFile; + + fontFile = NULL; + if (!fontFile) { + gfree(codeToGID); + } +#if HAVE_FREETYPE_H + if (!fontFile && ftEngine) { + fontFile = ftEngine->loadType1CFont(idA, +#if LOAD_FONTS_FROM_MEM + fontBuf, +#else + fileName, deleteFile, +#endif + enc); + } +#endif + +#if !LOAD_FONTS_FROM_MEM && !defined(_WIN32) && !defined(__ANDROID__) + // delete the (temporary) font file -- with Unix hard link + // semantics, this will remove the last link; otherwise it will + // return an error, leaving the file to be deleted later (if + // loadXYZFont failed, the file will always be deleted) + if (deleteFile) { + unlink(fontFile ? fontFile->fileName->getCString() : fileName); + } +#endif + + if (!fontFile) { + badFontFiles->append(idA); + } + + return fontFile; +} + +SplashFontFile *SplashFontEngine::loadOpenTypeT1CFont(SplashFontFileID *idA, +#if LOAD_FONTS_FROM_MEM + GString *fontBuf, +#else + char *fileName, + GBool deleteFile, +#endif + int *codeToGID, + const char **enc) { + SplashFontFile *fontFile; + + fontFile = NULL; + if (!fontFile) { + gfree(codeToGID); + } +#if HAVE_FREETYPE_H + if (!fontFile && ftEngine) { + fontFile = ftEngine->loadOpenTypeT1CFont(idA, +#if LOAD_FONTS_FROM_MEM + fontBuf, +#else + fileName, deleteFile, +#endif + enc); + } +#endif + +#if !LOAD_FONTS_FROM_MEM && !defined(_WIN32) && !defined(__ANDROID__) + // delete the (temporary) font file -- with Unix hard link + // semantics, this will remove the last link; otherwise it will + // return an error, leaving the file to be deleted later (if + // loadXYZFont failed, the file will always be deleted) + if (deleteFile) { + unlink(fontFile ? fontFile->fileName->getCString() : fileName); + } +#endif + + if (!fontFile) { + badFontFiles->append(idA); + } + + return fontFile; +} + +SplashFontFile *SplashFontEngine::loadCIDFont(SplashFontFileID *idA, +#if LOAD_FONTS_FROM_MEM + GString *fontBuf, +#else + char *fileName, + GBool deleteFile, +#endif + int *codeToGID, + int codeToGIDLen) { + SplashFontFile *fontFile; + + fontFile = NULL; +#if HAVE_FREETYPE_H + if (!fontFile && ftEngine) { + fontFile = ftEngine->loadCIDFont(idA, +#if LOAD_FONTS_FROM_MEM + fontBuf, +#else + fileName, deleteFile, +#endif + codeToGID, codeToGIDLen); + } +#endif + + if (!fontFile) { + gfree(codeToGID); + } + +#if !LOAD_FONTS_FROM_MEM && !defined(_WIN32) && !defined(__ANDROID__) + // delete the (temporary) font file -- with Unix hard link + // semantics, this will remove the last link; otherwise it will + // return an error, leaving the file to be deleted later (if + // loadXYZFont failed, the file will always be deleted) + if (deleteFile) { + unlink(fontFile ? fontFile->fileName->getCString() : fileName); + } +#endif + + if (!fontFile) { + badFontFiles->append(idA); + } + + return fontFile; +} + +SplashFontFile *SplashFontEngine::loadOpenTypeCFFFont(SplashFontFileID *idA, +#if LOAD_FONTS_FROM_MEM + GString *fontBuf, +#else + char *fileName, + GBool deleteFile, +#endif + int *codeToGID, + int codeToGIDLen) { + SplashFontFile *fontFile; + + fontFile = NULL; +#if HAVE_FREETYPE_H + if (!fontFile && ftEngine) { + fontFile = ftEngine->loadOpenTypeCFFFont(idA, +#if LOAD_FONTS_FROM_MEM + fontBuf, +#else + fileName, deleteFile, +#endif + codeToGID, codeToGIDLen); + } +#endif + + if (!fontFile) { + gfree(codeToGID); + } + +#if !LOAD_FONTS_FROM_MEM && !defined(_WIN32) && !defined(__ANDROID__) + // delete the (temporary) font file -- with Unix hard link + // semantics, this will remove the last link; otherwise it will + // return an error, leaving the file to be deleted later (if + // loadXYZFont failed, the file will always be deleted) + if (deleteFile) { + unlink(fontFile ? fontFile->fileName->getCString() : fileName); + } +#endif + + if (!fontFile) { + badFontFiles->append(idA); + } + + return fontFile; +} + +SplashFontFile *SplashFontEngine::loadTrueTypeFont(SplashFontFileID *idA, +#if LOAD_FONTS_FROM_MEM + GString *fontBuf, +#else + char *fileName, + GBool deleteFile, +#endif + int fontNum, + int *codeToGID, + int codeToGIDLen, + char *fontName) { + SplashFontFile *fontFile; + + fontFile = NULL; +#if HAVE_FREETYPE_H + if (!fontFile && ftEngine) { + fontFile = ftEngine->loadTrueTypeFont(idA, +#if LOAD_FONTS_FROM_MEM + fontBuf, +#else + fileName, deleteFile, +#endif + fontNum, codeToGID, codeToGIDLen); + } +#endif + + if (!fontFile) { + gfree(codeToGID); + } + +#if !LOAD_FONTS_FROM_MEM && !defined(_WIN32) && !defined(__ANDROID__) + // delete the (temporary) font file -- with Unix hard link + // semantics, this will remove the last link; otherwise it will + // return an error, leaving the file to be deleted later (if + // loadXYZFont failed, the file will always be deleted) + if (deleteFile) { + unlink(fontFile ? fontFile->fileName->getCString() : fileName); + } +#endif + + if (!fontFile) { + badFontFiles->append(idA); + } + + return fontFile; +} + +SplashFont *SplashFontEngine::getFont(SplashFontFile *fontFile, + SplashCoord *textMat, + SplashCoord *ctm) { + SplashCoord mat[4]; + SplashFont *font; + int i, j; + + mat[0] = textMat[0] * ctm[0] + textMat[1] * ctm[2]; + mat[1] = -(textMat[0] * ctm[1] + textMat[1] * ctm[3]); + mat[2] = textMat[2] * ctm[0] + textMat[3] * ctm[2]; + mat[3] = -(textMat[2] * ctm[1] + textMat[3] * ctm[3]); + if (!splashCheckDet(mat[0], mat[1], mat[2], mat[3], 0.01)) { + // avoid a singular (or close-to-singular) matrix + mat[0] = 0.01; mat[1] = 0; + mat[2] = 0; mat[3] = 0.01; + } + + font = fontCache[0]; + if (font && font->matches(fontFile, mat, textMat)) { + return font; + } + for (i = 1; i < splashFontCacheSize; ++i) { + font = fontCache[i]; + if (font && font->matches(fontFile, mat, textMat)) { + for (j = i; j > 0; --j) { + fontCache[j] = fontCache[j-1]; + } + fontCache[0] = font; + return font; + } + } + font = fontFile->makeFont(mat, textMat); + if (fontCache[splashFontCacheSize - 1]) { + delete fontCache[splashFontCacheSize - 1]; + } + for (j = splashFontCacheSize - 1; j > 0; --j) { + fontCache[j] = fontCache[j-1]; + } + fontCache[0] = font; + return font; +} diff --git a/splash/SplashFontEngine.h b/splash/SplashFontEngine.h new file mode 100644 index 0000000..59adb95 --- /dev/null +++ b/splash/SplashFontEngine.h @@ -0,0 +1,129 @@ +//======================================================================== +// +// SplashFontEngine.h +// +// Copyright 2003-2013 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef SPLASHFONTENGINE_H +#define SPLASHFONTENGINE_H + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +class GString; +class GList; + +class SplashFTFontEngine; +class SplashDTFontEngine; +class SplashDT4FontEngine; +class SplashFontFile; +class SplashFontFileID; +class SplashFont; + +//------------------------------------------------------------------------ + +#define splashFontCacheSize 16 + +#if HAVE_FREETYPE_H +#define splashFTNoHinting (1 << 0) +#endif + +//------------------------------------------------------------------------ +// SplashFontEngine +//------------------------------------------------------------------------ + +class SplashFontEngine { +public: + + // Create a font engine. + SplashFontEngine( +#if HAVE_FREETYPE_H + GBool enableFreeType, + Guint freeTypeFlags, +#endif + GBool aa); + + ~SplashFontEngine(); + + // Get a font file from the cache. Returns NULL if there is no + // matching entry in the cache. + SplashFontFile *getFontFile(SplashFontFileID *id); + + // Returns true if [id] refers to a bad font file, i.e., if one of + // the loadXXXFont functions has returned NULL for that ID. + GBool checkForBadFontFile(SplashFontFileID *id); + + // Load fonts - these create new SplashFontFile objects. + SplashFontFile *loadType1Font(SplashFontFileID *idA, +#if LOAD_FONTS_FROM_MEM + GString *fontBuf, +#else + char *fileName, GBool deleteFile, +#endif + const char **enc); + SplashFontFile *loadType1CFont(SplashFontFileID *idA, +#if LOAD_FONTS_FROM_MEM + GString *fontBuf, +#else + char *fileName, GBool deleteFile, +#endif + int *codeToGID, const char **enc); + SplashFontFile *loadOpenTypeT1CFont(SplashFontFileID *idA, +#if LOAD_FONTS_FROM_MEM + GString *fontBuf, +#else + char *fileName, GBool deleteFile, +#endif + int *codeToGID, const char **enc); + SplashFontFile *loadCIDFont(SplashFontFileID *idA, +#if LOAD_FONTS_FROM_MEM + GString *fontBuf, +#else + char *fileName, GBool deleteFile, +#endif + int *codeToGID, int codeToGIDLen); + SplashFontFile *loadOpenTypeCFFFont(SplashFontFileID *idA, +#if LOAD_FONTS_FROM_MEM + GString *fontBuf, +#else + char *fileName, GBool deleteFile, +#endif + int *codeToGID, int codeToGIDLen); + SplashFontFile *loadTrueTypeFont(SplashFontFileID *idA, +#if LOAD_FONTS_FROM_MEM + GString *fontBuf, +#else + char *fileName, GBool deleteFile, +#endif + int fontNum, + int *codeToGID, int codeToGIDLen, + char *fontName); + + // Get a font - this does a cache lookup first, and if not found, + // creates a new SplashFont object and adds it to the cache. The + // matrix, mat = textMat * ctm: + // [ mat[0] mat[1] ] + // [ mat[2] mat[3] ] + // specifies the font transform in PostScript style: + // [x' y'] = [x y] * mat + // Note that the Splash y axis points downward. + SplashFont *getFont(SplashFontFile *fontFile, + SplashCoord *textMat, SplashCoord *ctm); + +private: + + SplashFont *fontCache[splashFontCacheSize]; + GList *badFontFiles; // [SplashFontFileID] + +#if HAVE_FREETYPE_H + SplashFTFontEngine *ftEngine; +#endif +}; + +#endif diff --git a/splash/SplashFontFile.cc b/splash/SplashFontFile.cc new file mode 100644 index 0000000..2d260e3 --- /dev/null +++ b/splash/SplashFontFile.cc @@ -0,0 +1,84 @@ +//======================================================================== +// +// SplashFontFile.cc +// +// Copyright 2003-2013 Glyph & Cog, LLC +// +//======================================================================== + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <stdio.h> +#ifndef _WIN32 +# include <unistd.h> +#endif +#include "gmempp.h" +#include "GString.h" +#include "SplashFontFile.h" +#include "SplashFontFileID.h" + +#ifdef VMS +#if (__VMS_VER < 70000000) +extern "C" int unlink(char *filename); +#endif +#endif + +//------------------------------------------------------------------------ +// SplashFontFile +//------------------------------------------------------------------------ + +SplashFontFile::SplashFontFile(SplashFontFileID *idA, + SplashFontType fontTypeA, +#if LOAD_FONTS_FROM_MEM + GString *fontBufA +#else + char *fileNameA, GBool deleteFileA +#endif + ) { + id = idA; + fontType = fontTypeA; +#if LOAD_FONTS_FROM_MEM + fontBuf = fontBufA; +#else + fileName = new GString(fileNameA); + deleteFile = deleteFileA; +#endif + refCnt = 0; +} + +SplashFontFile::~SplashFontFile() { +#if LOAD_FONTS_FROM_MEM + delete fontBuf; +#else + if (deleteFile) { + unlink(fileName->getCString()); + } + delete fileName; +#endif + delete id; +} + +void SplashFontFile::incRefCnt() { +#if MULTITHREADED + gAtomicIncrement(&refCnt); +#else + ++refCnt; +#endif +} + +void SplashFontFile::decRefCnt() { + GBool done; + +#if MULTITHREADED + done = gAtomicDecrement(&refCnt) == 0; +#else + done = --refCnt == 0; +#endif + if (done) { + delete this; + } +} diff --git a/splash/SplashFontFile.h b/splash/SplashFontFile.h new file mode 100644 index 0000000..133e6ab --- /dev/null +++ b/splash/SplashFontFile.h @@ -0,0 +1,95 @@ +//======================================================================== +// +// SplashFontFile.h +// +// Copyright 2003-2013 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef SPLASHFONTFILE_H +#define SPLASHFONTFILE_H + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "SplashTypes.h" + +#if MULTITHREADED +#include "GMutex.h" +#endif + +class GString; +class SplashFontEngine; +class SplashFont; +class SplashFontFileID; + +//------------------------------------------------------------------------ +// SplashFontType +//------------------------------------------------------------------------ + +enum SplashFontType { + splashFontType1, // GfxFontType.fontType1 + splashFontType1C, // GfxFontType.fontType1C + splashFontOpenTypeT1C, // GfxFontType.fontType1COT + splashFontCID, // GfxFontType.fontCIDType0/fontCIDType0C + splashFontOpenTypeCFF, // GfxFontType.fontCIDType0COT + splashFontTrueType // GfxFontType.fontTrueType/fontTrueTypeOT/ + // fontCIDType2/fontCIDType2OT +}; + +//------------------------------------------------------------------------ +// SplashFontFile +//------------------------------------------------------------------------ + +class SplashFontFile { +public: + + virtual ~SplashFontFile(); + + // Create a new SplashFont, i.e., a scaled instance of this font + // file. + virtual SplashFont *makeFont(SplashCoord *mat, SplashCoord *textMat) = 0; + + // Get the font file ID. + SplashFontFileID *getID() { return id; } + + // Increment the reference count. + void incRefCnt(); + + // Decrement the reference count. If the new value is zero, delete + // the SplashFontFile object. + void decRefCnt(); + +protected: + + SplashFontFile(SplashFontFileID *idA, + SplashFontType fontTypeA, +#if LOAD_FONTS_FROM_MEM + GString *fontBufA +#else + char *fileNameA, GBool deleteFileA +#endif + ); + + SplashFontFileID *id; + SplashFontType fontType; +#if LOAD_FONTS_FROM_MEM + GString *fontBuf; +#else + GString *fileName; + GBool deleteFile; +#endif +#if MULTITHREADED + GAtomicCounter refCnt; +#else + int refCnt; +#endif + + friend class SplashFontEngine; +}; + +#endif diff --git a/splash/SplashFontFileID.cc b/splash/SplashFontFileID.cc new file mode 100644 index 0000000..27f5203 --- /dev/null +++ b/splash/SplashFontFileID.cc @@ -0,0 +1,26 @@ +//======================================================================== +// +// SplashFontFileID.cc +// +// Copyright 2003-2013 Glyph & Cog, LLC +// +//======================================================================== + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include "gmempp.h" +#include "SplashFontFileID.h" + +//------------------------------------------------------------------------ +// SplashFontFileID +//------------------------------------------------------------------------ + +SplashFontFileID::SplashFontFileID() { +} + +SplashFontFileID::~SplashFontFileID() { +} diff --git a/splash/SplashFontFileID.h b/splash/SplashFontFileID.h new file mode 100644 index 0000000..384018a --- /dev/null +++ b/splash/SplashFontFileID.h @@ -0,0 +1,32 @@ +//======================================================================== +// +// SplashFontFileID.h +// +// Copyright 2003-2013 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef SPLASHFONTFILEID_H +#define SPLASHFONTFILEID_H + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" + +//------------------------------------------------------------------------ +// SplashFontFileID +//------------------------------------------------------------------------ + +class SplashFontFileID { +public: + + SplashFontFileID(); + virtual ~SplashFontFileID(); + virtual GBool matches(SplashFontFileID *id) = 0; +}; + +#endif diff --git a/splash/SplashGlyphBitmap.h b/splash/SplashGlyphBitmap.h new file mode 100644 index 0000000..d375b3c --- /dev/null +++ b/splash/SplashGlyphBitmap.h @@ -0,0 +1,28 @@ +//======================================================================== +// +// SplashGlyphBitmap.h +// +// Copyright 2003-2013 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef SPLASHGLYPHBITMAP_H +#define SPLASHGLYPHBITMAP_H + +#include <aconf.h> + +#include "gtypes.h" + +//------------------------------------------------------------------------ +// SplashGlyphBitmap +//------------------------------------------------------------------------ + +struct SplashGlyphBitmap { + int x, y, w, h; // offset and size of glyph + GBool aa; // anti-aliased: true means 8-bit alpha + // bitmap; false means 1-bit + Guchar *data; // bitmap data + GBool freeData; // true if data memory should be freed +}; + +#endif diff --git a/splash/SplashMath.h b/splash/SplashMath.h new file mode 100644 index 0000000..45f4e53 --- /dev/null +++ b/splash/SplashMath.h @@ -0,0 +1,378 @@ +//======================================================================== +// +// SplashMath.h +// +// Copyright 2003-2013 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef SPLASHMATH_H +#define SPLASHMATH_H + +#include <aconf.h> + +#if USE_FIXEDPONT +# include "FixedPoint.h" +#else +# include <math.h> +# if (defined(__GNUC__) && defined(__SSE2__)) || \ + (defined(_WIN32) && (_M_IX86_FP == 2 || defined(_M_X64))) +# include <emmintrin.h> +# endif +#endif +#include "SplashTypes.h" + +static inline SplashCoord splashAbs(SplashCoord x) { +#if USE_FIXEDPOINT + return FixedPoint::abs(x); +#else + return fabs(x); +#endif +} + +// floor() and (int)() are implemented separately, which results +// in changing the FPCW multiple times - so we optimize it with +// some inline assembly or SSE intrinsics. +static inline int splashFloor(SplashCoord x) { +#if USE_FIXEDPOINT + + //--- fixed point + + return FixedPoint::floor(x); + +#elif (defined(__GNUC__) && defined(__SSE2__)) || \ + (defined(_WIN32) && (_M_IX86_FP == 2 || defined(_M_X64))) + + //--- SSE2 intrinsics + // NB: 64-bit x86 guarantees availability of SSE2. + + __m128d m1, m2; + int i, s; + + m1 = _mm_set_sd(x); + i = _mm_cvttsd_si32(m1); + m2 = _mm_cvtsi32_sd(m1, i); + s = _mm_ucomigt_sd(m2, m1); + return i - s; + +#elif defined(__GNUC__) && defined(__i386__) && !defined(__APPLE__) + + //--- x87 inline assembly (gcc/clang) + // (this code fails on OSX for reasons I don't understand) + + Gushort oldCW, newCW, t; + int result; + + __asm__ volatile("fnstcw %0\n" + "movw %0, %3\n" + "andw $0xf3ff, %3\n" + "orw $0x0400, %3\n" + "movw %3, %1\n" // round down + "fldcw %1\n" + "fistl %2\n" + "fldcw %0\n" + : "=m" (oldCW), "=m" (newCW), "=m" (result), "=r" (t) + : "t" (x)); + return result; + +#elif defined(_WIN32) && defined(_M_IX86) + + //--- x87 inline assembly (VC) + + Gushort oldCW, newCW; + int result; + + __asm fld QWORD PTR x + __asm fnstcw WORD PTR oldCW + __asm mov ax, WORD PTR oldCW + __asm and ax, 0xf3ff + __asm or ax, 0x0400 + __asm mov WORD PTR newCW, ax // round down + __asm fldcw WORD PTR newCW + __asm fistp DWORD PTR result + __asm fldcw WORD PTR oldCW + return result; + +#else + + //--- all others + + return (int)floor(x); + +#endif +} + +// ceil() and (int)() are implemented separately, which results +// in changing the FPCW multiple times - so we optimize it with +// some inline assembly or SSE intrinsics. +static inline int splashCeil(SplashCoord x) { +#if USE_FIXEDPOINT + + //--- fixed point + + return FixedPoint::ceil(x); + +#elif (defined(__GNUC__) && defined(__SSE2__)) || \ + (defined(_WIN32) && (_M_IX86_FP == 2 || defined(_M_X64))) + + //--- SSE2 intrinsics + // NB: 64-bit x86 guarantees availability of SSE2. + + __m128d m1, m2; + int i, s; + + m1 = _mm_set_sd(x); + i = _mm_cvttsd_si32(m1); + m2 = _mm_cvtsi32_sd(m1, i); + s = _mm_ucomilt_sd(m2, m1); + return i + s; + +#elif defined(__GNUC__) && defined(__i386__) && !defined(__APPLE__) + + //--- x87 inline assembly (gcc/clang) + // (this code fails on OSX for reasons I don't understand) + + Gushort oldCW, newCW, t; + int result; + + __asm__ volatile("fnstcw %0\n" + "movw %0, %3\n" + "andw $0xf3ff, %3\n" + "orw $0x0800, %3\n" + "movw %3, %1\n" // round up + "fldcw %1\n" + "fistl %2\n" + "fldcw %0\n" + : "=m" (oldCW), "=m" (newCW), "=m" (result), "=r" (t) + : "t" (x)); + return result; + +#elif defined(_WIN32) && defined(_M_IX86) + + //--- x87 inline assembly (VC) + + // ceil() and (int)() are implemented separately, which results + // in changing the FPCW multiple times - so we optimize it with + // some inline assembly + Gushort oldCW, newCW; + int result; + + __asm fld QWORD PTR x + __asm fnstcw WORD PTR oldCW + __asm mov ax, WORD PTR oldCW + __asm and ax, 0xf3ff + __asm or ax, 0x0800 + __asm mov WORD PTR newCW, ax // round up + __asm fldcw WORD PTR newCW + __asm fistp DWORD PTR result + __asm fldcw WORD PTR oldCW + return result; + +#else + + //--- all others + + return (int)ceil(x); + +#endif +} + +static inline int splashRound(SplashCoord x) { +#if USE_FIXEDPOINT + + //--- fixed point + + return FixedPoint::round(x); + +#else + + //--- all others + + return splashFloor(x + 0.5); + +#endif +} + +static inline SplashCoord splashAvg(SplashCoord x, SplashCoord y) { +#if USE_FIXEDPOINT + return FixedPoint::avg(x, y); +#else + return 0.5 * (x + y); +#endif +} + +static inline SplashCoord splashSqrt(SplashCoord x) { +#if USE_FIXEDPOINT + return FixedPoint::sqrt(x); +#else + return sqrt(x); +#endif +} + +static inline SplashCoord splashPow(SplashCoord x, SplashCoord y) { +#if USE_FIXEDPOINT + return FixedPoint::pow(x, y); +#else + return pow(x, y); +#endif +} + +static inline SplashCoord splashDist(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1) { + SplashCoord dx, dy; + dx = x1 - x0; + dy = y1 - y0; +#if USE_FIXEDPOINT + // this handles the situation where dx*dx or dy*dy is too large to + // fit in the 16.16 fixed point format + SplashCoord dxa, dya, d; + dxa = splashAbs(dx); + dya = splashAbs(dy); + if (dxa == 0 && dya == 0) { + return 0; + } else if (dxa > dya) { + d = dya / dxa; + return dxa * FixedPoint::sqrt(d*d + 1); + } else { + d = dxa / dya; + return dya * FixedPoint::sqrt(d*d + 1); + } +#else + return sqrt(dx * dx + dy * dy); +#endif +} + +static inline GBool splashCheckDet(SplashCoord m11, SplashCoord m12, + SplashCoord m21, SplashCoord m22, + SplashCoord epsilon) { +#if USE_FIXEDPOINT + return FixedPoint::checkDet(m11, m12, m21, m22, epsilon); +#else + return fabs(m11 * m22 - m12 * m21) >= epsilon; +#endif +} + +// Perform stroke adjustment on a SplashCoord range [xMin, xMax), +// resulting in an int range [*xMinI, *xMaxI). +// +// There are several options: +// +// 1. Round both edge coordinates. +// Pro: adjacent strokes/fills line up without any gaps or +// overlaps +// Con: lines with the same original floating point width can +// end up with different integer widths, e.g.: +// xMin = 10.1 xMax = 11.3 (width = 1.2) +// --> xMinI = 10 xMaxI = 11 (width = 1) +// but +// xMin = 10.4 xMax = 11.6 (width = 1.2) +// --> xMinI = 10 xMaxI = 12 (width = 2) +// +// 2. Round the min coordinate; add the ceiling of the width. +// Pro: lines with the same original floating point width will +// always end up with the same integer width +// Con: adjacent strokes/fills can have overlaps (which is +// problematic with transparency) +// (This could use floor on the min coordinate, instead of +// rounding, with similar results.) +// (If the width is rounded instead of using ceiling, the results +// Are similar, except that adjacent strokes/fills can have gaps +// as well as overlaps.) +// +// 3. Use floor on the min coordinate and ceiling on the max +// coordinate. +// Pro: lines always end up at least as wide as the original +// floating point width +// Con: adjacent strokes/fills can have overlaps, and lines with +// the same original floating point width can end up with +// different integer widths; the integer width can be more +// than one pixel wider than the original width, e.g.: +// xMin = 10.9 xMax = 12.1 (width = 1.2) +// --> xMinI = 10 xMaxI = 13 (width = 3) +// but +// xMin = 10.1 xMax = 11.3 (width = 1.2) +// --> xMinI = 10 xMaxI = 12 (width = 2) +// +// 4. Use a hybrid approach, choosing between two of the above +// options, based on width. E.g., use #2 if width <= 4, and use #1 +// if width > 4. +// +// If w >= 0 and strokeAdjMode is splashStrokeAdjustCAD then a special +// mode for projecting line caps is enabled, with w being the +// transformed line width. + +static inline void splashStrokeAdjust(SplashCoord xMin, SplashCoord xMax, + int *xMinI, int *xMaxI, + SplashStrokeAdjustMode strokeAdjMode, + SplashCoord w = -1) { + int x0, x1; + + // make sure the coords fit in 32-bit ints +#if USE_FIXEDPOINT + if (xMin < -32767) { + xMin = -32767; + } else if (xMin > 32767) { + xMin = 32767; + } + if (xMax < -32767) { + xMax = -32767; + } else if (xMax > 32767) { + xMax = 32767; + } +#else + if (xMin < -1e9) { + xMin = -1e9; + } else if (xMin > 1e9) { + xMin = 1e9; + } + if (xMax < -1e9) { + xMax = -1e9; + } else if (xMax > 1e9) { + xMax = 1e9; + } +#endif + + // this will never be called with strokeAdjMode == splashStrokeAdjustOff + if (strokeAdjMode == splashStrokeAdjustCAD) { + x0 = splashRound(xMin); + if (w >= 0) { + x1 = splashRound(xMax - w) + splashRound(w); + } else { + x1 = x0 + splashRound(xMax - xMin); + } + } else { + // NB: enable exactly one of these. +#if 1 // 1. Round both edge coordinates. + x0 = splashRound(xMin); + x1 = splashRound(xMax); +#endif +#if 0 // 2. Round the min coordinate; add the ceiling of the width. + x0 = splashRound(xMin); + x1 = x0 + splashCeil(xMax - xMin); +#endif +#if 0 // 3. Use floor on the min coord and ceiling on the max coord. + x0 = splashFloor(xMin); + x1 = splashCeil(xMax); +#endif +#if 0 // 4. Hybrid. + SplashCoord w = xMax - xMin; + x0 = splashRound(xMin); + if (w > 4) { + x1 = splashRound(xMax); + } else { + x1 = x0 + splashRound(w); + } +#endif + } + if (x0 == x1) { + if (xMin + xMax < 2 * x0) { + --x0; + } else { + ++x1; + } + } + *xMinI = x0; + *xMaxI = x1; +} + +#endif diff --git a/splash/SplashPath.cc b/splash/SplashPath.cc new file mode 100644 index 0000000..7921667 --- /dev/null +++ b/splash/SplashPath.cc @@ -0,0 +1,213 @@ +//======================================================================== +// +// SplashPath.cc +// +// Copyright 2003-2013 Glyph & Cog, LLC +// +//======================================================================== + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <string.h> +#include "gmem.h" +#include "gmempp.h" +#include "SplashErrorCodes.h" +#include "SplashPath.h" + +//------------------------------------------------------------------------ +// SplashPath +//------------------------------------------------------------------------ + +// A path can be in three possible states: +// +// 1. no current point -- zero or more finished subpaths +// [curSubpath == length] +// +// 2. one point in subpath +// [curSubpath == length - 1] +// +// 3. open subpath with two or more points +// [curSubpath < length - 1] + +SplashPath::SplashPath() { + pts = NULL; + flags = NULL; + length = size = 0; + curSubpath = 0; + hints = NULL; + hintsLength = hintsSize = 0; +} + +SplashPath::SplashPath(SplashPath *path) { + length = path->length; + size = path->size; + pts = (SplashPathPoint *)gmallocn(size, sizeof(SplashPathPoint)); + flags = (Guchar *)gmallocn(size, sizeof(Guchar)); + memcpy(pts, path->pts, length * sizeof(SplashPathPoint)); + memcpy(flags, path->flags, length * sizeof(Guchar)); + curSubpath = path->curSubpath; + if (path->hints) { + hintsLength = hintsSize = path->hintsLength; + hints = (SplashPathHint *)gmallocn(hintsSize, sizeof(SplashPathHint)); + memcpy(hints, path->hints, hintsLength * sizeof(SplashPathHint)); + } else { + hints = NULL; + hintsLength = hintsSize = 0; + } +} + +SplashPath::~SplashPath() { + gfree(pts); + gfree(flags); + gfree(hints); +} + +// Add space for <nPts> more points. +void SplashPath::grow(int nPts) { + if (length + nPts > size) { + if (size == 0) { + size = 32; + } + while (size < length + nPts) { + size *= 2; + } + pts = (SplashPathPoint *)greallocn(pts, size, sizeof(SplashPathPoint)); + flags = (Guchar *)greallocn(flags, size, sizeof(Guchar)); + } +} + +void SplashPath::append(SplashPath *path) { + int i; + + curSubpath = length + path->curSubpath; + grow(path->length); + for (i = 0; i < path->length; ++i) { + pts[length] = path->pts[i]; + flags[length] = path->flags[i]; + ++length; + } +} + +SplashError SplashPath::moveTo(SplashCoord x, SplashCoord y) { + if (onePointSubpath()) { + return splashErrBogusPath; + } + grow(1); + pts[length].x = x; + pts[length].y = y; + flags[length] = splashPathFirst | splashPathLast; + curSubpath = length++; + return splashOk; +} + +SplashError SplashPath::lineTo(SplashCoord x, SplashCoord y) { + if (noCurrentPoint()) { + return splashErrNoCurPt; + } + flags[length-1] &= (Guchar)~splashPathLast; + grow(1); + pts[length].x = x; + pts[length].y = y; + flags[length] = splashPathLast; + ++length; + return splashOk; +} + +SplashError SplashPath::curveTo(SplashCoord x1, SplashCoord y1, + SplashCoord x2, SplashCoord y2, + SplashCoord x3, SplashCoord y3) { + if (noCurrentPoint()) { + return splashErrNoCurPt; + } + flags[length-1] &= (Guchar)~splashPathLast; + grow(3); + pts[length].x = x1; + pts[length].y = y1; + flags[length] = splashPathCurve; + ++length; + pts[length].x = x2; + pts[length].y = y2; + flags[length] = splashPathCurve; + ++length; + pts[length].x = x3; + pts[length].y = y3; + flags[length] = splashPathLast; + ++length; + return splashOk; +} + +SplashError SplashPath::close(GBool force) { + if (noCurrentPoint()) { + return splashErrNoCurPt; + } + if (force || + curSubpath == length - 1 || + pts[length - 1].x != pts[curSubpath].x || + pts[length - 1].y != pts[curSubpath].y) { + lineTo(pts[curSubpath].x, pts[curSubpath].y); + } + flags[curSubpath] |= splashPathClosed; + flags[length - 1] |= splashPathClosed; + curSubpath = length; + return splashOk; +} + +void SplashPath::addStrokeAdjustHint(int ctrl0, int ctrl1, + int firstPt, int lastPt, + GBool projectingCap) { + if (hintsLength == hintsSize) { + hintsSize = hintsLength ? 2 * hintsLength : 8; + hints = (SplashPathHint *)greallocn(hints, hintsSize, + sizeof(SplashPathHint)); + } + hints[hintsLength].ctrl0 = ctrl0; + hints[hintsLength].ctrl1 = ctrl1; + hints[hintsLength].firstPt = firstPt; + hints[hintsLength].lastPt = lastPt; + hints[hintsLength].projectingCap = projectingCap; + ++hintsLength; +} + +void SplashPath::offset(SplashCoord dx, SplashCoord dy) { + int i; + + for (i = 0; i < length; ++i) { + pts[i].x += dx; + pts[i].y += dy; + } +} + +GBool SplashPath::getCurPt(SplashCoord *x, SplashCoord *y) { + if (noCurrentPoint()) { + return gFalse; + } + *x = pts[length - 1].x; + *y = pts[length - 1].y; + return gTrue; +} + +GBool SplashPath::containsZeroLengthSubpaths() { + GBool zeroLength; + int i; + + zeroLength = gTrue; // make gcc happy + for (i = 0; i < length; ++i) { + if (flags[i] & splashPathFirst) { + zeroLength = gTrue; + } else { + if (pts[i].x != pts[i-1].x || pts[i].y != pts[i-1].y) { + zeroLength = gFalse; + } + if (flags[i] & splashPathLast) { + if (zeroLength) { + return gTrue; + } + } + } + } + return gFalse; +} diff --git a/splash/SplashPath.h b/splash/SplashPath.h new file mode 100644 index 0000000..b5732b8 --- /dev/null +++ b/splash/SplashPath.h @@ -0,0 +1,133 @@ +//======================================================================== +// +// SplashPath.h +// +// Copyright 2003-2013 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef SPLASHPATH_H +#define SPLASHPATH_H + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" + +//------------------------------------------------------------------------ +// SplashPathPoint +//------------------------------------------------------------------------ + +struct SplashPathPoint { + SplashCoord x, y; +}; + +//------------------------------------------------------------------------ +// SplashPath.flags +//------------------------------------------------------------------------ + +// first point on each subpath sets this flag +#define splashPathFirst 0x01 + +// last point on each subpath sets this flag +#define splashPathLast 0x02 + +// if the subpath is closed, its first and last points must be +// identical, and must set this flag +#define splashPathClosed 0x04 + +// curve control points set this flag +#define splashPathCurve 0x08 + +//------------------------------------------------------------------------ +// SplashPathHint +//------------------------------------------------------------------------ + +struct SplashPathHint { + int ctrl0, ctrl1; + int firstPt, lastPt; + GBool projectingCap; +}; + +//------------------------------------------------------------------------ +// SplashPath +//------------------------------------------------------------------------ + +class SplashPath { +public: + + // Create an empty path. + SplashPath(); + + // Copy a path. + SplashPath *copy() { return new SplashPath(this); } + + ~SplashPath(); + + // Append <path> to <this>. + void append(SplashPath *path); + + // Start a new subpath. + SplashError moveTo(SplashCoord x, SplashCoord y); + + // Add a line segment to the last subpath. + SplashError lineTo(SplashCoord x, SplashCoord y); + + // Add a third-order (cubic) Bezier curve segment to the last + // subpath. + SplashError curveTo(SplashCoord x1, SplashCoord y1, + SplashCoord x2, SplashCoord y2, + SplashCoord x3, SplashCoord y3); + + // Close the last subpath, adding a line segment if necessary. If + // <force> is true, this adds a line segment even if the current + // point is equal to the first point in the subpath. + SplashError close(GBool force = gFalse); + + // Add a stroke adjustment hint. The controlling segments are + // <ctrl0> and <ctrl1> (where segments are identified by their first + // point), and the points to be adjusted are <firstPt> .. <lastPt>. + // <projectingCap> is true if the points are part of a projecting + // line cap. + void addStrokeAdjustHint(int ctrl0, int ctrl1, int firstPt, int lastPt, + GBool projectingCap = gFalse); + + // Add (<dx>, <dy>) to every point on this path. + void offset(SplashCoord dx, SplashCoord dy); + + // Get the points on the path. + int getLength() { return length; } + void getPoint(int i, SplashCoord *x, SplashCoord *y, Guchar *f) + { *x = pts[i].x; *y = pts[i].y; *f = flags[i]; } + + // Get the current point. + GBool getCurPt(SplashCoord *x, SplashCoord *y); + + // Returns true if the path contains one or more zero length + // subpaths. + GBool containsZeroLengthSubpaths(); + +private: + + SplashPath(SplashPath *path); + void grow(int nPts); + GBool noCurrentPoint() { return curSubpath == length; } + GBool onePointSubpath() { return curSubpath == length - 1; } + GBool openSubpath() { return curSubpath < length - 1; } + + SplashPathPoint *pts; // array of points + Guchar *flags; // array of flags + int length, size; // length/size of the pts and flags arrays + int curSubpath; // index of first point in last subpath + + SplashPathHint *hints; // list of hints + int hintsLength, hintsSize; + + friend class SplashXPath; + friend class Splash; +}; + +#endif diff --git a/splash/SplashPattern.cc b/splash/SplashPattern.cc new file mode 100644 index 0000000..0c5b509 --- /dev/null +++ b/splash/SplashPattern.cc @@ -0,0 +1,44 @@ +//======================================================================== +// +// SplashPattern.cc +// +// Copyright 2003-2013 Glyph & Cog, LLC +// +//======================================================================== + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include "gmempp.h" +#include "SplashMath.h" +#include "SplashScreen.h" +#include "SplashPattern.h" + +//------------------------------------------------------------------------ +// SplashPattern +//------------------------------------------------------------------------ + +SplashPattern::SplashPattern() { +} + +SplashPattern::~SplashPattern() { +} + +//------------------------------------------------------------------------ +// SplashSolidColor +//------------------------------------------------------------------------ + +SplashSolidColor::SplashSolidColor(SplashColorPtr colorA) { + splashColorCopy(color, colorA); +} + +SplashSolidColor::~SplashSolidColor() { +} + +void SplashSolidColor::getColor(int x, int y, SplashColorPtr c) { + splashColorCopy(c, color); +} + diff --git a/splash/SplashPattern.h b/splash/SplashPattern.h new file mode 100644 index 0000000..fcbe21d --- /dev/null +++ b/splash/SplashPattern.h @@ -0,0 +1,69 @@ +//======================================================================== +// +// SplashPattern.h +// +// Copyright 2003-2013 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef SPLASHPATTERN_H +#define SPLASHPATTERN_H + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" + +class SplashScreen; + +//------------------------------------------------------------------------ +// SplashPattern +//------------------------------------------------------------------------ + +class SplashPattern { +public: + + SplashPattern(); + + virtual SplashPattern *copy() = 0; + + virtual ~SplashPattern(); + + // Return the color value for a specific pixel. + virtual void getColor(int x, int y, SplashColorPtr c) = 0; + + + // Returns true if this pattern object will return the same color + // value for all pixels. + virtual GBool isStatic() = 0; + +private: +}; + +//------------------------------------------------------------------------ +// SplashSolidColor +//------------------------------------------------------------------------ + +class SplashSolidColor: public SplashPattern { +public: + + SplashSolidColor(SplashColorPtr colorA); + + virtual SplashPattern *copy() { return new SplashSolidColor(color); } + + virtual ~SplashSolidColor(); + + virtual void getColor(int x, int y, SplashColorPtr c); + + virtual GBool isStatic() { return gTrue; } + +private: + + SplashColor color; +}; + + +#endif diff --git a/splash/SplashScreen.cc b/splash/SplashScreen.cc new file mode 100644 index 0000000..9993edc --- /dev/null +++ b/splash/SplashScreen.cc @@ -0,0 +1,383 @@ +//======================================================================== +// +// SplashScreen.cc +// +// Copyright 2003-2013 Glyph & Cog, LLC +// +//======================================================================== + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <stdlib.h> +#include <string.h> +#if HAVE_STD_SORT +#include <algorithm> +#endif +#include "gmem.h" +#include "gmempp.h" +#include "SplashMath.h" +#include "SplashScreen.h" + +//------------------------------------------------------------------------ + +static SplashScreenParams defaultParams = { + splashScreenDispersed, // type + 2, // size + 2, // dotRadius + 1.0, // gamma + 0.0, // blackThreshold + 1.0 // whiteThreshold +}; + +//------------------------------------------------------------------------ + +struct SplashScreenPoint { + int x, y; + int dist; +}; + +#if HAVE_STD_SORT + +struct cmpDistancesFunctor { + bool operator()(const SplashScreenPoint &p0, const SplashScreenPoint &p1) { + return p0.dist < p1.dist; + } +}; + +#else // HAVE_STD_SORT + +static int cmpDistances(const void *p0, const void *p1) { + return ((SplashScreenPoint *)p0)->dist - ((SplashScreenPoint *)p1)->dist; +} + +#endif + +//------------------------------------------------------------------------ +// SplashScreen +//------------------------------------------------------------------------ + +// If <clustered> is true, this generates a 45 degree screen using a +// circular dot spot function. DPI = resolution / ((size / 2) * +// sqrt(2)). If <clustered> is false, this generates an optimal +// threshold matrix using recursive tesselation. Gamma correction +// (gamma = 1 / 1.33) is also computed here. +SplashScreen::SplashScreen(SplashScreenParams *params) { + Guchar u; + int black, white, i; + + if (!params) { + params = &defaultParams; + } + + // size must be a power of 2, and at least 2 + for (size = 2, log2Size = 1; size < params->size; size <<= 1, ++log2Size) ; + + switch (params->type) { + + case splashScreenDispersed: + mat = (Guchar *)gmallocn(size * size, sizeof(Guchar)); + buildDispersedMatrix(size/2, size/2, 1, size/2, 1); + break; + + case splashScreenClustered: + mat = (Guchar *)gmallocn(size * size, sizeof(Guchar)); + buildClusteredMatrix(); + break; + + case splashScreenStochasticClustered: + // size must be at least 2*r + while (size < (params->dotRadius << 1)) { + size <<= 1; + ++log2Size; + } + mat = (Guchar *)gmallocn(size * size, sizeof(Guchar)); + buildSCDMatrix(params->dotRadius); + break; + } + + sizeM1 = size - 1; + + // do gamma correction and compute minVal/maxVal + minVal = 255; + maxVal = 0; + black = splashRound((SplashCoord)255.0 * params->blackThreshold); + if (black < 1) { + black = 1; + } + white = splashRound((SplashCoord)255.0 * params->whiteThreshold); + if (white > 255) { + white = 255; + } + for (i = 0; i < size * size; ++i) { + u = (Guchar)splashRound((SplashCoord)255.0 * + splashPow((SplashCoord)mat[i] / 255.0, + params->gamma)); + if (u < black) { + u = (Guchar)black; + } else if (u >= white) { + u = (Guchar)white; + } + mat[i] = u; + if (u < minVal) { + minVal = u; + } else if (u > maxVal) { + maxVal = u; + } + } +} + +void SplashScreen::buildDispersedMatrix(int i, int j, int val, + int delta, int offset) { + if (delta == 0) { + // map values in [1, size^2] --> [1, 255] + mat[(i << log2Size) + j] = + (Guchar)(1 + (254 * (val - 1)) / (size * size - 1)); + } else { + buildDispersedMatrix(i, j, + val, delta / 2, 4*offset); + buildDispersedMatrix((i + delta) % size, (j + delta) % size, + val + offset, delta / 2, 4*offset); + buildDispersedMatrix((i + delta) % size, j, + val + 2*offset, delta / 2, 4*offset); + buildDispersedMatrix((i + 2*delta) % size, (j + delta) % size, + val + 3*offset, delta / 2, 4*offset); + } +} + +void SplashScreen::buildClusteredMatrix() { + SplashCoord *dist; + SplashCoord u, v, d; + Guchar val; + int size2, x, y, x1, y1, i; + + size2 = size >> 1; + + // initialize the threshold matrix + for (y = 0; y < size; ++y) { + for (x = 0; x < size; ++x) { + mat[(y << log2Size) + x] = 0; + } + } + + // build the distance matrix + dist = (SplashCoord *)gmallocn(size * size2, sizeof(SplashCoord)); + for (y = 0; y < size2; ++y) { + for (x = 0; x < size2; ++x) { + if (x + y < size2 - 1) { + u = (SplashCoord)x + 0.5 - 0; + v = (SplashCoord)y + 0.5 - 0; + } else { + u = (SplashCoord)x + 0.5 - (SplashCoord)size2; + v = (SplashCoord)y + 0.5 - (SplashCoord)size2; + } + dist[y * size2 + x] = u*u + v*v; + } + } + for (y = 0; y < size2; ++y) { + for (x = 0; x < size2; ++x) { + if (x < y) { + u = (SplashCoord)x + 0.5 - 0; + v = (SplashCoord)y + 0.5 - (SplashCoord)size2; + } else { + u = (SplashCoord)x + 0.5 - (SplashCoord)size2; + v = (SplashCoord)y + 0.5 - 0; + } + dist[(size2 + y) * size2 + x] = u*u + v*v; + } + } + + // build the threshold matrix + x1 = y1 = 0; // make gcc happy + for (i = 0; i < size * size2; ++i) { + d = -1; + for (y = 0; y < size; ++y) { + for (x = 0; x < size2; ++x) { + if (mat[(y << log2Size) + x] == 0 && + dist[y * size2 + x] > d) { + x1 = x; + y1 = y; + d = dist[y1 * size2 + x1]; + } + } + } + // map values in [0, 2*size*size2-1] --> [1, 255] + val = (Guchar)(1 + (254 * (2*i)) / (2*size*size2 - 1)); + mat[(y1 << log2Size) + x1] = val; + val = (Guchar)(1 + (254 * (2*i+1)) / (2*size*size2 - 1)); + if (y1 < size2) { + mat[((y1 + size2) << log2Size) + x1 + size2] = val; + } else { + mat[((y1 - size2) << log2Size) + x1 + size2] = val; + } + } + + gfree(dist); +} + +// Compute the distance between two points on a toroid. +int SplashScreen::distance(int x0, int y0, int x1, int y1) { + int dx0, dx1, dx, dy0, dy1, dy; + + dx0 = abs(x0 - x1); + dx1 = size - dx0; + dx = dx0 < dx1 ? dx0 : dx1; + dy0 = abs(y0 - y1); + dy1 = size - dy0; + dy = dy0 < dy1 ? dy0 : dy1; + return dx * dx + dy * dy; +} + +// Algorithm taken from: +// Victor Ostromoukhov and Roger D. Hersch, "Stochastic Clustered-Dot +// Dithering" in Color Imaging: Device-Independent Color, Color +// Hardcopy, and Graphic Arts IV, SPIE Vol. 3648, pp. 496-505, 1999. +void SplashScreen::buildSCDMatrix(int r) { + SplashScreenPoint *dots, *pts; + int dotsLen, dotsSize; + char *tmpl; + char *grid; + int *region, *dist; + int x, y, xx, yy, x0, x1, y0, y1, i, j, d, iMin, dMin, n; + + //~ this should probably happen somewhere else + srand(123); + + // generate the random space-filling curve + pts = (SplashScreenPoint *)gmallocn(size * size, sizeof(SplashScreenPoint)); + i = 0; + for (y = 0; y < size; ++y) { + for (x = 0; x < size; ++x) { + pts[i].x = x; + pts[i].y = y; + ++i; + } + } + for (i = 0; i < size * size; ++i) { + j = i + (int)((double)(size * size - i) * + (double)rand() / ((double)RAND_MAX + 1.0)); + x = pts[i].x; + y = pts[i].y; + pts[i].x = pts[j].x; + pts[i].y = pts[j].y; + pts[j].x = x; + pts[j].y = y; + } + + // construct the circle template + tmpl = (char *)gmallocn((r+1)*(r+1), sizeof(char)); + for (y = 0; y <= r; ++y) { + for (x = 0; x <= r; ++x) { + tmpl[y*(r+1) + x] = (x * y <= r * r) ? 1 : 0; + } + } + + // mark all grid cells as free + grid = (char *)gmallocn(size * size, sizeof(char)); + for (y = 0; y < size; ++y) { + for (x = 0; x < size; ++x) { + grid[(y << log2Size) + x] = 0; + } + } + + // walk the space-filling curve, adding dots + dotsLen = 0; + dotsSize = 32; + dots = (SplashScreenPoint *)gmallocn(dotsSize, sizeof(SplashScreenPoint)); + for (i = 0; i < size * size; ++i) { + x = pts[i].x; + y = pts[i].y; + if (!grid[(y << log2Size) + x]) { + if (dotsLen == dotsSize) { + dotsSize *= 2; + dots = (SplashScreenPoint *)greallocn(dots, dotsSize, + sizeof(SplashScreenPoint)); + } + dots[dotsLen++] = pts[i]; + for (yy = 0; yy <= r; ++yy) { + y0 = (y + yy) % size; + y1 = (y - yy + size) % size; + for (xx = 0; xx <= r; ++xx) { + if (tmpl[yy*(r+1) + xx]) { + x0 = (x + xx) % size; + x1 = (x - xx + size) % size; + grid[(y0 << log2Size) + x0] = 1; + grid[(y0 << log2Size) + x1] = 1; + grid[(y1 << log2Size) + x0] = 1; + grid[(y1 << log2Size) + x1] = 1; + } + } + } + } + } + + gfree(tmpl); + gfree(grid); + + // assign each cell to a dot, compute distance to center of dot + region = (int *)gmallocn(size * size, sizeof(int)); + dist = (int *)gmallocn(size * size, sizeof(int)); + for (y = 0; y < size; ++y) { + for (x = 0; x < size; ++x) { + iMin = 0; + dMin = distance(dots[0].x, dots[0].y, x, y); + for (i = 1; i < dotsLen; ++i) { + d = distance(dots[i].x, dots[i].y, x, y); + if (d < dMin) { + iMin = i; + dMin = d; + } + } + region[(y << log2Size) + x] = iMin; + dist[(y << log2Size) + x] = dMin; + } + } + + // compute threshold values + for (i = 0; i < dotsLen; ++i) { + n = 0; + for (y = 0; y < size; ++y) { + for (x = 0; x < size; ++x) { + if (region[(y << log2Size) + x] == i) { + pts[n].x = x; + pts[n].y = y; + pts[n].dist = distance(dots[i].x, dots[i].y, x, y); + ++n; + } + } + } +#if HAVE_STD_SORT + std::sort(pts, pts + n, cmpDistancesFunctor()); +#else + qsort(pts, n, sizeof(SplashScreenPoint), &cmpDistances); +#endif + for (j = 0; j < n; ++j) { + // map values in [0 .. n-1] --> [255 .. 1] + mat[(pts[j].y << log2Size) + pts[j].x] = + (Guchar)(255 - (254 * j) / (n - 1)); + } + } + + gfree(pts); + gfree(region); + gfree(dist); + + gfree(dots); +} + +SplashScreen::SplashScreen(SplashScreen *screen) { + size = screen->size; + sizeM1 = screen->sizeM1; + log2Size = screen->log2Size; + mat = (Guchar *)gmallocn(size * size, sizeof(Guchar)); + memcpy(mat, screen->mat, size * size * sizeof(Guchar)); + minVal = screen->minVal; + maxVal = screen->maxVal; +} + +SplashScreen::~SplashScreen() { + gfree(mat); +} diff --git a/splash/SplashScreen.h b/splash/SplashScreen.h new file mode 100644 index 0000000..560e275 --- /dev/null +++ b/splash/SplashScreen.h @@ -0,0 +1,81 @@ +//======================================================================== +// +// SplashScreen.h +// +// Copyright 2003-2013 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef SPLASHSCREEN_H +#define SPLASHSCREEN_H + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" + +//------------------------------------------------------------------------ +// SplashScreen +//------------------------------------------------------------------------ + +typedef Guchar *SplashScreenCursor; + +class SplashScreen { +public: + + SplashScreen(SplashScreenParams *params); + SplashScreen(SplashScreen *screen); + ~SplashScreen(); + + SplashScreen *copy() { return new SplashScreen(this); } + + // Return the computed pixel value (0=black, 1=white) for the gray + // level <value> at (<x>, <y>). + int test(int x, int y, Guchar value) { + int xx, yy; + xx = x & sizeM1; + yy = y & sizeM1; + return value < mat[(yy << log2Size) + xx] ? 0 : 1; + } + + // To do a series of tests with the same y value, call + // getTestCursor(y), and then call testWithCursor(cursor, x, value) + // for each x. + SplashScreenCursor getTestCursor(int y) { + int yy; + yy = y & sizeM1; + return &mat[yy << log2Size]; + } + + int testWithCursor(SplashScreenCursor cursor, int x, Guchar value) { + int xx = x & sizeM1; + return value >= cursor[xx]; + } + + // Returns true if value is above the white threshold or below the + // black threshold, i.e., if the corresponding halftone will be + // solid white or black. + GBool isStatic(Guchar value) { return value < minVal || value >= maxVal; } + +private: + + void buildDispersedMatrix(int i, int j, int val, + int delta, int offset); + void buildClusteredMatrix(); + int distance(int x0, int y0, int x1, int y1); + void buildSCDMatrix(int r); + + Guchar *mat; // threshold matrix + int size; // size of the threshold matrix + int sizeM1; // size - 1 + int log2Size; // log2(size) + Guchar minVal; // any pixel value below minVal generates + // solid black + Guchar maxVal; // any pixel value above maxVal generates + // solid white +}; + +#endif diff --git a/splash/SplashState.cc b/splash/SplashState.cc new file mode 100644 index 0000000..7fc5104 --- /dev/null +++ b/splash/SplashState.cc @@ -0,0 +1,349 @@ +//======================================================================== +// +// SplashState.cc +// +// Copyright 2003-2013 Glyph & Cog, LLC +// +//======================================================================== + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <string.h> +#include "gmem.h" +#include "gmempp.h" +#include "SplashPattern.h" +#include "SplashScreen.h" +#include "SplashClip.h" +#include "SplashBitmap.h" +#include "SplashState.h" + +//------------------------------------------------------------------------ +// SplashState +//------------------------------------------------------------------------ + +// number of components in each color mode +int splashColorModeNComps[] = { + 1, 1, 3, 3 +#if SPLASH_CMYK + , 4 +#endif +}; + +SplashState::SplashState(int width, int height, GBool vectorAntialias, + SplashScreenParams *screenParams) { + SplashColor color; + int i; + + matrix[0] = 1; matrix[1] = 0; + matrix[2] = 0; matrix[3] = 1; + matrix[4] = 0; matrix[5] = 0; + memset(&color, 0, sizeof(SplashColor)); + strokePattern = new SplashSolidColor(color); + fillPattern = new SplashSolidColor(color); + screen = new SplashScreen(screenParams); + blendFunc = NULL; + strokeAlpha = 1; + fillAlpha = 1; + lineWidth = 1; + lineCap = splashLineCapButt; + lineJoin = splashLineJoinMiter; + miterLimit = 10; + flatness = 1; + lineDash = NULL; + lineDashLength = 0; + lineDashPhase = 0; + strokeAdjust = splashStrokeAdjustOff; + clip = new SplashClip(0, 0, width, height); + clipIsShared = gFalse; + softMask = NULL; + deleteSoftMask = gFalse; + inNonIsolatedGroup = gFalse; + inKnockoutGroup = gFalse; +#if SPLASH_CMYK + rgbTransferR = (Guchar *)gmalloc(8 * 256); + rgbTransferG = rgbTransferR + 256; + rgbTransferB = rgbTransferG + 256; + grayTransfer = rgbTransferB + 256; + cmykTransferC = grayTransfer + 256; + cmykTransferM = cmykTransferC + 256; + cmykTransferY = cmykTransferM + 256; + cmykTransferK = cmykTransferY + 256; +#else + rgbTransferR = (Guchar *)gmalloc(4 * 256); + rgbTransferG = rgbTransferR + 256; + rgbTransferB = rgbTransferG + 256; + grayTransfer = rgbTransferB + 256; +#endif + for (i = 0; i < 256; ++i) { + rgbTransferR[i] = (Guchar)i; + rgbTransferG[i] = (Guchar)i; + rgbTransferB[i] = (Guchar)i; + grayTransfer[i] = (Guchar)i; +#if SPLASH_CMYK + cmykTransferC[i] = (Guchar)i; + cmykTransferM[i] = (Guchar)i; + cmykTransferY[i] = (Guchar)i; + cmykTransferK[i] = (Guchar)i; +#endif + } + transferIsShared = gFalse; + overprintMask = 0xffffffff; + enablePathSimplification = gFalse; + next = NULL; +} + +SplashState::SplashState(int width, int height, GBool vectorAntialias, + SplashScreen *screenA) { + SplashColor color; + int i; + + matrix[0] = 1; matrix[1] = 0; + matrix[2] = 0; matrix[3] = 1; + matrix[4] = 0; matrix[5] = 0; + memset(&color, 0, sizeof(SplashColor)); + strokePattern = new SplashSolidColor(color); + fillPattern = new SplashSolidColor(color); + screen = screenA->copy(); + blendFunc = NULL; + strokeAlpha = 1; + fillAlpha = 1; + lineWidth = 1; + lineCap = splashLineCapButt; + lineJoin = splashLineJoinMiter; + miterLimit = 10; + flatness = 1; + lineDash = NULL; + lineDashLength = 0; + lineDashPhase = 0; + strokeAdjust = splashStrokeAdjustOff; + clip = new SplashClip(0, 0, width, height); + clipIsShared = gFalse; + softMask = NULL; + deleteSoftMask = gFalse; + inNonIsolatedGroup = gFalse; + inKnockoutGroup = gFalse; +#if SPLASH_CMYK + rgbTransferR = (Guchar *)gmalloc(8 * 256); + rgbTransferG = rgbTransferR + 256; + rgbTransferB = rgbTransferG + 256; + grayTransfer = rgbTransferB + 256; + cmykTransferC = grayTransfer + 256; + cmykTransferM = cmykTransferC + 256; + cmykTransferY = cmykTransferM + 256; + cmykTransferK = cmykTransferY + 256; +#else + rgbTransferR = (Guchar *)gmalloc(4 * 256); + rgbTransferG = rgbTransferR + 256; + rgbTransferB = rgbTransferG + 256; + grayTransfer = rgbTransferB + 256; +#endif + for (i = 0; i < 256; ++i) { + rgbTransferR[i] = (Guchar)i; + rgbTransferG[i] = (Guchar)i; + rgbTransferB[i] = (Guchar)i; + grayTransfer[i] = (Guchar)i; +#if SPLASH_CMYK + cmykTransferC[i] = (Guchar)i; + cmykTransferM[i] = (Guchar)i; + cmykTransferY[i] = (Guchar)i; + cmykTransferK[i] = (Guchar)i; +#endif + } + transferIsShared = gFalse; + overprintMask = 0xffffffff; + enablePathSimplification = gFalse; + next = NULL; +} + +SplashState::SplashState(SplashState *state) { + memcpy(matrix, state->matrix, 6 * sizeof(SplashCoord)); + strokePattern = state->strokePattern->copy(); + fillPattern = state->fillPattern->copy(); + screen = state->screen->copy(); + blendFunc = state->blendFunc; + strokeAlpha = state->strokeAlpha; + fillAlpha = state->fillAlpha; + lineWidth = state->lineWidth; + lineCap = state->lineCap; + lineJoin = state->lineJoin; + miterLimit = state->miterLimit; + flatness = state->flatness; + if (state->lineDash) { + lineDashLength = state->lineDashLength; + lineDash = (SplashCoord *)gmallocn(lineDashLength, sizeof(SplashCoord)); + memcpy(lineDash, state->lineDash, lineDashLength * sizeof(SplashCoord)); + } else { + lineDash = NULL; + lineDashLength = 0; + } + lineDashPhase = state->lineDashPhase; + strokeAdjust = state->strokeAdjust; + clip = state->clip; + clipIsShared = gTrue; + softMask = state->softMask; + deleteSoftMask = gFalse; + inNonIsolatedGroup = state->inNonIsolatedGroup; + inKnockoutGroup = state->inKnockoutGroup; + rgbTransferR = state->rgbTransferR; + rgbTransferG = state->rgbTransferG; + rgbTransferB = state->rgbTransferB; + grayTransfer = state->grayTransfer; +#if SPLASH_CMYK + cmykTransferC = state->cmykTransferC; + cmykTransferM = state->cmykTransferM; + cmykTransferY = state->cmykTransferY; + cmykTransferK = state->cmykTransferK; +#endif + transferIsShared = gTrue; + overprintMask = state->overprintMask; + enablePathSimplification = state->enablePathSimplification; + next = NULL; +} + +SplashState::~SplashState() { + delete strokePattern; + delete fillPattern; + delete screen; + gfree(lineDash); + if (!clipIsShared) { + delete clip; + } + if (!transferIsShared) { + gfree(rgbTransferR); + } + if (deleteSoftMask && softMask) { + delete softMask; + } +} + +void SplashState::setStrokePattern(SplashPattern *strokePatternA) { + delete strokePattern; + strokePattern = strokePatternA; +} + +void SplashState::setFillPattern(SplashPattern *fillPatternA) { + delete fillPattern; + fillPattern = fillPatternA; +} + +void SplashState::setScreen(SplashScreen *screenA) { + delete screen; + screen = screenA; +} + +void SplashState::setLineDash(SplashCoord *lineDashA, int lineDashLengthA, + SplashCoord lineDashPhaseA) { + gfree(lineDash); + lineDashLength = lineDashLengthA; + if (lineDashLength > 0) { + lineDash = (SplashCoord *)gmallocn(lineDashLength, sizeof(SplashCoord)); + memcpy(lineDash, lineDashA, lineDashLength * sizeof(SplashCoord)); + } else { + lineDash = NULL; + } + lineDashPhase = lineDashPhaseA; +} + +GBool SplashState::lineDashContainsZeroLengthDashes() { + int i; + + if (lineDashLength == 0) { + return gFalse; + } + + // if the line dash array has an odd number of elements, we need to + // check all of the elements; if the length is even, we only need to + // check even-number elements + if (lineDashLength & 1) { + for (i = 0; i < lineDashLength; ++i) { + if (lineDash[i] == 0) { + return gTrue; + } + } + } else { + for (i = 0; i < lineDashLength; i += 2) { + if (lineDash[i] == 0) { + return gTrue; + } + } + } + return gFalse; +} + +void SplashState::clipResetToRect(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1) { + if (clipIsShared) { + clip = clip->copy(); + clipIsShared = gFalse; + } + clip->resetToRect(x0, y0, x1, y1); +} + +SplashError SplashState::clipToRect(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1) { + if (clipIsShared) { + clip = clip->copy(); + clipIsShared = gFalse; + } + return clip->clipToRect(x0, y0, x1, y1); +} + +SplashError SplashState::clipToPath(SplashPath *path, GBool eo) { + if (clipIsShared) { + clip = clip->copy(); + clipIsShared = gFalse; + } + return clip->clipToPath(path, matrix, flatness, eo, + enablePathSimplification, strokeAdjust); +} + +void SplashState::setSoftMask(SplashBitmap *softMaskA, GBool deleteBitmap) { + if (deleteSoftMask) { + delete softMask; + } + softMask = softMaskA; + deleteSoftMask = deleteBitmap; +} + +void SplashState::setTransfer(Guchar *red, Guchar *green, Guchar *blue, + Guchar *gray) { +#if SPLASH_CMYK + int i; +#endif + + if (transferIsShared) { +#if SPLASH_CMYK + rgbTransferR = (Guchar *)gmalloc(8 * 256); + rgbTransferG = rgbTransferR + 256; + rgbTransferB = rgbTransferG + 256; + grayTransfer = rgbTransferB + 256; + cmykTransferC = grayTransfer + 256; + cmykTransferM = cmykTransferC + 256; + cmykTransferY = cmykTransferM + 256; + cmykTransferK = cmykTransferY + 256; +#else + rgbTransferR = (Guchar *)gmalloc(4 * 256); + rgbTransferG = rgbTransferR + 256; + rgbTransferB = rgbTransferG + 256; + grayTransfer = rgbTransferB + 256; +#endif + transferIsShared = gFalse; + } + memcpy(rgbTransferR, red, 256); + memcpy(rgbTransferG, green, 256); + memcpy(rgbTransferB, blue, 256); + memcpy(grayTransfer, gray, 256); +#if SPLASH_CMYK + for (i = 0; i < 256; ++i) { + cmykTransferC[i] = (Guchar)(255 - rgbTransferR[255 - i]); + cmykTransferM[i] = (Guchar)(255 - rgbTransferG[255 - i]); + cmykTransferY[i] = (Guchar)(255 - rgbTransferB[255 - i]); + cmykTransferK[i] = (Guchar)(255 - grayTransfer[255 - i]); + } +#endif +} + diff --git a/splash/SplashState.h b/splash/SplashState.h new file mode 100644 index 0000000..be64b47 --- /dev/null +++ b/splash/SplashState.h @@ -0,0 +1,136 @@ +//======================================================================== +// +// SplashState.h +// +// Copyright 2003-2013 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef SPLASHSTATE_H +#define SPLASHSTATE_H + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" + +class SplashPattern; +class SplashScreen; +class SplashClip; +class SplashBitmap; +class SplashPath; + +//------------------------------------------------------------------------ +// line cap values +//------------------------------------------------------------------------ + +#define splashLineCapButt 0 +#define splashLineCapRound 1 +#define splashLineCapProjecting 2 + +//------------------------------------------------------------------------ +// line join values +//------------------------------------------------------------------------ + +#define splashLineJoinMiter 0 +#define splashLineJoinRound 1 +#define splashLineJoinBevel 2 + +//------------------------------------------------------------------------ +// SplashState +//------------------------------------------------------------------------ + +class SplashState { +public: + + // Create a new state object, initialized with default settings. + SplashState(int width, int height, GBool vectorAntialias, + SplashScreenParams *screenParams); + SplashState(int width, int height, GBool vectorAntialias, + SplashScreen *screenA); + + // Copy a state object. + SplashState *copy() { return new SplashState(this); } + + ~SplashState(); + + // Set the stroke pattern. This does not copy <strokePatternA>. + void setStrokePattern(SplashPattern *strokePatternA); + + // Set the fill pattern. This does not copy <fillPatternA>. + void setFillPattern(SplashPattern *fillPatternA); + + // Set the screen. This does not copy <screenA>. + void setScreen(SplashScreen *screenA); + + // Set the line dash pattern. This copies the <lineDashA> array. + void setLineDash(SplashCoord *lineDashA, int lineDashLengthA, + SplashCoord lineDashPhaseA); + + // Returns true if the current line dash pattern contains one or + // more zero-length "on" sections (dashes). + GBool lineDashContainsZeroLengthDashes(); + + void clipResetToRect(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1); + SplashError clipToRect(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1); + SplashError clipToPath(SplashPath *path, GBool eo); + + // Set the soft mask bitmap. + void setSoftMask(SplashBitmap *softMaskA, GBool deleteBitmap = gTrue); + + // Set the transfer function. + void setTransfer(Guchar *red, Guchar *green, Guchar *blue, Guchar *gray); + + +private: + + SplashState(SplashState *state); + + SplashCoord matrix[6]; + SplashPattern *strokePattern; + SplashPattern *fillPattern; + SplashScreen *screen; + SplashBlendFunc blendFunc; + SplashCoord strokeAlpha; + SplashCoord fillAlpha; + SplashCoord lineWidth; + int lineCap; + int lineJoin; + SplashCoord miterLimit; + SplashCoord flatness; + SplashCoord *lineDash; + int lineDashLength; + SplashCoord lineDashPhase; + SplashStrokeAdjustMode strokeAdjust; + SplashClip *clip; + GBool clipIsShared; + SplashBitmap *softMask; + GBool deleteSoftMask; + GBool inNonIsolatedGroup; + GBool inKnockoutGroup; + Guchar *rgbTransferR; + Guchar *rgbTransferG; + Guchar *rgbTransferB; + Guchar *grayTransfer; +#if SPLASH_CMYK + Guchar *cmykTransferC; + Guchar *cmykTransferM; + Guchar *cmykTransferY; + Guchar *cmykTransferK; +#endif + GBool transferIsShared; + Guint overprintMask; + GBool enablePathSimplification; + + + SplashState *next; // used by Splash class + + friend class Splash; +}; + +#endif diff --git a/splash/SplashTypes.h b/splash/SplashTypes.h new file mode 100644 index 0000000..5860884 --- /dev/null +++ b/splash/SplashTypes.h @@ -0,0 +1,145 @@ +//======================================================================== +// +// SplashTypes.h +// +// Copyright 2003-2013 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef SPLASHTYPES_H +#define SPLASHTYPES_H + +#include <aconf.h> +#include "gtypes.h" + +//------------------------------------------------------------------------ +// coordinates +//------------------------------------------------------------------------ + +#if USE_FIXEDPOINT +#include "FixedPoint.h" +typedef FixedPoint SplashCoord; +#else +typedef double SplashCoord; +#endif + +//------------------------------------------------------------------------ +// antialiasing +//------------------------------------------------------------------------ + +#define splashAASize 4 + +//------------------------------------------------------------------------ +// colors +//------------------------------------------------------------------------ + +enum SplashColorMode { + splashModeMono1, // 1 bit per component, 8 pixels per byte, + // MSbit is on the left + splashModeMono8, // 1 byte per component, 1 byte per pixel + splashModeRGB8, // 1 byte per component, 3 bytes per pixel: + // RGBRGB... + splashModeBGR8 // 1 byte per component, 3 bytes per pixel: + // BGRBGR... + +#if SPLASH_CMYK + , + splashModeCMYK8 // 1 byte per component, 4 bytes per pixel: + // CMYKCMYK... +#endif +}; + +// number of components in each color mode +// (defined in SplashState.cc) +extern int splashColorModeNComps[]; + +// max number of components in any SplashColor +#define splashMaxColorComps 3 +#if SPLASH_CMYK +# undef splashMaxColorComps +# define splashMaxColorComps 4 +#endif + +typedef Guchar SplashColor[splashMaxColorComps]; +typedef Guchar *SplashColorPtr; + +// RGB8 +static inline Guchar splashRGB8R(SplashColorPtr rgb8) { return rgb8[0]; } +static inline Guchar splashRGB8G(SplashColorPtr rgb8) { return rgb8[1]; } +static inline Guchar splashRGB8B(SplashColorPtr rgb8) { return rgb8[2]; } + +// BGR8 +static inline Guchar splashBGR8R(SplashColorPtr bgr8) { return bgr8[2]; } +static inline Guchar splashBGR8G(SplashColorPtr bgr8) { return bgr8[1]; } +static inline Guchar splashBGR8B(SplashColorPtr bgr8) { return bgr8[0]; } + +#if SPLASH_CMYK +// CMYK8 +static inline Guchar splashCMYK8C(SplashColorPtr cmyk8) { return cmyk8[0]; } +static inline Guchar splashCMYK8M(SplashColorPtr cmyk8) { return cmyk8[1]; } +static inline Guchar splashCMYK8Y(SplashColorPtr cmyk8) { return cmyk8[2]; } +static inline Guchar splashCMYK8K(SplashColorPtr cmyk8) { return cmyk8[3]; } +#endif + +static inline void splashColorCopy(SplashColorPtr dest, SplashColorPtr src) { + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; +#if SPLASH_CMYK + dest[3] = src[3]; +#endif +} + +static inline void splashColorXor(SplashColorPtr dest, SplashColorPtr src) { + dest[0] ^= src[0]; + dest[1] ^= src[1]; + dest[2] ^= src[2]; +#if SPLASH_CMYK + dest[3] ^= src[3]; +#endif +} + +//------------------------------------------------------------------------ +// blend functions +//------------------------------------------------------------------------ + +typedef void (*SplashBlendFunc)(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm); + +//------------------------------------------------------------------------ +// stroke adjustment mode +//------------------------------------------------------------------------ + +enum SplashStrokeAdjustMode { + splashStrokeAdjustOff, + splashStrokeAdjustNormal, + splashStrokeAdjustCAD +}; + +//------------------------------------------------------------------------ +// screen parameters +//------------------------------------------------------------------------ + +enum SplashScreenType { + splashScreenDispersed, + splashScreenClustered, + splashScreenStochasticClustered +}; + +struct SplashScreenParams { + SplashScreenType type; + int size; + int dotRadius; + SplashCoord gamma; + SplashCoord blackThreshold; + SplashCoord whiteThreshold; +}; + +//------------------------------------------------------------------------ +// error results +//------------------------------------------------------------------------ + +typedef int SplashError; + + +#endif diff --git a/splash/SplashXPath.cc b/splash/SplashXPath.cc new file mode 100644 index 0000000..4c77765 --- /dev/null +++ b/splash/SplashXPath.cc @@ -0,0 +1,645 @@ +//======================================================================== +// +// SplashXPath.cc +// +// Copyright 2003-2013 Glyph & Cog, LLC +// +//======================================================================== + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <stdlib.h> +#include <string.h> +#if HAVE_STD_SORT +#include <algorithm> +#endif +#include "gmem.h" +#include "gmempp.h" +#include "SplashMath.h" +#include "SplashPath.h" +#include "SplashXPath.h" + +//------------------------------------------------------------------------ + +#define minCosSquaredJoinAngle 0.75 +#define maxPointToLineDistanceSquared 0.04 + +//------------------------------------------------------------------------ + +struct SplashXPathPoint { + SplashCoord x, y; +}; + +struct SplashXPathAdjust { + int firstPt, lastPt; // range of points + GBool vert; // vertical or horizontal hint + SplashCoord x0a, x0b, // hint boundaries + xma, xmb, + x1a, x1b; + SplashCoord x0, x1, xm; // adjusted coordinates +}; + +//------------------------------------------------------------------------ + +// Transform a point from user space to device space. +inline void SplashXPath::transform(SplashCoord *matrix, + SplashCoord xi, SplashCoord yi, + SplashCoord *xo, SplashCoord *yo) { + // [ m[0] m[1] 0 ] + // [xo yo 1] = [xi yi 1] * [ m[2] m[3] 0 ] + // [ m[4] m[5] 1 ] + *xo = xi * matrix[0] + yi * matrix[2] + matrix[4]; + *yo = xi * matrix[1] + yi * matrix[3] + matrix[5]; +} + +//------------------------------------------------------------------------ +// SplashXPath +//------------------------------------------------------------------------ + +// SplashXPath segment coords are clipped to +/-maxCoord to avoid +// problems. The xMin/yMin/xMax/yMax fields are 32-bit integers, so +// coords need to be < 2^31 / aa{Horiz,Vert}. +#define maxCoord 100000000.0 + +void SplashXPath::clampCoords(SplashCoord *x, SplashCoord *y) { +#if !USE_FIXEDPOINT + if (*x > maxCoord) { + *x = maxCoord; + } else if (*x < -maxCoord) { + *x = -maxCoord; + } + if (*y > maxCoord) { + *y = maxCoord; + } else if (*y < -maxCoord) { + *y = -maxCoord; + } +#endif +} + +SplashXPath::SplashXPath(SplashPath *path, SplashCoord *matrix, + SplashCoord flatness, GBool closeSubpaths, + GBool simplify, + SplashStrokeAdjustMode strokeAdjMode) { + SplashXPathPoint *pts; + SplashCoord x0, y0, x1, y1, x2, y2, x3, y3, xsp, ysp, t; + int curSubpath, firstSegInSubpath, i; + GBool adjusted; + + //--- transform the points + pts = (SplashXPathPoint *)gmallocn(path->length, sizeof(SplashXPathPoint)); + for (i = 0; i < path->length; ++i) { + transform(matrix, path->pts[i].x, path->pts[i].y, &pts[i].x, &pts[i].y); + clampCoords(&pts[i].x, &pts[i].y); + } + + //--- do stroke adjustment + if (path->hints) { + adjusted = strokeAdjust(pts, path->hints, path->hintsLength, + strokeAdjMode); + } else { + adjusted = gFalse; + } + + //--- construct the segments + + segs = NULL; + length = size = 0; + + x0 = y0 = xsp = ysp = 0; // make gcc happy + curSubpath = 0; + firstSegInSubpath = 0; + i = 0; + while (i < path->length) { + + // first point in subpath - skip it + if (path->flags[i] & splashPathFirst) { + x0 = pts[i].x; + y0 = pts[i].y; + xsp = x0; + ysp = y0; + curSubpath = i; + ++i; + + } else { + + // curve segment + if (path->flags[i] & splashPathCurve) { + x1 = pts[i].x; + y1 = pts[i].y; + x2 = pts[i+1].x; + y2 = pts[i+1].y; + x3 = pts[i+2].x; + y3 = pts[i+2].y; + addCurve(x0, y0, x1, y1, x2, y2, x3, y3, + flatness, + (path->flags[i-1] & splashPathFirst), + (path->flags[i+2] & splashPathLast), + !closeSubpaths && + (path->flags[i-1] & splashPathFirst) && + !(path->flags[i-1] & splashPathClosed), + !closeSubpaths && + (path->flags[i+2] & splashPathLast) && + !(path->flags[i+2] & splashPathClosed)); + x0 = x3; + y0 = y3; + i += 3; + + // line segment + } else { + x1 = pts[i].x; + y1 = pts[i].y; + addSegment(x0, y0, x1, y1); + x0 = x1; + y0 = y1; + ++i; + } + + // end a subpath + if (path->flags[i-1] & splashPathLast) { + if (closeSubpaths && + (pts[i-1].x != pts[curSubpath].x || + pts[i-1].y != pts[curSubpath].y)) { + addSegment(x0, y0, xsp, ysp); + } + if (simplify && !adjusted) { + mergeSegments(firstSegInSubpath); + } + firstSegInSubpath = length; + } + } + } + + gfree(pts); + + finishSegments(); + + //--- check for a rectangle + isRect = gFalse; + rectX0 = rectY0 = rectX1 = rectY1 = 0; + if (length == 4) { +#if HAVE_STD_SORT + std::sort(segs, segs + length, SplashXPathSeg::cmpY); +#else + qsort(segs, length, sizeof(SplashXPathSeg), &SplashXPathSeg::cmpY); +#endif + if (segs[0].y0 == segs[0].y1 && + segs[1].x0 == segs[1].x1 && + segs[2].x0 == segs[2].x1 && + segs[3].y0 == segs[3].y1) { + isRect = gTrue; + rectX0 = segs[1].x0; + rectX1 = segs[2].x0; + rectY0 = segs[0].y0; + rectY1 = segs[3].y0; + } else if (segs[0].x0 == segs[0].x1 && + segs[1].y0 == segs[1].y1 && + segs[2].x0 == segs[2].x1 && + segs[3].y0 == segs[3].y1) { + isRect = gTrue; + rectX0 = segs[0].x0; + rectX1 = segs[2].x0; + rectY0 = segs[1].y0; + rectY1 = segs[3].y0; + } else if (segs[0].x0 == segs[0].x1 && + segs[1].x0 == segs[1].x1 && + segs[2].y0 == segs[2].y1 && + segs[3].y0 == segs[3].y1) { + isRect = gTrue; + rectX0 = segs[0].x0; + rectX1 = segs[1].x0; + rectY0 = segs[2].y0; + rectY1 = segs[3].y0; + } + if (isRect) { + if (rectX0 > rectX1) { + t = rectX0; rectX0 = rectX1; rectX1 = t; + } + if (rectY0 > rectY1) { + t = rectY0; rectY0 = rectY1; rectY1 = t; + } + } + } +} + +GBool SplashXPath::strokeAdjust(SplashXPathPoint *pts, + SplashPathHint *hints, int nHints, + SplashStrokeAdjustMode strokeAdjMode) { + SplashXPathAdjust *adjusts, *adjust; + SplashPathHint *hint; + SplashCoord x0, y0, x1, y1, x2, y2, x3, y3; + SplashCoord adj0, adj1, w, d; + int xi0, xi1; + int i, j; + GBool adjusted; + + adjusted = gFalse; + + // set up the stroke adjustment hints + adjusts = (SplashXPathAdjust *)gmallocn(nHints, sizeof(SplashXPathAdjust)); + for (i = 0; i < nHints; ++i) { + hint = &hints[i]; + x0 = pts[hint->ctrl0 ].x; y0 = pts[hint->ctrl0 ].y; + x1 = pts[hint->ctrl0 + 1].x; y1 = pts[hint->ctrl0 + 1].y; + x2 = pts[hint->ctrl1 ].x; y2 = pts[hint->ctrl1 ].y; + x3 = pts[hint->ctrl1 + 1].x; y3 = pts[hint->ctrl1 + 1].y; + w = -1; + if (splashAbs(x0 - x1) < 0.01 && splashAbs(x2 - x3) < 0.01) { + adjusts[i].vert = gTrue; + adj0 = x0; + adj1 = x2; + if (hint->projectingCap) { + w = splashAbs(y1 - y0); + } + } else if (splashAbs(y0 - y1) < 0.01 && splashAbs(y2 - y3) < 0.01) { + adjusts[i].vert = gFalse; + adj0 = y0; + adj1 = y2; + if (hint->projectingCap) { + w = splashAbs(x1 - x0); + } + } else { + goto done; + } + if (adj0 > adj1) { + x0 = adj0; + adj0 = adj1; + adj1 = x0; + } + d = adj1 - adj0; + if (d > 0.04) { + d = 0.01; + } else { + d *= 0.25; + } + adjusts[i].x0a = adj0 - d; + adjusts[i].x0b = adj0 + d; + adjusts[i].xma = (SplashCoord)0.5 * (adj0 + adj1) - d; + adjusts[i].xmb = (SplashCoord)0.5 * (adj0 + adj1) + d; + adjusts[i].x1a = adj1 - d; + adjusts[i].x1b = adj1 + d; + splashStrokeAdjust(adj0, adj1, &xi0, &xi1, strokeAdjMode, w); + adjusts[i].x0 = (SplashCoord)xi0; + // the "minus epsilon" thing here is needed when vector + // antialiasing is turned off -- otherwise stroke adjusted lines + // will touch an extra pixel on one edge + adjusts[i].x1 = (SplashCoord)xi1 - 0.001; + adjusts[i].xm = (SplashCoord)0.5 * (adjusts[i].x0 + adjusts[i].x1); + adjusts[i].firstPt = hint->firstPt; + adjusts[i].lastPt = hint->lastPt; + } + + // perform stroke adjustment + for (i = 0, adjust = adjusts; i < nHints; ++i, ++adjust) { + for (j = adjust->firstPt; j <= adjust->lastPt; ++j) { + if (adjust->vert) { + x0 = pts[j].x; + if (x0 > adjust->x0a && x0 < adjust->x0b) { + pts[j].x = adjust->x0; + } else if (x0 > adjust->xma && x0 < adjust->xmb) { + pts[j].x = adjust->xm; + } else if (x0 > adjust->x1a && x0 < adjust->x1b) { + pts[j].x = adjust->x1; + } + } else { + y0 = pts[j].y; + if (y0 > adjust->x0a && y0 < adjust->x0b) { + pts[j].y = adjust->x0; + } else if (y0 > adjust->xma && y0 < adjust->xmb) { + pts[j].y = adjust->xm; + } else if (y0 > adjust->x1a && y0 < adjust->x1b) { + pts[j].y = adjust->x1; + } + } + } + } + adjusted = gTrue; + + done: + gfree(adjusts); + return adjusted; +} + +SplashXPath::SplashXPath(SplashXPath *xPath) { + length = xPath->length; + size = xPath->size; + segs = (SplashXPathSeg *)gmallocn(size, sizeof(SplashXPathSeg)); + memcpy(segs, xPath->segs, length * sizeof(SplashXPathSeg)); + xMin = xPath->xMin; + yMin = xPath->yMin; + xMax = xPath->xMax; + yMax = xPath->yMax; +} + +SplashXPath::~SplashXPath() { + gfree(segs); +} + +// Add space for <nSegs> more segments +void SplashXPath::grow(int nSegs) { + if (length + nSegs > size) { + if (size == 0) { + size = 32; + } + while (size < length + nSegs) { + size *= 2; + } + segs = (SplashXPathSeg *)greallocn(segs, size, sizeof(SplashXPathSeg)); + } +} + +void SplashXPath::addCurve(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1, + SplashCoord x2, SplashCoord y2, + SplashCoord x3, SplashCoord y3, + SplashCoord flatness, + GBool first, GBool last, GBool end0, GBool end1) { + SplashCoord cx[splashMaxCurveSplits + 1][3]; + SplashCoord cy[splashMaxCurveSplits + 1][3]; + int cNext[splashMaxCurveSplits + 1]; + SplashCoord xl0, xl1, xl2, xr0, xr1, xr2, xr3, xx1, xx2, xh; + SplashCoord yl0, yl1, yl2, yr0, yr1, yr2, yr3, yy1, yy2, yh; + SplashCoord dx, dy, mx, my, d1, d2, flatness2; + int p1, p2, p3; + +#if USE_FIXEDPOINT + flatness2 = flatness; +#else + flatness2 = flatness * flatness; +#endif + + // initial segment + p1 = 0; + p2 = splashMaxCurveSplits; + cx[p1][0] = x0; cy[p1][0] = y0; + cx[p1][1] = x1; cy[p1][1] = y1; + cx[p1][2] = x2; cy[p1][2] = y2; + cx[p2][0] = x3; cy[p2][0] = y3; + cNext[p1] = p2; + + while (p1 < splashMaxCurveSplits) { + + // get the next segment + xl0 = cx[p1][0]; yl0 = cy[p1][0]; + xx1 = cx[p1][1]; yy1 = cy[p1][1]; + xx2 = cx[p1][2]; yy2 = cy[p1][2]; + p2 = cNext[p1]; + xr3 = cx[p2][0]; yr3 = cy[p2][0]; + + // compute the distances from the control points to the + // midpoint of the straight line (this is a bit of a hack, but + // it's much faster than computing the actual distances to the + // line) + mx = (xl0 + xr3) * 0.5; + my = (yl0 + yr3) * 0.5; +#if USE_FIXEDPOINT + d1 = splashDist(xx1, yy1, mx, my); + d2 = splashDist(xx2, yy2, mx, my); +#else + dx = xx1 - mx; + dy = yy1 - my; + d1 = dx*dx + dy*dy; + dx = xx2 - mx; + dy = yy2 - my; + d2 = dx*dx + dy*dy; +#endif + + // if the curve is flat enough, or no more subdivisions are + // allowed, add the straight line segment + if (p2 - p1 == 1 || (d1 <= flatness2 && d2 <= flatness2)) { + addSegment(xl0, yl0, xr3, yr3); + p1 = p2; + + // otherwise, subdivide the curve + } else { + xl1 = (xl0 + xx1) * 0.5; + yl1 = (yl0 + yy1) * 0.5; + xh = (xx1 + xx2) * 0.5; + yh = (yy1 + yy2) * 0.5; + xl2 = (xl1 + xh) * 0.5; + yl2 = (yl1 + yh) * 0.5; + xr2 = (xx2 + xr3) * 0.5; + yr2 = (yy2 + yr3) * 0.5; + xr1 = (xh + xr2) * 0.5; + yr1 = (yh + yr2) * 0.5; + xr0 = (xl2 + xr1) * 0.5; + yr0 = (yl2 + yr1) * 0.5; + // add the new subdivision points + p3 = (p1 + p2) / 2; + cx[p1][1] = xl1; cy[p1][1] = yl1; + cx[p1][2] = xl2; cy[p1][2] = yl2; + cNext[p1] = p3; + cx[p3][0] = xr0; cy[p3][0] = yr0; + cx[p3][1] = xr1; cy[p3][1] = yr1; + cx[p3][2] = xr2; cy[p3][2] = yr2; + cNext[p3] = p2; + } + } +} + +void SplashXPath::addSegment(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1) { + grow(1); + segs[length].x0 = x0; + segs[length].y0 = y0; + segs[length].x1 = x1; + segs[length].y1 = y1; + ++length; +} + +// Returns true if the angle between (x0,y0)-(x1,y1) and +// (x1,y1)-(x2,y2) is close to 180 degrees. +static GBool joinAngleIsFlat(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1, + SplashCoord x2, SplashCoord y2) { + SplashCoord dx1, dy1, dx2, dy2, d, len1, len2; + + dx1 = x1 - x0; + dy1 = y1 - y0; + dx2 = x2 - x1; + dy2 = y2 - y1; + d = dx1 * dx2 + dy1 * dy2; + len1 = dx1 * dx1 + dy1 * dy1; + len2 = dx2 * dx2 + dy2 * dy2; + return d > 0 && d * d > len1 * len2 * minCosSquaredJoinAngle; +} + +// Returns true if (x1,y1) is sufficiently close to the segment +// (x0,y0)-(x2,y2), looking at the perpendicular point-to-line +// distance. +static GBool pointCloseToSegment(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1, + SplashCoord x2, SplashCoord y2) { + SplashCoord t1, t2, dx, dy; + + // compute the perpendicular distance from the point to the segment, + // i.e., the projection of (x0,y0)-(x1,y1) onto a unit normal to the + // segment (this actually computes the square of the distance) + dx = x2 - x0; + dy = y2 - y0; + t1 = dx*dx + dy*dy; + if (t1 < 0.0001) { + // degenerate case: (x0,y0) and (x2,y2) are (nearly) identical -- + // just compute the distance to (x1,y1) + dx = x0 - x1; + dy = y0 - y1; + t2 = dx*dx + dy*dy; + return t2 < maxPointToLineDistanceSquared; + } + t2 = x1 * dy - dx * y1 - x0 * y2 + x2 * y0; + // actual distance = t2 / sqrt(t1) + return t2 * t2 < t1 * maxPointToLineDistanceSquared; +} + +// Attempt to simplify the path by merging sequences of consecutive +// segments in [first] .. [length]-1. +void SplashXPath::mergeSegments(int first) { + GBool horiz, vert; + int in, out, prev, i, j; + + in = out = first; + while (in < length) { + + // skip zero-length segments + if (segs[in].x0 == segs[in].x1 && segs[in].y0 == segs[in].y1) { + ++in; + continue; + } + + horiz = segs[in].y0 == segs[in].y1; + vert = segs[in].x0 == segs[in].x1; + + // check for a sequence of mergeable segments: in .. i + prev = in; + for (i = in + 1; i < length; ++i) { + + // skip zero-length segments + if (segs[i].x0 == segs[i].x1 && segs[i].y0 == segs[i].y1) { + continue; + } + + // check for a horizontal or vertical segment + if ((horiz && segs[in].y0 != segs[in].y1) || + (vert && segs[in].x0 != segs[in].x1)) { + break; + } + + // check the angle between segs i-1 and i + // (actually, we compare seg i to the previous non-zero-length + // segment, which may not be i-1) + if (!joinAngleIsFlat(segs[prev].x0, segs[prev].y0, + segs[i].x0, segs[i].y0, + segs[i].x1, segs[i].y1)) { + break; + } + + // check the distances from the ends of segs in .. i-1 to the + // proposed new segment + for (j = in; j < i; ++j) { + if (!pointCloseToSegment(segs[in].x0, segs[in].y0, + segs[j].x1, segs[j].y1, + segs[i].x1, segs[i].y1)) { + break; + } + } + if (j < i) { + break; + } + + prev = i; + } + + // we can merge segs: in .. i-1 + // (this may be the single segment: in) + segs[out].x0 = segs[in].x0; + segs[out].y0 = segs[in].y0; + segs[out].x1 = segs[i-1].x1; + segs[out].y1 = segs[i-1].y1; + in = i; + ++out; + } + + length = out; +} + +void SplashXPath::finishSegments() { + SplashXPathSeg *seg; + SplashCoord xMinFP, xMaxFP, yMinFP, yMaxFP, t; + int i; + + xMinFP = yMinFP = xMaxFP = yMaxFP = 0; + + for (i = 0; i < length; ++i) { + seg = &segs[i]; + + //--- compute the slopes + if (seg->y0 <= seg->y1) { + seg->count = 1; + } else { + t = seg->x0; seg->x0 = seg->x1; seg->x1 = t; + t = seg->y0; seg->y0 = seg->y1; seg->y1 = t; + seg->count = -1; + } +#if USE_FIXEDPOINT + if (seg->y0 == seg->y1 || seg->x0 == seg->x1 || + !FixedPoint::divCheck(seg->x1 - seg->x0, seg->y1 - seg->y0, + &seg->dxdy) || + !FixedPoint::divCheck(seg->y1 - seg->y0, seg->x1 - seg->x0, + &seg->dydx)) { + seg->dxdy = 0; + seg->dydx = 0; + } +#else + if (splashAbs(seg->y1 - seg->y0) < 1e-200 || + splashAbs(seg->x1 - seg->x0) < 1e-200) { + seg->dxdy = 0; + seg->dydx = 0; + } else { + seg->dxdy = (seg->x1 - seg->x0) / (seg->y1 - seg->y0); + if (seg->dxdy == 0) { + seg->dydx = 0; + } else { + seg->dydx = 1 / seg->dxdy; + } + } +#endif + + //--- update bbox + if (i == 0) { + if (seg->x0 <= seg->x1) { + xMinFP = seg->x0; + xMaxFP = seg->x1; + } else { + xMinFP = seg->x1; + xMaxFP = seg->x0; + } + yMinFP = seg->y0; + yMaxFP = seg->y1; + } else { + if (seg->x0 < xMinFP) { + xMinFP = seg->x0; + } else if (seg->x0 > xMaxFP) { + xMaxFP = seg->x0; + } + if (seg->x1 < xMinFP) { + xMinFP = seg->x1; + } else if (seg->x1 > xMaxFP) { + xMaxFP = seg->x1; + } + if (seg->y0 < yMinFP) { + yMinFP = seg->y0; + } + if (seg->y1 > yMaxFP) { + yMaxFP = seg->y1; + } + } + } + + xMin = splashFloor(xMinFP); + yMin = splashFloor(yMinFP); + xMax = splashFloor(xMaxFP); + yMax = splashFloor(yMaxFP); +} diff --git a/splash/SplashXPath.h b/splash/SplashXPath.h new file mode 100644 index 0000000..82d7889 --- /dev/null +++ b/splash/SplashXPath.h @@ -0,0 +1,143 @@ +//======================================================================== +// +// SplashXPath.h +// +// Copyright 2003-2013 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef SPLASHXPATH_H +#define SPLASHXPATH_H + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" + +class SplashPath; +struct SplashXPathPoint; +struct SplashPathHint; + +//------------------------------------------------------------------------ + +#define splashMaxCurveSplits (1 << 10) + +//------------------------------------------------------------------------ +// SplashXPathSeg +//------------------------------------------------------------------------ + +struct SplashXPathSeg { + SplashCoord x0, y0; // first endpoint (y0 <= y1) + SplashCoord x1, y1; // second endpoint + SplashCoord dxdy; // slope: delta-x / delta-y + SplashCoord dydx; // slope: delta-y / delta-x + int count; // EO/NZWN counter increment + + //----- used by SplashXPathScanner + int iy; + SplashCoord sx0, sx1, mx; + SplashXPathSeg *prev, *next; + +#if HAVE_STD_SORT + + static bool cmpMX(const SplashXPathSeg &s0, + const SplashXPathSeg &s1) { + if (s0.iy != s1.iy) { + return s0.iy < s1.iy; + } + return s0.mx < s1.mx; + } + + static bool cmpY(const SplashXPathSeg &seg0, + const SplashXPathSeg &seg1) { + return seg0.y0 < seg1.y0; + } + +#else + + static int cmpMX(const void *p0, const void *p1) { + SplashXPathSeg *s0 = (SplashXPathSeg *)p0; + SplashXPathSeg *s1 = (SplashXPathSeg *)p1; + SplashCoord cmp; + + if (s0->iy != s1->iy) { + return s0->iy - s1->iy; + } + cmp = s0->mx - s1->mx; + return (cmp < 0) ? -1 : (cmp > 0) ? 1 : 0; + } + + static int cmpY(const void *seg0, const void *seg1) { + SplashCoord cmp; + + cmp = ((SplashXPathSeg *)seg0)->y0 + - ((SplashXPathSeg *)seg1)->y0; + return (cmp > 0) ? 1 : (cmp < 0) ? -1 : 0; + } + +#endif +}; + +//------------------------------------------------------------------------ +// SplashXPath +//------------------------------------------------------------------------ + +class SplashXPath { +public: + + // Expands (converts to segments) and flattens (converts curves to + // lines) <path>. Transforms all points from user space to device + // space, via <matrix>. If <closeSubpaths> is true, closes all open + // subpaths. + SplashXPath(SplashPath *path, SplashCoord *matrix, + SplashCoord flatness, GBool closeSubpaths, + GBool simplify, SplashStrokeAdjustMode strokeAdjMode); + + // Copy an expanded path. + SplashXPath *copy() { return new SplashXPath(this); } + + ~SplashXPath(); + + int getXMin() { return xMin; } + int getXMax() { return xMax; } + int getYMin() { return yMin; } + int getYMax() { return yMax; } + +private: + + static void clampCoords(SplashCoord *x, SplashCoord *y); + SplashXPath(SplashXPath *xPath); + void transform(SplashCoord *matrix, SplashCoord xi, SplashCoord yi, + SplashCoord *xo, SplashCoord *yo); + GBool strokeAdjust(SplashXPathPoint *pts, + SplashPathHint *hints, int nHints, + SplashStrokeAdjustMode strokeAdjMode); + void grow(int nSegs); + void addCurve(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1, + SplashCoord x2, SplashCoord y2, + SplashCoord x3, SplashCoord y3, + SplashCoord flatness, + GBool first, GBool last, GBool end0, GBool end1); + void mergeSegments(int first); + void addSegment(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1); + void finishSegments(); + + SplashXPathSeg *segs; + int length, size; // length and size of segs array + int xMin, xMax; + int yMin, yMax; + + GBool isRect; + SplashCoord rectX0, rectY0, rectX1, rectY1; + + friend class SplashXPathScanner; + friend class SplashClip; + friend class Splash; +}; + +#endif diff --git a/splash/SplashXPathScanner.cc b/splash/SplashXPathScanner.cc new file mode 100644 index 0000000..3f167b8 --- /dev/null +++ b/splash/SplashXPathScanner.cc @@ -0,0 +1,620 @@ +//======================================================================== +// +// SplashXPathScanner.cc +// +// Copyright 2003-2013 Glyph & Cog, LLC +// +//======================================================================== + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include <stdlib.h> +#include <string.h> +#if HAVE_STD_SORT +#include <algorithm> +#endif +#include "gmem.h" +#include "gmempp.h" +#include "GList.h" +#include "SplashMath.h" +#include "SplashXPath.h" +#include "SplashXPathScanner.h" + +//------------------------------------------------------------------------ + +#if ANTIALIAS_256 + +#define aaVert 15 +#define aaHoriz 17 + +#else + +#define aaVert 4 +#define aaHoriz 4 + +static Guchar map16to255[17] = { + 0, + 16, + 32, + 48, + 64, + 80, + 96, + 112, + 128, + 143, + 159, + 175, + 191, + 207, + 223, + 239, + 255 +}; + +#endif + +//------------------------------------------------------------------------ + +SplashXPathScanner::SplashXPathScanner(SplashXPath *xPathA, GBool eo, + int yMinA, int yMaxA) { + xPath = xPathA; + eoMask = eo ? 1 : 0xffffffff; + yMin = yMinA; + yMax = yMaxA; + if (xPath->isRect) { + rectX0I = splashFloor(xPath->rectX0); + rectY0I = splashFloor(xPath->rectY0); + rectX1I = splashFloor(xPath->rectX1); + rectY1I = splashFloor(xPath->rectY1); + } + + pre = &preSeg; + post = &postSeg; + pre->mx = xPath->xMin - 1; + post->mx = xPath->xMax + 1; + + resetDone = gFalse; + resetAA = gFalse; +} + +SplashXPathScanner::~SplashXPathScanner() { +} + +void SplashXPathScanner::insertSegmentBefore(SplashXPathSeg *s, + SplashXPathSeg *sNext) { + SplashXPathSeg *sPrev; + + sPrev = sNext->prev; + sPrev->next = s; + s->prev = sPrev; + s->next = sNext; + sNext->prev = s; +} + +void SplashXPathScanner::removeSegment(SplashXPathSeg *s) { + SplashXPathSeg *sPrev, *sNext; + + sPrev = s->prev; + sNext = s->next; + sPrev->next = sNext; + sNext->prev = sPrev; + s->prev = s->next = NULL; +} + +void SplashXPathScanner::moveSegmentAfter(SplashXPathSeg *s, + SplashXPathSeg *sPrev) { + SplashXPathSeg *sNext; + + s->prev->next = s->next; + s->next->prev = s->prev; + + sNext = sPrev->next; + sPrev->next = s; + s->prev = sPrev; + s->next = sNext; + sNext->prev = s; +} + +void SplashXPathScanner::reset(GBool aa, GBool aaChanged) { + SplashXPathSeg *seg; + SplashCoord y; + int i; + + //--- initialize segment parameters + for (i = 0; i < xPath->length; ++i) { + seg = &xPath->segs[i]; + if (aa) { + if (aaChanged) { + seg->iy = splashFloor(seg->y0 * aaVert); + } + y = (SplashCoord)(seg->iy + 1) / (SplashCoord)aaVert; + } else { + if (aaChanged) { + seg->iy = splashFloor(seg->y0); + } + y = (SplashCoord)(seg->iy + 1); + } + seg->sx0 = seg->x0; + if (seg->y1 <= y) { + seg->sx1 = seg->x1; + } else { + seg->sx1 = seg->x0 + (y - seg->y0) * seg->dxdy; + } + seg->mx = (seg->sx0 <= seg->sx1) ? seg->sx0 : seg->sx1; + seg->prev = seg->next = NULL; + } + + //--- sort the inactive segments by iy, mx + if (aaChanged) { +#if HAVE_STD_SORT + std::sort(xPath->segs, xPath->segs + xPath->length, &SplashXPathSeg::cmpMX); +#else + qsort(xPath->segs, xPath->length, sizeof(SplashXPathSeg), + &SplashXPathSeg::cmpMX); +#endif + } + + //--- initialize the active list + pre->prev = NULL; + pre->next = post; + post->prev = pre; + post->next = NULL; + + //--- initialize the scan state + nextSeg = 0; + if (xPath->length) { + yBottomI = xPath->segs[0].iy; + if (aa) { + yBottomI -= yBottomI % aaVert; + } + } else { + yBottomI = 0; + } + yTopI = yBottomI - 1; + if (aa) { + yTop = (SplashCoord)yTopI / (SplashCoord)aaVert; + yBottom = (SplashCoord)yBottomI / (SplashCoord)aaVert; + } else { + yTop = (SplashCoord)yTopI; + yBottom = (SplashCoord)yBottomI; + } + + resetDone = gTrue; + resetAA = aa; +} + +void SplashXPathScanner::skip(int newYBottomI, GBool aa) { + SplashXPathSeg *s0, *s1,*s2; + int iy; + + yTopI = newYBottomI - 1; + yBottomI = newYBottomI; + if (aa) { + yTop = (SplashCoord)yTopI / (SplashCoord)aaVert; + yBottom = (SplashCoord)yBottomI / (SplashCoord)aaVert; + } else { + yTop = (SplashCoord)yTopI; + yBottom = (SplashCoord)yBottomI; + } + + //--- remove finished segments; update sx0, sx1, mx for active segments + s0 = pre->next; + while (s0 != post) { + s1 = s0->next; + + // check for a finished segment + if (s0->y1 < yTop) { + removeSegment(s0); + + // compute sx0, sx1, mx + } else { + if (s0->y0 >= yTop) { + s0->sx0 = s0->x0; + } else { + s0->sx0 = s0->x0 + (yTop - s0->y0) * s0->dxdy; + } + if (s0->y1 <= yBottom) { + s0->sx1 = s0->x1; + } else { + s0->sx1 = s0->x0 + (yBottom - s0->y0) * s0->dxdy; + } + s0->mx = (s0->sx0 <= s0->sx1) ? s0->sx0 : s0->sx1; + } + + s0 = s1; + } + + //--- check for intersections + s0 = pre->next; + if (s0 != post) { + s1 = s0->next; + while (s1 != post) { + if (s1->mx < s0->mx) { + for (s2 = s0->prev; s1->mx < s2->mx; s2 = s2->prev) ; + moveSegmentAfter(s1, s2); + } else { + s0 = s1; + } + s1 = s0->next; + } + } + + //--- insert new segments with a merge sort + // - this has to be done one (sub)scanline at a time, because the + // inactive list is bin-sorted by (sub)scanline + while (nextSeg < xPath->length && xPath->segs[nextSeg].iy <= yTopI) { + // the first inactive segment determines the next scanline to process + iy = xPath->segs[nextSeg].iy; + s0 = pre->next; + do { + s1 = &xPath->segs[nextSeg]; + ++nextSeg; + if (s1->y1 < yTop) { + continue; + } + if (s1->y0 >= yTop) { + s1->sx0 = s1->x0; + } else { + s1->sx0 = s1->x0 + (yTop - s1->y0) * s1->dxdy; + } + if (s1->y1 <= yBottom) { + s1->sx1 = s1->x1; + } else { + s1->sx1 = s1->x0 + (yBottom - s1->y0) * s1->dxdy; + } + s1->mx = (s1->sx0 <= s1->sx1) ? s1->sx0 : s1->sx1; + insertSegmentBefore(s1, s0); + } while (nextSeg < xPath->length && xPath->segs[nextSeg].iy <= iy); + } +} + +void SplashXPathScanner::advance(GBool aa) { + SplashXPathSeg *s, *sNext, *s1; + + yTopI = yBottomI; + yTop = yBottom; + yBottomI = yTopI + 1; + if (aa) { + yBottom = (SplashCoord)yBottomI / (SplashCoord)aaVert; + } else { + yBottom = (SplashCoord)yBottomI; + } + + s = pre->next; + while (s != post) { + sNext = s->next; + + // check for a finished segment + if (s->y1 < yTop) { + removeSegment(s); + + } else { + + // compute sx0, sx1, mx + s->sx0 = s->sx1; + if (s->y1 <= yBottom) { + s->sx1 = s->x1; + } else { + s->sx1 = s->x0 + (yBottom - s->y0) * s->dxdy; + } + s->mx = (s->sx0 <= s->sx1) ? s->sx0 : s->sx1; + + // check for intersection + if (s->mx < s->prev->mx) { + for (s1 = s->prev->prev; s->mx < s1->mx; s1 = s1->prev) ; + moveSegmentAfter(s, s1); + } + } + + s = sNext; + } + + // insert new segments + s = pre->next; + while (nextSeg < xPath->length && xPath->segs[nextSeg].iy <= yTopI) { + s1 = &xPath->segs[nextSeg]; + ++nextSeg; + while (s1->mx > s->mx) { + s = s->next; + } + insertSegmentBefore(s1, s); + } +} + +void SplashXPathScanner::generatePixels(int x0, int x1, Guchar *line, + int *xMin, int *xMax) { + SplashXPathSeg *s; + int fillCount, x, xEnd, ix0, ix1, t; + + fillCount = 0; + x = x0 * aaHoriz; + xEnd = (x1 + 1) * aaHoriz; + for (s = pre->next; s != post && x < xEnd; s = s->next) { + ix0 = splashFloor(s->sx0 * aaHoriz); + ix1 = splashFloor(s->sx1 * aaHoriz); + if (ix0 > ix1) { + t = ix0; ix0 = ix1; ix1 = t; + } + if (!(fillCount & eoMask)) { + if (ix0 > x) { + x = ix0; + } + } + if (ix1 >= xEnd) { + ix1 = xEnd - 1; + } + if (x / aaHoriz < *xMin) { + *xMin = x / aaHoriz; + } + if (ix1 / aaHoriz > *xMax) { + *xMax = ix1 / aaHoriz; + } + for (; x <= ix1; ++x) { + ++line[x / aaHoriz]; + } + if (s->y0 <= yTop && s->y1 > yTop) { + fillCount += s->count; + } + } +} + +void SplashXPathScanner::generatePixelsBinary(int x0, int x1, Guchar *line, + int *xMin, int *xMax) { + SplashXPathSeg *s; + int fillCount, x, xEnd, ix0, ix1, t; + + fillCount = 0; + x = x0; + xEnd = x1 + 1; + for (s = pre->next; s != post && x < xEnd; s = s->next) { + ix0 = splashFloor(s->sx0); + ix1 = splashFloor(s->sx1); + if (ix0 > ix1) { + t = ix0; ix0 = ix1; ix1 = t; + } + if (!(fillCount & eoMask)) { + if (ix0 > x) { + x = ix0; + } + } + if (ix1 >= xEnd) { + ix1 = xEnd - 1; + } + if (x < *xMin) { + *xMin = x; + } + if (ix1 > *xMax) { + *xMax = ix1; + } + for (; x <= ix1; ++x) { + line[x] = 255; + } + if (s->y0 <= yTop && s->y1 > yTop) { + fillCount += s->count; + } + } +} + +void SplashXPathScanner::drawRectangleSpan(Guchar *line, int y, + int x0, int x1, + int *xMin, int *xMax) { + SplashCoord edge; + Guchar pix; + int xe, x; + + if (rectX0I > x1 || rectX1I < x0) { + return; + } + + *xMin = x0 <= rectX0I ? rectX0I : x0; + *xMax = rectX1I <= x1 ? rectX1I : x1; + + //--- upper edge + if (y == rectY0I) { + + // handle a rectangle less than one pixel high + if (rectY0I == rectY1I) { + edge = xPath->rectY1 - xPath->rectY0; + } else { + edge = (SplashCoord)1 - (xPath->rectY0 - rectY0I); + } + + // upper left corner + if (x0 <= rectX0I) { + pix = (Guchar)splashCeil(edge + * ((SplashCoord)1 - (xPath->rectX0 - rectX0I)) + * 255); + if (pix < 16) { + pix = 16; + } + line[rectX0I] = pix; + x = rectX0I + 1; + } else { + x = x0; + } + + // upper right corner + if (rectX1I <= x1) { + pix = (Guchar)splashCeil(edge * (xPath->rectX1 - rectX1I) * 255); + if (pix < 16) { + pix = 16; + } + line[rectX1I] = pix; + xe = rectX1I - 1; + } else { + xe = x1; + } + + // upper edge + pix = (Guchar)splashCeil(edge * 255); + if (pix < 16) { + pix = 16; + } + for (; x <= xe; ++x) { + line[x] = pix; + } + + //--- lower edge + } else if (y == rectY1I) { + edge = xPath->rectY1 - rectY1I; + + // lower left corner + if (x0 <= rectX0I) { + pix = (Guchar)splashCeil(edge + * ((SplashCoord)1 - (xPath->rectX0 - rectX0I)) + * 255); + if (pix < 16) { + pix = 16; + } + line[rectX0I] = pix; + x = rectX0I + 1; + } else { + x = x0; + } + + // lower right corner + if (rectX1I <= x1) { + pix = (Guchar)splashCeil(edge * (xPath->rectX1 - rectX1I) * 255); + if (pix < 16) { + pix = 16; + } + line[rectX1I] = pix; + xe = rectX1I - 1; + } else { + xe = x1; + } + + // lower edge + pix = (Guchar)splashCeil(edge * 255); + if (pix < 16) { + pix = 16; + } + for (; x <= xe; ++x) { + line[x] = pix; + } + + //--- between the upper and lower edges + } else if (y > rectY0I && y < rectY1I) { + + // left edge + if (x0 <= rectX0I) { + pix = (Guchar)splashCeil(((SplashCoord)1 - (xPath->rectX0 - rectX0I)) + * 255); + if (pix < 16) { + pix = 16; + } + line[rectX0I] = pix; + x = rectX0I + 1; + } else { + x = x0; + } + + // right edge + if (rectX1I <= x1) { + pix = (Guchar)splashCeil((xPath->rectX1 - rectX1I) * 255); + if (pix < 16) { + pix = 16; + } + line[rectX1I] = pix; + xe = rectX1I - 1; + } else { + xe = x1; + } + + // middle + for (; x <= xe; ++x) { + line[x] = 255; + } + } +} + +void SplashXPathScanner::drawRectangleSpanBinary(Guchar *line, int y, + int x0, int x1, + int *xMin, int *xMax) { + int xe, x; + + if (y >= rectY0I && y <= rectY1I) { + if (x0 <= rectX0I) { + x = rectX0I; + } else { + x = x0; + } + *xMin = x; + if (rectX1I <= x1) { + xe = rectX1I; + } else { + xe = x1; + } + *xMax = xe; + for (; x <= xe; ++x) { + line[x] = 255; + } + } +} + +void SplashXPathScanner::getSpan(Guchar *line, int y, int x0, int x1, + int *xMin, int *xMax) { + int iy, x, k; + + iy = y * aaVert; + if (!resetDone || !resetAA) { + reset(gTrue, gTrue); + } else if (yBottomI > iy) { + reset(gTrue, gFalse); + } + memset(line + x0, 0, x1 - x0 + 1); + + *xMin = x1 + 1; + *xMax = x0 - 1; + + if (xPath->isRect) { + drawRectangleSpan(line, y, x0, x1, xMin, xMax); + return; + } + + if (yBottomI < iy) { + skip(iy, gTrue); + } + for (k = 0; k < aaVert; ++k, ++iy) { + advance(gTrue); + generatePixels(x0, x1, line, xMin, xMax); + } + +#if !ANTIALIAS_256 + for (x = *xMin; x <= *xMax; ++x) { + line[x] = map16to255[line[x]]; + } +#endif +} + +void SplashXPathScanner::getSpanBinary(Guchar *line, int y, int x0, int x1, + int *xMin, int *xMax) { + int iy; + + iy = y; + if (!resetDone || resetAA) { + reset(gFalse, gTrue); + } else if (yBottomI > iy) { + reset(gFalse, gFalse); + } + memset(line + x0, 0, x1 - x0 + 1); + + *xMin = x1 + 1; + *xMax = x0 - 1; + + if (xPath->isRect) { + drawRectangleSpanBinary(line, y, x0, x1, xMin, xMax); + return; + } + + if (yBottomI < iy) { + skip(iy, gFalse); + } + advance(gFalse); + generatePixelsBinary(x0, x1, line, xMin, xMax); +} diff --git a/splash/SplashXPathScanner.h b/splash/SplashXPathScanner.h new file mode 100644 index 0000000..39cc0eb --- /dev/null +++ b/splash/SplashXPathScanner.h @@ -0,0 +1,84 @@ +//======================================================================== +// +// SplashXPathScanner.h +// +// Copyright 2003-2013 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef SPLASHXPATHSCANNER_H +#define SPLASHXPATHSCANNER_H + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" +#include "SplashXPath.h" + +class GList; + +//------------------------------------------------------------------------ + +// Set this to 0 for antialiasing with 16 levels of gray. +// Set it to 1 for (much slower) antialiasing with 256 levels of gray. +#define ANTIALIAS_256 0 + +//------------------------------------------------------------------------ +// SplashXPathScanner +//------------------------------------------------------------------------ + +class SplashXPathScanner { +public: + + // Create a new SplashXPathScanner object. <xPathA> must be sorted. + SplashXPathScanner(SplashXPath *xPathA, GBool eo, + int yMinA, int yMaxA); + + ~SplashXPathScanner(); + + // Compute shape values for a scan line. Fills in line[] with shape + // values for one scan line: ([x0, x1], y). The values are in [0, + // 255]. Also returns the min/max x positions with non-zero shape + // values. + void getSpan(Guchar *line, int y, int x0, int x1, int *xMin, int *xMax); + + // Like getSpan(), but uses the values 0 and 255 only. Writes 255 + // for all pixels which include non-zero area inside the path. + void getSpanBinary(Guchar *line, int y, int x0, int x1, + int *xMin, int *xMax); + +private: + + void insertSegmentBefore(SplashXPathSeg *s, SplashXPathSeg *sNext); + void removeSegment(SplashXPathSeg *s); + void moveSegmentAfter(SplashXPathSeg *s, SplashXPathSeg *sPrev); + void reset(GBool aa, GBool aaChanged); + void skip(int newYBottomI, GBool aa); + void advance(GBool aa); + void generatePixels(int x0, int x1, Guchar *line, int *xMin, int *xMax); + void generatePixelsBinary(int x0, int x1, Guchar *line, + int *xMin, int *xMax); + void drawRectangleSpan(Guchar *line, int y, int x0, int x1, + int *xMin, int *xMax); + void drawRectangleSpanBinary(Guchar *line, int y, int x0, int x1, + int *xMin, int *xMax); + + SplashXPath *xPath; + int eoMask; + int yMin, yMax; + int rectX0I, rectY0I, rectX1I, rectY1I; + + SplashXPathSeg preSeg, postSeg; + SplashXPathSeg *pre, *post; + + GBool resetDone; + GBool resetAA; + int nextSeg; + int yTopI, yBottomI; + SplashCoord yTop, yBottom; +}; + +#endif diff --git a/splash/cmake_install.cmake b/splash/cmake_install.cmake new file mode 100644 index 0000000..b77fd18 --- /dev/null +++ b/splash/cmake_install.cmake @@ -0,0 +1,44 @@ +# Install script for directory: /home/calvin/src/xpdf-4.04/splash + +# Set the install prefix +if(NOT DEFINED CMAKE_INSTALL_PREFIX) + set(CMAKE_INSTALL_PREFIX "/usr/local") +endif() +string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") + +# Set the install configuration name. +if(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME) + if(BUILD_TYPE) + string(REGEX REPLACE "^[^A-Za-z0-9_]+" "" + CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}") + else() + set(CMAKE_INSTALL_CONFIG_NAME "") + endif() + message(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"") +endif() + +# Set the component getting installed. +if(NOT CMAKE_INSTALL_COMPONENT) + if(COMPONENT) + message(STATUS "Install component: \"${COMPONENT}\"") + set(CMAKE_INSTALL_COMPONENT "${COMPONENT}") + else() + set(CMAKE_INSTALL_COMPONENT) + endif() +endif() + +# Install shared libraries without execute permission? +if(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE) + set(CMAKE_INSTALL_SO_NO_EXE "1") +endif() + +# Is this installation the result of a crosscompile? +if(NOT DEFINED CMAKE_CROSSCOMPILING) + set(CMAKE_CROSSCOMPILING "FALSE") +endif() + +# Set default install directory permissions. +if(NOT DEFINED CMAKE_OBJDUMP) + set(CMAKE_OBJDUMP "/usr/bin/objdump") +endif() + diff --git a/splash/libsplash.a b/splash/libsplash.a Binary files differnew file mode 100644 index 0000000..3be214e --- /dev/null +++ b/splash/libsplash.a |