Merge remote-tracking branch 'origin/poppler-0.20'
Conflicts:
poppler/Form.cc
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7386cfd..8836ae4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -15,8 +15,8 @@
test_big_endian(WORDS_BIGENDIAN)
set(POPPLER_MAJOR_VERSION "0")
-set(POPPLER_MINOR_VERSION "20")
-set(POPPLER_MICRO_VERSION "5")
+set(POPPLER_MINOR_VERSION "21")
+set(POPPLER_MICRO_VERSION "0")
set(POPPLER_VERSION "${POPPLER_MAJOR_VERSION}.${POPPLER_MINOR_VERSION}.${POPPLER_MICRO_VERSION}")
# command line switches
@@ -28,7 +28,7 @@
option(ENABLE_UTILS "Compile poppler command line utils." ON)
option(ENABLE_CPP "Compile poppler cpp wrapper." ON)
option(ENABLE_LIBOPENJPEG "Use libopenjpeg for JPX streams." ON)
-option(ENABLE_LCMS "Use liblcms for color management." ON)
+set(ENABLE_CMS "auto" CACHE STRING "Use color management system. Possible values: auto, lcms1, lcms2. 'auto' prefers lcms2 over lcms1 if both are available. Unset to disable color management system.")
option(ENABLE_LIBCURL "Build libcurl based HTTP support." OFF)
option(ENABLE_ZLIB "Build with zlib (not totally safe)." OFF)
option(USE_FIXEDPOINT "Use fixed point arithmetic in the Splash backend" OFF)
@@ -136,16 +136,22 @@
set(ENABLE_LIBOPENJPEG ${LIBOPENJPEG_FOUND})
set(HAVE_OPENJPEG_H ON)
endif(ENABLE_LIBOPENJPEG)
-if(ENABLE_LCMS)
+if(ENABLE_CMS STREQUAL "auto")
find_package(LCMS2)
- if(LCMS2_FOUND)
- set(USE_CMS ${LCMS2_FOUND})
- else(LCMS2_FOUND)
+ set(USE_CMS ${LCMS2_FOUND})
+ if(NOT LCMS2_FOUND)
find_package(LCMS)
set(USE_CMS ${LCMS_FOUND})
set(USE_LCMS1 ${LCMS_FOUND})
- endif(LCMS2_FOUND)
-endif(ENABLE_LCMS)
+ endif(NOT LCMS2_FOUND)
+elseif(ENABLE_CMS STREQUAL "lcms1")
+ find_package(LCMS)
+ set(USE_CMS ${LCMS_FOUND})
+ set(USE_LCMS1 ${LCMS_FOUND})
+elseif(ENABLE_CMS STREQUAL "lcms2")
+ find_package(LCMS2)
+ set(USE_CMS ${LCMS2_FOUND})
+endif()
if(ENABLE_LIBCURL)
find_package(CURL)
include_directories(${CURL_INCLUDE_DIR})
@@ -237,6 +243,7 @@
goo/JpegWriter.cc
goo/ImgWriter.cc
goo/gstrtod.cc
+ goo/grandom.cc
fofi/FoFiBase.cc
fofi/FoFiEncodings.cc
fofi/FoFiTrueType.cc
@@ -290,6 +297,7 @@
poppler/strtok_r.cpp
poppler/UnicodeMap.cc
poppler/UnicodeTypeTable.cc
+ poppler/UTF.cc
poppler/XRef.cc
poppler/PSOutputDev.cc
poppler/TextOutputDev.cc
@@ -386,7 +394,7 @@
else(MSVC)
add_library(poppler SHARED ${poppler_SRCS})
endif(MSVC)
-set_target_properties(poppler PROPERTIES VERSION 28.0.0 SOVERSION 28)
+set_target_properties(poppler PROPERTIES VERSION 29.0.0 SOVERSION 29)
target_link_libraries(poppler ${poppler_LIBS})
target_link_libraries(poppler LINK_INTERFACE_LIBRARIES "")
install(TARGETS poppler RUNTIME DESTINATION bin LIBRARY DESTINATION lib${LIB_SUFFIX} ARCHIVE DESTINATION lib${LIB_SUFFIX})
@@ -460,6 +468,7 @@
poppler/SecurityHandler.h
poppler/StdinCachedFile.h
poppler/StdinPDFDocBuilder.h
+ poppler/UTF.h
poppler/UTF8.h
poppler/XpdfPluginAPI.h
poppler/Sound.h
@@ -478,6 +487,7 @@
goo/ImgWriter.h
goo/GooLikely.h
goo/gstrtod.h
+ goo/grandom.h
DESTINATION include/poppler/goo)
if(PNG_FOUND)
install(FILES
diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake
index 04de970..6e547ed 100644
--- a/ConfigureChecks.cmake
+++ b/ConfigureChecks.cmake
@@ -33,6 +33,7 @@
check_function_exists(popen HAVE_POPEN)
check_function_exists(mkstemp HAVE_MKSTEMP)
check_function_exists(mkstemps HAVE_MKSTEMPS)
+check_function_exists(rand_r HAVE_RAND_R)
macro(CHECK_FOR_DIR include var)
check_c_source_compiles(
diff --git a/NEWS b/NEWS
index f29ea93..c0381a5 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,42 @@
+Release 0.21.0
+ core:
+ * Support the modification of files with Encrypt
+ * Annotation improvements
+ * Form improvements
+ * Splash: Implement DeviceN support
+ * Splash: Avoid bogus memory error for tilingPattern
+ * TextOutputDev: Allow multiple fonts in a TextWord
+ * Kill the concept of base dir
+ * PSOutputDev: Always write HiResBoundingBox (Bug #53159)
+ * Convert UTF-16 to UCS-4 when reading toUnicode cmap
+ * GooString formatting: add support for uppercase hexadecimal
+ * Use error() instead of fprintf(stderr, ...) in Annot::layoutText
+ * poppler-config.h: remove WITH_FONTCONFIGURATION_* macros
+
+ glib:
+ * Annotation improvements
+ * Add poppler_page_remove_annot()
+ * Add poppler_document_new_from_stream
+ * Add poppler_document_new_from_gfile
+ * Add poppler_page_find_text_with_options (Bug #2951)
+ * Demo improvements
+ * Port tests and demo to GTK+3
+
+ qt4:
+ * Add accessor methods for movie poster information
+ * Make 'additional actions' available in Annotation API (Bug #53589)
+ * Add whole-page search method to Poppler::Page
+ * Small changes in tests
+
+ utils:
+ * pdftohtml: Make the output more xhtml compliant
+ * pdftohtml: Add -fontfullname. (Bug #49872)
+ * pdftohtml: Do not invoke gs anymore
+
+ build system:
+ * Add the possibility of using lcms1 even if lcms2 is installed
+ * Remove extra fontconfig CFLAGS and LIBS
+
Release 0.20.5
core:
* Fix crashes in malformed documents
diff --git a/cmake/modules/FindGTK.cmake b/cmake/modules/FindGTK.cmake
index 4d66bd3..1a32483 100644
--- a/cmake/modules/FindGTK.cmake
+++ b/cmake/modules/FindGTK.cmake
@@ -2,8 +2,8 @@
# Once done this will define
#
# GTK_FOUND - system has GTK
-# GTK2_CFLAGS - the GTK CFlags
-# GTK2_LIBRARIES - Link these to use GTK
+# GTK3_CFLAGS - the GTK CFlags
+# GTK3_LIBRARIES - Link these to use GTK
#
# Copyright 2008-2010 Pino Toscano, <pino@kde.org>
#
@@ -15,8 +15,8 @@
if (NOT WIN32)
find_package(PkgConfig REQUIRED)
- pkg_check_modules(GTK2 "gtk+-2.0>=2.14" "gdk-pixbuf-2.0" "gthread-2.0" "gio-2.0")
+ pkg_check_modules(GTK3 "gtk+-3.0>=3.0" "gdk-pixbuf-2.0" "gthread-2.0" "gio-2.0")
- find_package_handle_standard_args(GTK DEFAULT_MSG GTK2_LIBRARIES GTK2_CFLAGS)
+ find_package_handle_standard_args(GTK DEFAULT_MSG GTK3_LIBRARIES GTK3_CFLAGS)
endif(NOT WIN32)
diff --git a/config.h.cmake b/config.h.cmake
index 3c7b968..cde219f 100644
--- a/config.h.cmake
+++ b/config.h.cmake
@@ -76,6 +76,9 @@
/* Define to 1 if you have the `mkstemps' function. */
#cmakedefine HAVE_MKSTEMPS 1
+/* Define to 1 if you have the `rand_r' function. */
+#cmakedefine HAVE_RAND_R 1
+
/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
#cmakedefine HAVE_NDIR_H 1
diff --git a/configure.ac b/configure.ac
index 7b6fb31..2c44efb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
m4_define([poppler_version_major],[0])
-m4_define([poppler_version_minor],[20])
-m4_define([poppler_version_micro],[5])
+m4_define([poppler_version_minor],[21])
+m4_define([poppler_version_micro],[0])
m4_define([poppler_version],[poppler_version_major.poppler_version_minor.poppler_version_micro])
AC_PREREQ(2.59)
@@ -133,6 +133,7 @@
AC_CHECK_DECL(gettimeofday, [AC_CHECK_FUNC(gettimeofday, AC_DEFINE(HAVE_GETTIMEOFDAY, 1, [Defines if gettimeofday is available on your system]))],[],[#include <sys/time.h>])
AC_CHECK_FUNC(localtime_r, AC_DEFINE(HAVE_LOCALTIME_R, 1, [Defines if localtime_r is available on your system]))
AC_CHECK_FUNC(gmtime_r, AC_DEFINE(HAVE_GMTIME_R, 1, [Defines if gmtime_r is available on your system]))
+AC_CHECK_FUNC(rand_r, AC_DEFINE(HAVE_RAND_R, 1, [Defines if rand_r is available on your system]))
dnl ##### Check for extra libraries needed by X. (LynxOS needs this.)
AC_CHECK_FUNC(gethostbyname)
@@ -531,12 +532,12 @@
enable_poppler_glib=$enableval,
enable_poppler_glib="try")
if test x$enable_poppler_glib = xyes; then
- PKG_CHECK_MODULES(POPPLER_GLIB, glib-2.0 >= $GLIB_REQUIRED gobject-2.0 >= $GLIB_REQUIRED cairo >= $CAIRO_VERSION)
+ PKG_CHECK_MODULES(POPPLER_GLIB, glib-2.0 >= $GLIB_REQUIRED gobject-2.0 >= $GLIB_REQUIRED gio-2.0 >= $GLIB_REQUIRED cairo >= $CAIRO_VERSION)
elif test x$enable_poppler_glib = xtry; then
- PKG_CHECK_MODULES(POPPLER_GLIB, glib-2.0 >= $GLIB_REQUIRED gobject-2.0 >= $GLIB_REQUIRED cairo >= $CAIRO_VERSION,
+ PKG_CHECK_MODULES(POPPLER_GLIB, glib-2.0 >= $GLIB_REQUIRED gobject-2.0 >= $GLIB_REQUIRED gio-2.0 >= $GLIB_REQUIRED cairo >= $CAIRO_VERSION,
[enable_poppler_glib="yes"],
[enable_poppler_glib="no"
- use_glib="no (requires glib-2.0 >= $GLIB_REQUIRED gobject-2.0 >= $GLIB_REQUIRED cairo >= $CAIRO_VERSION)"])
+ use_glib="no (requires glib-2.0 >= $GLIB_REQUIRED gobject-2.0 >= $GLIB_REQUIRED gio-2.0 >= $GLIB_REQUIRED cairo >= $CAIRO_VERSION)"])
fi
if test x$enable_poppler_glib = xyes; then
# Check for introspection
@@ -644,9 +645,9 @@
enable_gtk_test=$enableval,
enable_gtk_test="try")
if test x$enable_gtk_test = xyes; then
- PKG_CHECK_MODULES(GTK_TEST, gtk+-2.0 >= 2.14 gdk-pixbuf-2.0 gthread-2.0 gio-2.0)
+ PKG_CHECK_MODULES(GTK_TEST, gtk+-3.0 >= 3.0 gdk-pixbuf-2.0)
elif test x$enable_gtk_test = xtry; then
- PKG_CHECK_MODULES(GTK_TEST, gtk+-2.0 >= 2.14 gdk-pixbuf-2.0 gthread-2.0 gio-2.0,
+ PKG_CHECK_MODULES(GTK_TEST, gtk+-3.0 >= 3.0 gdk-pixbuf-2.0,
[enable_gtk_test="yes"],
[enable_gtk_test="no"])
fi
@@ -660,7 +661,7 @@
AM_CONDITIONAL(BUILD_UTILS, test x$enable_utils = xyes)
AC_ARG_ENABLE(compile-warnings,
- AC_HELP_STRING([--enable-compile-warnings=@<:@no/yes/kde@:>@]
+ AC_HELP_STRING([--enable-compile-warnings=@<:@no/yes/kde@:>@],
[Turn on compiler warnings.]),,
[enable_compile_warnings="yes"])
@@ -669,31 +670,30 @@
dnl
AC_ARG_ENABLE(cms,
- AC_HELP_STRING([--disable-cms],
- [Don't use color management system.]),
- enable_cms=$enableval,
- enable_cms="try")
-if test x$enable_cms = xyes; then
+ AC_HELP_STRING([--enable-cms=@<:@auto/lcms1/lcms2/none@:>@],
+ [Use color management system. 'auto' prefers lcms2 over lcms1 if both are available [[default=auto]]]),
+ [enable_cms=$enableval],
+ [enable_cms="auto"])
+if test x$enable_cms = xauto; then
PKG_CHECK_MODULES(LCMS, lcms2, [lcms2=yes], [lcms2=no])
if test x$lcms2 = xno; then
- PKG_CHECK_MODULES(LCMS, lcms)
+ PKG_CHECK_MODULES(LCMS, lcms, [lcms1=yes], [lcms1=no])
fi
-elif test x$enable_cms = xtry; then
- PKG_CHECK_MODULES(LCMS, lcms2,[lcms2=yes],[lcms2=no])
- if test x$lcms2 = xyes; then
- enable_cms=yes
- else
- PKG_CHECK_MODULES(LCMS, lcms,[enable_cms=yes],[enable_cms=no])
- fi
+elif test x$enable_cms = xlcms1; then
+ PKG_CHECK_MODULES(LCMS, lcms, [lcms1=yes], [lcms1=no])
+elif test x$enable_cms = xlcms2; then
+ PKG_CHECK_MODULES(LCMS, lcms2, [lcms2=yes], [lcms2=no])
fi
-if test "x$enable_cms" = "xyes"; then
+if test x$lcms1 = xyes || test x$lcms2 = xyes; then
+ enable_cms=yes
AC_DEFINE(USE_CMS, 1, [Defines if use cms])
- if test "x$lcms2" != "xyes"; then
+ if test x$lcms1 = xyes; then
lcms1=yes;
AC_DEFINE(USE_LCMS1, 1, [Defines if use lcms1])
fi
fi
+
AM_CONDITIONAL(USE_CMS, test x$enable_cms = xyes)
AM_CONDITIONAL(USE_LCMS1, test x$lcms1 = xyes)
diff --git a/cpp/Doxyfile b/cpp/Doxyfile
index c63ae5a..8a2aa70 100644
--- a/cpp/Doxyfile
+++ b/cpp/Doxyfile
@@ -31,7 +31,7 @@
# This could be handy for archiving the generated documentation or
# if some version control system is used.
-PROJECT_NUMBER = 0.20.5
+PROJECT_NUMBER = 0.21.0
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
# base path where the generated documentation will be put.
diff --git a/glib/CMakeLists.txt b/glib/CMakeLists.txt
index 92e23bd..a6f1e89 100644
--- a/glib/CMakeLists.txt
+++ b/glib/CMakeLists.txt
@@ -69,6 +69,8 @@
poppler-movie.cc
poppler-media.cc
poppler.cc
+ poppler-cached-file-loader.cc
+ poppler-input-stream.cc
)
set(poppler_glib_generated_SRCS
${CMAKE_CURRENT_BINARY_DIR}/poppler-enums.c
@@ -77,7 +79,7 @@
${CMAKE_SOURCE_DIR}/poppler/CairoRescaleBox.cc
)
add_library(poppler-glib SHARED ${poppler_glib_SRCS} ${poppler_glib_generated_SRCS})
-set_target_properties(poppler-glib PROPERTIES VERSION 8.4.0 SOVERSION 8)
+set_target_properties(poppler-glib PROPERTIES VERSION 8.5.0 SOVERSION 8)
target_link_libraries(poppler-glib poppler ${GLIB2_LIBRARIES} ${CAIRO_LIBRARIES} ${FREETYPE_LIBRARIES})
install(TARGETS poppler-glib RUNTIME DESTINATION bin LIBRARY DESTINATION lib${LIB_SUFFIX} ARCHIVE DESTINATION lib${LIB_SUFFIX})
diff --git a/glib/Makefile.am b/glib/Makefile.am
index 83c724f..f1a8b7a 100644
--- a/glib/Makefile.am
+++ b/glib/Makefile.am
@@ -7,7 +7,6 @@
-I$(top_srcdir)/poppler \
$(POPPLER_GLIB_CFLAGS) \
$(FREETYPE_CFLAGS) \
- $(FONTCONFIG_CFLAGS) \
$(POPPLER_GLIB_DISABLE_DEPRECATED) \
$(POPPLER_GLIB_DISABLE_SINGLE_INCLUDES)
@@ -64,6 +63,10 @@
poppler-layer.cc \
poppler-media.cc \
poppler-movie.cc \
+ poppler-cached-file-loader.cc \
+ poppler-cached-file-loader.h \
+ poppler-input-stream.cc \
+ poppler-input-stream.h \
poppler.cc \
poppler-private.h
@@ -71,10 +74,9 @@
$(top_builddir)/poppler/libpoppler.la \
$(top_builddir)/poppler/libpoppler-cairo.la \
$(POPPLER_GLIB_LIBS) \
- $(FREETYPE_LIBS) \
- $(FONTCONFIG_LIBS)
+ $(FREETYPE_LIBS)
-libpoppler_glib_la_LDFLAGS = -version-info 12:0:4 @create_shared_lib@ @auto_import_flags@
+libpoppler_glib_la_LDFLAGS = -version-info 13:0:5 @create_shared_lib@ @auto_import_flags@
BUILT_SOURCES = \
poppler-enums.c \
diff --git a/glib/demo/CMakeLists.txt b/glib/demo/CMakeLists.txt
index 286fbd7..316371e 100644
--- a/glib/demo/CMakeLists.txt
+++ b/glib/demo/CMakeLists.txt
@@ -1,8 +1,8 @@
include_directories(
- ${GTK2_INCLUDE_DIRS}
+ ${GTK3_INCLUDE_DIRS}
)
-add_definitions(${GTK2_CFLAGS_OTHER})
+add_definitions(${GTK3_CFLAGS_OTHER})
set(poppler_glib_demo_SRCS
main.c
@@ -25,4 +25,4 @@
selections.c
)
poppler_add_test(poppler-glib-demo BUILD_GTK_TESTS ${poppler_glib_demo_SRCS})
-target_link_libraries(poppler-glib-demo poppler-glib ${GTK2_LIBRARIES})
+target_link_libraries(poppler-glib-demo poppler-glib ${GTK3_LIBRARIES})
diff --git a/glib/demo/annots.c b/glib/demo/annots.c
index 7075028..e0b5d91 100644
--- a/glib/demo/annots.c
+++ b/glib/demo/annots.c
@@ -40,6 +40,7 @@
PopplerDocument *doc;
PopplerPage *page;
+ GtkWidget *tree_view;
GtkListStore *model;
GtkWidget *annot_view;
GtkWidget *timer_label;
@@ -281,6 +282,28 @@
}
static void
+pgd_annots_remove_annot (GtkWidget *button,
+ PgdAnnotsDemo *demo)
+{
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (demo->tree_view));
+
+ if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
+ PopplerAnnot *annot;
+
+ gtk_tree_model_get (model, &iter,
+ ANNOTS_COLUMN, &annot,
+ -1);
+ poppler_page_remove_annot (demo->page, annot);
+ g_object_unref (annot);
+ gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
+ }
+}
+
+static void
pgd_annot_view_set_annot_markup (GtkWidget *table,
PopplerAnnotMarkup *markup,
gint *row)
@@ -289,35 +312,35 @@
PopplerRectangle rect;
text = poppler_annot_markup_get_label (markup);
- pgd_table_add_property (GTK_TABLE (table), "<b>Label:</b>", text, row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Label:</b>", text, row);
g_free (text);
if (poppler_annot_markup_has_popup (markup)) {
- pgd_table_add_property (GTK_TABLE (table), "<b>Popup is open:</b>",
+ pgd_table_add_property (GTK_GRID (table), "<b>Popup is open:</b>",
poppler_annot_markup_get_popup_is_open (markup) ? "Yes" : "No", row);
poppler_annot_markup_get_popup_rectangle (markup, &rect);
text = g_strdup_printf ("X1: %.2f, Y1: %.2f, X2: %.2f, Y2: %.2f",
rect.x1, rect.y1, rect.x2, rect.y2);
- pgd_table_add_property (GTK_TABLE (table), "<b>Popup Rectangle:</b>", text, row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Popup Rectangle:</b>", text, row);
g_free (text);
}
text = g_strdup_printf ("%f", poppler_annot_markup_get_opacity (markup));
- pgd_table_add_property (GTK_TABLE (table), "<b>Opacity:</b>", text, row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Opacity:</b>", text, row);
g_free (text);
text = get_markup_date (markup);
- pgd_table_add_property (GTK_TABLE (table), "<b>Date:</b>", text, row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Date:</b>", text, row);
g_free (text);
text = poppler_annot_markup_get_subject (markup);
- pgd_table_add_property (GTK_TABLE (table), "<b>Subject:</b>", text, row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Subject:</b>", text, row);
g_free (text);
- pgd_table_add_property (GTK_TABLE (table), "<b>Reply To:</b>", get_markup_reply_to (markup), row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Reply To:</b>", get_markup_reply_to (markup), row);
- pgd_table_add_property (GTK_TABLE (table), "<b>External Data:</b>", get_markup_external_data (markup), row);
+ pgd_table_add_property (GTK_GRID (table), "<b>External Data:</b>", get_markup_external_data (markup), row);
}
static void
@@ -327,14 +350,14 @@
{
gchar *text;
- pgd_table_add_property (GTK_TABLE (table), "<b>Is open:</b>",
+ pgd_table_add_property (GTK_GRID (table), "<b>Is open:</b>",
poppler_annot_text_get_is_open (annot) ? "Yes" : "No", row);
text = poppler_annot_text_get_icon (annot);
- pgd_table_add_property (GTK_TABLE (table), "<b>Icon:</b>", text, row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Icon:</b>", text, row);
g_free (text);
- pgd_table_add_property (GTK_TABLE (table), "<b>State:</b>", get_text_state (annot), row);
+ pgd_table_add_property (GTK_GRID (table), "<b>State:</b>", get_text_state (annot), row);
}
static void
@@ -344,10 +367,10 @@
{
gchar *text;
- pgd_table_add_property (GTK_TABLE (table), "<b>Quadding:</b>", get_free_text_quadding (annot), row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Quadding:</b>", get_free_text_quadding (annot), row);
text = get_free_text_callout_line (annot);
- pgd_table_add_property (GTK_TABLE (table), "<b>Callout:</b>", text, row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Callout:</b>", text, row);
g_free (text);
}
@@ -408,14 +431,14 @@
gchar *text;
text = poppler_annot_file_attachment_get_name (annot);
- pgd_table_add_property (GTK_TABLE (table), "<b>Attachment Name:</b>", text, row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Attachment Name:</b>", text, row);
g_free (text);
button = gtk_button_new_with_label ("Save Attachment");
g_signal_connect (G_OBJECT (button), "clicked",
G_CALLBACK (pgd_annot_save_file_attachment_button_clicked),
(gpointer)annot);
- pgd_table_add_property_with_custom_widget (GTK_TABLE (table), "<b>File Attachment:</b>", button, row);
+ pgd_table_add_property_with_custom_widget (GTK_GRID (table), "<b>File Attachment:</b>", button, row);
gtk_widget_show (button);
}
@@ -429,12 +452,12 @@
gchar *text;
text = poppler_annot_movie_get_title (annot);
- pgd_table_add_property (GTK_TABLE (table), "<b>Movie Title:</b>", text, row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Movie Title:</b>", text, row);
g_free (text);
movie_view = pgd_movie_view_new ();
pgd_movie_view_set_movie (movie_view, poppler_annot_movie_get_movie (annot));
- pgd_table_add_property_with_custom_widget (GTK_TABLE (table), "<b>Movie:</b>", movie_view, row);
+ pgd_table_add_property_with_custom_widget (GTK_GRID (table), "<b>Movie:</b>", movie_view, row);
gtk_widget_show (movie_view);
}
@@ -447,44 +470,45 @@
action_view = pgd_action_view_new (NULL);
pgd_action_view_set_action (action_view, poppler_annot_screen_get_action (annot));
- pgd_table_add_property_with_custom_widget (GTK_TABLE (table), "<b>Action:</b>", action_view, row);
+ pgd_table_add_property_with_custom_widget (GTK_GRID (table), "<b>Action:</b>", action_view, row);
gtk_widget_show (action_view);
}
static void
-pgd_annot_view_set_annot (GtkWidget *annot_view,
- PopplerAnnot *annot)
+pgd_annot_view_set_annot (PgdAnnotsDemo *demo,
+ PopplerAnnot *annot)
{
GtkWidget *alignment;
GtkWidget *table;
+ GtkWidget *button;
GEnumValue *enum_value;
gint row = 0;
gchar *text, *warning;
time_t timet;
- alignment = gtk_bin_get_child (GTK_BIN (annot_view));
+ alignment = gtk_bin_get_child (GTK_BIN (demo->annot_view));
if (alignment) {
- gtk_container_remove (GTK_CONTAINER (annot_view), alignment);
+ gtk_container_remove (GTK_CONTAINER (demo->annot_view), alignment);
}
alignment = gtk_alignment_new (0.5, 0.5, 1, 1);
gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 5, 5, 12, 5);
- gtk_container_add (GTK_CONTAINER (annot_view), alignment);
+ gtk_container_add (GTK_CONTAINER (demo->annot_view), alignment);
gtk_widget_show (alignment);
if (!annot)
return;
- table = gtk_table_new (10, 2, FALSE);
- gtk_table_set_col_spacings (GTK_TABLE (table), 6);
- gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+ table = gtk_grid_new ();
+ gtk_grid_set_column_spacing (GTK_GRID (table), 6);
+ gtk_grid_set_row_spacing (GTK_GRID (table), 6);
text = poppler_annot_get_contents (annot);
- pgd_table_add_property (GTK_TABLE (table), "<b>Contents:</b>", text, &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Contents:</b>", text, &row);
g_free (text);
text = poppler_annot_get_name (annot);
- pgd_table_add_property (GTK_TABLE (table), "<b>Name:</b>", text, &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Name:</b>", text, &row);
g_free (text);
text = poppler_annot_get_modified (annot);
@@ -492,15 +516,15 @@
g_free (text);
text = pgd_format_date (timet);
}
- pgd_table_add_property (GTK_TABLE (table), "<b>Modified:</b>", text, &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Modified:</b>", text, &row);
g_free (text);
text = g_strdup_printf ("%d", poppler_annot_get_flags (annot));
- pgd_table_add_property (GTK_TABLE (table), "<b>Flags:</b>", text, &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Flags:</b>", text, &row);
g_free (text);
text = g_strdup_printf ("%d", poppler_annot_get_page_index (annot));
- pgd_table_add_property (GTK_TABLE (table), "<b>Page:</b>", text, &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Page:</b>", text, &row);
g_free (text);
if (POPPLER_IS_ANNOT_MARKUP (annot))
@@ -527,6 +551,13 @@
break;
}
+ button = gtk_button_new_from_stock (GTK_STOCK_REMOVE);
+ g_signal_connect (G_OBJECT (button), "clicked",
+ G_CALLBACK (pgd_annots_remove_annot),
+ (gpointer) demo);
+ gtk_grid_attach (GTK_GRID (table), button, 0, row, 2, 1);
+ gtk_widget_show (button);
+
gtk_container_add (GTK_CONTAINER (alignment), table);
gtk_widget_show (table);
}
@@ -540,7 +571,7 @@
GTimer *timer;
gtk_list_store_clear (demo->model);
- pgd_annot_view_set_annot (demo->annot_view, NULL);
+ pgd_annot_view_set_annot (demo, NULL);
if (demo->page) {
g_object_unref (demo->page);
@@ -632,8 +663,10 @@
gtk_tree_model_get (model, &iter,
ANNOTS_COLUMN, &annot,
-1);
- pgd_annot_view_set_annot (demo->annot_view, annot);
+ pgd_annot_view_set_annot (demo, annot);
g_object_unref (annot);
+ } else {
+ pgd_annot_view_set_annot (demo, NULL);
}
}
@@ -666,22 +699,16 @@
vbox = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
-#if GTK_CHECK_VERSION (2, 24, 0)
type_selector = gtk_combo_box_text_new ();
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (type_selector), "POPPLER_ANNOT_UNKNOWN");
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (type_selector), "POPPLER_ANNOT_TEXT");
-#else
- type_selector = gtk_combo_box_new_text ();
- gtk_combo_box_append_text (GTK_COMBO_BOX (type_selector), "POPPLER_ANNOT_UNKNOWN");
- gtk_combo_box_append_text (GTK_COMBO_BOX (type_selector), "POPPLER_ANNOT_TEXT");
-#endif
gtk_combo_box_set_active (GTK_COMBO_BOX (type_selector), 1);
gtk_box_pack_start (GTK_BOX (vbox), type_selector, TRUE, TRUE, 0);
gtk_widget_show (type_selector);
- hbox = gtk_hbox_new (FALSE, 6);
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
- rect_hbox = gtk_hbox_new (FALSE, 6);
+ rect_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
label = gtk_label_new ("x1:");
gtk_box_pack_start (GTK_BOX (rect_hbox), label, TRUE, TRUE, 0);
@@ -694,7 +721,7 @@
gtk_box_pack_start (GTK_BOX (hbox), rect_hbox, FALSE, TRUE, 0);
gtk_widget_show (rect_hbox);
- rect_hbox = gtk_hbox_new (FALSE, 6);
+ rect_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
label = gtk_label_new ("x2:");
gtk_box_pack_start (GTK_BOX (rect_hbox), label, TRUE, TRUE, 0);
@@ -707,7 +734,7 @@
gtk_box_pack_start (GTK_BOX (hbox), rect_hbox, FALSE, TRUE, 0);
gtk_widget_show (rect_hbox);
- rect_hbox = gtk_hbox_new (FALSE, 6);
+ rect_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
label = gtk_label_new ("y1:");
gtk_box_pack_start (GTK_BOX (rect_hbox), label, TRUE, TRUE, 0);
@@ -720,7 +747,7 @@
gtk_box_pack_start (GTK_BOX (hbox), rect_hbox, FALSE, TRUE, 0);
gtk_widget_show (rect_hbox);
- rect_hbox = gtk_hbox_new (FALSE, 6);
+ rect_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
label = gtk_label_new ("y2:");
gtk_box_pack_start (GTK_BOX (rect_hbox), label, TRUE, TRUE, 0);
@@ -771,9 +798,9 @@
n_pages = poppler_document_get_n_pages (document);
- vbox = gtk_vbox_new (FALSE, 12);
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
- hbox = gtk_hbox_new (FALSE, 6);
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
label = gtk_label_new ("Page:");
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
@@ -815,7 +842,7 @@
gtk_box_pack_start (GTK_BOX (vbox), demo->timer_label, FALSE, TRUE, 0);
gtk_widget_show (demo->timer_label);
- hpaned = gtk_hpaned_new ();
+ hpaned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
demo->annot_view = pgd_annot_view_new ();
@@ -831,6 +858,7 @@
G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
G_TYPE_OBJECT);
treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (demo->model));
+ demo->tree_view = treeview;
renderer = gtk_cell_renderer_text_new ();
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
diff --git a/glib/demo/attachments.c b/glib/demo/attachments.c
index 63565dd..1b74274 100644
--- a/glib/demo/attachments.c
+++ b/glib/demo/attachments.c
@@ -280,7 +280,7 @@
GtkWidget *hbox, *button;
gboolean has_attachments;
- vbox = gtk_vbox_new (FALSE, 12);
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
swindow = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow),
@@ -327,7 +327,7 @@
if (!has_attachments)
return vbox;
- hbox = gtk_hbutton_box_new ();
+ hbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_SPREAD);
button = gtk_button_new_with_label ("Save");
diff --git a/glib/demo/find.c b/glib/demo/find.c
index 632e610..664c597 100644
--- a/glib/demo/find.c
+++ b/glib/demo/find.c
@@ -26,20 +26,28 @@
Y2_COLUMN,
VISIBLE_COLUMN,
+ PAGE_COLUMN,
+ PAGE_RECT,
N_COLUMNS
};
typedef struct {
PopplerDocument *doc;
- GtkTreeModel *model;
+ GtkWidget *treeview;
+ GtkWidget *darea;
GtkWidget *entry;
GtkWidget *progress;
+ PopplerFindFlags options;
gint n_pages;
gint page_index;
-
+
guint idle_id;
+
+ cairo_surface_t *surface;
+ gint selected_page;
+ GdkRectangle selected_match;
} PgdFindDemo;
static void
@@ -58,10 +66,10 @@
demo->doc = NULL;
}
- if (demo->model) {
- g_object_unref (demo->model);
- demo->model = NULL;
- }
+ if (demo->surface) {
+ cairo_surface_destroy (demo->surface);
+ demo->surface = NULL;
+ }
g_free (demo);
}
@@ -83,9 +91,10 @@
static gboolean
pgd_find_find_text (PgdFindDemo *demo)
{
- PopplerPage *page;
- GList *matches;
- GTimer *timer;
+ PopplerPage *page;
+ GList *matches;
+ GTimer *timer;
+ GtkTreeModel *model;
page = poppler_document_get_page (demo->doc, demo->page_index);
if (!page) {
@@ -93,52 +102,66 @@
return demo->page_index < demo->n_pages;
}
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (demo->treeview));
timer = g_timer_new ();
- matches = poppler_page_find_text (page, gtk_entry_get_text (GTK_ENTRY (demo->entry)));
+ matches = poppler_page_find_text_with_options (page, gtk_entry_get_text (GTK_ENTRY (demo->entry)), demo->options);
g_timer_stop (timer);
if (matches) {
GtkTreeIter iter;
gchar *str;
GList *l;
+ gdouble height;
gint n_match = 0;
str = g_strdup_printf ("%d matches found on page %d in %.4f seconds",
g_list_length (matches), demo->page_index + 1,
g_timer_elapsed (timer, NULL));
- gtk_tree_store_append (GTK_TREE_STORE (demo->model), &iter, NULL);
- gtk_tree_store_set (GTK_TREE_STORE (demo->model), &iter,
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
TITLE_COLUMN, str,
VISIBLE_COLUMN, FALSE,
+ PAGE_COLUMN, demo->page_index,
-1);
g_free (str);
-
+
+ poppler_page_get_size (page, NULL, &height);
+
for (l = matches; l && l->data; l = g_list_next (l)) {
PopplerRectangle *rect = (PopplerRectangle *)l->data;
GtkTreeIter iter_child;
gchar *x1, *y1, *x2, *y2;
+ gdouble tmp;
str = g_strdup_printf ("Match %d", ++n_match);
x1 = g_strdup_printf ("%.2f", rect->x1);
y1 = g_strdup_printf ("%.2f", rect->y1);
x2 = g_strdup_printf ("%.2f", rect->x2);
y2 = g_strdup_printf ("%.2f", rect->y2);
-
- gtk_tree_store_append (GTK_TREE_STORE (demo->model), &iter_child, &iter);
- gtk_tree_store_set (GTK_TREE_STORE (demo->model), &iter_child,
+
+ tmp = rect->y1;
+ rect->y1 = height - rect->y2;
+ rect->y2 = height - tmp;
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &iter_child, &iter);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &iter_child,
TITLE_COLUMN, str,
X1_COLUMN, x1,
Y1_COLUMN, y1,
X2_COLUMN, x2,
Y2_COLUMN, y2,
VISIBLE_COLUMN, TRUE,
+ PAGE_COLUMN, demo->page_index,
+ PAGE_RECT, rect,
-1);
g_free (str);
g_free (x1);
g_free (y1);
g_free (x2);
g_free (y2);
- poppler_rectangle_free (rect);
+ g_object_weak_ref (G_OBJECT (model),
+ (GWeakNotify)poppler_rectangle_free,
+ rect);
}
g_list_free (matches);
}
@@ -152,11 +175,115 @@
return demo->page_index < demo->n_pages;
}
+static cairo_surface_t *
+pgd_find_render_page (PgdFindDemo *demo)
+{
+ cairo_t *cr;
+ PopplerPage *page;
+ gdouble width, height;
+ cairo_surface_t *surface = NULL;
+
+ page = poppler_document_get_page (demo->doc, demo->selected_page);
+ if (!page)
+ return NULL;
+
+ poppler_page_get_size (page, &width, &height);
+ gtk_widget_set_size_request (demo->darea, width, height);
+
+ surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
+ width, height);
+ cr = cairo_create (surface);
+
+ cairo_save (cr);
+ cairo_set_source_rgb (cr, 1, 1, 1);
+ cairo_rectangle (cr, 0, 0, width, height);
+ cairo_fill (cr);
+ cairo_restore (cr);
+
+ cairo_save (cr);
+ poppler_page_render (page, cr);
+ cairo_restore (cr);
+
+ cairo_destroy (cr);
+ g_object_unref (page);
+
+ return surface;
+}
+
+static gboolean
+pgd_find_viewer_drawing_area_draw (GtkWidget *area,
+ cairo_t *cr,
+ PgdFindDemo *demo)
+{
+ if (demo->selected_page == -1)
+ return FALSE;
+
+ if (!demo->surface) {
+ demo->surface = pgd_find_render_page (demo);
+ if (!demo->surface)
+ return FALSE;
+ }
+
+ cairo_set_source_surface (cr, demo->surface, 0, 0);
+ cairo_paint (cr);
+
+ if (demo->selected_match.width > 0 && demo->selected_match.height > 0) {
+ cairo_set_source_rgb (cr, 1., 1., 0.);
+ cairo_set_operator (cr, CAIRO_OPERATOR_MULTIPLY);
+ gdk_cairo_rectangle (cr, &demo->selected_match);
+ cairo_fill (cr);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+pgd_find_viewer_redraw (PgdFindDemo *demo)
+{
+ cairo_surface_destroy (demo->surface);
+ demo->surface = NULL;
+
+ gtk_widget_queue_draw (demo->darea);
+
+ return FALSE;
+}
+
+static void
+pgd_find_viewer_queue_redraw (PgdFindDemo *demo)
+{
+ g_idle_add ((GSourceFunc)pgd_find_viewer_redraw, demo);
+}
+
+static GtkTreeModel *
+pgd_find_create_model ()
+{
+ return GTK_TREE_MODEL (gtk_tree_store_new (N_COLUMNS,
+ G_TYPE_STRING,
+ G_TYPE_STRING, G_TYPE_STRING,
+ G_TYPE_STRING, G_TYPE_STRING,
+ G_TYPE_BOOLEAN, G_TYPE_UINT,
+ G_TYPE_POINTER));
+}
+
static void
pgd_find_button_clicked (GtkButton *button,
PgdFindDemo *demo)
{
- gtk_tree_store_clear (GTK_TREE_STORE (demo->model));
+ GtkTreeModel *model;
+
+ /* Delete the model and create a new one instead of
+ * just clearing it to make sure rectangle are free.
+ * This is a workaround because GtkTreeModel doesn't
+ * support boxed types and we have to store rectangles
+ * as pointers that are freed when the model is deleted.
+ */
+ model = pgd_find_create_model ();
+ gtk_tree_view_set_model (GTK_TREE_VIEW (demo->treeview), model);
+ g_object_unref (model);
+
+ demo->selected_page = -1;
+ pgd_find_viewer_queue_redraw (demo);
+
demo->page_index = 0;
pgd_find_update_progress (demo, demo->page_index);
if (demo->idle_id > 0)
@@ -174,25 +301,99 @@
gtk_widget_set_sensitive (button, text != NULL && text[0] != '\0');
}
+static void
+pgd_find_selection_changed (GtkTreeSelection *treeselection,
+ PgdFindDemo *demo)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ if (gtk_tree_selection_get_selected (treeselection, &model, &iter)) {
+ guint page_index;
+ PopplerRectangle *rect;
+
+ gtk_tree_model_get (model, &iter,
+ PAGE_COLUMN, &page_index,
+ PAGE_RECT, &rect,
+ -1);
+
+ if (rect) {
+ demo->selected_match.x = rect->x1;
+ demo->selected_match.y = rect->y1;
+ demo->selected_match.width = rect->x2 - rect->x1;
+ demo->selected_match.height = rect->y2 - rect->y1;
+ } else {
+ demo->selected_match.width = 0;
+ demo->selected_match.height = 0;
+ }
+
+ if (page_index != demo->selected_page) {
+ demo->selected_page = page_index;
+ pgd_find_viewer_queue_redraw (demo);
+ } else {
+ gtk_widget_queue_draw (demo->darea);
+ }
+ }
+}
+
+static void
+pgd_find_case_sensitive_toggled (GtkToggleButton *togglebutton,
+ PgdFindDemo *demo)
+{
+ if (gtk_toggle_button_get_active (togglebutton))
+ demo->options |= POPPLER_FIND_CASE_SENSITIVE;
+ else
+ demo->options &= ~POPPLER_FIND_CASE_SENSITIVE;
+}
+
+static void
+pgd_find_backwards_toggled (GtkToggleButton *togglebutton,
+ PgdFindDemo *demo)
+{
+ if (gtk_toggle_button_get_active (togglebutton))
+ demo->options |= POPPLER_FIND_BACKWARDS;
+ else
+ demo->options &= ~POPPLER_FIND_BACKWARDS;
+}
+
+static void
+pgd_find_whole_words_toggled (GtkToggleButton *togglebutton,
+ PgdFindDemo *demo)
+{
+ if (gtk_toggle_button_get_active (togglebutton))
+ demo->options |= POPPLER_FIND_WHOLE_WORDS_ONLY;
+ else
+ demo->options &= ~POPPLER_FIND_WHOLE_WORDS_ONLY;
+}
+
GtkWidget *
pgd_find_create_widget (PopplerDocument *document)
{
- PgdFindDemo *demo;
- GtkWidget *vbox, *hbox;
- GtkWidget *button;
- GtkWidget *swindow;
- GtkWidget *treeview;
- GtkCellRenderer *renderer;
+ PgdFindDemo *demo;
+ GtkWidget *vbox, *hbox;
+ GtkWidget *button;
+ GtkWidget *swindow;
+ GtkWidget *checkbutton;
+ GtkTreeModel *model;
+ GtkWidget *treeview;
+ GtkCellRenderer *renderer;
+ GtkWidget *hpaned;
+ GtkTreeSelection *selection;
demo = g_new0 (PgdFindDemo, 1);
demo->doc = g_object_ref (document);
demo->n_pages = poppler_document_get_n_pages (document);
+ demo->selected_page = -1;
+ demo->options = POPPLER_FIND_DEFAULT;
- vbox = gtk_vbox_new (FALSE, 12);
+ hpaned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
+ gtk_paned_set_position (GTK_PANED (hpaned), 300);
- hbox = gtk_hbox_new (FALSE, 6);
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
+
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
demo->entry = gtk_entry_new ();
gtk_box_pack_start (GTK_BOX (hbox), demo->entry, FALSE, TRUE, 0);
@@ -218,21 +419,47 @@
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 6);
gtk_widget_show (hbox);
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+
+ checkbutton = gtk_check_button_new_with_label ("Case sensitive");
+ g_signal_connect (checkbutton, "toggled",
+ G_CALLBACK (pgd_find_case_sensitive_toggled),
+ demo);
+ gtk_box_pack_start (GTK_BOX (hbox), checkbutton, FALSE, FALSE, 0);
+ gtk_widget_show (checkbutton);
+
+ checkbutton = gtk_check_button_new_with_label ("Backwards");
+ g_signal_connect (checkbutton, "toggled",
+ G_CALLBACK (pgd_find_backwards_toggled),
+ demo);
+ gtk_box_pack_start (GTK_BOX (hbox), checkbutton, FALSE, FALSE, 0);
+ gtk_widget_show (checkbutton);
+
+ checkbutton = gtk_check_button_new_with_label ("Whole words only");
+ g_signal_connect (checkbutton, "toggled",
+ G_CALLBACK (pgd_find_whole_words_toggled),
+ demo);
+ gtk_box_pack_start (GTK_BOX (hbox), checkbutton, FALSE, FALSE, 0);
+ gtk_widget_show (checkbutton);
+
+ gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+ gtk_widget_show (hbox);
+
swindow = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
- demo->model = GTK_TREE_MODEL (
- gtk_tree_store_new (N_COLUMNS,
- G_TYPE_STRING,
- G_TYPE_STRING, G_TYPE_STRING,
- G_TYPE_STRING, G_TYPE_STRING,
- G_TYPE_BOOLEAN));
- treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (demo->model));
+ model = pgd_find_create_model ();
+ treeview = gtk_tree_view_new_with_model (model);
+ g_object_unref (model);
+ demo->treeview = treeview;
gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (treeview), TRUE);
- gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)),
- GTK_SELECTION_NONE);
-
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
+ gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
+ g_signal_connect (selection, "changed",
+ G_CALLBACK (pgd_find_selection_changed),
+ demo);
+
renderer = gtk_cell_renderer_text_new ();
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
TITLE_COLUMN, "Matches",
@@ -271,8 +498,23 @@
gtk_container_add (GTK_CONTAINER (swindow), treeview);
gtk_widget_show (treeview);
- gtk_box_pack_start (GTK_BOX (vbox), swindow, TRUE, TRUE, 0);
- gtk_widget_show (swindow);
+ gtk_paned_add1 (GTK_PANED (hpaned), swindow);
+ gtk_widget_show (swindow);
+
+ demo->darea = gtk_drawing_area_new ();
+ g_signal_connect (demo->darea, "draw",
+ G_CALLBACK (pgd_find_viewer_drawing_area_draw),
+ demo);
+
+ swindow = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (swindow), demo->darea);
+ gtk_widget_show (demo->darea);
+
+ gtk_paned_add2 (GTK_PANED (hpaned), swindow);
+ gtk_widget_show (swindow);
+
+ gtk_box_pack_start (GTK_BOX (vbox), hpaned, TRUE, TRUE, 0);
+ gtk_widget_show (hpaned);
g_object_weak_ref (G_OBJECT (vbox),
(GWeakNotify)pgd_find_free,
diff --git a/glib/demo/fonts.c b/glib/demo/fonts.c
index 24eb87c..d0ffa3d 100644
--- a/glib/demo/fonts.c
+++ b/glib/demo/fonts.c
@@ -228,9 +228,9 @@
demo->doc = g_object_ref (document);
- vbox = gtk_vbox_new (FALSE, 12);
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
- hbox = gtk_hbox_new (FALSE, 6);
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
demo->progress = gtk_progress_bar_new ();
gtk_progress_bar_set_ellipsize (GTK_PROGRESS_BAR (demo->progress),
diff --git a/glib/demo/forms.c b/glib/demo/forms.c
index 3a74ef5..9dfe3cd 100644
--- a/glib/demo/forms.c
+++ b/glib/demo/forms.c
@@ -79,7 +79,7 @@
}
static void
-pgd_form_field_view_add_choice_items (GtkTable *table,
+pgd_form_field_view_add_choice_items (GtkGrid *table,
PopplerFormField *field,
gint *selected,
gint *row)
@@ -92,8 +92,7 @@
label = gtk_label_new (NULL);
g_object_set (G_OBJECT (label), "xalign", 0.0, NULL);
gtk_label_set_markup (GTK_LABEL (label), "<b>Items:</b>");
- gtk_table_attach (GTK_TABLE (table), label, 0, 1, *row, *row + 1,
- GTK_FILL, GTK_FILL, 0, 0);
+ gtk_grid_attach (GTK_GRID (table), label, 0, *row, 1, 1);
gtk_widget_show (label);
swindow = gtk_scrolled_window_new (NULL, NULL);
@@ -120,8 +119,7 @@
gtk_container_add (GTK_CONTAINER (swindow), textview);
gtk_widget_show (textview);
- gtk_table_attach (GTK_TABLE (table), swindow, 1, 2, *row, *row + 1,
- GTK_FILL, GTK_FILL, 0, 0);
+ gtk_grid_attach (GTK_GRID (table), swindow, 1, *row, 1, 1);
gtk_widget_show (swindow);
*row += 1;
@@ -151,23 +149,23 @@
if (!field)
return;
- table = gtk_table_new (13, 2, FALSE);
- gtk_table_set_col_spacings (GTK_TABLE (table), 6);
- gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+ table = gtk_grid_new ();
+ gtk_grid_set_column_spacing (GTK_GRID (table), 6);
+ gtk_grid_set_row_spacing (GTK_GRID (table), 6);
text = poppler_form_field_get_name (field);
if (text) {
- pgd_table_add_property (GTK_TABLE (table), "<b>Name:</b>", text, &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Name:</b>", text, &row);
g_free (text);
}
text = poppler_form_field_get_partial_name (field);
if (text) {
- pgd_table_add_property (GTK_TABLE (table), "<b>Partial Name:</b>", text, &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Partial Name:</b>", text, &row);
g_free (text);
}
text = poppler_form_field_get_mapping_name (field);
if (text) {
- pgd_table_add_property (GTK_TABLE (table), "<b>Mapping Name:</b>", text, &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Mapping Name:</b>", text, &row);
g_free (text);
}
@@ -177,7 +175,7 @@
action_view = pgd_action_view_new (NULL);
pgd_action_view_set_action (action_view, action);
- pgd_table_add_property_with_custom_widget (GTK_TABLE (table), "<b>Action:</b>", action_view, &row);
+ pgd_table_add_property_with_custom_widget (GTK_GRID (table), "<b>Action:</b>", action_view, &row);
gtk_widget_show (action_view);
}
@@ -185,30 +183,30 @@
case POPPLER_FORM_FIELD_BUTTON:
enum_value = g_enum_get_value ((GEnumClass *) g_type_class_ref (POPPLER_TYPE_FORM_BUTTON_TYPE),
poppler_form_field_button_get_button_type (field));
- pgd_table_add_property (GTK_TABLE (table), "<b>Button Type:</b>", enum_value->value_name, &row);
- pgd_table_add_property (GTK_TABLE (table), "<b>Button State:</b>",
+ pgd_table_add_property (GTK_GRID (table), "<b>Button Type:</b>", enum_value->value_name, &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Button State:</b>",
poppler_form_field_button_get_state (field) ? "Active" : "Inactive", &row);
break;
case POPPLER_FORM_FIELD_TEXT:
enum_value = g_enum_get_value ((GEnumClass *) g_type_class_ref (POPPLER_TYPE_FORM_TEXT_TYPE),
poppler_form_field_text_get_text_type (field));
- pgd_table_add_property (GTK_TABLE (table), "<b>Text Type:</b>", enum_value->value_name, &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Text Type:</b>", enum_value->value_name, &row);
text = poppler_form_field_text_get_text (field);
- pgd_table_add_property (GTK_TABLE (table), "<b>Contents:</b>", text, &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Contents:</b>", text, &row);
g_free (text);
text = g_strdup_printf ("%d", poppler_form_field_text_get_max_len (field));
- pgd_table_add_property (GTK_TABLE (table), "<b>Max Length:</b>", text, &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Max Length:</b>", text, &row);
g_free (text);
- pgd_table_add_property (GTK_TABLE (table), "<b>Do spellcheck:</b>",
+ pgd_table_add_property (GTK_GRID (table), "<b>Do spellcheck:</b>",
poppler_form_field_text_do_spell_check (field) ? "Yes" : "No", &row);
- pgd_table_add_property (GTK_TABLE (table), "<b>Do scroll:</b>",
+ pgd_table_add_property (GTK_GRID (table), "<b>Do scroll:</b>",
poppler_form_field_text_do_scroll (field) ? "Yes" : "No", &row);
- pgd_table_add_property (GTK_TABLE (table), "<b>Rich Text:</b>",
+ pgd_table_add_property (GTK_GRID (table), "<b>Rich Text:</b>",
poppler_form_field_text_is_rich_text (field) ? "Yes" : "No", &row);
- pgd_table_add_property (GTK_TABLE (table), "<b>Pasword type:</b>",
+ pgd_table_add_property (GTK_GRID (table), "<b>Pasword type:</b>",
poppler_form_field_text_is_password (field) ? "Yes" : "No", &row);
break;
case POPPLER_FORM_FIELD_CHOICE: {
@@ -217,32 +215,32 @@
enum_value = g_enum_get_value ((GEnumClass *) g_type_class_ref (POPPLER_TYPE_FORM_CHOICE_TYPE),
poppler_form_field_choice_get_choice_type (field));
- pgd_table_add_property (GTK_TABLE (table), "<b>Choice Type:</b>", enum_value->value_name, &row);
- pgd_table_add_property (GTK_TABLE (table), "<b>Editable:</b>",
+ pgd_table_add_property (GTK_GRID (table), "<b>Choice Type:</b>", enum_value->value_name, &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Editable:</b>",
poppler_form_field_choice_is_editable (field) ? "Yes" : "No", &row);
- pgd_table_add_property (GTK_TABLE (table), "<b>Multiple Selection:</b>",
+ pgd_table_add_property (GTK_GRID (table), "<b>Multiple Selection:</b>",
poppler_form_field_choice_can_select_multiple (field) ? "Yes" : "No", &row);
- pgd_table_add_property (GTK_TABLE (table), "<b>Do spellcheck:</b>",
+ pgd_table_add_property (GTK_GRID (table), "<b>Do spellcheck:</b>",
poppler_form_field_choice_do_spell_check (field) ? "Yes" : "No", &row);
- pgd_table_add_property (GTK_TABLE (table), "<b>Commit on Change:</b>",
+ pgd_table_add_property (GTK_GRID (table), "<b>Commit on Change:</b>",
poppler_form_field_choice_commit_on_change (field) ? "Yes" : "No", &row);
text = g_strdup_printf ("%d", poppler_form_field_choice_get_n_items (field));
- pgd_table_add_property (GTK_TABLE (table), "<b>Number of items:</b>", text, &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Number of items:</b>", text, &row);
g_free (text);
- pgd_form_field_view_add_choice_items (GTK_TABLE (table), field, &selected, &row);
+ pgd_form_field_view_add_choice_items (GTK_GRID (table), field, &selected, &row);
if (selected >= 0 && poppler_form_field_choice_get_n_items (field) > selected) {
item = poppler_form_field_choice_get_item (field, selected);
text = g_strdup_printf ("%d (%s)", selected, item);
g_free (item);
- pgd_table_add_property (GTK_TABLE (table), "<b>Selected item:</b>", text, &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Selected item:</b>", text, &row);
g_free (text);
}
text = poppler_form_field_choice_get_text (field);
- pgd_table_add_property (GTK_TABLE (table), "<b>Contents:</b>", text, &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Contents:</b>", text, &row);
g_free (text);
}
break;
@@ -390,9 +388,9 @@
n_pages = poppler_document_get_n_pages (document);
- vbox = gtk_vbox_new (FALSE, 12);
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
- hbox = gtk_hbox_new (FALSE, 6);
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
label = gtk_label_new ("Page:");
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
@@ -427,7 +425,7 @@
gtk_box_pack_start (GTK_BOX (vbox), demo->timer_label, FALSE, TRUE, 0);
gtk_widget_show (demo->timer_label);
- hpaned = gtk_hpaned_new ();
+ hpaned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
demo->field_view = pgd_form_field_view_new ();
diff --git a/glib/demo/images.c b/glib/demo/images.c
index 6e987d2..3623fd7 100644
--- a/glib/demo/images.c
+++ b/glib/demo/images.c
@@ -61,11 +61,10 @@
}
static gboolean
-pgd_image_view_drawing_area_expose (GtkWidget *area,
- GdkEventExpose *event,
- GtkWidget *image_view)
+pgd_image_view_drawing_area_draw (GtkWidget *area,
+ cairo_t *cr,
+ GtkWidget *image_view)
{
- cairo_t *cr;
cairo_surface_t *image;
image = g_object_get_data (G_OBJECT (image_view), "image-surface");
@@ -75,11 +74,9 @@
gtk_widget_set_size_request (area,
cairo_image_surface_get_width (image),
cairo_image_surface_get_height (image));
-
- cr = gdk_cairo_create (gtk_widget_get_window (area));
+
cairo_set_source_surface (cr, image, 0, 0);
cairo_paint (cr);
- cairo_destroy (cr);
return TRUE;
}
@@ -93,8 +90,8 @@
swindow = gtk_scrolled_window_new (NULL, NULL);
darea = gtk_drawing_area_new ();
- g_signal_connect (G_OBJECT (darea), "expose_event",
- G_CALLBACK (pgd_image_view_drawing_area_expose),
+ g_signal_connect (G_OBJECT (darea), "draw",
+ G_CALLBACK (pgd_image_view_drawing_area_draw),
(gpointer)swindow);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
@@ -229,9 +226,9 @@
n_pages = poppler_document_get_n_pages (document);
- vbox = gtk_vbox_new (FALSE, 12);
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
- hbox = gtk_hbox_new (FALSE, 6);
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
label = gtk_label_new ("Page:");
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
@@ -266,7 +263,7 @@
gtk_box_pack_start (GTK_BOX (vbox), demo->timer_label, FALSE, TRUE, 0);
gtk_widget_show (demo->timer_label);
- hpaned = gtk_hpaned_new ();
+ hpaned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
demo->image_view = pgd_image_view_new ();
diff --git a/glib/demo/info.cc b/glib/demo/info.cc
index e05cc15..590ddc7 100644
--- a/glib/demo/info.cc
+++ b/glib/demo/info.cc
@@ -23,7 +23,7 @@
#include "utils.h"
static void
-pgd_info_add_permissions (GtkTable *table,
+pgd_info_add_permissions (GtkGrid *table,
PopplerPermissions permissions,
gint *row)
{
@@ -33,12 +33,11 @@
label = gtk_label_new (NULL);
g_object_set (G_OBJECT (label), "xalign", 0.0, NULL);
gtk_label_set_markup (GTK_LABEL (label), "<b>Permissions:</b>");
- gtk_table_attach (GTK_TABLE (table), label, 0, 1, *row, *row + 1,
- GTK_FILL, GTK_FILL, 0, 0);
+ gtk_grid_attach (GTK_GRID (table), label, 0, *row, 1, 1);
gtk_widget_show (label);
- vbox = gtk_vbox_new (FALSE, 0);
- hbox = gtk_hbox_new (FALSE, 6);
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
checkbox = gtk_check_button_new_with_label ("Print");
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbox),
@@ -73,7 +72,7 @@
gtk_box_pack_start (GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
gtk_widget_show (hbox);
- hbox = gtk_hbox_new (FALSE, 6);
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
checkbox = gtk_check_button_new_with_label ("Extract contents");
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbox),
@@ -96,15 +95,14 @@
gtk_box_pack_start (GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
gtk_widget_show (hbox);
- gtk_table_attach (GTK_TABLE (table), vbox, 1, 2, *row, *row + 1,
- GTK_FILL, GTK_FILL, 0, 0);
+ gtk_grid_attach (GTK_GRID (table), vbox, 1, *row, 1, 1);
gtk_widget_show (vbox);
*row += 1;
}
static void
-pgd_info_add_metadata (GtkTable *table,
+pgd_info_add_metadata (GtkGrid *table,
const gchar *metadata,
gint *row)
{
@@ -115,8 +113,7 @@
label = gtk_label_new (NULL);
g_object_set (G_OBJECT (label), "xalign", 0.0, NULL);
gtk_label_set_markup (GTK_LABEL (label), "<b>Metadata:</b>");
- gtk_table_attach (GTK_TABLE (table), label, 0, 1, *row, *row + 1,
- GTK_FILL, GTK_FILL, 0, 0);
+ gtk_grid_attach (GTK_GRID (table), label, 0, *row, 1, 1);
gtk_widget_show (label);
swindow = gtk_scrolled_window_new (NULL, NULL);
@@ -132,10 +129,10 @@
gtk_container_add (GTK_CONTAINER (swindow), textview);
gtk_widget_show (textview);
-
- gtk_table_attach (GTK_TABLE (table), swindow, 1, 2, *row, *row + 1,
- (GtkAttachOptions)(GTK_EXPAND | GTK_FILL),
- (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0);
+
+ gtk_grid_attach (GTK_GRID (table), swindow, 1, *row, 1, 1);
+ gtk_widget_set_hexpand (swindow, TRUE);
+ gtk_widget_set_vexpand (swindow, TRUE);
gtk_widget_show (swindow);
*row += 1;
@@ -181,7 +178,7 @@
"metadata", &metadata,
NULL);
- vbox = gtk_vbox_new (FALSE, 12);
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
backend = poppler_get_backend ();
enum_value = g_enum_get_value ((GEnumClass *) g_type_class_ref (POPPLER_TYPE_BACKEND), backend);
@@ -205,61 +202,61 @@
gtk_container_add (GTK_CONTAINER (frame), alignment);
gtk_widget_show (alignment);
- table = gtk_table_new (14, 2, FALSE);
- gtk_table_set_col_spacings (GTK_TABLE (table), 6);
- gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+ table = gtk_grid_new ();
+ gtk_grid_set_column_spacing (GTK_GRID (table), 6);
+ gtk_grid_set_row_spacing (GTK_GRID (table), 6);
- pgd_table_add_property (GTK_TABLE (table), "<b>Format:</b>", format, &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Format:</b>", format, &row);
g_free (format);
- pgd_table_add_property (GTK_TABLE (table), "<b>Title:</b>", title, &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Title:</b>", title, &row);
g_free (title);
- pgd_table_add_property (GTK_TABLE (table), "<b>Author:</b>", author, &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Author:</b>", author, &row);
g_free (author);
- pgd_table_add_property (GTK_TABLE (table), "<b>Subject:</b>", subject, &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Subject:</b>", subject, &row);
g_free (subject);
- pgd_table_add_property (GTK_TABLE (table), "<b>Keywords:</b>", keywords, &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Keywords:</b>", keywords, &row);
g_free (keywords);
- pgd_table_add_property (GTK_TABLE (table), "<b>Creator:</b>", creator, &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Creator:</b>", creator, &row);
g_free (creator);
- pgd_table_add_property (GTK_TABLE (table), "<b>Producer:</b>", producer, &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Producer:</b>", producer, &row);
g_free (producer);
- pgd_table_add_property (GTK_TABLE (table), "<b>Linearized:</b>", linearized ? "Yes" : "No", &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Linearized:</b>", linearized ? "Yes" : "No", &row);
str = pgd_format_date (creation_date);
- pgd_table_add_property (GTK_TABLE (table), "<b>Creation Date:</b>", str, &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Creation Date:</b>", str, &row);
g_free (str);
str = pgd_format_date (mod_date);
- pgd_table_add_property (GTK_TABLE (table), "<b>Modification Date:</b>", str, &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Modification Date:</b>", str, &row);
g_free (str);
enum_value = g_enum_get_value ((GEnumClass *) g_type_class_peek (POPPLER_TYPE_PAGE_MODE), mode);
- pgd_table_add_property (GTK_TABLE (table), "<b>Page Mode:</b>", enum_value->value_name, &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Page Mode:</b>", enum_value->value_name, &row);
enum_value = g_enum_get_value ((GEnumClass *) g_type_class_peek (POPPLER_TYPE_PAGE_LAYOUT), layout);
- pgd_table_add_property (GTK_TABLE (table), "<b>Page Layout:</b>", enum_value->value_name, &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Page Layout:</b>", enum_value->value_name, &row);
if (poppler_document_get_id (document, &perm_id, &up_id)) {
str = g_strndup (perm_id, 32);
g_free (perm_id);
- pgd_table_add_property (GTK_TABLE (table), "<b>Permanent ID:</b>", str, &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Permanent ID:</b>", str, &row);
g_free (str);
str = g_strndup (up_id, 32);
g_free (up_id);
- pgd_table_add_property (GTK_TABLE (table), "<b>Update ID:</b>", str, &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Update ID:</b>", str, &row);
g_free (str);
}
- pgd_info_add_permissions (GTK_TABLE (table), permissions, &row);
+ pgd_info_add_permissions (GTK_GRID (table), permissions, &row);
- pgd_info_add_metadata (GTK_TABLE (table), metadata, &row);
+ pgd_info_add_metadata (GTK_GRID (table), metadata, &row);
g_free (metadata);
/* TODO: view_prefs */
diff --git a/glib/demo/layers.c b/glib/demo/layers.c
index fc0ba35..c55de42 100644
--- a/glib/demo/layers.c
+++ b/glib/demo/layers.c
@@ -181,24 +181,18 @@
}
static gboolean
-pgd_layers_viewer_drawing_area_expose (GtkWidget *area,
- GdkEventExpose *event,
- PgdLayersDemo *demo)
+pgd_layers_viewer_drawing_area_draw (GtkWidget *area,
+ cairo_t *cr,
+ PgdLayersDemo *demo)
{
- cairo_t *cr;
-
if (!demo->surface) {
demo->surface = pgd_layers_render_page (demo);
if (!demo->surface)
return FALSE;
}
- gdk_window_clear (gtk_widget_get_window (area));
-
- cr = gdk_cairo_create (gtk_widget_get_window (area));
cairo_set_source_surface (cr, demo->surface, 0, 0);
cairo_paint (cr);
- cairo_destroy (cr);
return TRUE;
}
@@ -238,9 +232,9 @@
guint n_pages;
gchar *str;
- vbox = gtk_vbox_new (FALSE, 6);
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
- hbox = gtk_hbox_new (FALSE, 6);
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
label = gtk_label_new ("Page:");
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
@@ -264,8 +258,8 @@
gtk_widget_show (hbox);
demo->darea = gtk_drawing_area_new ();
- g_signal_connect (G_OBJECT (demo->darea), "expose_event",
- G_CALLBACK (pgd_layers_viewer_drawing_area_expose),
+ g_signal_connect (G_OBJECT (demo->darea), "draw",
+ G_CALLBACK (pgd_layers_viewer_drawing_area_draw),
(gpointer)demo);
swindow = gtk_scrolled_window_new (NULL, NULL);
@@ -385,7 +379,7 @@
demo = g_new0 (PgdLayersDemo, 1);
demo->doc = g_object_ref (document);
- hpaned = gtk_hpaned_new ();
+ hpaned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
viewer = pgd_layers_create_viewer (demo);
diff --git a/glib/demo/links.c b/glib/demo/links.c
index 6cb4a5d..3670436 100644
--- a/glib/demo/links.c
+++ b/glib/demo/links.c
@@ -178,9 +178,9 @@
n_pages = poppler_document_get_n_pages (document);
- vbox = gtk_vbox_new (FALSE, 12);
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
- hbox = gtk_hbox_new (FALSE, 6);
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
label = gtk_label_new ("Page:");
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
@@ -215,7 +215,7 @@
gtk_box_pack_start (GTK_BOX (vbox), demo->timer_label, FALSE, TRUE, 0);
gtk_widget_show (demo->timer_label);
- hpaned = gtk_hpaned_new ();
+ hpaned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
demo->action_view = pgd_action_view_new (document);
diff --git a/glib/demo/main.c b/glib/demo/main.c
index f52c5b8..2523800 100644
--- a/glib/demo/main.c
+++ b/glib/demo/main.c
@@ -180,9 +180,6 @@
action_area = gtk_dialog_get_action_area (dialog);
/* Set the dialog up with HIG properties */
-#if !GTK_CHECK_VERSION (2, 22, 0)
- gtk_dialog_set_has_separator (dialog, FALSE);
-#endif
gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
gtk_box_set_spacing (GTK_BOX (content_area), 2); /* 2 * 5 + 2 = 12 */
gtk_container_set_border_width (GTK_CONTAINER (action_area), 5);
@@ -206,7 +203,7 @@
-1);
/* Build contents */
- hbox = gtk_hbox_new (FALSE, 12);
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
gtk_box_pack_start (GTK_BOX (content_area), hbox, TRUE, TRUE, 0);
gtk_widget_show (hbox);
@@ -218,7 +215,7 @@
gtk_box_pack_start (GTK_BOX (hbox), icon, FALSE, FALSE, 0);
gtk_widget_show (icon);
- main_vbox = gtk_vbox_new (FALSE, 18);
+ main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 18);
gtk_box_pack_start (GTK_BOX (hbox), main_vbox, TRUE, TRUE, 0);
gtk_widget_show (main_vbox);
@@ -238,7 +235,7 @@
FALSE, FALSE, 0);
gtk_widget_show (label);
- vbox = gtk_vbox_new (FALSE, 6);
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
gtk_box_pack_start (GTK_BOX (main_vbox), vbox, FALSE, FALSE, 0);
gtk_widget_show (vbox);
@@ -252,9 +249,9 @@
FALSE, FALSE, 0);
gtk_widget_show (entry_container);
- table = gtk_table_new (1, 2, FALSE);
- gtk_table_set_col_spacings (GTK_TABLE (table), 12);
- gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+ table = gtk_grid_new ();
+ gtk_grid_set_column_spacing (GTK_GRID (table), 12);
+ gtk_grid_set_row_spacing (GTK_GRID (table), 6);
gtk_container_add (GTK_CONTAINER (entry_container), table);
gtk_widget_show (table);
@@ -270,13 +267,11 @@
G_CALLBACK (pgd_demo_auth_dialog_entry_activated),
dialog);
- gtk_table_attach (GTK_TABLE (table), label,
- 0, 1, 0, 1,
- GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
+ gtk_grid_attach (GTK_GRID (table), label, 0, 0, 1, 1);
gtk_widget_show (label);
- gtk_table_attach_defaults (GTK_TABLE (table), password_entry,
- 1, 2, 0, 1);
+ gtk_grid_attach (GTK_GRID (table), password_entry, 1, 0, 1, 1);
+ gtk_widget_set_hexpand (password_entry, TRUE);
gtk_widget_show (password_entry);
gtk_label_set_mnemonic_widget (GTK_LABEL (label), password_entry);
@@ -293,7 +288,6 @@
GtkWidget *treeview;
GtkTreeSelection *selection;
GFile *file;
- gchar *uri;
GTimer *timer;
GError *error = NULL;
GtkAccelGroup *gtk_accel;
@@ -304,19 +298,12 @@
return 1;
}
-/* Threading is always enabled starting from GLib 2.24.0 */
-#if !GLIB_CHECK_VERSION (2, 24, 0)
- if (!g_thread_supported ())
- g_thread_init (NULL);
-#endif
-
gtk_init (&argc, &argv);
file = g_file_new_for_commandline_arg (argv[1]);
- uri = g_file_get_uri (file);
timer = g_timer_new ();
- document = poppler_document_new_from_file (uri, NULL, &error);
+ document = poppler_document_new_from_gfile (file, NULL, NULL, &error);
g_timer_stop (timer);
if (error) {
while (g_error_matches (error, POPPLER_ERROR, POPPLER_ERROR_ENCRYPTED)) {
@@ -327,7 +314,6 @@
if (gtk_dialog_run (dialog) != GTK_RESPONSE_OK) {
g_print ("Error: no password provided\n");
g_object_unref (file);
- g_free (uri);
return 1;
}
@@ -336,7 +322,7 @@
password = g_object_get_data (G_OBJECT (dialog), "pgd-password");
g_timer_start (timer);
- document = poppler_document_new_from_file (uri, password, &error);
+ document = poppler_document_new_from_gfile (file, password, NULL, &error);
g_timer_stop (timer);
gtk_widget_destroy (GTK_WIDGET (dialog));
@@ -346,14 +332,12 @@
g_print ("Error: %s\n", error->message);
g_error_free (error);
g_object_unref (file);
- g_free (uri);
return 1;
}
}
g_object_unref (file);
- g_free (uri);
g_print ("Document successfully loaded in %.4f seconds\n",
g_timer_elapsed (timer, NULL));
@@ -373,7 +357,7 @@
g_closure_unref (closure);
gtk_window_add_accel_group (GTK_WINDOW(win), gtk_accel);
- hbox = gtk_hbox_new (FALSE, 6);
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
treeview = pgd_demo_list_create ();
gtk_box_pack_start (GTK_BOX (hbox), treeview, FALSE, TRUE, 0);
diff --git a/glib/demo/outline.c b/glib/demo/outline.c
index 5dc7189..55874cc 100644
--- a/glib/demo/outline.c
+++ b/glib/demo/outline.c
@@ -161,7 +161,7 @@
GtkTreeSelection *selection;
GtkWidget *hpaned, *action;
- hpaned = gtk_hpaned_new ();
+ hpaned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
action = pgd_action_view_new (document);
diff --git a/glib/demo/page.c b/glib/demo/page.c
index 7ab008c..ddf7789 100644
--- a/glib/demo/page.c
+++ b/glib/demo/page.c
@@ -229,9 +229,9 @@
n_pages = poppler_document_get_n_pages (document);
- vbox = gtk_vbox_new (FALSE, 12);
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
- hbox = gtk_hbox_new (FALSE, 6);
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
label = gtk_label_new ("Page:");
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
@@ -260,7 +260,7 @@
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
gtk_widget_show (hbox);
- hbox = gtk_hbox_new (FALSE, 6);
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
frame = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
@@ -274,18 +274,17 @@
gtk_container_add (GTK_CONTAINER (frame), alignment);
gtk_widget_show (alignment);
- table = gtk_table_new (3, 2, FALSE);
+ table = gtk_grid_new ();
+ gtk_grid_set_column_spacing (GTK_GRID (table), 6);
+ gtk_grid_set_row_spacing (GTK_GRID (table), 6);
- gtk_table_set_col_spacings (GTK_TABLE (table), 6);
- gtk_table_set_row_spacings (GTK_TABLE (table), 6);
-
- pgd_table_add_property_with_value_widget (GTK_TABLE (table), "<b>Page Index:</b>",
+ pgd_table_add_property_with_value_widget (GTK_GRID (table), "<b>Page Index:</b>",
&(demo->index), NULL, &row);
- pgd_table_add_property_with_value_widget (GTK_TABLE (table), "<b>Page Label:</b>",
+ pgd_table_add_property_with_value_widget (GTK_GRID (table), "<b>Page Label:</b>",
&(demo->label), NULL, &row);
- pgd_table_add_property_with_value_widget (GTK_TABLE (table), "<b>Page Size:</b>",
+ pgd_table_add_property_with_value_widget (GTK_GRID (table), "<b>Page Size:</b>",
&(demo->size), NULL, &row);
- pgd_table_add_property_with_value_widget (GTK_TABLE (table), "<b>Page Duration:</b>",
+ pgd_table_add_property_with_value_widget (GTK_GRID (table), "<b>Page Duration:</b>",
&(demo->duration), NULL, &row);
gtk_container_add (GTK_CONTAINER (alignment), table);
@@ -307,7 +306,7 @@
gtk_container_add (GTK_CONTAINER (frame), alignment);
gtk_widget_show (alignment);
- thumnail_box = gtk_vbox_new (FALSE, 6);
+ thumnail_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
demo->thumbnail = gtk_image_new ();
gtk_box_pack_start (GTK_BOX (thumnail_box), demo->thumbnail, TRUE, TRUE, 0);
diff --git a/glib/demo/print.c b/glib/demo/print.c
index 17bbe0e..8147036 100644
--- a/glib/demo/print.c
+++ b/glib/demo/print.c
@@ -114,24 +114,18 @@
PGD_PRINT_OPTIONS,
PRINT_DOCUMENT_MARKUPS);
- hbox = gtk_hbox_new (FALSE, 0);
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_container_set_border_width (GTK_CONTAINER (hbox), 12);
label = gtk_label_new ("Print: ");
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
-#if GTK_CHECK_VERSION (2, 24, 0)
combo = gtk_combo_box_text_new ();
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "Document");
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "Document and markup");
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "Document and stamps");
-#else
- combo = gtk_combo_box_new_text ();
- gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "Document");
- gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "Document and markup");
- gtk_combo_box_append_text (GTK_COMBO_BOX (combo), "Document and stamps");
-#endif
+
demo->options_combo = combo;
gtk_combo_box_set_active (GTK_COMBO_BOX (combo), options);
gtk_box_pack_start (GTK_BOX (hbox), combo, FALSE, FALSE, 0);
@@ -210,9 +204,9 @@
demo->doc = g_object_ref (document);
- vbox = gtk_vbox_new (FALSE, 12);
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
- hbox = gtk_hbox_new (FALSE, 6);
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
button = gtk_button_new_with_label ("Print...");
g_signal_connect (G_OBJECT (button), "clicked",
diff --git a/glib/demo/render.c b/glib/demo/render.c
index bb7afbd..48e9210 100644
--- a/glib/demo/render.c
+++ b/glib/demo/render.c
@@ -23,16 +23,10 @@
#include "render.h"
-typedef enum {
- PGD_RENDER_CAIRO,
- PGD_RENDER_PIXBUF
-} PgdRenderMode;
-
typedef struct {
PopplerDocument *doc;
/* Properties */
- PgdRenderMode mode;
gint page;
gdouble scale;
gint rotate;
@@ -48,7 +42,6 @@
GtkWidget *timer_label;
cairo_surface_t *surface;
- GdkPixbuf *pixbuf;
} PgdRenderDemo;
static void
@@ -61,53 +54,25 @@
g_object_unref (demo->doc);
demo->doc = NULL;
}
-
+
if (demo->surface) {
cairo_surface_destroy (demo->surface);
demo->surface = NULL;
}
- if (demo->pixbuf) {
- g_object_unref (demo->pixbuf);
- demo->pixbuf = NULL;
- }
-
g_free (demo);
}
static gboolean
-pgd_render_drawing_area_expose (GtkWidget *area,
- GdkEventExpose *event,
- PgdRenderDemo *demo)
+pgd_render_drawing_area_draw (GtkWidget *area,
+ cairo_t *cr,
+ PgdRenderDemo *demo)
{
- if (demo->mode == PGD_RENDER_CAIRO && !demo->surface)
+ if (!demo->surface)
return FALSE;
- if (demo->mode == PGD_RENDER_PIXBUF && !demo->pixbuf)
- return FALSE;
-
- gdk_window_clear (gtk_widget_get_window (area));
-
- if (demo->mode == PGD_RENDER_CAIRO) {
- cairo_t *cr;
-
- cr = gdk_cairo_create (gtk_widget_get_window (area));
- cairo_set_source_surface (cr, demo->surface, 0, 0);
- cairo_paint (cr);
- cairo_destroy (cr);
- } else if (demo->mode == PGD_RENDER_PIXBUF) {
- gdk_draw_pixbuf (gtk_widget_get_window (area),
- gtk_widget_get_style(area)->fg_gc[GTK_STATE_NORMAL],
- demo->pixbuf,
- 0, 0,
- 0, 0,
- gdk_pixbuf_get_width (demo->pixbuf),
- gdk_pixbuf_get_height (demo->pixbuf),
- GDK_RGB_DITHER_NORMAL,
- 0, 0);
- } else {
- g_assert_not_reached ();
- }
+ cairo_set_source_surface (cr, demo->surface, 0, 0);
+ cairo_paint (cr);
return TRUE;
}
@@ -122,6 +87,7 @@
gint x, y;
gchar *str;
GTimer *timer;
+ cairo_t *cr;
page = poppler_document_get_page (demo->doc, demo->page);
if (!page)
@@ -131,10 +97,6 @@
cairo_surface_destroy (demo->surface);
demo->surface = NULL;
- if (demo->pixbuf)
- g_object_unref (demo->pixbuf);
- demo->pixbuf = NULL;
-
poppler_page_get_size (page, &page_width, &page_height);
if (demo->rotate == 0 || demo->rotate == 180) {
@@ -149,90 +111,58 @@
y = demo->slice.x * demo->scale;
}
- if (demo->mode == PGD_RENDER_CAIRO) {
- cairo_t *cr;
+ timer = g_timer_new ();
+ demo->surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+ width, height);
+ cr = cairo_create (demo->surface);
- timer = g_timer_new ();
- demo->surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
- width, height);
- cr = cairo_create (demo->surface);
+ cairo_save (cr);
+ switch (demo->rotate) {
+ case 90:
+ cairo_translate (cr, x + width, -y);
+ break;
+ case 180:
+ cairo_translate (cr, x + width, y + height);
+ break;
+ case 270:
+ cairo_translate (cr, -x, y + height);
+ break;
+ default:
+ cairo_translate (cr, -x, -y);
+ }
- cairo_save (cr);
- switch (demo->rotate) {
- case 90:
- cairo_translate (cr, x + width, -y);
- break;
- case 180:
- cairo_translate (cr, x + width, y + height);
- break;
- case 270:
- cairo_translate (cr, -x, y + height);
- break;
- default:
- cairo_translate (cr, -x, -y);
- }
+ if (demo->scale != 1.0)
+ cairo_scale (cr, demo->scale, demo->scale);
- if (demo->scale != 1.0)
- cairo_scale (cr, demo->scale, demo->scale);
-
- if (demo->rotate != 0)
- cairo_rotate (cr, demo->rotate * G_PI / 180.0);
+ if (demo->rotate != 0)
+ cairo_rotate (cr, demo->rotate * G_PI / 180.0);
- if (demo->printing)
- poppler_page_render_for_printing (page, cr);
- else
- poppler_page_render (page, cr);
- cairo_restore (cr);
+ if (demo->printing)
+ poppler_page_render_for_printing (page, cr);
+ else
+ poppler_page_render (page, cr);
+ cairo_restore (cr);
- cairo_set_operator (cr, CAIRO_OPERATOR_DEST_OVER);
- cairo_set_source_rgb (cr, 1., 1., 1.);
- cairo_paint (cr);
+ cairo_set_operator (cr, CAIRO_OPERATOR_DEST_OVER);
+ cairo_set_source_rgb (cr, 1., 1., 1.);
+ cairo_paint (cr);
- g_timer_stop (timer);
-
- cairo_destroy (cr);
- } else if (demo->mode == PGD_RENDER_PIXBUF) {
-#ifdef POPPLER_WITH_GDK
- timer = g_timer_new ();
- demo->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
- FALSE, 8, width, height);
- gdk_pixbuf_fill (demo->pixbuf, 0xffffff);
- if (demo->printing) {
- poppler_page_render_to_pixbuf_for_printing (page,
- x, y,
- width,
- height,
- demo->scale,
- demo->rotate,
- demo->pixbuf);
- } else {
- poppler_page_render_to_pixbuf (page,
- x, y,
- width,
- height,
- demo->scale,
- demo->rotate,
- demo->pixbuf);
- }
- g_timer_stop (timer);
-#endif /* POPPLER_WITH_GDK */
- } else {
- g_assert_not_reached ();
- }
+ g_timer_stop (timer);
+ cairo_destroy (cr);
g_object_unref (page);
-
+
str = g_strdup_printf ("<i>Page rendered in %.4f seconds</i>",
g_timer_elapsed (timer, NULL));
gtk_label_set_markup (GTK_LABEL (demo->timer_label), str);
g_free (str);
-
+
g_timer_destroy (timer);
-
+
gtk_widget_set_size_request (demo->darea, width, height);
gtk_widget_queue_draw (demo->darea);
}
-
+
static void
pgd_render_slice_selector_setup (PgdRenderDemo *demo)
{
@@ -288,13 +218,6 @@
}
static void
-pgd_render_mode_selector_changed (GtkComboBox *combobox,
- PgdRenderDemo *demo)
-{
- demo->mode = gtk_combo_box_get_active (combobox);
-}
-
-static void
pgd_render_slice_selector_value_changed (GtkSpinButton *spinbutton,
PgdRenderDemo *demo)
{
@@ -312,7 +235,6 @@
GtkWidget *page_hbox, *page_selector;
GtkWidget *scale_hbox, *scale_selector;
GtkWidget *rotate_hbox, *rotate_selector;
- GtkWidget *mode_hbox, *mode_selector;
GtkWidget *printing_selector;
GtkWidget *slice_hbox, *slice_selector;
GtkWidget *button;
@@ -321,18 +243,18 @@
n_pages = poppler_document_get_n_pages (demo->doc);
- vbox = gtk_vbox_new (FALSE, 6);
-
- hbox = gtk_hbox_new (FALSE, 12);
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
gtk_widget_show (hbox);
- page_hbox = gtk_hbox_new (FALSE, 6);
+ page_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
label = gtk_label_new ("Page:");
gtk_box_pack_start (GTK_BOX (page_hbox), label, TRUE, TRUE, 0);
gtk_widget_show (label);
-
+
page_selector = gtk_spin_button_new_with_range (1, n_pages, 1);
g_signal_connect (G_OBJECT (page_selector), "value-changed",
G_CALLBACK (pgd_render_page_selector_value_changed),
@@ -349,12 +271,12 @@
gtk_box_pack_start (GTK_BOX (hbox), page_hbox, FALSE, TRUE, 0);
gtk_widget_show (page_hbox);
- scale_hbox = gtk_hbox_new (FALSE, 6);
-
+ scale_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+
label = gtk_label_new ("Scale:");
gtk_box_pack_start (GTK_BOX (scale_hbox), label, TRUE, TRUE, 0);
gtk_widget_show (label);
-
+
scale_selector = gtk_spin_button_new_with_range (0, 10.0, 0.1);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (scale_selector), 1.0);
g_signal_connect (G_OBJECT (scale_selector), "value-changed",
@@ -366,25 +288,17 @@
gtk_box_pack_start (GTK_BOX (hbox), scale_hbox, FALSE, TRUE, 0);
gtk_widget_show (scale_hbox);
- rotate_hbox = gtk_hbox_new (FALSE, 6);
+ rotate_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
label = gtk_label_new ("Rotate:");
gtk_box_pack_start (GTK_BOX (rotate_hbox), label, TRUE, TRUE, 0);
gtk_widget_show (label);
-#if GTK_CHECK_VERSION (2, 24, 0)
rotate_selector = gtk_combo_box_text_new ();
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (rotate_selector), "0");
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (rotate_selector), "90");
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (rotate_selector), "180");
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (rotate_selector), "270");
-#else
- rotate_selector = gtk_combo_box_new_text ();
- gtk_combo_box_append_text (GTK_COMBO_BOX (rotate_selector), "0");
- gtk_combo_box_append_text (GTK_COMBO_BOX (rotate_selector), "90");
- gtk_combo_box_append_text (GTK_COMBO_BOX (rotate_selector), "180");
- gtk_combo_box_append_text (GTK_COMBO_BOX (rotate_selector), "270");
-#endif
gtk_combo_box_set_active (GTK_COMBO_BOX (rotate_selector), 0);
g_signal_connect (G_OBJECT (rotate_selector), "changed",
G_CALLBACK (pgd_render_rotate_selector_changed),
@@ -395,35 +309,6 @@
gtk_box_pack_start (GTK_BOX (hbox), rotate_hbox, FALSE, TRUE, 0);
gtk_widget_show (rotate_hbox);
- mode_hbox = gtk_hbox_new (FALSE, 6);
-
- label = gtk_label_new ("Mode:");
- gtk_box_pack_start (GTK_BOX (mode_hbox), label, TRUE, TRUE, 0);
- gtk_widget_show (label);
-
-#if GTK_CHECK_VERSION (2, 24, 0)
- mode_selector = gtk_combo_box_text_new ();
- gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (mode_selector), "cairo");
-#ifdef POPPLER_WITH_GDK
- gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (mode_selector), "pixbuf");
-#endif
-#else // ! GTK_CHECK_VERSION (2, 24, 0)
- mode_selector = gtk_combo_box_new_text ();
- gtk_combo_box_append_text (GTK_COMBO_BOX (mode_selector), "cairo");
-#ifdef POPPLER_WITH_GDK
- gtk_combo_box_append_text (GTK_COMBO_BOX (mode_selector), "pixbuf");
-#endif
-#endif // GTK_CHECK_VERSION (2, 24, 0)
- gtk_combo_box_set_active (GTK_COMBO_BOX (mode_selector), 0);
- g_signal_connect (G_OBJECT (mode_selector), "changed",
- G_CALLBACK (pgd_render_mode_selector_changed),
- (gpointer)demo);
- gtk_box_pack_start (GTK_BOX (mode_hbox), mode_selector, TRUE, TRUE, 0);
- gtk_widget_show (mode_selector);
-
- gtk_box_pack_start (GTK_BOX (hbox), mode_hbox, FALSE, TRUE, 0);
- gtk_widget_show (mode_hbox);
-
printing_selector = gtk_check_button_new_with_label ("Printing");
g_signal_connect (printing_selector, "toggled",
G_CALLBACK (pgd_render_printing_selector_changed),
@@ -431,11 +316,11 @@
gtk_box_pack_start (GTK_BOX (hbox), printing_selector, FALSE, TRUE, 0);
gtk_widget_show (printing_selector);
- hbox = gtk_hbox_new (FALSE, 12);
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
gtk_widget_show (hbox);
- slice_hbox = gtk_hbox_new (FALSE, 6);
+ slice_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
label = gtk_label_new ("x:");
gtk_box_pack_start (GTK_BOX (slice_hbox), label, TRUE, TRUE, 0);
@@ -451,8 +336,8 @@
gtk_box_pack_start (GTK_BOX (hbox), slice_hbox, FALSE, TRUE, 0);
gtk_widget_show (slice_hbox);
- slice_hbox = gtk_hbox_new (FALSE, 6);
-
+ slice_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+
label = gtk_label_new ("y:");
gtk_box_pack_start (GTK_BOX (slice_hbox), label, TRUE, TRUE, 0);
gtk_widget_show (label);
@@ -466,9 +351,9 @@
gtk_box_pack_start (GTK_BOX (hbox), slice_hbox, FALSE, TRUE, 0);
gtk_widget_show (slice_hbox);
-
- slice_hbox = gtk_hbox_new (FALSE, 6);
-
+
+ slice_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+
label = gtk_label_new ("width:");
gtk_box_pack_start (GTK_BOX (slice_hbox), label, TRUE, TRUE, 0);
gtk_widget_show (label);
@@ -482,9 +367,9 @@
gtk_box_pack_start (GTK_BOX (hbox), slice_hbox, FALSE, TRUE, 0);
gtk_widget_show (slice_hbox);
-
- slice_hbox = gtk_hbox_new (FALSE, 6);
-
+
+ slice_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+
label = gtk_label_new ("height:");
gtk_box_pack_start (GTK_BOX (slice_hbox), label, TRUE, TRUE, 0);
gtk_widget_show (label);
@@ -528,17 +413,17 @@
demo->doc = g_object_ref (document);
demo->scale = 1.0;
- vbox = gtk_vbox_new (FALSE, 6);
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
hbox = pgd_render_properties_selector_create (demo);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 6);
gtk_widget_show (hbox);
demo->darea = gtk_drawing_area_new ();
- g_signal_connect (G_OBJECT (demo->darea), "expose_event",
- G_CALLBACK (pgd_render_drawing_area_expose),
+ g_signal_connect (G_OBJECT (demo->darea), "draw",
+ G_CALLBACK (pgd_render_drawing_area_draw),
(gpointer)demo);
-
+
demo->swindow = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (demo->swindow),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
diff --git a/glib/demo/selections.c b/glib/demo/selections.c
index bfd9070..4ec5d6b 100644
--- a/glib/demo/selections.c
+++ b/glib/demo/selections.c
@@ -77,7 +77,6 @@
cairo_region_destroy (demo->selected_region);
demo->selected_region = NULL;
}
- gtk_widget_set_sensitive(demo->copy_button, FALSE);
}
static void
@@ -172,7 +171,7 @@
gdk_window_set_cursor (window, cursor);
gdk_flush ();
if (cursor)
- gdk_cursor_unref (cursor);
+ g_object_unref (cursor);
}
static gboolean
@@ -220,19 +219,13 @@
}
static gboolean
-pgd_selections_drawing_area_expose (GtkWidget *area,
- GdkEventExpose *event,
- PgdSelectionsDemo *demo)
+pgd_selections_drawing_area_draw (GtkWidget *area,
+ cairo_t *cr,
+ PgdSelectionsDemo *demo)
{
- cairo_t *cr;
-
if (!demo->surface)
return FALSE;
- gdk_window_clear (gtk_widget_get_window (area));
-
- cr = gdk_cairo_create (gtk_widget_get_window (area));
-
cairo_save (cr);
cairo_set_source_surface (cr, demo->surface, 0, 0);
cairo_paint (cr);
@@ -243,8 +236,6 @@
cairo_paint (cr);
}
- cairo_destroy (cr);
-
return TRUE;
}
@@ -335,7 +326,8 @@
pgd_selections_drawing_area_realize (GtkWidget *area,
PgdSelectionsDemo *demo)
{
- GtkStyle *style = gtk_widget_get_style (area);
+ GtkStyleContext *style_context = gtk_widget_get_style_context (area);
+ GdkRGBA rgba;
gtk_widget_add_events (area,
GDK_POINTER_MOTION_HINT_MASK |
@@ -344,10 +336,10 @@
GDK_BUTTON_RELEASE_MASK);
g_object_set (area, "has-tooltip", TRUE, NULL);
- gtk_color_button_set_color (GTK_COLOR_BUTTON (demo->fg_color_button),
- &style->text[GTK_STATE_SELECTED]);
- gtk_color_button_set_color (GTK_COLOR_BUTTON (demo->bg_color_button),
- &style->base[GTK_STATE_SELECTED]);
+ gtk_style_context_get_color (style_context, GTK_STATE_FLAG_SELECTED, &rgba);
+ gtk_color_button_set_rgba (GTK_COLOR_BUTTON (demo->fg_color_button), &rgba);
+ gtk_style_context_get_background_color (style_context, GTK_STATE_FLAG_SELECTED, &rgba);
+ gtk_color_button_set_rgba (GTK_COLOR_BUTTON (demo->bg_color_button), &rgba);
}
static gboolean
@@ -401,6 +393,7 @@
pgd_selections_clear_selections (demo);
pgd_selections_update_selection_region (demo);
+ gtk_widget_set_sensitive (demo->copy_button, FALSE);
if (demo->surface)
cairo_surface_destroy (demo->surface);
@@ -463,12 +456,12 @@
GParamSpec *pspec,
PgdSelectionsDemo *demo)
{
- GdkColor color;
+ GdkRGBA color;
- gtk_color_button_get_color (GTK_COLOR_BUTTON (button), &color);
- demo->glyph_color.red = color.red;
- demo->glyph_color.green = color.green;
- demo->glyph_color.blue = color.blue;
+ gtk_color_button_get_rgba (GTK_COLOR_BUTTON (button), &color);
+ demo->glyph_color.red = CLAMP ((guint) (color.red * 65535), 0, 65535);
+ demo->glyph_color.green = CLAMP ((guint) (color.green * 65535), 0, 65535);
+ demo->glyph_color.blue = CLAMP ((guint) (color.blue * 65535), 0, 65535);
}
static void
@@ -476,12 +469,12 @@
GParamSpec *pspec,
PgdSelectionsDemo *demo)
{
- GdkColor color;
+ GdkRGBA color;
- gtk_color_button_get_color (GTK_COLOR_BUTTON (button), &color);
- demo->background_color.red = color.red;
- demo->background_color.green = color.green;
- demo->background_color.blue = color.blue;
+ gtk_color_button_get_rgba (GTK_COLOR_BUTTON (button), &color);
+ demo->background_color.red = CLAMP ((guint) (color.red * 65535), 0, 65535);
+ demo->background_color.green = CLAMP ((guint) (color.green * 65535), 0, 65535);
+ demo->background_color.blue = CLAMP ((guint) (color.blue * 65535), 0, 65535);
}
GtkWidget *
@@ -499,13 +492,13 @@
n_pages = poppler_document_get_n_pages (demo->doc);
- vbox = gtk_vbox_new (FALSE, 6);
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
- hbox = gtk_hbox_new (FALSE, 12);
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
gtk_widget_show (hbox);
- page_hbox = gtk_hbox_new (FALSE, 6);
+ page_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
label = gtk_label_new ("Page:");
gtk_box_pack_start (GTK_BOX (page_hbox), label, TRUE, TRUE, 0);
@@ -527,7 +520,7 @@
gtk_box_pack_start (GTK_BOX (hbox), page_hbox, FALSE, TRUE, 0);
gtk_widget_show (page_hbox);
- scale_hbox = gtk_hbox_new (FALSE, 6);
+ scale_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
label = gtk_label_new ("Scale:");
gtk_box_pack_start (GTK_BOX (scale_hbox), label, TRUE, TRUE, 0);
@@ -544,25 +537,17 @@
gtk_box_pack_start (GTK_BOX (hbox), scale_hbox, FALSE, TRUE, 0);
gtk_widget_show (scale_hbox);
- rotate_hbox = gtk_hbox_new (FALSE, 6);
+ rotate_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
label = gtk_label_new ("Rotate:");
gtk_box_pack_start (GTK_BOX (rotate_hbox), label, TRUE, TRUE, 0);
gtk_widget_show (label);
-#if GTK_CHECK_VERSION (2, 24, 0)
rotate_selector = gtk_combo_box_text_new ();
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (rotate_selector), "0");
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (rotate_selector), "90");
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (rotate_selector), "180");
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (rotate_selector), "270");
-#else
- rotate_selector = gtk_combo_box_new_text ();
- gtk_combo_box_append_text (GTK_COMBO_BOX (rotate_selector), "0");
- gtk_combo_box_append_text (GTK_COMBO_BOX (rotate_selector), "90");
- gtk_combo_box_append_text (GTK_COMBO_BOX (rotate_selector), "180");
- gtk_combo_box_append_text (GTK_COMBO_BOX (rotate_selector), "270");
-#endif
gtk_combo_box_set_active (GTK_COMBO_BOX (rotate_selector), 0);
#if 0
g_signal_connect (G_OBJECT (rotate_selector), "changed",
@@ -575,11 +560,11 @@
gtk_box_pack_start (GTK_BOX (hbox), rotate_hbox, FALSE, TRUE, 0);
gtk_widget_show (rotate_hbox);
- hbox = gtk_hbox_new (FALSE, 12);
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
gtk_widget_show (hbox);
- color_hbox = gtk_hbox_new (FALSE, 6);
+ color_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
label = gtk_label_new ("Foreground Color:");
gtk_box_pack_start (GTK_BOX (color_hbox), label, TRUE, TRUE, 0);
@@ -595,7 +580,7 @@
gtk_box_pack_start (GTK_BOX (hbox), color_hbox, FALSE, TRUE, 0);
gtk_widget_show (color_hbox);
- color_hbox = gtk_hbox_new (FALSE, 6);
+ color_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
label = gtk_label_new ("Background Color:");
gtk_box_pack_start (GTK_BOX (color_hbox), label, TRUE, TRUE, 0);
@@ -643,7 +628,7 @@
pgd_selections_clear_selections (demo);
- vbox = gtk_vbox_new (FALSE, 6);
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
hbox = pgd_selections_properties_selector_create (demo);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 6);
@@ -653,8 +638,8 @@
g_signal_connect (demo->darea, "realize",
G_CALLBACK (pgd_selections_drawing_area_realize),
(gpointer)demo);
- g_signal_connect (demo->darea, "expose_event",
- G_CALLBACK (pgd_selections_drawing_area_expose),
+ g_signal_connect (demo->darea, "draw",
+ G_CALLBACK (pgd_selections_drawing_area_draw),
(gpointer)demo);
g_signal_connect (demo->darea, "button_press_event",
G_CALLBACK (pgd_selections_drawing_area_button_press),
diff --git a/glib/demo/text.c b/glib/demo/text.c
index 3a7b2cd..b05581d 100644
--- a/glib/demo/text.c
+++ b/glib/demo/text.c
@@ -303,11 +303,11 @@
n_pages = poppler_document_get_n_pages (document);
- vbox = gtk_vbox_new (FALSE, 12);
- vbox2 = gtk_vbox_new (FALSE, 12);
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
+ vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
textinfo = gtk_label_new ("TextInfo");
- hbox = gtk_hbox_new (FALSE, 6);
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
label = gtk_label_new ("Page:");
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
@@ -342,7 +342,7 @@
gtk_box_pack_start (GTK_BOX (vbox), demo->timer_label, FALSE, TRUE, 0);
gtk_widget_show (demo->timer_label);
- hpaned = gtk_hpaned_new ();
+ hpaned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
gtk_paned_set_position (GTK_PANED (hpaned), 300);
swindow = gtk_scrolled_window_new (NULL, NULL);
@@ -398,7 +398,7 @@
gtk_container_add (GTK_CONTAINER (swindow), treeview);
gtk_widget_show (treeview);
- gtk_container_add (GTK_CONTAINER (vbox2), swindow);
+ gtk_box_pack_start (GTK_BOX (vbox2), swindow, TRUE, TRUE, 0);
gtk_widget_show (swindow);
/* Text attributes */
@@ -414,18 +414,18 @@
gtk_container_add (GTK_CONTAINER (frame), alignment);
gtk_widget_show (alignment);
- table = gtk_table_new (4, 2, FALSE);
- gtk_table_set_col_spacings (GTK_TABLE (table), 6);
- gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+ table = gtk_grid_new ();
+ gtk_grid_set_column_spacing (GTK_GRID (table), 6);
+ gtk_grid_set_row_spacing (GTK_GRID (table), 6);
demo->font_name = gtk_label_new (NULL);
- pgd_table_add_property_with_custom_widget (GTK_TABLE (table), "<b>Font Name:</b>", demo->font_name, &row);
+ pgd_table_add_property_with_custom_widget (GTK_GRID (table), "<b>Font Name:</b>", demo->font_name, &row);
demo->font_size = gtk_label_new (NULL);
- pgd_table_add_property_with_custom_widget (GTK_TABLE (table), "<b>Font Size:</b>", demo->font_size, &row);
+ pgd_table_add_property_with_custom_widget (GTK_GRID (table), "<b>Font Size:</b>", demo->font_size, &row);
demo->is_underlined = gtk_label_new (NULL);
- pgd_table_add_property_with_custom_widget (GTK_TABLE (table), "<b>Underlined:</b>", demo->is_underlined, &row);
+ pgd_table_add_property_with_custom_widget (GTK_GRID (table), "<b>Underlined:</b>", demo->is_underlined, &row);
demo->text_color = gtk_image_new ();
- pgd_table_add_property_with_custom_widget (GTK_TABLE (table), "<b>Color:</b>", demo->text_color, &row);
+ pgd_table_add_property_with_custom_widget (GTK_GRID (table), "<b>Color:</b>", demo->text_color, &row);
gtk_container_add (GTK_CONTAINER (alignment), table);
gtk_widget_show (table);
diff --git a/glib/demo/transitions.c b/glib/demo/transitions.c
index b6188b5..e6e2ab4 100644
--- a/glib/demo/transitions.c
+++ b/glib/demo/transitions.c
@@ -275,9 +275,9 @@
demo->doc = g_object_ref (document);
- vbox = gtk_vbox_new (FALSE, 12);
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
- hbox = gtk_hbox_new (FALSE, 6);
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
demo->progress = gtk_progress_bar_new ();
gtk_progress_bar_set_ellipsize (GTK_PROGRESS_BAR (demo->progress),
diff --git a/glib/demo/utils.c b/glib/demo/utils.c
index 625596c..f1d47c8 100644
--- a/glib/demo/utils.c
+++ b/glib/demo/utils.c
@@ -24,7 +24,7 @@
#include "utils.h"
void
-pgd_table_add_property_with_custom_widget (GtkTable *table,
+pgd_table_add_property_with_custom_widget (GtkGrid *table,
const gchar *markup,
GtkWidget *widget,
gint *row)
@@ -34,19 +34,18 @@
label = gtk_label_new (NULL);
g_object_set (G_OBJECT (label), "xalign", 0.0, NULL);
gtk_label_set_markup (GTK_LABEL (label), markup);
- gtk_table_attach (GTK_TABLE (table), label, 0, 1, *row, *row + 1,
- GTK_FILL, GTK_FILL, 0, 0);
+ gtk_grid_attach (GTK_GRID (table), label, 0, *row, 1, 1);
gtk_widget_show (label);
- gtk_table_attach (GTK_TABLE (table), widget, 1, 2, *row, *row + 1,
- GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0);
+ gtk_grid_attach (GTK_GRID (table), widget, 1, *row, 1, 1);
+ gtk_widget_set_hexpand (widget, TRUE);
gtk_widget_show (widget);
*row += 1;
}
void
-pgd_table_add_property_with_value_widget (GtkTable *table,
+pgd_table_add_property_with_value_widget (GtkGrid *table,
const gchar *markup,
GtkWidget **value_widget,
const gchar *value,
@@ -64,7 +63,7 @@
}
void
-pgd_table_add_property (GtkTable *table,
+pgd_table_add_property (GtkGrid *table,
const gchar *markup,
const gchar *value,
gint *row)
@@ -93,7 +92,7 @@
static void
pgd_action_view_add_destination (GtkWidget *action_view,
- GtkTable *table,
+ GtkGrid *table,
PopplerDest *dest,
gboolean remote,
gint *row)
@@ -165,13 +164,13 @@
alignment = gtk_alignment_new (0.5, 0.5, 1, 1);
gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 5, 5, 12, 5);
- new_table = gtk_table_new (8, 2, FALSE);
- gtk_table_set_col_spacings (GTK_TABLE (new_table), 6);
- gtk_table_set_row_spacings (GTK_TABLE (new_table), 6);
- gtk_table_attach_defaults (table, alignment, 0, 2, *row, *row + 1);
+ new_table = gtk_grid_new ();
+ gtk_grid_set_column_spacing (GTK_GRID (new_table), 6);
+ gtk_grid_set_row_spacing (GTK_GRID (new_table), 6);
+ gtk_grid_attach (GTK_GRID(table), alignment, 0, *row, 1, 1);
gtk_widget_show (alignment);
- pgd_action_view_add_destination (action_view, GTK_TABLE (new_table),
+ pgd_action_view_add_destination (action_view, GTK_GRID (new_table),
new_dest, FALSE, &new_row);
poppler_dest_free (new_dest);
@@ -329,68 +328,68 @@
if (!action)
return;
- table = gtk_table_new (10, 2, FALSE);
- gtk_table_set_col_spacings (GTK_TABLE (table), 6);
- gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+ table = gtk_grid_new ();
+ gtk_grid_set_column_spacing (GTK_GRID (table), 6);
+ gtk_grid_set_row_spacing (GTK_GRID (table), 6);
- pgd_table_add_property (GTK_TABLE (table), "<b>Title:</b>", action->any.title, &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Title:</b>", action->any.title, &row);
switch (action->type) {
case POPPLER_ACTION_UNKNOWN:
- pgd_table_add_property (GTK_TABLE (table), "<b>Type:</b>", "Unknown", &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Type:</b>", "Unknown", &row);
break;
case POPPLER_ACTION_NONE:
- pgd_table_add_property (GTK_TABLE (table), "<b>Type:</b>", "None", &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Type:</b>", "None", &row);
break;
case POPPLER_ACTION_GOTO_DEST:
- pgd_action_view_add_destination (action_view, GTK_TABLE (table), action->goto_dest.dest, FALSE, &row);
+ pgd_action_view_add_destination (action_view, GTK_GRID (table), action->goto_dest.dest, FALSE, &row);
break;
case POPPLER_ACTION_GOTO_REMOTE:
- pgd_table_add_property (GTK_TABLE (table), "<b>Type:</b>", "Remote Destination", &row);
- pgd_table_add_property (GTK_TABLE (table), "<b>Filename:</b>", action->goto_remote.file_name, &row);
- pgd_action_view_add_destination (action_view, GTK_TABLE (table), action->goto_remote.dest, TRUE, &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Type:</b>", "Remote Destination", &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Filename:</b>", action->goto_remote.file_name, &row);
+ pgd_action_view_add_destination (action_view, GTK_GRID (table), action->goto_remote.dest, TRUE, &row);
break;
case POPPLER_ACTION_LAUNCH:
- pgd_table_add_property (GTK_TABLE (table), "<b>Type:</b>", "Launch", &row);
- pgd_table_add_property (GTK_TABLE (table), "<b>Filename:</b>", action->launch.file_name, &row);
- pgd_table_add_property (GTK_TABLE (table), "<b>Params:</b>", action->launch.params, &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Type:</b>", "Launch", &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Filename:</b>", action->launch.file_name, &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Params:</b>", action->launch.params, &row);
break;
case POPPLER_ACTION_URI:
- pgd_table_add_property (GTK_TABLE (table), "<b>Type:</b>", "External URI", &row);
- pgd_table_add_property (GTK_TABLE (table), "<b>URI</b>", action->uri.uri, &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Type:</b>", "External URI", &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>URI</b>", action->uri.uri, &row);
break;
case POPPLER_ACTION_NAMED:
- pgd_table_add_property (GTK_TABLE (table), "<b>Type:</b>", "Named Action", &row);
- pgd_table_add_property (GTK_TABLE (table), "<b>Name:</b>", action->named.named_dest, &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Type:</b>", "Named Action", &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Name:</b>", action->named.named_dest, &row);
break;
case POPPLER_ACTION_MOVIE: {
GtkWidget *movie_view = pgd_movie_view_new ();
- pgd_table_add_property (GTK_TABLE (table), "<b>Type:</b>", "Movie", &row);
- pgd_table_add_property (GTK_TABLE (table), "<b>Operation:</b>", get_movie_op (action->movie.operation), &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Type:</b>", "Movie", &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Operation:</b>", get_movie_op (action->movie.operation), &row);
pgd_movie_view_set_movie (movie_view, action->movie.movie);
- pgd_table_add_property_with_custom_widget (GTK_TABLE (table), "<b>Movie:</b>", movie_view, &row);
+ pgd_table_add_property_with_custom_widget (GTK_GRID (table), "<b>Movie:</b>", movie_view, &row);
}
break;
case POPPLER_ACTION_RENDITION: {
gchar *text;
- pgd_table_add_property (GTK_TABLE (table), "<b>Type:</b>", "Rendition", &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Type:</b>", "Rendition", &row);
text = g_strdup_printf ("%d", action->rendition.op);
- pgd_table_add_property (GTK_TABLE (table), "<b>Operation:</b>", text, &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Operation:</b>", text, &row);
g_free (text);
if (action->rendition.media) {
gboolean embedded = poppler_media_is_embedded (action->rendition.media);
GtkWidget *button;
- pgd_table_add_property (GTK_TABLE (table), "<b>Embedded:</b>", embedded ? "Yes": "No", &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Embedded:</b>", embedded ? "Yes": "No", &row);
if (embedded) {
const gchar *mime_type = poppler_media_get_mime_type (action->rendition.media);
- pgd_table_add_property (GTK_TABLE (table), "<b>Mime type:</b>",
+ pgd_table_add_property (GTK_GRID (table), "<b>Mime type:</b>",
mime_type ? mime_type : "",
&row);
} else {
- pgd_table_add_property (GTK_TABLE (table), "<b>Filename:</b>",
+ pgd_table_add_property (GTK_GRID (table), "<b>Filename:</b>",
poppler_media_get_filename (action->rendition.media),
&row);
}
@@ -399,7 +398,7 @@
g_signal_connect (button, "clicked",
G_CALLBACK (pgd_action_view_play_rendition),
action->rendition.media);
- pgd_table_add_property_with_custom_widget (GTK_TABLE (table), NULL, button, &row);
+ pgd_table_add_property_with_custom_widget (GTK_GRID (table), NULL, button, &row);
gtk_widget_show (button);
}
}
@@ -408,7 +407,7 @@
GList *l;
GtkWidget *button;
- pgd_table_add_property (GTK_TABLE (table), "<b>Type:</b>", "OCGState", &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Type:</b>", "OCGState", &row);
for (l = action->ocg_state.state_list; l; l = g_list_next (l)) {
PopplerActionLayer *action_layer = (PopplerActionLayer *)l->data;
@@ -426,7 +425,7 @@
text = g_strdup_printf ("%d layers Toggle", n_layers);
break;
}
- pgd_table_add_property (GTK_TABLE (table), "<b>Action:</b>", text, &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Action:</b>", text, &row);
g_free (text);
}
@@ -434,7 +433,7 @@
g_signal_connect (button, "clicked",
G_CALLBACK (pgd_action_view_do_action_layer),
action->ocg_state.state_list);
- pgd_table_add_property_with_custom_widget (GTK_TABLE (table), NULL, button, &row);
+ pgd_table_add_property_with_custom_widget (GTK_GRID (table), NULL, button, &row);
gtk_widget_show (button);
}
break;
@@ -443,7 +442,7 @@
GtkWidget *textview;
GtkWidget *swindow;
- pgd_table_add_property (GTK_TABLE (table), "<b>Type:</b>", "JavaScript", &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Type:</b>", "JavaScript", &row);
buffer = gtk_text_buffer_new (NULL);
if (action->javascript.script)
@@ -459,7 +458,7 @@
gtk_container_add (GTK_CONTAINER (swindow), textview);
gtk_widget_show (textview);
- pgd_table_add_property_with_custom_widget (GTK_TABLE (table), NULL, swindow, &row);
+ pgd_table_add_property_with_custom_widget (GTK_GRID (table), NULL, swindow, &row);
gtk_widget_show (swindow);
}
break;
@@ -565,19 +564,19 @@
if (!movie)
return;
- table = gtk_table_new (10, 2, FALSE);
- gtk_table_set_col_spacings (GTK_TABLE (table), 6);
- gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+ table = gtk_grid_new ();
+ gtk_grid_set_column_spacing (GTK_GRID (table), 6);
+ gtk_grid_set_row_spacing (GTK_GRID (table), 6);
- pgd_table_add_property (GTK_TABLE (table), "<b>Filename:</b>", poppler_movie_get_filename (movie), &row);
- pgd_table_add_property (GTK_TABLE (table), "<b>Need Poster:</b>", poppler_movie_need_poster (movie) ? "Yes" : "No", &row);
- pgd_table_add_property (GTK_TABLE (table), "<b>Show Controls:</b>", poppler_movie_show_controls (movie) ? "Yes" : "No", &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Filename:</b>", poppler_movie_get_filename (movie), &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Need Poster:</b>", poppler_movie_need_poster (movie) ? "Yes" : "No", &row);
+ pgd_table_add_property (GTK_GRID (table), "<b>Show Controls:</b>", poppler_movie_show_controls (movie) ? "Yes" : "No", &row);
button = gtk_button_new_from_stock (GTK_STOCK_MEDIA_PLAY);
g_signal_connect (button, "clicked",
G_CALLBACK (pgd_movie_view_play_movie),
movie);
- pgd_table_add_property_with_custom_widget (GTK_TABLE (table), NULL, button, &row);
+ pgd_table_add_property_with_custom_widget (GTK_GRID (table), NULL, button, &row);
gtk_widget_show (button);
gtk_container_add (GTK_CONTAINER (alignment), table);
diff --git a/glib/demo/utils.h b/glib/demo/utils.h
index 452f3fa..026cfb4 100644
--- a/glib/demo/utils.h
+++ b/glib/demo/utils.h
@@ -24,16 +24,16 @@
G_BEGIN_DECLS
-void pgd_table_add_property (GtkTable *table,
+void pgd_table_add_property (GtkGrid *table,
const gchar *markup,
const gchar *value,
gint *row);
-void pgd_table_add_property_with_value_widget (GtkTable *table,
+void pgd_table_add_property_with_value_widget (GtkGrid *table,
const gchar *markup,
GtkWidget **value_widget,
const gchar *value,
gint *row);
-void pgd_table_add_property_with_custom_widget (GtkTable *table,
+void pgd_table_add_property_with_custom_widget (GtkGrid *table,
const gchar *markup,
GtkWidget *widget,
gint *row);
diff --git a/glib/poppler-annot.cc b/glib/poppler-annot.cc
index 2a544f1..728e64b 100644
--- a/glib/poppler-annot.cc
+++ b/glib/poppler-annot.cc
@@ -114,12 +114,27 @@
G_DEFINE_TYPE (PopplerAnnotMovie, poppler_annot_movie, POPPLER_TYPE_ANNOT)
G_DEFINE_TYPE (PopplerAnnotScreen, poppler_annot_screen, POPPLER_TYPE_ANNOT)
+static PopplerAnnot *
+_poppler_create_annot (GType annot_type, Annot *annot)
+{
+ PopplerAnnot *poppler_annot;
+
+ poppler_annot = POPPLER_ANNOT (g_object_new (annot_type, NULL));
+ poppler_annot->annot = annot;
+ annot->incRefCnt();
+
+ return poppler_annot;
+}
+
static void
poppler_annot_finalize (GObject *object)
{
PopplerAnnot *poppler_annot = POPPLER_ANNOT (object);
- poppler_annot->annot = NULL;
+ if (poppler_annot->annot) {
+ poppler_annot->annot->decRefCnt();
+ poppler_annot->annot = NULL;
+ }
G_OBJECT_CLASS (poppler_annot_parent_class)->finalize (object);
}
@@ -140,12 +155,7 @@
PopplerAnnot *
_poppler_annot_new (Annot *annot)
{
- PopplerAnnot *poppler_annot;
-
- poppler_annot = POPPLER_ANNOT (g_object_new (POPPLER_TYPE_ANNOT, NULL));
- poppler_annot->annot = annot;
-
- return poppler_annot;
+ return _poppler_create_annot (POPPLER_TYPE_ANNOT, annot);
}
static void
@@ -171,12 +181,7 @@
PopplerAnnot *
_poppler_annot_text_new (Annot *annot)
{
- PopplerAnnot *poppler_annot;
-
- poppler_annot = POPPLER_ANNOT (g_object_new (POPPLER_TYPE_ANNOT_TEXT, NULL));
- poppler_annot->annot = annot;
-
- return poppler_annot;
+ return _poppler_create_annot (POPPLER_TYPE_ANNOT_TEXT, annot);
}
/**
@@ -218,12 +223,7 @@
PopplerAnnot *
_poppler_annot_free_text_new (Annot *annot)
{
- PopplerAnnot *poppler_annot;
-
- poppler_annot = POPPLER_ANNOT (g_object_new (POPPLER_TYPE_ANNOT_FREE_TEXT, NULL));
- poppler_annot->annot = annot;
-
- return poppler_annot;
+ return _poppler_create_annot (POPPLER_TYPE_ANNOT_FREE_TEXT, annot);
}
static void
@@ -239,12 +239,7 @@
PopplerAnnot *
_poppler_annot_file_attachment_new (Annot *annot)
{
- PopplerAnnot *poppler_annot;
-
- poppler_annot = POPPLER_ANNOT (g_object_new (POPPLER_TYPE_ANNOT_FILE_ATTACHMENT, NULL));
- poppler_annot->annot = annot;
-
- return poppler_annot;
+ return _poppler_create_annot (POPPLER_TYPE_ANNOT_FILE_ATTACHMENT, annot);
}
@@ -280,9 +275,7 @@
PopplerAnnot *poppler_annot;
AnnotMovie *annot_movie;
- poppler_annot = POPPLER_ANNOT (g_object_new (POPPLER_TYPE_ANNOT_MOVIE, NULL));
- poppler_annot->annot = annot;
-
+ poppler_annot = _poppler_create_annot (POPPLER_TYPE_ANNOT_MOVIE, annot);
annot_movie = static_cast<AnnotMovie *>(poppler_annot->annot);
POPPLER_ANNOT_MOVIE (poppler_annot)->movie = _poppler_movie_new (annot_movie->getMovie());
@@ -322,9 +315,7 @@
AnnotScreen *annot_screen;
LinkAction *action;
- poppler_annot = POPPLER_ANNOT (g_object_new (POPPLER_TYPE_ANNOT_SCREEN, NULL));
- poppler_annot->annot = annot;
-
+ poppler_annot = _poppler_create_annot (POPPLER_TYPE_ANNOT_SCREEN, annot);
annot_screen = static_cast<AnnotScreen *>(poppler_annot->annot);
action = annot_screen->getAction();
if (action)
diff --git a/glib/poppler-cached-file-loader.cc b/glib/poppler-cached-file-loader.cc
new file mode 100644
index 0000000..bf462b6
--- /dev/null
+++ b/glib/poppler-cached-file-loader.cc
@@ -0,0 +1,108 @@
+/* poppler-cached-file-loader.h: glib interface to poppler
+ *
+ * Copyright (C) 2012 Carlos Garcia Campos <carlosgc@gnome.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "poppler-cached-file-loader.h"
+
+PopplerCachedFileLoader::PopplerCachedFileLoader(GInputStream *inputStreamA, GCancellable *cancellableA, goffset lengthA)
+{
+ inputStream = (GInputStream *)g_object_ref(inputStreamA);
+ cancellable = cancellableA ? (GCancellable *)g_object_ref(cancellableA) : NULL;
+ length = lengthA;
+ url = NULL;
+ cachedFile = NULL;
+}
+
+PopplerCachedFileLoader::~PopplerCachedFileLoader()
+{
+ g_object_unref(inputStream);
+ if (cancellable)
+ g_object_unref(cancellable);
+}
+
+size_t PopplerCachedFileLoader::init(GooString *urlA, CachedFile *cachedFileA)
+{
+ size_t size;
+ gssize bytesRead;
+ char buf[CachedFileChunkSize];
+
+ url = urlA;
+ cachedFile = cachedFileA;
+
+ if (length != (goffset)-1)
+ return length;
+
+ if (G_IS_FILE_INPUT_STREAM(inputStream)) {
+ GFileInfo *info;
+
+ info = g_file_input_stream_query_info(G_FILE_INPUT_STREAM (inputStream), G_FILE_ATTRIBUTE_STANDARD_SIZE, cancellable, NULL);
+ if (!info) {
+ error(errInternal, -1, "Failed to get size of '{0:t}'.", urlA);
+ return (size_t)-1;
+ }
+
+ length = g_file_info_get_size(info);
+ g_object_unref(info);
+
+ return length;
+ }
+
+ // Unknown stream length, read the whole stream and return the size.
+ CachedFileWriter writer = CachedFileWriter(cachedFile, NULL);
+ size = 0;
+ do {
+ bytesRead = g_input_stream_read(inputStream, buf, CachedFileChunkSize, cancellable, NULL);
+ if (bytesRead == -1)
+ break;
+
+ writer.write(buf, bytesRead);
+ size += bytesRead;
+ } while (bytesRead > 0);
+
+ return size;
+}
+
+int PopplerCachedFileLoader::load(const std::vector<ByteRange> &ranges, CachedFileWriter *writer)
+{
+ char buf[CachedFileChunkSize];
+ gssize bytesRead;
+ size_t rangeBytesRead, bytesToRead, size;
+
+ if (length == (goffset)-1)
+ return 0;
+
+ size = 0;
+ for (size_t i = 0; i < ranges.size(); i++) {
+ bytesToRead = MIN(CachedFileChunkSize, ranges[i].length);
+ rangeBytesRead = 0;
+ g_seekable_seek(G_SEEKABLE(inputStream), ranges[i].offset, G_SEEK_SET, cancellable, NULL);
+ do {
+ bytesRead = g_input_stream_read(inputStream, buf, bytesToRead, cancellable, NULL);
+ if (bytesRead == -1)
+ return -1;
+
+ writer->write(buf, bytesRead);
+ size += bytesRead;
+ rangeBytesRead += bytesRead;
+ bytesToRead = ranges[i].length - rangeBytesRead;
+ } while (bytesRead > 0 && bytesToRead > 0);
+ }
+
+ return 0;
+}
diff --git a/glib/poppler-cached-file-loader.h b/glib/poppler-cached-file-loader.h
new file mode 100644
index 0000000..3660435
--- /dev/null
+++ b/glib/poppler-cached-file-loader.h
@@ -0,0 +1,44 @@
+/* poppler-cached-file-loader.h: glib interface to poppler
+ *
+ * Copyright (C) 2012 Carlos Garcia Campos <carlosgc@gnome.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __POPPLER_CACHED_FILE_LOADER_H__
+#define __POPPLER_CACHED_FILE_LOADER_H__
+
+#include <gio/gio.h>
+#ifndef __GI_SCANNER__
+#include <CachedFile.h>
+
+class PopplerCachedFileLoader: public CachedFileLoader {
+public:
+ PopplerCachedFileLoader(GInputStream* inputStreamA, GCancellable *cancellableA, goffset lengthA = -1);
+ ~PopplerCachedFileLoader();
+ size_t init(GooString *url, CachedFile* cachedFile);
+ int load(const std::vector<ByteRange> &ranges, CachedFileWriter *writer);
+
+private:
+ GInputStream *inputStream;
+ GCancellable *cancellable;
+ goffset length;
+ GooString *url;
+ CachedFile *cachedFile;
+};
+
+#endif /* __GI_SCANNER__ */
+
+#endif /* __POPPLER_CACHED_FILE_LOADER_H__ */
diff --git a/glib/poppler-document.cc b/glib/poppler-document.cc
index 74d7635..5670300 100644
--- a/glib/poppler-document.cc
+++ b/glib/poppler-document.cc
@@ -38,6 +38,8 @@
#include "poppler.h"
#include "poppler-private.h"
#include "poppler-enums.h"
+#include "poppler-input-stream.h"
+#include "poppler-cached-file-loader.h"
/**
* SECTION:poppler-document
@@ -245,6 +247,117 @@
return _poppler_document_new_from_pdfdoc (newDoc, error);
}
+static inline gboolean
+stream_is_memory_buffer_or_local_file (GInputStream *stream)
+{
+ return G_IS_MEMORY_INPUT_STREAM(stream) ||
+ (G_IS_FILE_INPUT_STREAM(stream) && strcmp(g_type_name_from_instance((GTypeInstance*)stream), "GLocalFileInputStream") == 0);
+}
+
+/**
+ * poppler_document_new_from_stream:
+ * @stream: a #GInputStream to read from
+ * @length: the stream length, or -1 if not known
+ * @password: (allow-none): password to unlock the file with, or %NULL
+ * @cancellable: (allow-none): a #GCancellable, or %NULL
+ * @error: (allow-none): Return location for an error, or %NULL
+ *
+ * Creates a new #PopplerDocument reading the PDF contents from @stream.
+ * Note that the given #GInputStream must be seekable or %G_IO_ERROR_NOT_SUPPORTED
+ * will be returned.
+ * Possible errors include those in the #POPPLER_ERROR and #G_FILE_ERROR
+ * domains.
+ *
+ * Returns: (transfer full): a new #PopplerDocument, or %NULL
+ *
+ * Since: 0.22
+ */
+PopplerDocument *
+poppler_document_new_from_stream (GInputStream *stream,
+ goffset length,
+ const char *password,
+ GCancellable *cancellable,
+ GError **error)
+{
+ Object obj;
+ PDFDoc *newDoc;
+ BaseStream *str;
+ GooString *password_g;
+
+ g_return_val_if_fail(G_IS_INPUT_STREAM(stream), NULL);
+ g_return_val_if_fail(length == (goffset)-1 || length > 0, NULL);
+
+ if (!globalParams) {
+ globalParams = new GlobalParams();
+ }
+
+ if (!G_IS_SEEKABLE(stream) || !g_seekable_can_seek(G_SEEKABLE(stream))) {
+ g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ "Stream is not seekable");
+ return NULL;
+ }
+
+ obj.initNull();
+ if (stream_is_memory_buffer_or_local_file(stream)) {
+ str = new PopplerInputStream(stream, cancellable, 0, gFalse, 0, &obj);
+ } else {
+ CachedFile *cachedFile = new CachedFile(new PopplerCachedFileLoader(stream, cancellable, length), new GooString());
+ str = new CachedFileStream(cachedFile, 0, gFalse, cachedFile->getLength(), &obj);
+ }
+
+ password_g = poppler_password_to_latin1(password);
+ newDoc = new PDFDoc(str, password_g, password_g);
+ delete password_g;
+
+ return _poppler_document_new_from_pdfdoc (newDoc, error);
+}
+
+/**
+ * poppler_document_new_from_gfile:
+ * @file: a #GFile to load
+ * @password: (allow-none): password to unlock the file with, or %NULL
+ * @cancellable: (allow-none): a #GCancellable, or %NULL
+ * @error: (allow-none): Return location for an error, or %NULL
+ *
+ * Creates a new #PopplerDocument reading the PDF contents from @file.
+ * Possible errors include those in the #POPPLER_ERROR and #G_FILE_ERROR
+ * domains.
+ *
+ * Returns: (transfer full): a new #PopplerDocument, or %NULL
+ *
+ * Since: 0.22
+ */
+PopplerDocument *
+poppler_document_new_from_gfile (GFile *file,
+ const char *password,
+ GCancellable *cancellable,
+ GError **error)
+{
+ PopplerDocument *document;
+ GFileInputStream *stream;
+
+ g_return_val_if_fail(G_IS_FILE(file), NULL);
+
+ if (g_file_is_native(file)) {
+ gchar *uri;
+
+ uri = g_file_get_uri(file);
+ document = poppler_document_new_from_file(uri, password, error);
+ g_free(uri);
+
+ return document;
+ }
+
+ stream = g_file_read(file, cancellable, error);
+ if (!stream)
+ return NULL;
+
+ document = poppler_document_new_from_stream(G_INPUT_STREAM(stream), -1, password, cancellable, error);
+ g_object_unref(stream);
+
+ return document;
+}
+
static gboolean
handle_save_error (int err_code,
GError **error)
diff --git a/glib/poppler-document.h b/glib/poppler-document.h
index 7051830..a34e88c 100644
--- a/glib/poppler-document.h
+++ b/glib/poppler-document.h
@@ -20,6 +20,7 @@
#define __POPPLER_DOCUMENT_H__
#include <glib-object.h>
+#include <gio/gio.h>
#include "poppler.h"
G_BEGIN_DECLS
@@ -172,6 +173,15 @@
int length,
const char *password,
GError **error);
+PopplerDocument *poppler_document_new_from_stream (GInputStream *stream,
+ goffset length,
+ const char *password,
+ GCancellable *cancellable,
+ GError **error);
+PopplerDocument *poppler_document_new_from_gfile (GFile *file,
+ const char *password,
+ GCancellable *cancellable,
+ GError **error);
gboolean poppler_document_save (PopplerDocument *document,
const char *uri,
GError **error);
diff --git a/glib/poppler-input-stream.cc b/glib/poppler-input-stream.cc
new file mode 100644
index 0000000..99fcb6f
--- /dev/null
+++ b/glib/poppler-input-stream.cc
@@ -0,0 +1,141 @@
+/* poppler-input-stream.cc: glib interface to poppler
+ *
+ * Copyright (C) 2012 Carlos Garcia Campos <carlosgc@gnome.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "poppler-input-stream.h"
+
+PopplerInputStream::PopplerInputStream(GInputStream *inputStreamA, GCancellable *cancellableA,
+ Guint startA, GBool limitedA, Guint lengthA, Object *dictA)
+ : BaseStream(dictA, lengthA)
+{
+ inputStream = (GInputStream *)g_object_ref(inputStreamA);
+ cancellable = cancellableA ? (GCancellable *)g_object_ref(cancellableA) : NULL;
+ start = startA;
+ limited = limitedA;
+ length = lengthA;
+ bufPtr = bufEnd = buf;
+ bufPos = start;
+}
+
+PopplerInputStream::~PopplerInputStream()
+{
+ close();
+ g_object_unref(inputStream);
+ if (cancellable)
+ g_object_unref(cancellable);
+}
+
+Stream *PopplerInputStream::makeSubStream(Guint startA, GBool limitedA,
+ Guint lengthA, Object *dictA)
+{
+ return new PopplerInputStream(inputStream, cancellable, startA, limitedA, lengthA, dictA);
+}
+
+void PopplerInputStream::reset()
+{
+ GSeekable *seekable = G_SEEKABLE(inputStream);
+
+ savePos = (Guint)g_seekable_tell(seekable);
+ g_seekable_seek(seekable, start, G_SEEK_SET, cancellable, NULL);
+ saved = gTrue;
+ bufPtr = bufEnd = buf;
+ bufPos = start;
+}
+
+void PopplerInputStream::close()
+{
+ if (!saved)
+ return;
+ g_seekable_seek(G_SEEKABLE(inputStream), savePos, G_SEEK_SET, cancellable, NULL);
+ saved = gFalse;
+}
+
+void PopplerInputStream::setPos(Guint pos, int dir)
+{
+ Guint size;
+ GSeekable *seekable = G_SEEKABLE(inputStream);
+
+ if (dir >= 0) {
+ g_seekable_seek(seekable, pos, G_SEEK_SET, cancellable, NULL);
+ } else {
+ g_seekable_seek(seekable, 0, G_SEEK_END, cancellable, NULL);
+ size = (Guint)g_seekable_tell(seekable);
+
+ if (pos > size)
+ pos = size;
+
+ g_seekable_seek(seekable, -(goffset)pos, G_SEEK_END, cancellable, NULL);
+ bufPos = (Guint)g_seekable_tell(seekable);
+ }
+ bufPtr = bufEnd = buf;
+}
+
+void PopplerInputStream::moveStart(int delta)
+{
+ start += delta;
+ bufPtr = bufEnd = buf;
+ bufPos = start;
+}
+
+GBool PopplerInputStream::fillBuf()
+{
+ int n;
+
+ bufPos += bufEnd - buf;
+ bufPtr = bufEnd = buf;
+ if (limited && bufPos >= start + length) {
+ return gFalse;
+ }
+
+ if (limited && bufPos + inputStreamBufSize > start + length) {
+ n = start + length - bufPos;
+ } else {
+ n = inputStreamBufSize;
+ }
+
+ n = g_input_stream_read(inputStream, buf, n, cancellable, NULL);
+ bufEnd = buf + n;
+ if (bufPtr >= bufEnd) {
+ return gFalse;
+ }
+
+ return gTrue;
+}
+
+int PopplerInputStream::getChars(int nChars, Guchar *buffer)
+{
+ int n, m;
+
+ n = 0;
+ while (n < nChars) {
+ if (bufPtr >= bufEnd) {
+ if (!fillBuf()) {
+ break;
+ }
+ }
+ m = (int)(bufEnd - bufPtr);
+ if (m > nChars - n) {
+ m = nChars - n;
+ }
+ memcpy(buffer + n, bufPtr, m);
+ bufPtr += m;
+ n += m;
+ }
+ return n;
+}
diff --git a/glib/poppler-input-stream.h b/glib/poppler-input-stream.h
new file mode 100644
index 0000000..0d795f4
--- /dev/null
+++ b/glib/poppler-input-stream.h
@@ -0,0 +1,74 @@
+/* poppler-input-stream.h: glib interface to poppler
+ *
+ * Copyright (C) 2012 Carlos Garcia Campos <carlosgc@gnome.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __POPPLER_INPUT_STREAM_H__
+#define __POPPLER_INPUT_STREAM_H__
+
+#include <gio/gio.h>
+#ifndef __GI_SCANNER__
+#include <Object.h>
+#include <Stream.h>
+
+#define inputStreamBufSize 1024
+
+class PopplerInputStream: public BaseStream {
+public:
+
+ PopplerInputStream(GInputStream *inputStream, GCancellable *cancellableA,
+ Guint startA, GBool limitedA, Guint lengthA, Object *dictA);
+ virtual ~PopplerInputStream();
+ virtual Stream *makeSubStream(Guint start, GBool limited,
+ Guint lengthA, Object *dictA);
+ virtual StreamKind getKind() { return strWeird; }
+ virtual void reset();
+ virtual void close();
+ virtual int getChar()
+ { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); }
+ virtual int lookChar()
+ { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); }
+ virtual int getPos() { return bufPos + (bufPtr - buf); }
+ virtual void setPos(Guint pos, int dir = 0);
+ virtual Guint getStart() { return start; }
+ virtual void moveStart(int delta);
+
+ virtual int getUnfilteredChar() { return getChar(); }
+ virtual void unfilteredReset() { reset(); }
+
+private:
+
+ GBool fillBuf();
+
+ virtual GBool hasGetChars() { return true; }
+ virtual int getChars(int nChars, Guchar *buffer);
+
+ GInputStream *inputStream;
+ GCancellable *cancellable;
+ Guint start;
+ GBool limited;
+ char buf[inputStreamBufSize];
+ char *bufPtr;
+ char *bufEnd;
+ Guint bufPos;
+ int savePos;
+ GBool saved;
+};
+
+#endif /* __GI_SCANNER__ */
+
+#endif /* __POPPLER_INPUT_STREAM_H__ */
diff --git a/glib/poppler-page.cc b/glib/poppler-page.cc
index 2e0e44e..b362a62 100644
--- a/glib/poppler-page.cc
+++ b/glib/poppler-page.cc
@@ -852,18 +852,23 @@
}
/**
- * poppler_page_find_text:
+ * poppler_page_find_text_with_options:
* @page: a #PopplerPage
* @text: the text to search for (UTF-8 encoded)
- *
- * A #GList of rectangles for each occurance of the text on the page.
+ * @options: find options
+ *
+ * Finds @text in @page with the given #PopplerFindFlags options and
+ * returns a #GList of rectangles for each occurance of the text on the page.
* The coordinates are in PDF points.
- *
+ *
* Return value: (element-type PopplerRectangle) (transfer full): a #GList of #PopplerRectangle,
+ *
+ * Since: 0.22
**/
GList *
-poppler_page_find_text (PopplerPage *page,
- const char *text)
+poppler_page_find_text_with_options (PopplerPage *page,
+ const char *text,
+ PopplerFindFlags options)
{
PopplerRectangle *match;
GList *matches;
@@ -872,6 +877,7 @@
glong ucs4_len;
double height;
TextPage *text_dev;
+ gboolean backwards;
g_return_val_if_fail (POPPLER_IS_PAGE (page), NULL);
g_return_val_if_fail (text != NULL, NULL);
@@ -880,17 +886,19 @@
ucs4 = g_utf8_to_ucs4_fast (text, -1, &ucs4_len);
poppler_page_get_size (page, NULL, &height);
-
+
+ backwards = options & POPPLER_FIND_BACKWARDS;
matches = NULL;
xMin = 0;
- yMin = 0;
+ yMin = backwards ? height : 0;
while (text_dev->findText (ucs4, ucs4_len,
- gFalse, gTrue, // startAtTop, stopAtBottom
- gFalse, gFalse, // startAtLast, stopAtLast
- gFalse, gFalse, // caseSensitive, backwards
- gFalse, // wholeWord
- &xMin, &yMin, &xMax, &yMax))
+ gFalse, gTrue, // startAtTop, stopAtBottom
+ gTrue, gFalse, // startAtLast, stopAtLast
+ options & POPPLER_FIND_CASE_SENSITIVE,
+ backwards,
+ options & POPPLER_FIND_WHOLE_WORDS_ONLY,
+ &xMin, &yMin, &xMax, &yMax))
{
match = poppler_rectangle_new ();
match->x1 = xMin;
@@ -905,6 +913,24 @@
return g_list_reverse (matches);
}
+/**
+ * poppler_page_find_text:
+ * @page: a #PopplerPage
+ * @text: the text to search for (UTF-8 encoded)
+ *
+ * Finds @text in @page with the default options (%POPPLER_FIND_DEFAULT) and
+ * returns a #GList of rectangles for each occurance of the text on the page.
+ * The coordinates are in PDF points.
+ *
+ * Return value: (element-type PopplerRectangle) (transfer full): a #GList of #PopplerRectangle,
+ **/
+GList *
+poppler_page_find_text (PopplerPage *page,
+ const char *text)
+{
+ return poppler_page_find_text_with_options (page, text, POPPLER_FIND_DEFAULT);
+}
+
static CairoImageOutputDev *
poppler_page_get_image_output_dev (PopplerPage *page,
GBool (*imgDrawDeviceCbk)(int img_id, void *data),
@@ -1433,6 +1459,25 @@
page->page->addAnnot (annot->annot);
}
+/**
+ * poppler_page_remove_annot:
+ * @page: a #PopplerPage
+ * @annot: a #PopplerAnnot to remove
+ *
+ * Removes annotation @annot from @page
+ *
+ * Since: 0.22
+ */
+void
+poppler_page_remove_annot (PopplerPage *page,
+ PopplerAnnot *annot)
+{
+ g_return_if_fail (POPPLER_IS_PAGE (page));
+ g_return_if_fail (POPPLER_IS_ANNOT (annot));
+
+ page->page->removeAnnot (annot->annot);
+}
+
/* PopplerRectangle type */
POPPLER_DEFINE_BOXED_TYPE (PopplerRectangle, poppler_rectangle,
@@ -1502,9 +1547,9 @@
}
static gchar *
-get_font_name_from_word (TextWord *word)
+get_font_name_from_word (TextWord *word, gint word_i)
{
- GooString *font_name = word->getFontName();
+ GooString *font_name = word->getFontName(word_i);
const gchar *name;
gboolean subset;
gint i;
@@ -1530,12 +1575,12 @@
* Allocates a new PopplerTextAttributes with word attributes
*/
static PopplerTextAttributes *
-poppler_text_attributes_new_from_word (TextWord *word)
+poppler_text_attributes_new_from_word (TextWord *word, gint i)
{
PopplerTextAttributes *attrs = poppler_text_attributes_new ();
gdouble r, g, b;
- attrs->font_name = get_font_name_from_word (word);
+ attrs->font_name = get_font_name_from_word (word, i);
attrs->font_size = word->getFontSize();
attrs->is_underlined = word->isUnderlined();
word->getColor (&r, &g, &b);
@@ -2028,11 +2073,11 @@
}
static gboolean
-word_text_attributes_equal (TextWord *a, TextWord *b)
+word_text_attributes_equal (TextWord *a, gint ai, TextWord *b, gint bi)
{
double ar, ag, ab, br, bg, bb;
- if (!a->getFontInfo()->matches (b->getFontInfo()))
+ if (!a->getFontInfo(ai)->matches (b->getFontInfo(bi)))
return FALSE;
if (a->getFontSize() != b->getFontSize())
@@ -2082,23 +2127,32 @@
return NULL;
}
+ TextWord *word, *prev_word = NULL;
+ gint word_i, prev_word_i;
+
// Calculating each word attributes
for (i = 0; i < wordlist->getLength (); i++)
{
- TextWord *word = wordlist->get (i);
+ word = wordlist->get (i);
- // each char of the word has the same attributes
- if (i > 0 && word_text_attributes_equal (word, wordlist->get (i - 1))) {
- attrs = previous;
- } else {
- attrs = poppler_text_attributes_new_from_word (word);
- attrs->start_index = offset;
- if (previous)
- previous->end_index--;
- previous = attrs;
- attributes = g_list_prepend (attributes, attrs);
- }
- offset += word->getLength () + 1;
+ for (word_i = 0; word_i < word->getLength (); word_i++)
+ {
+ if (prev_word && word_text_attributes_equal (word, word_i, prev_word, prev_word_i)) {
+ attrs = previous;
+ } else {
+ attrs = poppler_text_attributes_new_from_word (word, word_i);
+ attrs->start_index = offset;
+ if (previous)
+ previous->end_index--;
+ previous = attrs;
+ attributes = g_list_prepend (attributes, attrs);
+ }
+ offset++;
+ attrs->end_index = offset;
+ prev_word = word;
+ prev_word_i = word_i;
+ }
+ offset++;
attrs->end_index = offset;
}
if (attrs)
diff --git a/glib/poppler-page.h b/glib/poppler-page.h
index 7b36843..c081b8c 100644
--- a/glib/poppler-page.h
+++ b/glib/poppler-page.h
@@ -60,6 +60,9 @@
gboolean poppler_page_get_thumbnail_size (PopplerPage *page,
int *width,
int *height);
+GList *poppler_page_find_text_with_options (PopplerPage *page,
+ const char *text,
+ PopplerFindFlags options);
GList *poppler_page_find_text (PopplerPage *page,
const char *text);
void poppler_page_render_to_ps (PopplerPage *page,
@@ -89,6 +92,8 @@
void poppler_page_free_annot_mapping (GList *list);
void poppler_page_add_annot (PopplerPage *page,
PopplerAnnot *annot);
+void poppler_page_remove_annot (PopplerPage *page,
+ PopplerAnnot *annot);
void poppler_page_get_crop_box (PopplerPage *page,
PopplerRectangle *rect);
gboolean poppler_page_get_text_layout (PopplerPage *page,
diff --git a/glib/poppler.h b/glib/poppler.h
index 6c2eefd..2d190f3 100644
--- a/glib/poppler.h
+++ b/glib/poppler.h
@@ -153,6 +153,24 @@
POPPLER_PRINT_ALL = POPPLER_PRINT_MARKUP_ANNOTS
} PopplerPrintFlags;
+/**
+ * PopplerFindFlags:
+ * @POPPLER_FIND_CASE_SENSITIVE: do case sensitive search
+ * @POPPLER_FIND_BACKWARDS: search backwards
+ * @POPPLER_FIND_WHOLE_WORDS_ONLY: search only whole words
+ *
+ * Flags using while searching text in a page
+ *
+ * Since: 0.22
+ */
+typedef enum /*< flags >*/
+{
+ POPPLER_FIND_DEFAULT = 0,
+ POPPLER_FIND_CASE_SENSITIVE = 1 << 0,
+ POPPLER_FIND_BACKWARDS = 1 << 1,
+ POPPLER_FIND_WHOLE_WORDS_ONLY = 1 << 2
+} PopplerFindFlags;
+
typedef struct _PopplerDocument PopplerDocument;
typedef struct _PopplerIndexIter PopplerIndexIter;
typedef struct _PopplerFontsIter PopplerFontsIter;
diff --git a/glib/reference/poppler-docs.sgml b/glib/reference/poppler-docs.sgml
index d15bd18..a9d5158 100644
--- a/glib/reference/poppler-docs.sgml
+++ b/glib/reference/poppler-docs.sgml
@@ -54,6 +54,10 @@
<title>Index of new symbols in 0.20</title>
<xi:include href="xml/api-index-0.20.xml"><xi:fallback /></xi:include>
</index>
+ <index id="api-index-0-22">
+ <title>Index of new symbols in 0.22</title>
+ <xi:include href="xml/api-index-0.22.xml"><xi:fallback /></xi:include>
+ </index>
<xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
</book>
diff --git a/glib/reference/poppler-sections.txt b/glib/reference/poppler-sections.txt
index 5a6708b..6fb14bc 100644
--- a/glib/reference/poppler-sections.txt
+++ b/glib/reference/poppler-sections.txt
@@ -33,6 +33,7 @@
poppler_page_selection_region_free
poppler_page_get_selected_text
poppler_page_find_text
+poppler_page_find_text_with_options
poppler_page_get_text
poppler_page_get_text_layout
poppler_page_get_text_attributes
@@ -47,6 +48,7 @@
poppler_page_get_annot_mapping
poppler_page_free_annot_mapping
poppler_page_add_annot
+poppler_page_remove_annot
poppler_rectangle_new
poppler_rectangle_copy
poppler_rectangle_free
@@ -115,6 +117,8 @@
PopplerPermissions
poppler_document_new_from_file
poppler_document_new_from_data
+poppler_document_new_from_stream
+poppler_document_new_from_gfile
poppler_document_save
poppler_document_save_a_copy
poppler_document_get_id
@@ -335,6 +339,7 @@
PopplerBackend
PopplerColor
PopplerPrintFlags
+PopplerFindFlags
poppler_get_backend
poppler_get_version
poppler_date_parse
diff --git a/goo/GooString.cc b/goo/GooString.cc
index fc78d90..451a70e 100644
--- a/goo/GooString.cc
+++ b/goo/GooString.cc
@@ -20,6 +20,8 @@
// Copyright (C) 2007 Jeff Muizelaar <jeff@infidigm.net>
// Copyright (C) 2008-2011 Albert Astals Cid <aacid@kde.org>
// Copyright (C) 2011 Kenji Uno <ku@digitaldolphins.jp>
+// Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
+// Copyright (C) 2012 Adrian Johnson <ajohnson@redneon.com>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
@@ -65,29 +67,35 @@
enum GooStringFormatType {
fmtIntDecimal,
fmtIntHex,
+ fmtIntHexUpper,
fmtIntOctal,
fmtIntBinary,
fmtUIntDecimal,
fmtUIntHex,
+ fmtUIntHexUpper,
fmtUIntOctal,
fmtUIntBinary,
fmtLongDecimal,
fmtLongHex,
+ fmtLongHexUpper,
fmtLongOctal,
fmtLongBinary,
fmtULongDecimal,
fmtULongHex,
+ fmtULongHexUpper,
fmtULongOctal,
fmtULongBinary,
#ifdef LLONG_MAX
fmtLongLongDecimal,
fmtLongLongHex,
+ fmtLongLongHexUpper,
fmtLongLongOctal,
fmtLongLongBinary,
#endif
#ifdef ULLONG_MAX
fmtULongLongDecimal,
fmtULongLongHex,
+ fmtULongLongHexUpper,
fmtULongLongOctal,
fmtULongLongBinary,
#endif
@@ -101,13 +109,13 @@
};
static const char *formatStrings[] = {
- "d", "x", "o", "b", "ud", "ux", "uo", "ub",
- "ld", "lx", "lo", "lb", "uld", "ulx", "ulo", "ulb",
+ "d", "x", "X", "o", "b", "ud", "ux", "uX", "uo", "ub",
+ "ld", "lx", "lX", "lo", "lb", "uld", "ulx", "ulX", "ulo", "ulb",
#ifdef LLONG_MAX
- "lld", "llx", "llo", "llb",
+ "lld", "llx", "llX", "llo", "llb",
#endif
#ifdef ULLONG_MAX
- "ulld", "ullx", "ullo", "ullb",
+ "ulld", "ullx", "ullX", "ullo", "ullb",
#endif
"f", "gs", "g",
"c",
@@ -388,6 +396,7 @@
switch (ft) {
case fmtIntDecimal:
case fmtIntHex:
+ case fmtIntHexUpper:
case fmtIntOctal:
case fmtIntBinary:
case fmtSpace:
@@ -395,18 +404,21 @@
break;
case fmtUIntDecimal:
case fmtUIntHex:
+ case fmtUIntHexUpper:
case fmtUIntOctal:
case fmtUIntBinary:
args[argsLen].ui = va_arg(argList, Guint);
break;
case fmtLongDecimal:
case fmtLongHex:
+ case fmtLongHexUpper:
case fmtLongOctal:
case fmtLongBinary:
args[argsLen].l = va_arg(argList, long);
break;
case fmtULongDecimal:
case fmtULongHex:
+ case fmtULongHexUpper:
case fmtULongOctal:
case fmtULongBinary:
args[argsLen].ul = va_arg(argList, Gulong);
@@ -414,6 +426,7 @@
#ifdef LLONG_MAX
case fmtLongLongDecimal:
case fmtLongLongHex:
+ case fmtLongLongHexUpper:
case fmtLongLongOctal:
case fmtLongLongBinary:
args[argsLen].ll = va_arg(argList, long long);
@@ -422,6 +435,7 @@
#ifdef ULLONG_MAX
case fmtULongLongDecimal:
case fmtULongLongHex:
+ case fmtULongLongHexUpper:
case fmtULongLongOctal:
case fmtULongLongBinary:
args[argsLen].ull = va_arg(argList, unsigned long long);
@@ -454,6 +468,10 @@
case fmtIntHex:
formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 16, &str, &len);
break;
+ case fmtIntHexUpper:
+ formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 16, &str, &len,
+ gTrue);
+ break;
case fmtIntOctal:
formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 8, &str, &len);
break;
@@ -468,6 +486,10 @@
formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 16,
&str, &len);
break;
+ case fmtUIntHexUpper:
+ formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 16,
+ &str, &len, gTrue);
+ break;
case fmtUIntOctal:
formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 8, &str, &len);
break;
@@ -480,6 +502,10 @@
case fmtLongHex:
formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 16, &str, &len);
break;
+ case fmtLongHexUpper:
+ formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 16, &str, &len,
+ gTrue);
+ break;
case fmtLongOctal:
formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 8, &str, &len);
break;
@@ -494,6 +520,10 @@
formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 16,
&str, &len);
break;
+ case fmtULongHexUpper:
+ formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 16,
+ &str, &len, gTrue);
+ break;
case fmtULongOctal:
formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 8, &str, &len);
break;
@@ -507,6 +537,10 @@
case fmtLongLongHex:
formatInt(arg.ll, buf, sizeof(buf), zeroFill, width, 16, &str, &len);
break;
+ case fmtLongLongHexUpper:
+ formatInt(arg.ll, buf, sizeof(buf), zeroFill, width, 16, &str, &len,
+ gTrue);
+ break;
case fmtLongLongOctal:
formatInt(arg.ll, buf, sizeof(buf), zeroFill, width, 8, &str, &len);
break;
@@ -523,6 +557,10 @@
formatUInt(arg.ull, buf, sizeof(buf), zeroFill, width, 16,
&str, &len);
break;
+ case fmtULongLongHexUpper:
+ formatUInt(arg.ull, buf, sizeof(buf), zeroFill, width, 16,
+ &str, &len, gTrue);
+ break;
case fmtULongLongOctal:
formatUInt(arg.ull, buf, sizeof(buf), zeroFill, width, 8,
&str, &len);
@@ -595,16 +633,20 @@
gfree(args);
return this;
}
+
+static const char lowerCaseDigits[17] = "0123456789abcdef";
+static const char upperCaseDigits[17] = "0123456789ABCDEF";
+
#ifdef LLONG_MAX
void GooString::formatInt(long long x, char *buf, int bufSize,
GBool zeroFill, int width, int base,
- char **p, int *len) {
+ char **p, int *len, GBool upperCase) {
#else
void GooString::formatInt(long x, char *buf, int bufSize,
GBool zeroFill, int width, int base,
- char **p, int *len) {
+ char **p, int *len, GBool upperCase) {
#endif
- static char vals[17] = "0123456789abcdef";
+ const char *vals = upperCase ? upperCaseDigits : lowerCaseDigits;
GBool neg;
int start, i, j;
@@ -636,13 +678,13 @@
#ifdef ULLONG_MAX
void GooString::formatUInt(unsigned long long x, char *buf, int bufSize,
GBool zeroFill, int width, int base,
- char **p, int *len) {
+ char **p, int *len, GBool upperCase) {
#else
void GooString::formatUInt(Gulong x, char *buf, int bufSize,
GBool zeroFill, int width, int base,
- char **p, int *len) {
+ char **p, int *len, GBool upperCase) {
#endif
- static char vals[17] = "0123456789abcdef";
+ const char *vals = upperCase ? upperCaseDigits : lowerCaseDigits;
int i, j;
i = bufSize;
@@ -854,7 +896,7 @@
GBool GooString::hasUnicodeMarker(void)
{
- return (s[0] & 0xff) == 0xfe && (s[1] & 0xff) == 0xff;
+ return length > 1 && (s[0] & 0xff) == 0xfe && (s[1] & 0xff) == 0xff;
}
GooString *GooString::sanitizedName(GBool psmode)
diff --git a/goo/GooString.h b/goo/GooString.h
index 23558b0..b24051b 100644
--- a/goo/GooString.h
+++ b/goo/GooString.h
@@ -18,6 +18,7 @@
// Copyright (C) 2006 Kristian Høgsberg <krh@redhat.com>
// Copyright (C) 2006 Krzysztof Kowalczyk <kkowalczyk@gmail.com>
// Copyright (C) 2008-2010, 2012 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
@@ -80,10 +81,10 @@
// - <precision> is the number of digits to the right of the decimal
// point (for floating point numbers)
// - <type> is one of:
- // d, x, o, b -- int in decimal, hex, octal, binary
- // ud, ux, uo, ub -- unsigned int
- // ld, lx, lo, lb, uld, ulx, ulo, ulb -- long, unsigned long
- // lld, llx, llo, llb, ulld, ullx, ullo, ullb
+ // d, x, X, o, b -- int in decimal, lowercase hex, uppercase hex, octal, binary
+ // ud, ux, uX, uo, ub -- unsigned int
+ // ld, lx, lX, lo, lb, uld, ulx, ulX, ulo, ulb -- long, unsigned long
+ // lld, llx, llX, llo, llb, ulld, ullx, ullX, ullo, ullb
// -- long long, unsigned long long
// f, g -- double
// c -- char
@@ -170,20 +171,20 @@
#ifdef LLONG_MAX
static void formatInt(long long x, char *buf, int bufSize,
GBool zeroFill, int width, int base,
- char **p, int *len);
+ char **p, int *len, GBool upperCase = gFalse);
#else
static void formatInt(long x, char *buf, int bufSize,
GBool zeroFill, int width, int base,
- char **p, int *len);
+ char **p, int *len, GBool upperCase = gFalse);
#endif
#ifdef ULLONG_MAX
static void formatUInt(unsigned long long x, char *buf, int bufSize,
GBool zeroFill, int width, int base,
- char **p, int *len);
+ char **p, int *len, GBool upperCase = gFalse);
#else
static void formatUInt(Gulong x, char *buf, int bufSize,
GBool zeroFill, int width, int base,
- char **p, int *len);
+ char **p, int *len, GBool upperCase = gFalse);
#endif
static void formatDouble(double x, char *buf, int bufSize, int prec,
GBool trim, char **p, int *len);
diff --git a/goo/Makefile.am b/goo/Makefile.am
index f4f9730..0764e79 100644
--- a/goo/Makefile.am
+++ b/goo/Makefile.am
@@ -18,7 +18,8 @@
TiffWriter.h \
ImgWriter.h \
GooLikely.h \
- gstrtod.h
+ gstrtod.h \
+ grandom.h
endif
@@ -59,4 +60,5 @@
TiffWriter.cc \
ImgWriter.cc \
gtypes_p.h \
- gstrtod.cc
+ gstrtod.cc \
+ grandom.cc
diff --git a/goo/TiffWriter.cc b/goo/TiffWriter.cc
index f63b245..9c134f9 100644
--- a/goo/TiffWriter.cc
+++ b/goo/TiffWriter.cc
@@ -4,7 +4,8 @@
//
// This file is licensed under the GPLv2 or later
//
-// Copyright (C) 2010 William Bader <williambader@hotmail.com>
+// Copyright (C) 2010, 2012 William Bader <williambader@hotmail.com>
+// Copyright (C) 2012 Albert Astals Cid <aacid@kde.org>
//
//========================================================================
@@ -126,6 +127,14 @@
photometric = PHOTOMETRIC_RGB;
break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ case splashModeDeviceN8:
+ samplesperpixel = 4;
+ photometric = PHOTOMETRIC_SEPARATED;
+ break;
+#endif
+
default:
fprintf(stderr, "TiffWriter: Mode %d not supported\n", splashMode);
return false;
@@ -159,6 +168,13 @@
TIFFSetField(f, TIFFTAG_YRESOLUTION, (double) vDPI);
TIFFSetField(f, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
+#if SPLASH_CMYK
+ if (splashMode == splashModeCMYK8 || splashMode == splashModeDeviceN8) {
+ TIFFSetField(f, TIFFTAG_INKSET, INKSET_CMYK);
+ TIFFSetField(f, TIFFTAG_NUMBEROFINKS, 4);
+ }
+#endif
+
return true;
}
diff --git a/goo/TiffWriter.h b/goo/TiffWriter.h
index 1f4b5eb..bffd17a 100644
--- a/goo/TiffWriter.h
+++ b/goo/TiffWriter.h
@@ -4,7 +4,7 @@
//
// This file is licensed under the GPLv2 or later
//
-// Copyright (C) 2010 William Bader <williambader@hotmail.com>
+// Copyright (C) 2010, 2012 William Bader <williambader@hotmail.com>
// Copyright (C) 2011 Albert Astals Cid <aacid@kde.org>
//
//========================================================================
@@ -38,6 +38,8 @@
bool writePointers(unsigned char **rowPointers, int rowCount);
bool writeRow(unsigned char **rowData);
+ bool supportCMYK() { return true; }
+
bool close();
private:
diff --git a/goo/gfile.cc b/goo/gfile.cc
index 7522424..604c0fa 100644
--- a/goo/gfile.cc
+++ b/goo/gfile.cc
@@ -19,7 +19,7 @@
// Copyright (C) 2006 Kristian Høgsberg <krh@redhat.com>
// Copyright (C) 2008 Adam Batkin <adam@batkin.net>
// Copyright (C) 2008, 2010 Hib Eris <hib@hiberis.nl>
-// Copyright (C) 2009 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2009, 2012 Albert Astals Cid <aacid@kde.org>
// Copyright (C) 2009 Kovid Goyal <kovid@kovidgoyal.net>
//
// To see a description of the changes please see the Changelog file that
@@ -60,52 +60,6 @@
//------------------------------------------------------------------------
-GooString *getHomeDir() {
-#ifdef VMS
- //---------- VMS ----------
- return new GooString("SYS$LOGIN:");
-
-#elif defined(__EMX__) || defined(_WIN32)
- //---------- OS/2+EMX and Win32 ----------
- char *s;
- GooString *ret;
-
- if ((s = getenv("HOME")))
- ret = new GooString(s);
- else
- ret = new GooString(".");
- return ret;
-
-#elif defined(ACORN)
- //---------- RISCOS ----------
- return new GooString("@");
-
-#elif defined(MACOS)
- //---------- MacOS ----------
- return new GooString(":");
-
-#else
- //---------- Unix ----------
- char *s;
- struct passwd *pw;
- GooString *ret;
-
- if ((s = getenv("HOME"))) {
- ret = new GooString(s);
- } else {
- if ((s = getenv("USER")))
- pw = getpwnam(s);
- else
- pw = getpwuid(getuid());
- if (pw)
- ret = new GooString(pw->pw_dir);
- else
- ret = new GooString(".");
- }
- return ret;
-#endif
-}
-
GooString *getCurrentDir() {
char buf[PATH_MAX+1];
@@ -363,88 +317,6 @@
#endif
}
-GooString *makePathAbsolute(GooString *path) {
-#ifdef VMS
- //---------- VMS ----------
- char buf[PATH_MAX+1];
-
- if (!isAbsolutePath(path->getCString())) {
- if (getcwd(buf, sizeof(buf))) {
- path->insert(0, buf);
- }
- }
- return path;
-
-#elif defined(_WIN32)
- //---------- Win32 ----------
- char buf[MAX_PATH];
- char *fp;
-
- buf[0] = '\0';
- if (!GetFullPathName(path->getCString(), MAX_PATH, buf, &fp)) {
- path->clear();
- return path;
- }
- path->clear();
- path->append(buf);
- return path;
-
-#elif defined(ACORN)
- //---------- RISCOS ----------
- path->insert(0, '@');
- return path;
-
-#elif defined(MACOS)
- //---------- MacOS ----------
- path->del(0, 1);
- return path;
-
-#else
- //---------- Unix and OS/2+EMX ----------
- struct passwd *pw;
- char buf[PATH_MAX+1];
- GooString *s;
- char *p1, *p2;
- int n;
-
- if (path->getChar(0) == '~') {
- if (path->getChar(1) == '/' ||
-#ifdef __EMX__
- path->getChar(1) == '\\' ||
-#endif
- path->getLength() == 1) {
- path->del(0, 1);
- s = getHomeDir();
- path->insert(0, s);
- delete s;
- } else {
- p1 = path->getCString() + 1;
-#ifdef __EMX__
- for (p2 = p1; *p2 && *p2 != '/' && *p2 != '\\'; ++p2) ;
-#else
- for (p2 = p1; *p2 && *p2 != '/'; ++p2) ;
-#endif
- if ((n = p2 - p1) > PATH_MAX)
- n = PATH_MAX;
- strncpy(buf, p1, n);
- buf[n] = '\0';
- if ((pw = getpwnam(buf))) {
- path->del(0, p2 - p1 + 1);
- path->insert(0, pw->pw_dir);
- }
- }
- } else if (!isAbsolutePath(path->getCString())) {
- if (getcwd(buf, sizeof(buf))) {
-#ifndef __EMX__
- path->insert(0, '/');
-#endif
- path->insert(0, buf);
- }
- }
- return path;
-#endif
-}
-
time_t getModTime(char *fileName) {
#ifdef _WIN32
//~ should implement this, but it's (currently) only used in xpdf
@@ -545,14 +417,6 @@
#endif
}
-GBool executeCommand(char *cmd) {
-#ifdef VMS
- return system(cmd) ? gTrue : gFalse;
-#else
- return system(cmd) ? gFalse : gTrue;
-#endif
-}
-
#ifdef WIN32
GooString *fileNameToUTF8(char *path) {
GooString *s;
diff --git a/goo/gfile.h b/goo/gfile.h
index 46b8958..cefd679 100644
--- a/goo/gfile.h
+++ b/goo/gfile.h
@@ -16,7 +16,7 @@
// under GPL version 2 or later
//
// Copyright (C) 2006 Kristian Høgsberg <krh@redhat.com>
-// Copyright (C) 2009, 2011 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2009, 2011, 2012 Albert Astals Cid <aacid@kde.org>
// Copyright (C) 2009 Kovid Goyal <kovid@kovidgoyal.net>
//
// To see a description of the changes please see the Changelog file that
@@ -71,9 +71,6 @@
//------------------------------------------------------------------------
-// Get home directory path.
-extern GooString *getHomeDir();
-
// Get current directory.
extern GooString *getCurrentDir();
@@ -88,10 +85,6 @@
// Is this an absolute path or file name?
extern GBool isAbsolutePath(char *path);
-// Make this path absolute by prepending current directory (if path is
-// relative) or prepending user's directory (if path starts with '~').
-extern GooString *makePathAbsolute(GooString *path);
-
// Get the modification time for <fileName>. Returns 0 if there is an
// error.
extern time_t getModTime(char *fileName);
@@ -104,9 +97,6 @@
// should be "w" or "wb". Returns true on success.
extern GBool openTempFile(GooString **name, FILE **f, const char *mode);
-// Execute <command>. Returns true on success.
-extern GBool executeCommand(char *cmd);
-
#ifdef WIN32
// Convert a file name from Latin-1 to UTF-8.
extern GooString *fileNameToUTF8(char *path);
diff --git a/goo/grandom.cc b/goo/grandom.cc
new file mode 100644
index 0000000..1237175
--- /dev/null
+++ b/goo/grandom.cc
@@ -0,0 +1,70 @@
+/*
+ * grandom.cc
+ *
+ * This file is licensed under the GPLv2 or later
+ *
+ * Pseudo-random number generation
+ *
+ * Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
+ */
+
+#include <config.h>
+#include "grandom.h"
+#include "gtypes.h"
+
+#ifdef HAVE_RAND_R // rand_r backend (POSIX)
+
+static GBool initialized = gFalse;
+
+#include <stdlib.h>
+#include <time.h>
+static unsigned int seed;
+
+static void initialize() {
+ if (!initialized) {
+ seed = time(NULL);
+ initialized = gTrue;
+ }
+}
+
+void grandom_fill(Guchar *buff, int size)
+{
+ initialize();
+ while (size--)
+ *buff++ = rand_r(&seed) % 256;
+}
+
+double grandom_double()
+{
+ initialize();
+ return rand_r(&seed) / (1 + (double)RAND_MAX);
+}
+
+#else // srand+rand backend (unsafe, because it may interfere with the application)
+
+static GBool initialized = gFalse;
+
+#include <stdlib.h>
+#include <time.h>
+
+static void initialize() {
+ if (!initialized) {
+ srand(time(NULL));
+ initialized = gTrue;
+ }
+}
+
+void grandom_fill(Guchar *buff, int size)
+{
+ initialize();
+ while (size--)
+ *buff++ = rand() % 256;
+}
+
+double grandom_double()
+{
+ initialize();
+ return rand() / (1 + (double)RAND_MAX);
+}
+
+#endif
diff --git a/goo/grandom.h b/goo/grandom.h
new file mode 100644
index 0000000..45fa791
--- /dev/null
+++ b/goo/grandom.h
@@ -0,0 +1,34 @@
+/*
+ * grandom.h
+ *
+ * This file is licensed under the GPLv2 or later
+ *
+ * Pseudo-random number generation
+ *
+ * Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
+ */
+
+#ifndef GRANDOM_H
+#define GRANDOM_H
+
+#include "gtypes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Fills the given buffer with random bytes
+ */
+extern void grandom_fill(Guchar *buff, int size);
+
+/*
+ * Returns a random number in [0,1)
+ */
+extern double grandom_double();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/poppler-glib-uninstalled.pc.in b/poppler-glib-uninstalled.pc.in
index 5fcb6f2..5506c4e 100644
--- a/poppler-glib-uninstalled.pc.in
+++ b/poppler-glib-uninstalled.pc.in
@@ -1,7 +1,7 @@
Name: poppler-glib
Description: GLib wrapper for poppler - uninstalled
Version: @VERSION@
-Requires: glib-2.0 >= @GLIB_REQUIRED@ gobject-2.0 >= @GLIB_REQUIRED@ cairo >= @CAIRO_VERSION@
+Requires: glib-2.0 >= @GLIB_REQUIRED@ gobject-2.0 >= @GLIB_REQUIRED@ gio-2.0 >= @GLIB_REQUIRED@ cairo >= @CAIRO_VERSION@
Libs: ${pc_top_builddir}/${pcfiledir}/glib/libpoppler-glib.la
Cflags: -I${pc_top_builddir}/${pcfiledir}/glib
diff --git a/poppler-glib.pc.in b/poppler-glib.pc.in
index 9ba8978..cd30feb 100644
--- a/poppler-glib.pc.in
+++ b/poppler-glib.pc.in
@@ -6,7 +6,7 @@
Name: poppler-glib
Description: GLib wrapper for poppler
Version: @VERSION@
-Requires: glib-2.0 >= @GLIB_REQUIRED@ gobject-2.0 >= @GLIB_REQUIRED@ cairo >= @CAIRO_VERSION@
+Requires: glib-2.0 >= @GLIB_REQUIRED@ gobject-2.0 >= @GLIB_REQUIRED@ gio-2.0 >= @GLIB_REQUIRED@ cairo >= @CAIRO_VERSION@
@PC_REQUIRES_PRIVATE@
Libs: -L${libdir} -lpoppler-glib
diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index 675ec84..dae0f62 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -16,7 +16,7 @@
// Copyright (C) 2006 Scott Turner <scotty1024@mac.com>
// Copyright (C) 2007, 2008 Julien Rebetez <julienr@svn.gnome.org>
// Copyright (C) 2007-2012 Albert Astals Cid <aacid@kde.org>
-// Copyright (C) 2007-2011 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright (C) 2007-2012 Carlos Garcia Campos <carlosgc@gnome.org>
// Copyright (C) 2007, 2008 Iñigo Martínez <inigomartinez@gmail.com>
// Copyright (C) 2007 Jeff Muizelaar <jeff@infidigm.net>
// Copyright (C) 2008, 2011 Pino Toscano <pino@kde.org>
@@ -26,6 +26,7 @@
// Copyright (C) 2011 José Aliste <jaliste@src.gnome.org>
// Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
// Copyright (C) 2012 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2012 Tobias Koenig <tokoe@kdab.com>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
@@ -196,6 +197,34 @@
return newRect;
}
+static LinkAction* getAdditionalAction(Annot::AdditionalActionsType type, Object *additionalActions, PDFDoc *doc) {
+ Object additionalActionsObject;
+ LinkAction *linkAction = NULL;
+
+ if (additionalActions->fetch(doc->getXRef(), &additionalActionsObject)->isDict()) {
+ const char *key = (type == Annot::actionCursorEntering ? "E" :
+ type == Annot::actionCursorLeaving ? "X" :
+ type == Annot::actionMousePressed ? "D" :
+ type == Annot::actionMouseReleased ? "U" :
+ type == Annot::actionFocusIn ? "Fo" :
+ type == Annot::actionFocusOut ? "BI" :
+ type == Annot::actionPageOpening ? "PO" :
+ type == Annot::actionPageClosing ? "PC" :
+ type == Annot::actionPageVisible ? "PV" :
+ type == Annot::actionPageInvisible ? "PI" : NULL);
+
+ Object actionObject;
+
+ if (additionalActionsObject.dictLookup(key, &actionObject)->isDict())
+ linkAction = LinkAction::parseAction(&actionObject, doc->getCatalog()->getBaseURI());
+ actionObject.free();
+ }
+
+ additionalActionsObject.free();
+
+ return linkAction;
+}
+
//------------------------------------------------------------------------
// AnnotBorderEffect
//------------------------------------------------------------------------
@@ -784,50 +813,38 @@
appearDict.free();
}
-void AnnotAppearance::getAppearanceStream(AnnotAppearance::AnnotAppearanceType type, const char *state, Object *dest) {
+void AnnotAppearance::getAppearanceStream(AnnotAppearanceType type, const char *state, Object *dest) {
Object apData, stream;
apData.initNull();
// Obtain dictionary or stream associated to appearance type
- if (type == appearRollover) {
- appearDict.dictLookupNF("R", &apData);
- } else if (type == appearDown) {
- appearDict.dictLookupNF("D", &apData);
- }
- if (apData.isNull()) { // Normal appearance, also used as fallback
+ switch (type) {
+ case appearRollover:
+ if (appearDict.dictLookupNF("R", &apData)->isNull())
+ appearDict.dictLookupNF("N", &apData);
+ break;
+ case appearDown:
+ if (appearDict.dictLookupNF("D", &apData)->isNull())
+ appearDict.dictLookupNF("N", &apData);
+ break;
+ case appearNormal:
appearDict.dictLookupNF("N", &apData);
- }
-
- // Search state if it's a subdictionary
- if (apData.isDict() && state) {
- Object obj1;
- apData.dictLookupNF(state, &obj1);
- apData.free();
- obj1.copy(&apData);
- obj1.free();
+ break;
}
dest->initNull();
- // Sanity check on the value we are about to return: it must be a ref to stream
- if (apData.isRef()) {
- apData.fetch(xref, &stream);
- if (stream.isStream()) {
- apData.copy(dest);
- } else {
- error(errSyntaxWarning, -1, "AP points to a non-stream object");
- }
- stream.free();
- }
+ if (apData.isDict() && state)
+ apData.dictLookupNF(state, dest);
+ else if (apData.isRef())
+ apData.copy(dest);
apData.free();
}
GooString * AnnotAppearance::getStateKey(int i) {
Object obj1;
GooString * res = NULL;
- appearDict.dictLookupNF("N", &obj1);
- if (obj1.isDict()) {
+ if (appearDict.dictLookupNF("N", &obj1)->isDict())
res = new GooString(obj1.dictGetKey(i));
- }
obj1.free();
return res;
}
@@ -835,10 +852,8 @@
int AnnotAppearance::getNumStates() {
Object obj1;
int res = 0;
- appearDict.dictLookupNF("N", &obj1);
- if (obj1.isDict()) {
+ if (appearDict.dictLookupNF("N", &obj1)->isDict())
res = obj1.dictGetLength();
- }
obj1.free();
return res;
}
@@ -1186,6 +1201,7 @@
}
obj1.free();
+ // Note: This value is overwritten by Annots ctor
if (dict->lookupNF("P", &obj1)->isRef()) {
Ref ref = obj1.getRef();
@@ -1417,13 +1433,22 @@
}
}
-void Annot::setPage(Ref *pageRef, int pageIndex)
-{
+void Annot::setPage(int pageIndex, GBool updateP) {
+ Page *pageobj = doc->getPage(pageIndex);
Object obj1;
- obj1.initRef(pageRef->num, pageRef->gen);
- update("P", &obj1);
- page = pageIndex;
+ if (pageobj) {
+ Ref pageRef = pageobj->getRef();
+ obj1.initRef(pageRef.num, pageRef.gen);
+ page = pageIndex;
+ } else {
+ obj1.initNull();
+ page = 0;
+ }
+
+ if (updateP) {
+ update("P", &obj1);
+ }
}
void Annot::setAppearanceState(const char *state) {
@@ -1485,6 +1510,11 @@
valueObject.free();
}
+void Annot::removeReferencedObjects() {
+ // Remove appearance streams (if any)
+ invalidateAppearance();
+}
+
void Annot::incRefCnt() {
refCnt++;
}
@@ -1935,6 +1965,18 @@
update ("CreationDate", &obj1);
}
+void AnnotMarkup::removeReferencedObjects() {
+ Page *pageobj = doc->getPage(page);
+ assert(pageobj != NULL); // We're called when removing an annot from a page
+
+ // Remove popup
+ if (popup) {
+ pageobj->removeAnnot(popup);
+ }
+
+ Annot::removeReferencedObjects();
+}
+
//------------------------------------------------------------------------
// AnnotText
//------------------------------------------------------------------------
@@ -2350,7 +2392,7 @@
appearBuf->append ("Q\n");
// Force 24x24 rectangle
- PDFRectangle fixedRect(rect->x1, rect->y1, rect->x1 + 24, rect->y1 + 24);
+ PDFRectangle fixedRect(rect->x1, rect->y2 - 24, rect->x1 + 24, rect->y2);
appearBBox = new AnnotAppearanceBBox(&fixedRect);
double bbox[4];
appearBBox->getBBoxRect(bbox);
@@ -3718,10 +3760,9 @@
if (action)
delete action;
-
- if (additionActions)
- delete additionActions;
-
+
+ additionalActions.free();
+
if (parent)
delete parent;
}
@@ -3761,12 +3802,7 @@
}
obj1.free();
- if(dict->lookup("AA", &obj1)->isDict()) {
- additionActions = NULL;
- } else {
- additionActions = NULL;
- }
- obj1.free();
+ dict->lookupNF("AA", &additionalActions);
if(dict->lookup("Parent", &obj1)->isDict()) {
parent = NULL;
@@ -3778,6 +3814,11 @@
updatedAppearanceStream.num = updatedAppearanceStream.gen = -1;
}
+LinkAction* AnnotWidget::getAdditionalAction(AdditionalActionsType type)
+{
+ return ::getAdditionalAction(type, &additionalActions, doc);
+}
+
// Grand unified handler for preparing text strings to be drawn into form
// fields. Takes as input a text string (in PDFDocEncoding or UTF-16).
// Converts some or all of this string to the appropriate encoding for the
@@ -3894,8 +3935,7 @@
}
} else {
ccToUnicode->decRefCnt();
- fprintf(stderr,
- "warning: layoutText: cannot convert U+%04X\n", uChar);
+ error(errSyntaxError, -1, "AnnotWidget::layoutText, cannot convert U+{0:04uX}", uChar);
}
}
@@ -5140,7 +5180,7 @@
if (action)
delete action;
- additionAction.free();
+ additionalActions.free();
}
void AnnotScreen::initialize(PDFDoc *docA, Dict* dict) {
@@ -5164,14 +5204,21 @@
}
obj1.free();
- dict->lookup("AA", &additionAction);
+ dict->lookupNF("AA", &additionalActions);
appearCharacs = NULL;
if(dict->lookup("MK", &obj1)->isDict()) {
appearCharacs = new AnnotAppearanceCharacs(obj1.getDict());
}
obj1.free();
+}
+LinkAction* AnnotScreen::getAdditionalAction(AdditionalActionsType type)
+{
+ if (type == actionFocusIn || type == actionFocusOut) // not defined for screen annotation
+ return NULL;
+
+ return ::getAdditionalAction(type, &additionalActions, doc);
}
//------------------------------------------------------------------------
@@ -6450,7 +6497,7 @@
// Annots
//------------------------------------------------------------------------
-Annots::Annots(PDFDoc *docA, Object *annotsObj) {
+Annots::Annots(PDFDoc *docA, int page, Object *annotsObj) {
Annot *annot;
Object obj1;
int i;
@@ -6471,6 +6518,7 @@
annot = createAnnot (obj1.getDict(), &obj2);
if (annot) {
if (annot->isOk()) {
+ annot->setPage(page, gFalse); // Don't change /P
appendAnnot(annot);
}
annot->decRefCnt();
diff --git a/poppler/Annot.h b/poppler/Annot.h
index 7cbc143..68ddeb7 100644
--- a/poppler/Annot.h
+++ b/poppler/Annot.h
@@ -23,6 +23,7 @@
// Copyright (C) 2008 Tomas Are Haavet <tomasare@gmail.com>
// Copyright (C) 2009-2011 Albert Astals Cid <aacid@kde.org>
// Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
+// Copyright (C) 2012 Tobias Koenig <tokoe@kdab.com>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
@@ -43,6 +44,7 @@
class CharCodeToUnicode;
class GfxFont;
class GfxResources;
+class Page;
class PDFDoc;
class Form;
class FormWidget;
@@ -471,6 +473,8 @@
//------------------------------------------------------------------------
class Annot {
+ friend class Annots;
+ friend class Page;
public:
enum AnnotFlag {
flagUnknown = 0x0000,
@@ -515,6 +519,22 @@
type3D // 3D 25
};
+ /**
+ * Describes the additional actions of a screen or widget annotation.
+ */
+ enum AdditionalActionsType {
+ actionCursorEntering, ///< Performed when the cursor enters the annotation's active area
+ actionCursorLeaving, ///< Performed when the cursor exists the annotation's active area
+ actionMousePressed, ///< Performed when the mouse button is pressed inside the annotation's active area
+ actionMouseReleased, ///< Performed when the mouse button is released inside the annotation's active area
+ actionFocusIn, ///< Performed when the annotation receives the input focus
+ actionFocusOut, ///< Performed when the annotation loses the input focus
+ actionPageOpening, ///< Performed when the page containing the annotation is opened
+ actionPageClosing, ///< Performed when the page containing the annotation is closed
+ actionPageVisible, ///< Performed when the page containing the annotation becomes visible
+ actionPageInvisible ///< Performed when the page containing the annotation becomes invisible
+ };
+
Annot(PDFDoc *docA, PDFRectangle *rectA);
Annot(PDFDoc *docA, Dict *dict);
Annot(PDFDoc *docA, Dict *dict, Object *obj);
@@ -551,8 +571,6 @@
// new_color.
void setColor(AnnotColor *new_color);
- void setPage(Ref *pageRef, int pageIndex);
-
void setAppearanceState(const char *state);
// Delete appearance streams and reset appearance state
@@ -587,10 +605,12 @@
// write vStr[i:j[ in appearBuf
void initialize (PDFDoc *docA, Dict *dict);
+ void setPage (int new_page, GBool updateP); // Called by Page::addAnnot and Annots ctor
protected:
virtual ~Annot();
+ virtual void removeReferencedObjects(); // Called by Page::removeAnnot
void setColor(AnnotColor *color, GBool fill);
void drawCircle(double cx, double cy, double r, GBool fill);
void drawCircleTopLeft(double cx, double cy, double r);
@@ -699,6 +719,8 @@
void setDate(GooString *new_date);
protected:
+ virtual void removeReferencedObjects();
+
GooString *label; // T (Default autor)
AnnotPopup *popup; // Popup
double opacity; // CA (Default 1.0)
@@ -800,7 +822,7 @@
AnnotAppearanceCharacs *getAppearCharacs() { return appearCharacs; }
LinkAction* getAction() { return action; }
- Object* getAdditionActions() { return &additionAction; }
+ LinkAction *getAdditionalAction(AdditionalActionsType type);
private:
void initialize(PDFDoc *docA, Dict *dict);
@@ -811,7 +833,7 @@
AnnotAppearanceCharacs* appearCharacs; // MK
LinkAction *action; // A
- Object additionAction; // AA
+ Object additionalActions; // AA
};
//------------------------------------------------------------------------
@@ -1274,7 +1296,7 @@
AnnotWidgetHighlightMode getMode() { return mode; }
AnnotAppearanceCharacs *getAppearCharacs() { return appearCharacs; }
LinkAction *getAction() { return action; }
- Dict *getAdditionActions() { return additionActions; }
+ LinkAction *getAdditionalAction(AdditionalActionsType type);
Dict *getParent() { return parent; }
private:
@@ -1293,7 +1315,7 @@
AnnotWidgetHighlightMode mode; // H (Default I)
AnnotAppearanceCharacs *appearCharacs; // MK
LinkAction *action; // A
- Dict *additionActions; // AA
+ Object additionalActions; // AA
// inherited from Annot
// AnnotBorderBS border; // BS
Dict *parent; // Parent
@@ -1367,8 +1389,8 @@
class Annots {
public:
- // Build a list of Annot objects.
- Annots(PDFDoc *docA, Object *annotsObj);
+ // Build a list of Annot objects and call setPage on them
+ Annots(PDFDoc *docA, int page, Object *annotsObj);
~Annots();
diff --git a/poppler/CairoOutputDev.cc b/poppler/CairoOutputDev.cc
index b70183e..2cd67c9 100644
--- a/poppler/CairoOutputDev.cc
+++ b/poppler/CairoOutputDev.cc
@@ -23,7 +23,7 @@
// Copyright (C) 2008-2012 Adrian Johnson <ajohnson@redneon.com>
// Copyright (C) 2008 Michael Vrable <mvrable@cs.ucsd.edu>
// Copyright (C) 2008, 2009 Chris Wilson <chris@chris-wilson.co.uk>
-// Copyright (C) 2008 Hib Eris <hib@hiberis.nl>
+// Copyright (C) 2008, 2012 Hib Eris <hib@hiberis.nl>
// Copyright (C) 2009, 2010 David Benjamin <davidben@mit.edu>
// Copyright (C) 2011, 2012 Thomas Freitag <Thomas.Freitag@alfa.de>
// Copyright (C) 2012 Patrick Pfeifer <p2000@mailinator.com>
@@ -61,7 +61,7 @@
#include "CairoOutputDev.h"
#include "CairoFontEngine.h"
#include "CairoRescaleBox.h"
-#include "UTF8.h"
+#include "UnicodeMap.h"
//------------------------------------------------------------------------
// #define LOG_CAIRO
@@ -945,10 +945,21 @@
fill_pattern = cairo_pattern_create_mesh ();
for (i = 0; i < shading->getNTriangles(); i++) {
- shading->getTriangle(i,
- &x0, &y0, &color[0],
- &x1, &y1, &color[1],
- &x2, &y2, &color[2]);
+ if (shading->isParameterized()) {
+ double color0, color1, color2;
+ shading->getTriangle(i, &x0, &y0, &color0,
+ &x1, &y1, &color1,
+ &x2, &y2, &color2);
+ shading->getParameterizedColor(color0, &color[0]);
+ shading->getParameterizedColor(color1, &color[1]);
+ shading->getParameterizedColor(color2, &color[2]);
+ } else {
+ shading->getTriangle(i,
+ &x0, &y0, &color[0],
+ &x1, &y1, &color[1],
+ &x2, &y2, &color[2]);
+
+ }
cairo_mesh_pattern_begin_patch (fill_pattern);
@@ -1169,6 +1180,8 @@
glyphs[glyphCount].y = y - originY;
glyphCount++;
if (use_show_text_glyphs) {
+ GooString enc("UTF-8");
+ UnicodeMap *utf8Map = globalParams->getUnicodeMap(&enc);
if (utf8Max - utf8Count < uLen*6) {
// utf8 encoded characters can be up to 6 bytes
if (utf8Max > uLen*6)
@@ -1179,7 +1192,7 @@
}
clusters[clusterCount].num_bytes = 0;
for (int i = 0; i < uLen; i++) {
- int size = mapUTF8 (u[i], utf8 + utf8Count, utf8Max - utf8Count);
+ int size = utf8Map->mapUnicode(u[i], utf8 + utf8Count, utf8Max - utf8Count);
utf8Count += size;
clusters[clusterCount].num_bytes += size;
}
diff --git a/poppler/Catalog.cc b/poppler/Catalog.cc
index 0f42356..cf6dff0 100644
--- a/poppler/Catalog.cc
+++ b/poppler/Catalog.cc
@@ -24,6 +24,7 @@
// Copyright (C) 2008, 2011 Pino Toscano <pino@kde.org>
// Copyright (C) 2009 Ilya Gorenbein <igorenbein@finjan.com>
// Copyright (C) 2010 Hib Eris <hib@hiberis.nl>
+// Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
@@ -864,6 +865,24 @@
return &dests;
}
+Catalog::FormType Catalog::getFormType()
+{
+ Object xfa;
+ FormType res = NoForm;
+
+ if (acroForm.isDict()) {
+ acroForm.dictLookup("XFA", &xfa);
+ if (xfa.isStream() || xfa.isArray()) {
+ res = XfaForm;
+ } else {
+ res = AcroForm;
+ }
+ xfa.free();
+ }
+
+ return res;
+}
+
Form *Catalog::getForm()
{
if (!form) {
diff --git a/poppler/Catalog.h b/poppler/Catalog.h
index cdb1f13..ef469ec 100644
--- a/poppler/Catalog.h
+++ b/poppler/Catalog.h
@@ -20,6 +20,7 @@
// Copyright (C) 2007 Julien Rebetez <julienr@svn.gnome.org>
// Copyright (C) 2008, 2011 Pino Toscano <pino@kde.org>
// Copyright (C) 2010 Hib Eris <hib@hiberis.nl>
+// Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
@@ -153,6 +154,14 @@
OCGs *getOptContentConfig() { return optContent; }
+ enum FormType
+ {
+ NoForm,
+ AcroForm,
+ XfaForm
+ };
+
+ FormType getFormType();
Form* getForm();
ViewerPreferences *getViewerPreferences();
diff --git a/poppler/CharCodeToUnicode.cc b/poppler/CharCodeToUnicode.cc
index d0e6c7f..16ba6d4 100644
--- a/poppler/CharCodeToUnicode.cc
+++ b/poppler/CharCodeToUnicode.cc
@@ -21,6 +21,7 @@
// Copyright (C) 2010 William Bader <williambader@hotmail.com>
// Copyright (C) 2010 Jakub Wilk <ubanus@users.sf.net>
// Copyright (C) 2012 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2012 Adrian Johnson <ajohnson@redneon.com>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
@@ -43,6 +44,7 @@
#include "GlobalParams.h"
#include "PSTokenizer.h"
#include "CharCodeToUnicode.h"
+#include "UTF.h"
//------------------------------------------------------------------------
@@ -437,7 +439,7 @@
for (i = oldLen; i < mapLen; ++i) {
map[i] = 0;
}
- }
+ }
}
if (n <= 4) {
if (!parseHex(uStr, n, &u)) {
@@ -445,6 +447,9 @@
return;
}
map[code] = u + offset;
+ if (!UnicodeIsValid(map[code])) {
+ map[code] = 0xfffd;
+ }
} else {
if (sMapLen >= sMapSize) {
sMapSize = sMapSize + 16;
@@ -453,15 +458,18 @@
}
map[code] = 0;
sMap[sMapLen].c = code;
- sMap[sMapLen].len = n / 4;
- sMap[sMapLen].u = (Unicode*)gmallocn(sMap[sMapLen].len, sizeof(Unicode));
- for (j = 0; j < sMap[sMapLen].len; ++j) {
- if (!parseHex(uStr + j*4, 4, &sMap[sMapLen].u[j])) {
+ int utf16Len = n / 4;
+ Unicode *utf16 = (Unicode*)gmallocn(utf16Len, sizeof(Unicode));
+ for (j = 0; j < utf16Len; ++j) {
+ if (!parseHex(uStr + j*4, 4, &utf16[j])) {
+ gfree(utf16);
error(errSyntaxWarning, -1, "Illegal entry in ToUnicode CMap");
return;
}
}
- sMap[sMapLen].u[sMap[sMapLen].len - 1] += offset;
+ utf16[utf16Len - 1] += offset;
+ sMap[sMapLen].len = UTF16toUCS4(utf16, utf16Len, &sMap[sMapLen].u);
+ gfree(utf16);
++sMapLen;
}
}
@@ -590,7 +598,11 @@
sMap[i].len = len;
sMap[i].u = (Unicode*)gmallocn(len, sizeof(Unicode));
for (j = 0; j < len; ++j) {
- sMap[i].u[j] = u[j];
+ if (UnicodeIsValid(u[j])) {
+ sMap[i].u[j] = u[j];
+ } else {
+ sMap[i].u[j] = 0xfffd;
+ }
}
}
}
diff --git a/poppler/Decrypt.cc b/poppler/Decrypt.cc
index 24af996..44f6961 100644
--- a/poppler/Decrypt.cc
+++ b/poppler/Decrypt.cc
@@ -17,6 +17,7 @@
// Copyright (C) 2008, 2010 Albert Astals Cid <aacid@kde.org>
// Copyright (C) 2009 Matthias Franz <matthias@ktug.or.kr>
// Copyright (C) 2009 David Benjamin <davidben@mit.edu>
+// Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
@@ -31,15 +32,23 @@
#include <string.h>
#include "goo/gmem.h"
+#include "goo/grandom.h"
#include "Decrypt.h"
#include "Error.h"
-static void aesKeyExpansion(DecryptAESState *s,
- Guchar *objKey, int objKeyLen);
+static void rc4InitKey(Guchar *key, int keyLen, Guchar *state);
+static Guchar rc4DecryptByte(Guchar *state, Guchar *x, Guchar *y, Guchar c);
+
+static GBool aesReadBlock(Stream *str, Guchar *in, GBool addPadding);
+
+static void aesKeyExpansion(DecryptAESState *s, Guchar *objKey, int objKeyLen, GBool decrypt);
+static void aesEncryptBlock(DecryptAESState *s, Guchar *in);
static void aesDecryptBlock(DecryptAESState *s, Guchar *in, GBool last);
-static void aes256KeyExpansion(DecryptAES256State *s,
- Guchar *objKey, int objKeyLen);
+
+static void aes256KeyExpansion(DecryptAES256State *s, Guchar *objKey, int objKeyLen, GBool decrypt);
+static void aes256EncryptBlock(DecryptAES256State *s, Guchar *in);
static void aes256DecryptBlock(DecryptAES256State *s, Guchar *in, GBool last);
+
static void sha256(Guchar *msg, int msgLen, Guchar *hash);
static const Guchar passwordPad[32] = {
@@ -90,7 +99,7 @@
memcpy(test + len, ownerKey->getCString() + 40, 8);
memcpy(test + len + 8, userKey->getCString(), 48);
sha256(test, len + 56, test);
- aes256KeyExpansion(&state, test, 32);
+ aes256KeyExpansion(&state, test, 32, gTrue);
for (i = 0; i < 16; ++i) {
state.cbc[i] = 0;
}
@@ -121,7 +130,7 @@
memcpy(test, userPassword->getCString(), len);
memcpy(test + len, userKey->getCString() + 40, 8);
sha256(test, len + 8, test);
- aes256KeyExpansion(&state, test, 32);
+ aes256KeyExpansion(&state, test, 32, gTrue);
for (i = 0; i < 16; ++i) {
state.cbc[i] = 0;
}
@@ -269,12 +278,11 @@
}
//------------------------------------------------------------------------
-// DecryptStream
+// BaseCryptStream
//------------------------------------------------------------------------
-DecryptStream::DecryptStream(Stream *strA, Guchar *fileKey,
- CryptAlgorithm algoA, int keyLength,
- int objNum, int objGen):
+BaseCryptStream::BaseCryptStream(Stream *strA, Guchar *fileKey, CryptAlgorithm algoA,
+ int keyLength, int objNum, int objGen):
FilterStream(strA)
{
int i;
@@ -318,32 +326,162 @@
}
charactersRead = 0;
+ autoDelete = gTrue;
}
-DecryptStream::~DecryptStream() {
- delete str;
+BaseCryptStream::~BaseCryptStream() {
+ if (autoDelete) {
+ delete str;
+ }
}
-void DecryptStream::reset() {
- int i;
-
+void BaseCryptStream::reset() {
charactersRead = 0;
+ nextCharBuff = EOF;
str->reset();
+}
+
+int BaseCryptStream::getPos() {
+ return charactersRead;
+}
+
+int BaseCryptStream::getChar() {
+ // Read next character and empty the buffer, so that a new character will be read next time
+ int c = lookChar();
+ nextCharBuff = EOF;
+
+ if (c != EOF)
+ charactersRead++;
+ return c;
+}
+
+GBool BaseCryptStream::isBinary(GBool last) {
+ return str->isBinary(last);
+}
+
+void BaseCryptStream::setAutoDelete(GBool val) {
+ autoDelete = val;
+}
+
+//------------------------------------------------------------------------
+// EncryptStream
+//------------------------------------------------------------------------
+
+EncryptStream::EncryptStream(Stream *strA, Guchar *fileKey, CryptAlgorithm algoA,
+ int keyLength, int objNum, int objGen):
+ BaseCryptStream(strA, fileKey, algoA, keyLength, objNum, objGen)
+{
+ // Fill the CBC initialization vector for AES and AES-256
+ switch (algo) {
+ case cryptAES:
+ grandom_fill(state.aes.cbc, 16);
+ break;
+ case cryptAES256:
+ grandom_fill(state.aes256.cbc, 16);
+ break;
+ default:
+ break;
+ }
+}
+
+EncryptStream::~EncryptStream() {
+}
+
+void EncryptStream::reset() {
+ BaseCryptStream::reset();
+
switch (algo) {
case cryptRC4:
state.rc4.x = state.rc4.y = 0;
rc4InitKey(objKey, objKeyLength, state.rc4.state);
- state.rc4.buf = EOF;
break;
case cryptAES:
- aesKeyExpansion(&state.aes, objKey, objKeyLength);
+ aesKeyExpansion(&state.aes, objKey, objKeyLength, gFalse);
+ memcpy(state.aes.buf, state.aes.cbc, 16); // Copy CBC IV to buf
+ state.aes.bufIdx = 0;
+ state.aes.paddingReached = gFalse;
+ break;
+ case cryptAES256:
+ aes256KeyExpansion(&state.aes256, objKey, objKeyLength, gFalse);
+ memcpy(state.aes256.buf, state.aes256.cbc, 16); // Copy CBC IV to buf
+ state.aes256.bufIdx = 0;
+ state.aes256.paddingReached = gFalse;
+ break;
+ }
+}
+
+int EncryptStream::lookChar() {
+ Guchar in[16];
+ int c;
+
+ if (nextCharBuff != EOF)
+ return nextCharBuff;
+
+ c = EOF; // make gcc happy
+ switch (algo) {
+ case cryptRC4:
+ if ((c = str->getChar()) != EOF) {
+ // RC4 is XOR-based: the decryption algorithm works for encryption too
+ c = rc4DecryptByte(state.rc4.state, &state.rc4.x, &state.rc4.y, (Guchar)c);
+ }
+ break;
+ case cryptAES:
+ if (state.aes.bufIdx == 16 && !state.aes.paddingReached) {
+ state.aes.paddingReached = !aesReadBlock(str, in, gTrue);
+ aesEncryptBlock(&state.aes, in);
+ }
+ if (state.aes.bufIdx == 16) {
+ c = EOF;
+ } else {
+ c = state.aes.buf[state.aes.bufIdx++];
+ }
+ break;
+ case cryptAES256:
+ if (state.aes256.bufIdx == 16 && !state.aes256.paddingReached) {
+ state.aes256.paddingReached = !aesReadBlock(str, in, gTrue);
+ aes256EncryptBlock(&state.aes256, in);
+ }
+ if (state.aes256.bufIdx == 16) {
+ c = EOF;
+ } else {
+ c = state.aes256.buf[state.aes256.bufIdx++];
+ }
+ break;
+ }
+ return (nextCharBuff = c);
+}
+
+//------------------------------------------------------------------------
+// DecryptStream
+//------------------------------------------------------------------------
+
+DecryptStream::DecryptStream(Stream *strA, Guchar *fileKey, CryptAlgorithm algoA,
+ int keyLength, int objNum, int objGen):
+ BaseCryptStream(strA, fileKey, algoA, keyLength, objNum, objGen)
+{
+}
+
+DecryptStream::~DecryptStream() {
+}
+
+void DecryptStream::reset() {
+ int i;
+ BaseCryptStream::reset();
+
+ switch (algo) {
+ case cryptRC4:
+ state.rc4.x = state.rc4.y = 0;
+ rc4InitKey(objKey, objKeyLength, state.rc4.state);
+ break;
+ case cryptAES:
+ aesKeyExpansion(&state.aes, objKey, objKeyLength, gTrue);
for (i = 0; i < 16; ++i) {
state.aes.cbc[i] = str->getChar();
}
state.aes.bufIdx = 16;
break;
case cryptAES256:
- aes256KeyExpansion(&state.aes256, objKey, objKeyLength);
+ aes256KeyExpansion(&state.aes256, objKey, objKeyLength, gTrue);
for (i = 0; i < 16; ++i) {
state.aes256.cbc[i] = str->getChar();
}
@@ -352,36 +490,25 @@
}
}
-int DecryptStream::getPos() {
- return charactersRead;
-}
-
-int DecryptStream::getChar() {
+int DecryptStream::lookChar() {
Guchar in[16];
- int c, i;
+ int c;
+
+ if (nextCharBuff != EOF)
+ return nextCharBuff;
c = EOF; // make gcc happy
switch (algo) {
case cryptRC4:
- if (state.rc4.buf == EOF) {
- c = str->getChar();
- if (c != EOF) {
- state.rc4.buf = rc4DecryptByte(state.rc4.state, &state.rc4.x,
- &state.rc4.y, (Guchar)c);
- }
+ if ((c = str->getChar()) != EOF) {
+ c = rc4DecryptByte(state.rc4.state, &state.rc4.x, &state.rc4.y, (Guchar)c);
}
- c = state.rc4.buf;
- state.rc4.buf = EOF;
break;
case cryptAES:
if (state.aes.bufIdx == 16) {
- for (i = 0; i < 16; ++i) {
- if ((c = str->getChar()) == EOF) {
- return EOF;
- }
- in[i] = (Guchar)c;
+ if (aesReadBlock(str, in, gFalse)) {
+ aesDecryptBlock(&state.aes, in, str->lookChar() == EOF);
}
- aesDecryptBlock(&state.aes, in, str->lookChar() == EOF);
}
if (state.aes.bufIdx == 16) {
c = EOF;
@@ -391,13 +518,9 @@
break;
case cryptAES256:
if (state.aes256.bufIdx == 16) {
- for (i = 0; i < 16; ++i) {
- if ((c = str->getChar()) == EOF) {
- return EOF;
- }
- in[i] = (Guchar)c;
+ if (aesReadBlock(str, in, gFalse)) {
+ aes256DecryptBlock(&state.aes256, in, str->lookChar() == EOF);
}
- aes256DecryptBlock(&state.aes256, in, str->lookChar() == EOF);
}
if (state.aes256.bufIdx == 16) {
c = EOF;
@@ -406,72 +529,14 @@
}
break;
}
- if (c != EOF)
- charactersRead++;
- return c;
-}
-
-int DecryptStream::lookChar() {
- Guchar in[16];
- int c, i;
-
- c = EOF; // make gcc happy
- switch (algo) {
- case cryptRC4:
- if (state.rc4.buf == EOF) {
- c = str->getChar();
- if (c != EOF) {
- state.rc4.buf = rc4DecryptByte(state.rc4.state, &state.rc4.x,
- &state.rc4.y, (Guchar)c);
- }
- }
- c = state.rc4.buf;
- break;
- case cryptAES:
- if (state.aes.bufIdx == 16) {
- for (i = 0; i < 16; ++i) {
- if ((c = str->getChar()) == EOF) {
- return EOF;
- }
- in[i] = c;
- }
- aesDecryptBlock(&state.aes, in, str->lookChar() == EOF);
- }
- if (state.aes.bufIdx == 16) {
- c = EOF;
- } else {
- c = state.aes.buf[state.aes.bufIdx];
- }
- break;
- case cryptAES256:
- if (state.aes256.bufIdx == 16) {
- for (i = 0; i < 16; ++i) {
- if ((c = str->getChar()) == EOF) {
- return EOF;
- }
- in[i] = c;
- }
- aes256DecryptBlock(&state.aes256, in, str->lookChar() == EOF);
- }
- if (state.aes256.bufIdx == 16) {
- c = EOF;
- } else {
- c = state.aes256.buf[state.aes256.bufIdx];
- }
- break;
- }
- return c;
-}
-
-GBool DecryptStream::isBinary(GBool last) {
- return str->isBinary(last);
+ return (nextCharBuff = c);
}
//------------------------------------------------------------------------
// RC4-compatible decryption
//------------------------------------------------------------------------
-void rc4InitKey(Guchar *key, int keyLen, Guchar *state) {
+static void rc4InitKey(Guchar *key, int keyLen, Guchar *state) {
Guchar index1, index2;
Guchar t;
int i;
@@ -492,7 +557,7 @@
}
}
-Guchar rc4DecryptByte(Guchar *state, Guchar *x, Guchar *y, Guchar c) {
+static Guchar rc4DecryptByte(Guchar *state, Guchar *x, Guchar *y, Guchar c) {
Guchar x1, y1, tx, ty;
x1 = *x = (*x + 1) % 256;
@@ -508,6 +573,32 @@
// AES decryption
//------------------------------------------------------------------------
+// Returns gFalse if EOF was reached, gTrue otherwise
+static GBool aesReadBlock(Stream *str, Guchar *in, GBool addPadding)
+{
+ int c, i;
+
+ for (i = 0; i < 16; ++i) {
+ if ((c = str->getChar()) != EOF) {
+ in[i] = (Guchar)c;
+ } else {
+ break;
+ }
+ }
+
+ if (i == 16) {
+ return gTrue;
+ } else {
+ if (addPadding) {
+ c = 16 - i;
+ while (i < 16) {
+ in[i++] = (Guchar)c;
+ }
+ }
+ return gFalse;
+ }
+}
+
static const Guchar sbox[256] = {
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
@@ -571,6 +662,14 @@
return ((x << 8) & 0xffffffff) | (x >> 24);
}
+static inline void subBytes(Guchar *state) {
+ int i;
+
+ for (i = 0; i < 16; ++i) {
+ state[i] = sbox[state[i]];
+ }
+}
+
static inline void invSubBytes(Guchar *state) {
int i;
@@ -579,6 +678,29 @@
}
}
+static inline void shiftRows(Guchar *state) {
+ Guchar t;
+
+ t = state[4];
+ state[4] = state[5];
+ state[5] = state[6];
+ state[6] = state[7];
+ state[7] = t;
+
+ t = state[8];
+ state[8] = state[10];
+ state[10] = t;
+ t = state[9];
+ state[9] = state[11];
+ state[11] = t;
+
+ t = state[15];
+ state[15] = state[14];
+ state[14] = state[13];
+ state[13] = state[12];
+ state[12] = t;
+}
+
static inline void invShiftRows(Guchar *state) {
Guchar t;
@@ -602,6 +724,17 @@
state[15] = t;
}
+// {02} \cdot s
+static inline Guchar mul02(Guchar s) {
+ return (s & 0x80) ? ((s << 1) ^ 0x1b) : (s << 1);
+}
+
+// {03} \cdot s
+static inline Guchar mul03(Guchar s) {
+ Guchar s2 = (s & 0x80) ? ((s << 1) ^ 0x1b) : (s << 1);
+ return s ^ s2;
+}
+
// {09} \cdot s
static inline Guchar mul09(Guchar s) {
Guchar s2, s4, s8;
@@ -642,6 +775,22 @@
return s2 ^ s4 ^ s8;
}
+static inline void mixColumns(Guchar *state) {
+ int c;
+ Guchar s0, s1, s2, s3;
+
+ for (c = 0; c < 4; ++c) {
+ s0 = state[c];
+ s1 = state[4+c];
+ s2 = state[8+c];
+ s3 = state[12+c];
+ state[c] = mul02(s0) ^ mul03(s1) ^ s2 ^ s3;
+ state[4+c] = s0 ^ mul02(s1) ^ mul03(s2) ^ s3;
+ state[8+c] = s0 ^ s1 ^ mul02(s2) ^ mul03(s3);
+ state[12+c] = mul03(s0) ^ s1 ^ s2 ^ mul02(s3);
+ }
+}
+
static inline void invMixColumns(Guchar *state) {
int c;
Guchar s0, s1, s2, s3;
@@ -686,7 +835,7 @@
}
static void aesKeyExpansion(DecryptAESState *s,
- Guchar *objKey, int /*objKeyLen*/) {
+ Guchar *objKey, int /*objKeyLen*/, GBool decrypt) {
Guint temp;
int i, round;
@@ -703,11 +852,52 @@
}
s->w[i] = s->w[i-4] ^ temp;
}
- for (round = 1; round <= 9; ++round) {
- invMixColumnsW(&s->w[round * 4]);
+
+ /* In case of decryption, adjust the key schedule for the equivalent inverse cipher */
+ if (decrypt) {
+ for (round = 1; round <= 9; ++round) {
+ invMixColumnsW(&s->w[round * 4]);
+ }
}
}
+static void aesEncryptBlock(DecryptAESState *s, Guchar *in) {
+ int c, round;
+
+ // initial state (input is xor'd with previous output because of CBC)
+ for (c = 0; c < 4; ++c) {
+ s->state[c] = in[4*c] ^ s->buf[4*c];
+ s->state[4+c] = in[4*c+1] ^ s->buf[4*c+1];
+ s->state[8+c] = in[4*c+2] ^ s->buf[4*c+2];
+ s->state[12+c] = in[4*c+3] ^ s->buf[4*c+3];
+ }
+
+ // round 0
+ addRoundKey(s->state, &s->w[0]);
+
+ // rounds 1-9
+ for (round = 1; round <= 9; ++round) {
+ subBytes(s->state);
+ shiftRows(s->state);
+ mixColumns(s->state);
+ addRoundKey(s->state, &s->w[round * 4]);
+ }
+
+ // round 10
+ subBytes(s->state);
+ shiftRows(s->state);
+ addRoundKey(s->state, &s->w[10 * 4]);
+
+ for (c = 0; c < 4; ++c) {
+ s->buf[4*c] = s->state[c];
+ s->buf[4*c+1] = s->state[4+c];
+ s->buf[4*c+2] = s->state[8+c];
+ s->buf[4*c+3] = s->state[12+c];
+ }
+
+ s->bufIdx = 0;
+}
+
static void aesDecryptBlock(DecryptAESState *s, Guchar *in, GBool last) {
int c, round, n, i;
@@ -767,7 +957,7 @@
//------------------------------------------------------------------------
static void aes256KeyExpansion(DecryptAES256State *s,
- Guchar *objKey, int objKeyLen) {
+ Guchar *objKey, int objKeyLen, GBool decrypt) {
Guint temp;
int i, round;
@@ -786,11 +976,52 @@
}
s->w[i] = s->w[i-8] ^ temp;
}
- for (round = 1; round <= 13; ++round) {
- invMixColumnsW(&s->w[round * 4]);
+
+ /* In case of decryption, adjust the key schedule for the equivalent inverse cipher */
+ if (decrypt) {
+ for (round = 1; round <= 13; ++round) {
+ invMixColumnsW(&s->w[round * 4]);
+ }
}
}
+static void aes256EncryptBlock(DecryptAES256State *s, Guchar *in) {
+ int c, round;
+
+ // initial state (input is xor'd with previous output because of CBC)
+ for (c = 0; c < 4; ++c) {
+ s->state[c] = in[4*c] ^ s->buf[4*c];
+ s->state[4+c] = in[4*c+1] ^ s->buf[4*c+1];
+ s->state[8+c] = in[4*c+2] ^ s->buf[4*c+2];
+ s->state[12+c] = in[4*c+3] ^ s->buf[4*c+3];
+ }
+
+ // round 0
+ addRoundKey(s->state, &s->w[0]);
+
+ // rounds 1-13
+ for (round = 1; round <= 13; ++round) {
+ subBytes(s->state);
+ shiftRows(s->state);
+ mixColumns(s->state);
+ addRoundKey(s->state, &s->w[round * 4]);
+ }
+
+ // round 14
+ subBytes(s->state);
+ shiftRows(s->state);
+ addRoundKey(s->state, &s->w[14 * 4]);
+
+ for (c = 0; c < 4; ++c) {
+ s->buf[4*c] = s->state[c];
+ s->buf[4*c+1] = s->state[4+c];
+ s->buf[4*c+2] = s->state[8+c];
+ s->buf[4*c+3] = s->state[12+c];
+ }
+
+ s->bufIdx = 0;
+}
+
static void aes256DecryptBlock(DecryptAES256State *s, Guchar *in, GBool last) {
int c, round, n, i;
diff --git a/poppler/Decrypt.h b/poppler/Decrypt.h
index d947f41..c049f5c 100644
--- a/poppler/Decrypt.h
+++ b/poppler/Decrypt.h
@@ -15,6 +15,7 @@
//
// Copyright (C) 2008 Julien Rebetez <julien@fhtagn.net>
// Copyright (C) 2009 David Benjamin <davidben@mit.edu>
+// Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
@@ -63,13 +64,19 @@
};
//------------------------------------------------------------------------
-// DecryptStream
+// Helper classes
//------------------------------------------------------------------------
+/* DecryptRC4State, DecryptAESState, DecryptAES256State are named like this for
+ * historical reasons, but they're used for encryption too.
+ * In case of decryption, the cbc field in AES and AES-256 contains the previous
+ * input block or the CBC initialization vector (IV) if the stream has just been
+ * reset). In case of encryption, it always contains the IV, whereas the
+ * previous output is kept in buf. The paddingReached field is only used in
+ * case of encryption. */
struct DecryptRC4State {
Guchar state[256];
Guchar x, y;
- int buf;
};
struct DecryptAESState {
@@ -77,6 +84,7 @@
Guchar state[16];
Guchar cbc[16];
Guchar buf[16];
+ GBool paddingReached; // encryption only
int bufIdx;
};
@@ -85,30 +93,32 @@
Guchar state[16];
Guchar cbc[16];
Guchar buf[16];
+ GBool paddingReached; // encryption only
int bufIdx;
};
-class DecryptStream: public FilterStream {
+class BaseCryptStream : public FilterStream {
public:
- DecryptStream(Stream *strA, Guchar *fileKey,
- CryptAlgorithm algoA, int keyLength,
- int objNum, int objGen);
- virtual ~DecryptStream();
+ BaseCryptStream(Stream *strA, Guchar *fileKey, CryptAlgorithm algoA,
+ int keyLength, int objNum, int objGen);
+ virtual ~BaseCryptStream();
virtual StreamKind getKind() { return strWeird; }
virtual void reset();
virtual int getChar();
- virtual int lookChar();
+ virtual int lookChar() = 0;
virtual int getPos();
virtual GBool isBinary(GBool last);
virtual Stream *getUndecodedStream() { return this; }
+ void setAutoDelete(GBool val);
-private:
-
+protected:
CryptAlgorithm algo;
int objKeyLength;
Guchar objKey[32];
int charactersRead; // so that getPos() can be correct
+ int nextCharBuff; // EOF means not read yet
+ GBool autoDelete;
union {
DecryptRC4State rc4;
@@ -116,11 +126,33 @@
DecryptAES256State aes256;
} state;
};
+
+//------------------------------------------------------------------------
+// EncryptStream / DecryptStream
+//------------------------------------------------------------------------
+
+class EncryptStream : public BaseCryptStream {
+public:
+
+ EncryptStream(Stream *strA, Guchar *fileKey, CryptAlgorithm algoA,
+ int keyLength, int objNum, int objGen);
+ ~EncryptStream();
+ virtual void reset();
+ virtual int lookChar();
+};
+
+class DecryptStream : public BaseCryptStream {
+public:
+
+ DecryptStream(Stream *strA, Guchar *fileKey, CryptAlgorithm algoA,
+ int keyLength, int objNum, int objGen);
+ ~DecryptStream();
+ virtual void reset();
+ virtual int lookChar();
+};
//------------------------------------------------------------------------
-extern void rc4InitKey(Guchar *key, int keyLen, Guchar *state);
-extern Guchar rc4DecryptByte(Guchar *state, Guchar *x, Guchar *y, Guchar c);
extern void md5(Guchar *msg, int msgLen, Guchar *digest);
#endif
diff --git a/poppler/Form.cc b/poppler/Form.cc
index 0940932..78c25e3 100644
--- a/poppler/Form.cc
+++ b/poppler/Form.cc
@@ -162,8 +162,6 @@
type = formButton;
parent = static_cast<FormFieldButton*>(field);
onStr = NULL;
- siblingsID = NULL;
- numSiblingsID = 0;
Object obj1, obj2;
@@ -196,8 +194,6 @@
FormWidgetButton::~FormWidgetButton ()
{
- if (siblingsID)
- gfree(siblingsID);
delete onStr;
}
@@ -236,12 +232,6 @@
return onStr ? parent->getState(onStr->getCString()) : gFalse;
}
-void FormWidgetButton::setNumSiblingsID (int i)
-{
- numSiblingsID = i;
- siblingsID = (unsigned*)greallocn(siblingsID, numSiblingsID, sizeof(unsigned));
-}
-
FormWidgetText::FormWidgetText (PDFDoc *docA, Object *aobj, unsigned num, Ref ref, FormField *p) :
FormWidget(docA, aobj, num, ref, p)
@@ -803,6 +793,8 @@
Dict* dict = obj.getDict();
active_child = -1;
noAllOff = false;
+ siblings = NULL;
+ numSiblings = 0;
appearanceState.initNull();
Object obj1;
@@ -853,20 +845,31 @@
}
#endif
+void FormFieldButton::setNumSiblings (int num)
+{
+ numSiblings = num;
+ siblings = (FormFieldButton**)greallocn(siblings, numSiblings, sizeof(FormFieldButton*));
+}
+
void FormFieldButton::fillChildrenSiblingsID()
{
if (!terminal) {
for(int i=0; i<numChildren; i++) {
- children[i]->fillChildrenSiblingsID();
- }
- } else {
- for(int i=0; i<numChildren; i++) {
- FormWidgetButton *btn = static_cast<FormWidgetButton*>(widgets[i]);
- btn->setNumSiblingsID(numChildren-1);
- for(int j=0, counter=0; j<numChildren; j++) {
- if (i == j) continue;
- btn->setSiblingsID(counter, widgets[j]->getID());
- counter++;
+ FormFieldButton *child = dynamic_cast<FormFieldButton*>(children[i]);
+ if (child != NULL) {
+ // Fill the siblings of this node childs
+ child->setNumSiblings(numChildren-1);
+ for(int j=0, counter=0; j<numChildren; j++) {
+ FormFieldButton *otherChild = dynamic_cast<FormFieldButton*>(children[j]);
+ if (i == j) continue;
+ if (child == otherChild) continue;
+ child->setSibling(counter, otherChild);
+ counter++;
+ }
+
+ // now call ourselves on the child
+ // to fill its children data
+ child->fillChildrenSiblingsID();
}
}
}
@@ -957,6 +960,8 @@
FormFieldButton::~FormFieldButton()
{
appearanceState.free();
+ if (siblings)
+ gfree(siblings);
}
//------------------------------------------------------------------------
@@ -1125,44 +1130,70 @@
}
obj1.free();
- // find selected items and convert choice's human readable strings to UTF16
- if (Form::fieldLookup(dict, "V", &obj1)->isString()) {
- for (int i = 0; i < numChoices; i++) {
- if (!choices[i].optionName)
- continue;
-
- if (choices[i].optionName->cmp(obj1.getString()) == 0)
- choices[i].selected = true;
-
- if (!choices[i].optionName->hasUnicodeMarker()) {
- int len;
- char* buffer = pdfDocEncodingToUTF16(choices[i].optionName, &len);
- choices[i].optionName->Set(buffer, len);
- delete [] buffer;
+ // Find selected items
+ // Note: PDF specs say that /V has precedence over /I, but acroread seems to
+ // do the opposite. We do the same.
+ if (Form::fieldLookup(dict, "I", &obj1)->isArray()) {
+ for (int i = 0; i < obj1.arrayGetLength(); i++) {
+ Object obj2;
+ if (obj1.arrayGet(i, &obj2)->isInt() && obj2.getInt() >= 0 && obj2.getInt() < numChoices) {
+ choices[obj2.getInt()].selected = true;
}
+ obj2.free();
}
- } else if (obj1.isArray()) {
- for (int i = 0; i < numChoices; i++) {
- if (!choices[i].optionName)
- continue;
+ } else {
+ obj1.free();
+ // Note: According to PDF specs, /V should *never* contain the exportVal.
+ // However, if /Opt is an array of (exportVal,optionName) pairs, acroread
+ // seems to expect the exportVal instead of the optionName and so we do too.
+ if (Form::fieldLookup(dict, "V", &obj1)->isString()) {
+ GBool optionFound = gFalse;
- for (int j = 0; j < obj1.arrayGetLength(); j++) {
- Object obj2;
-
- obj1.arrayGet(j, &obj2);
- if (choices[i].optionName->cmp(obj2.getString()) == 0) {
- choices[i].selected = true;
- obj2.free();
- break;
+ for (int i = 0; i < numChoices; i++) {
+ if (choices[i].exportVal) {
+ if (choices[i].exportVal->cmp(obj1.getString()) == 0) {
+ optionFound = gTrue;
+ }
+ } else if (choices[i].optionName) {
+ if (choices[i].optionName->cmp(obj1.getString()) == 0) {
+ optionFound = gTrue;
+ }
}
- obj2.free();
+
+ if (optionFound) {
+ choices[i].selected = true;
+ break; // We've determined that this option is selected. No need to keep on scanning
+ }
}
- if (!choices[i].optionName->hasUnicodeMarker()) {
- int len;
- char* buffer = pdfDocEncodingToUTF16(choices[i].optionName, &len);
- choices[i].optionName->Set(buffer, len);
- delete [] buffer;
+ // Set custom value if /V doesn't refer to any predefined option and the field is user-editable
+ if (!optionFound && edit) {
+ editedChoice = obj1.getString()->copy();
+ }
+ } else if (obj1.isArray()) {
+ for (int i = 0; i < numChoices; i++) {
+ for (int j = 0; j < obj1.arrayGetLength(); j++) {
+ Object obj2;
+ obj1.arrayGet(j, &obj2);
+ GBool matches = gFalse;
+
+ if (choices[i].exportVal) {
+ if (choices[i].exportVal->cmp(obj2.getString()) == 0) {
+ matches = gTrue;
+ }
+ } else if (choices[i].optionName) {
+ if (choices[i].optionName->cmp(obj2.getString()) == 0) {
+ matches = gTrue;
+ }
+ }
+
+ obj2.free();
+
+ if (matches) {
+ choices[i].selected = true;
+ break; // We've determined that this option is selected. No need to keep on scanning
+ }
+ }
}
}
}
@@ -1188,35 +1219,61 @@
#endif
void FormFieldChoice::updateSelection() {
- Object obj1;
+ Object objV, objI, obj1;
+ objI.initNull();
- //this is an editable combo-box with user-entered text
if (edit && editedChoice) {
- obj1.initString(editedChoice->copy());
+ // This is an editable combo-box with user-entered text
+ objV.initString(editedChoice->copy());
} else {
- int numSelected = getNumSelected();
+ const int numSelected = getNumSelected();
+
+ // Create /I array only if multiple selection is allowed (as per PDF spec)
+ if (multiselect) {
+ objI.initArray(xref);
+ }
+
if (numSelected == 0) {
- obj1.initString(new GooString(""));
+ // No options are selected
+ objV.initString(new GooString(""));
} else if (numSelected == 1) {
+ // Only one option is selected
for (int i = 0; i < numChoices; i++) {
- if (choices[i].optionName && choices[i].selected) {
- obj1.initString(choices[i].optionName->copy());
- break;
+ if (choices[i].selected) {
+ if (multiselect) {
+ objI.arrayAdd(obj1.initInt(i));
+ }
+
+ if (choices[i].exportVal) {
+ objV.initString(choices[i].exportVal->copy());
+ } else if (choices[i].optionName) {
+ objV.initString(choices[i].optionName->copy());
+ }
+
+ break; // We've just written the selected option. No need to keep on scanning
}
}
} else {
- obj1.initArray(xref);
+ // More than one option is selected
+ objV.initArray(xref);
for (int i = 0; i < numChoices; i++) {
- if (choices[i].optionName && choices[i].selected) {
- Object obj2;
- obj2.initString(choices[i].optionName->copy());
- obj1.arrayAdd(&obj2);
+ if (choices[i].selected) {
+ if (multiselect) {
+ objI.arrayAdd(obj1.initInt(i));
+ }
+
+ if (choices[i].exportVal) {
+ objV.arrayAdd(obj1.initString(choices[i].exportVal->copy()));
+ } else if (choices[i].optionName) {
+ objV.arrayAdd(obj1.initString(choices[i].optionName->copy()));
+ }
}
}
}
}
- obj.getDict()->set("V", &obj1);
+ obj.getDict()->set("V", &objV);
+ obj.getDict()->set("I", &objI);
xref->setModifiedObject(&obj, ref);
updateChildrenAppearance();
}
@@ -1229,20 +1286,30 @@
}
void FormFieldChoice::deselectAll () {
+ delete editedChoice;
+ editedChoice = NULL;
+
unselectAll();
updateSelection();
}
void FormFieldChoice::toggle (int i)
{
+ delete editedChoice;
+ editedChoice = NULL;
+
choices[i].selected = !choices[i].selected;
updateSelection();
}
void FormFieldChoice::select (int i)
{
+ delete editedChoice;
+ editedChoice = NULL;
+
if (!multiselect)
unselectAll();
+
choices[i].selected = true;
updateSelection();
}
diff --git a/poppler/Form.h b/poppler/Form.h
index 4146728..ef67748 100644
--- a/poppler/Form.h
+++ b/poppler/Form.h
@@ -6,7 +6,7 @@
//
// Copyright 2006 Julien Rebetez <julienr@svn.gnome.org>
// Copyright 2007, 2008, 2011 Carlos Garcia Campos <carlosgc@gnome.org>
-// Copyright 2007-2010 Albert Astals Cid <aacid@kde.org>
+// Copyright 2007-2010, 2012 Albert Astals Cid <aacid@kde.org>
// Copyright 2010 Mark Riedesel <mark@klowner.com>
// Copyright 2011 Pino Toscano <pino@kde.org>
// Copyright 2012 Fabio D'Urso <fabiodurso@hotmail.it>
@@ -159,17 +159,7 @@
void setAppearanceState(const char *state);
void updateWidgetAppearance();
- void setNumSiblingsID (int i);
- void setSiblingsID (int i, unsigned id) { siblingsID[i] = id; }
-
- //For radio buttons, return the IDs of the other radio buttons in the same group
- unsigned* getSiblingsID () const { return siblingsID; }
- int getNumSiblingsID () const { return numSiblingsID; }
-
protected:
- unsigned* siblingsID; // IDs of dependent buttons (each button of a radio field has all the others buttons
- // of the same field in this array)
- int numSiblingsID;
GooString *onStr;
FormFieldButton *parent;
};
@@ -287,6 +277,7 @@
GooString *getFullyQualifiedName();
FormWidget* findWidgetByRef (Ref aref);
+ int getNumWidgets() { return terminal ? numChildren : 0; }
FormWidget *getWidget(int i) { return terminal ? widgets[i] : NULL; }
// only implemented in FormFieldButton
@@ -351,6 +342,13 @@
char *getAppearanceState() { return appearanceState.isName() ? appearanceState.getName() : NULL; }
void fillChildrenSiblingsID ();
+
+ void setNumSiblings (int num);
+ void setSibling (int i, FormFieldButton *id) { siblings[i] = id; }
+
+ //For radio buttons, return the fields of the other radio buttons in the same group
+ FormFieldButton* getSibling (int i) const { return siblings[i]; }
+ int getNumSiblings () const { return numSiblings; }
#ifdef DEBUG_FORMS
void print(int indent = 0);
@@ -360,6 +358,10 @@
protected:
void updateState(char *state);
+ FormFieldButton** siblings; // IDs of dependent buttons (each button of a radio field has all the others buttons
+ // of the same field in this array)
+ int numSiblings;
+
FormButtonType btype;
int size;
int active_child; //only used for combo box
diff --git a/poppler/Function.cc b/poppler/Function.cc
index 2c3aa8a..d26aed8 100644
--- a/poppler/Function.cc
+++ b/poppler/Function.cc
@@ -510,6 +510,20 @@
}
}
+GBool SampledFunction::hasDifferentResultSet(Function *func) {
+ if (func->getType() == 0) {
+ SampledFunction *compTo = (SampledFunction *) func;
+ if (compTo->getSampleNumber() != nSamples)
+ return gTrue;
+ double *compSamples = compTo->getSamples();
+ for (int i = 0; i < nSamples; i++) {
+ if (samples[i] != compSamples[i])
+ return gTrue;
+ }
+ }
+ return gFalse;
+}
+
//------------------------------------------------------------------------
// ExponentialFunction
//------------------------------------------------------------------------
diff --git a/poppler/Function.h b/poppler/Function.h
index a456dfe..25df133 100644
--- a/poppler/Function.h
+++ b/poppler/Function.h
@@ -16,6 +16,7 @@
// Copyright (C) 2009, 2010 Albert Astals Cid <aacid@kde.org>
// Copyright (C) 2010 Christian Feuersänger <cfeuersaenger@googlemail.com>
// Copyright (C) 2011 Andrea Canciani <ranma42@gmail.com>
+// Copyright (C) 2012 Thomas Freitag <Thomas.Freitag@alfa.de>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
@@ -79,6 +80,7 @@
double getRangeMin(int i) { return range[i][0]; }
double getRangeMax(int i) { return range[i][1]; }
GBool getHasRange() { return hasRange; }
+ virtual GBool hasDifferentResultSet(Function *func) { return gFalse; }
// Transform an input tuple into an output tuple.
virtual void transform(double *in, double *out) = 0;
@@ -126,6 +128,7 @@
virtual int getType() { return 0; }
virtual void transform(double *in, double *out);
virtual GBool isOk() { return ok; }
+ virtual GBool hasDifferentResultSet(Function *func);
int getSampleSize(int i) { return sampleSize[i]; }
double getEncodeMin(int i) { return encode[i][0]; }
@@ -133,6 +136,7 @@
double getDecodeMin(int i) { return decode[i][0]; }
double getDecodeMax(int i) { return decode[i][1]; }
double *getSamples() { return samples; }
+ int getSampleNumber() { return nSamples; }
private:
diff --git a/poppler/Gfx.cc b/poppler/Gfx.cc
index 4e663b4..8ee2026 100644
--- a/poppler/Gfx.cc
+++ b/poppler/Gfx.cc
@@ -36,6 +36,7 @@
// Copyright (C) 2011 Axel Strübing <axel.struebing@freenet.de>
// Copyright (C) 2012 Even Rouault <even.rouault@mines-paris.org>
// Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
+// Copyright (C) 2012 Lu Wang <coolwanglu@gmail.com>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
@@ -4285,7 +4286,7 @@
obj1.free();
// if drawing is disabled, skip over inline image data
- if (!ocState) {
+ if (!ocState || !out->needNonText()) {
str->reset();
n = height * ((width + 7) / 8);
for (i = 0; i < n; ++i) {
@@ -4544,7 +4545,7 @@
}
// if drawing is disabled, skip over inline image data
- if (!ocState) {
+ if (!ocState || !out->needNonText()) {
str->reset();
n = height * ((width * colorMap->getNumPixelComps() *
colorMap->getBits() + 7) / 8);
diff --git a/poppler/GfxState.cc b/poppler/GfxState.cc
index b8cb007..73a3781 100644
--- a/poppler/GfxState.cc
+++ b/poppler/GfxState.cc
@@ -248,6 +248,7 @@
GfxColorSpace::GfxColorSpace() {
overprintMask = 0x0f;
+ mapping = NULL;
}
GfxColorSpace::~GfxColorSpace() {
@@ -321,6 +322,10 @@
return cs;
}
+void GfxColorSpace::createMapping(GooList *separationList, int maxSepComps) {
+ return;
+}
+
void GfxColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
int maxImgPixel) {
int i;
@@ -354,9 +359,8 @@
}
return hp;
}
- // try to load from user directory
- GooString *path = globalParams->getBaseDir();
- path->append(COLOR_PROFILE_DIR);
+ // try to load from global directory
+ GooString *path = new GooString(GLOBAL_COLOR_PROFILE_DIR);
path->append(fileName);
// check if open the file
if ((fp = fopen(path->getCString(),"r")) != NULL) {
@@ -364,17 +368,6 @@
hp = cmsOpenProfileFromFile(path->getCString(),"r");
}
delete path;
- if (hp == NULL) {
- // load from global directory
- path = new GooString(GLOBAL_COLOR_PROFILE_DIR);
- path->append(fileName);
- // check if open the file
- if ((fp = fopen(path->getCString(),"r")) != NULL) {
- fclose(fp);
- hp = cmsOpenProfileFromFile(path->getCString(),"r");
- }
- delete path;
- }
return hp;
}
@@ -614,6 +607,12 @@
cmyk->k = clip01(gfxColorComp1 - color->c[0]);
}
+void GfxDeviceGrayColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) {
+ for (int i = 0; i < gfxColorMaxComps; i++)
+ deviceN->c[i] = 0;
+ deviceN->c[3] = clip01(gfxColorComp1 - color->c[0]);
+}
+
void GfxDeviceGrayColorSpace::getDefaultColor(GfxColor *color) {
color->c[0] = 0;
}
@@ -822,6 +821,17 @@
cmyk->k = k;
}
+void GfxCalGrayColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) {
+ GfxCMYK cmyk;
+ for (int i = 0; i < gfxColorMaxComps; i++)
+ deviceN->c[i] = 0;
+ getCMYK(color, &cmyk);
+ deviceN->c[0] = cmyk.c;
+ deviceN->c[1] = cmyk.m;
+ deviceN->c[2] = cmyk.y;
+ deviceN->c[3] = cmyk.k;
+}
+
void GfxCalGrayColorSpace::getDefaultColor(GfxColor *color) {
color->c[0] = 0;
}
@@ -907,6 +917,17 @@
cmyk->k = k;
}
+void GfxDeviceRGBColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) {
+ GfxCMYK cmyk;
+ for (int i = 0; i < gfxColorMaxComps; i++)
+ deviceN->c[i] = 0;
+ getCMYK(color, &cmyk);
+ deviceN->c[0] = cmyk.c;
+ deviceN->c[1] = cmyk.m;
+ deviceN->c[2] = cmyk.y;
+ deviceN->c[3] = cmyk.k;
+}
+
void GfxDeviceRGBColorSpace::getDefaultColor(GfxColor *color) {
color->c[0] = 0;
color->c[1] = 0;
@@ -1139,6 +1160,17 @@
cmyk->k = k;
}
+void GfxCalRGBColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) {
+ GfxCMYK cmyk;
+ for (int i = 0; i < gfxColorMaxComps; i++)
+ deviceN->c[i] = 0;
+ getCMYK(color, &cmyk);
+ deviceN->c[0] = cmyk.c;
+ deviceN->c[1] = cmyk.m;
+ deviceN->c[2] = cmyk.y;
+ deviceN->c[3] = cmyk.k;
+}
+
void GfxCalRGBColorSpace::getDefaultColor(GfxColor *color) {
color->c[0] = 0;
color->c[1] = 0;
@@ -1239,6 +1271,15 @@
cmyk->k = clip01(color->c[3]);
}
+void GfxDeviceCMYKColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) {
+ for (int i = 0; i < gfxColorMaxComps; i++)
+ deviceN->c[i] = 0;
+ deviceN->c[0] = clip01(color->c[0]);
+ deviceN->c[1] = clip01(color->c[1]);
+ deviceN->c[2] = clip01(color->c[2]);
+ deviceN->c[3] = clip01(color->c[3]);
+}
+
void GfxDeviceCMYKColorSpace::getDefaultColor(GfxColor *color) {
color->c[0] = 0;
color->c[1] = 0;
@@ -1465,6 +1506,17 @@
cmyk->k = k;
}
+void GfxLabColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) {
+ GfxCMYK cmyk;
+ for (int i = 0; i < gfxColorMaxComps; i++)
+ deviceN->c[i] = 0;
+ getCMYK(color, &cmyk);
+ deviceN->c[0] = cmyk.c;
+ deviceN->c[1] = cmyk.m;
+ deviceN->c[2] = cmyk.y;
+ deviceN->c[3] = cmyk.k;
+}
+
void GfxLabColorSpace::getDefaultColor(GfxColor *color) {
color->c[0] = 0;
if (aMin > 0) {
@@ -1870,6 +1922,17 @@
#endif
}
+void GfxICCBasedColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) {
+ GfxCMYK cmyk;
+ for (int i = 0; i < gfxColorMaxComps; i++)
+ deviceN->c[i] = 0;
+ getCMYK(color, &cmyk);
+ deviceN->c[0] = cmyk.c;
+ deviceN->c[1] = cmyk.m;
+ deviceN->c[2] = cmyk.y;
+ deviceN->c[3] = cmyk.k;
+}
+
void GfxICCBasedColorSpace::getDefaultColor(GfxColor *color) {
int i;
@@ -2089,6 +2152,12 @@
base->getCMYK(mapColorToBase(color, &color2), cmyk);
}
+void GfxIndexedColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) {
+ GfxColor color2;
+
+ base->getDeviceN(mapColorToBase(color, &color2), deviceN);
+}
+
void GfxIndexedColorSpace::getDefaultColor(GfxColor *color) {
color->c[0] = 0;
}
@@ -2119,6 +2188,8 @@
overprintMask = 0x04;
} else if (!name->cmp("Black")) {
overprintMask = 0x08;
+ } else if (!name->cmp("All")) {
+ overprintMask = 0xffffffff;
}
}
@@ -2126,23 +2197,32 @@
GfxColorSpace *altA,
Function *funcA,
GBool nonMarkingA,
- Guint overprintMaskA) {
+ Guint overprintMaskA,
+ int *mappingA) {
name = nameA;
alt = altA;
func = funcA;
nonMarking = nonMarkingA;
overprintMask = overprintMaskA;
+ mapping = mappingA;
}
GfxSeparationColorSpace::~GfxSeparationColorSpace() {
delete name;
delete alt;
delete func;
+ if (mapping != NULL)
+ gfree(mapping);
}
GfxColorSpace *GfxSeparationColorSpace::copy() {
+ int *mappingA = NULL;
+ if (mapping != NULL) {
+ mappingA = (int *) gmalloc(sizeof(int));
+ *mappingA = *mapping;
+ }
return new GfxSeparationColorSpace(name->copy(), alt->copy(), func->copy(),
- nonMarking, overprintMask);
+ nonMarking, overprintMask, mappingA);
}
//~ handle the 'All' and 'None' colorants
@@ -2235,10 +2315,75 @@
alt->getCMYK(&color2, cmyk);
}
+void GfxSeparationColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) {
+ for (int i = 0; i < gfxColorMaxComps; i++)
+ deviceN->c[i] = 0;
+ if (mapping == NULL || mapping[0] == -1) {
+ GfxCMYK cmyk;
+
+ getCMYK(color, &cmyk);
+ deviceN->c[0] = cmyk.c;
+ deviceN->c[1] = cmyk.m;
+ deviceN->c[2] = cmyk.y;
+ deviceN->c[3] = cmyk.k;
+ } else {
+ deviceN->c[mapping[0]] = color->c[0];
+ }
+}
+
void GfxSeparationColorSpace::getDefaultColor(GfxColor *color) {
color->c[0] = gfxColorComp1;
}
+void GfxSeparationColorSpace::createMapping(GooList *separationList, int maxSepComps) {
+ if (nonMarking)
+ return;
+ mapping = (int *)gmalloc(sizeof(int));
+ switch (overprintMask) {
+ case 0x01:
+ *mapping = 0;
+ break;
+ case 0x02:
+ *mapping = 1;
+ break;
+ case 0x04:
+ *mapping = 2;
+ break;
+ case 0x08:
+ *mapping = 3;
+ break;
+ default:
+ Guint newOverprintMask = 0x10;
+ for (int i = 0; i < separationList->getLength(); i++) {
+ GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)separationList->get(i);
+ if (!sepCS->getName()->cmp(name)) {
+ if (sepCS->getFunc()->hasDifferentResultSet(func)) {
+ error(errSyntaxWarning, -1,
+ "Different functions found for '{0:s}', convert immediately", name);
+ gfree(mapping);
+ mapping = NULL;
+ return;
+ }
+ *mapping = i+4;
+ overprintMask = newOverprintMask;
+ return;
+ }
+ newOverprintMask <<=1;
+ }
+ if (separationList->getLength() == maxSepComps) {
+ error(errSyntaxWarning, -1,
+ "Too many ({0:d}) spots, convert '{1:s}' immediately", maxSepComps, name);
+ gfree(mapping);
+ mapping = NULL;
+ return;
+ }
+ *mapping = separationList->getLength() + 4;
+ separationList->append(copy());
+ overprintMask = newOverprintMask;
+ break;
+ }
+}
+
//------------------------------------------------------------------------
// GfxDeviceNColorSpace
//------------------------------------------------------------------------
@@ -2246,14 +2391,17 @@
GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA,
GooString **namesA,
GfxColorSpace *altA,
- Function *funcA) {
+ Function *funcA,
+ GooList *sepsCSA) {
int i;
nComps = nCompsA;
alt = altA;
func = funcA;
+ sepsCS = sepsCSA;
nonMarking = gTrue;
overprintMask = 0;
+ mapping = NULL;
for (i = 0; i < nComps; ++i) {
names[i] = namesA[i];
if (names[i]->cmp("None")) {
@@ -2267,6 +2415,8 @@
overprintMask |= 0x04;
} else if (!names[i]->cmp("Black")) {
overprintMask |= 0x08;
+ } else if (!names[i]->cmp("All")) {
+ overprintMask = 0xffffffff;
} else {
overprintMask = 0x0f;
}
@@ -2277,6 +2427,8 @@
GooString **namesA,
GfxColorSpace *altA,
Function *funcA,
+ GooList *sepsCSA,
+ int *mappingA,
GBool nonMarkingA,
Guint overprintMaskA) {
int i;
@@ -2284,6 +2436,8 @@
nComps = nCompsA;
alt = altA;
func = funcA;
+ sepsCS = sepsCSA;
+ mapping = mappingA;
nonMarking = nonMarkingA;
overprintMask = overprintMaskA;
for (i = 0; i < nComps; ++i) {
@@ -2299,11 +2453,25 @@
}
delete alt;
delete func;
+ deleteGooList(sepsCS, GfxSeparationColorSpace);
+ if (mapping != NULL)
+ gfree(mapping);
}
GfxColorSpace *GfxDeviceNColorSpace::copy() {
+ int i;
+ int *mappingA = NULL;
+
+ GooList *sepsCSA = new GooList(sepsCS->getLength());
+ for (i = 0; i < sepsCS->getLength(); i++)
+ sepsCSA->append(((GfxSeparationColorSpace *) sepsCS->get(i))->copy());
+ if (mapping != NULL) {
+ mappingA = (int *)gmalloc(sizeof(int) * nComps);
+ for (i = 0; i < nComps; i++)
+ mappingA[i] = mapping[i];
+ }
return new GfxDeviceNColorSpace(nComps, names, alt->copy(), func->copy(),
- nonMarking, overprintMask);
+ sepsCSA, mappingA, nonMarking, overprintMask);
}
//~ handle the 'None' colorant
@@ -2315,6 +2483,7 @@
Function *funcA;
Object obj1, obj2;
int i;
+ GooList *separationList = new GooList();
if (arr->getLength() != 4 && arr->getLength() != 5) {
error(errSyntaxWarning, -1, "Bad DeviceN color space");
@@ -2351,7 +2520,26 @@
goto err4;
}
obj1.free();
- cs = new GfxDeviceNColorSpace(nCompsA, namesA, altA, funcA);
+ if (arr->getLength() == 5) {
+ if (!arr->get(4, &obj1)->isDict()) {
+ error(errSyntaxWarning, -1, "Bad DeviceN color space (attributes)");
+ goto err4;
+ }
+ Dict *attribs = obj1.getDict();
+ attribs->lookup("Colorants", &obj2);
+ if (obj2.isDict()) {
+ Dict *colorants = obj2.getDict();
+ for (i = 0; i < colorants->getLength(); i++) {
+ Object obj3;
+ colorants->getVal(i, &obj3);
+ separationList->append(GfxSeparationColorSpace::parse(obj3.getArray(), gfx, recursion));
+ obj3.free();
+ }
+ }
+ obj2.free();
+ obj1.free();
+ }
+ cs = new GfxDeviceNColorSpace(nCompsA, namesA, altA, funcA, separationList);
return cs;
err4:
@@ -2363,6 +2551,7 @@
err2:
obj1.free();
err1:
+ delete separationList;
return NULL;
}
@@ -2411,6 +2600,24 @@
alt->getCMYK(&color2, cmyk);
}
+void GfxDeviceNColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) {
+ for (int i = 0; i < gfxColorMaxComps; i++)
+ deviceN->c[i] = 0;
+ if (mapping == NULL) {
+ GfxCMYK cmyk;
+
+ getCMYK(color, &cmyk);
+ deviceN->c[0] = cmyk.c;
+ deviceN->c[1] = cmyk.m;
+ deviceN->c[2] = cmyk.y;
+ deviceN->c[3] = cmyk.k;
+ } else {
+ for (int j = 0; j < nComps; j++)
+ if (mapping[j] != -1)
+ deviceN->c[mapping[j]] = color->c[j];
+ }
+}
+
void GfxDeviceNColorSpace::getDefaultColor(GfxColor *color) {
int i;
@@ -2419,6 +2626,95 @@
}
}
+void GfxDeviceNColorSpace::createMapping(GooList *separationList, int maxSepComps) {
+ if (nonMarking) // None
+ return;
+ mapping = (int *)gmalloc(sizeof(int) * nComps);
+ Guint newOverprintMask = 0;
+ for (int i = 0; i < nComps; i++) {
+ if (!names[i]->cmp("None")) {
+ mapping[i] = -1;
+ } else if (!names[i]->cmp("Cyan")) {
+ newOverprintMask |= 0x01;
+ mapping[i] = 0;
+ } else if (!names[i]->cmp("Magenta")) {
+ newOverprintMask |= 0x02;
+ mapping[i] = 1;
+ } else if (!names[i]->cmp("Yellow")) {
+ newOverprintMask |= 0x04;
+ mapping[i] = 2;
+ } else if (!names[i]->cmp("Black")) {
+ newOverprintMask |= 0x08;
+ mapping[i] = 3;
+ } else {
+ Guint startOverprintMask = 0x10;
+ GBool found = gFalse;
+ Function *sepFunc = NULL;
+ if (nComps == 1)
+ sepFunc = func;
+ else {
+ for (int k = 0; k < sepsCS->getLength(); k++) {
+ GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)sepsCS->get(k);
+ if (!sepCS->getName()->cmp(names[i])) {
+ sepFunc = sepCS->getFunc();
+ break;
+ }
+ }
+ }
+ for (int j = 0; j < separationList->getLength(); j++) {
+ GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)separationList->get(j);
+ if (!sepCS->getName()->cmp(names[i])) {
+ if (sepFunc != NULL && sepCS->getFunc()->hasDifferentResultSet(sepFunc)) {
+ error(errSyntaxWarning, -1,
+ "Different functions found for '{0:s}', convert immediately", names[i]);
+ gfree(mapping);
+ mapping = NULL;
+ overprintMask = 0xffffffff;
+ return;
+ }
+ mapping[i] = j+4;
+ newOverprintMask |= startOverprintMask;
+ found = gTrue;
+ break;
+ }
+ startOverprintMask <<=1;
+ }
+ if (!found) {
+ if (separationList->getLength() == maxSepComps) {
+ error(errSyntaxWarning, -1,
+ "Too many ({0:d}) spots, convert '{1:s}' immediately", maxSepComps, names[i]);
+ gfree(mapping);
+ mapping = NULL;
+ overprintMask = 0xffffffff;
+ return;
+ }
+ mapping[i] = separationList->getLength() + 4;
+ newOverprintMask |= startOverprintMask;
+ if (nComps == 1)
+ separationList->append(new GfxSeparationColorSpace(names[i]->copy(),alt->copy(), func->copy()));
+ else {
+ for (int k = 0; k < sepsCS->getLength(); k++) {
+ GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)sepsCS->get(k);
+ if (!sepCS->getName()->cmp(names[i])) {
+ found = gTrue;
+ separationList->append(sepCS->copy());
+ break;
+ }
+ }
+ if(!found) {
+ error(errSyntaxWarning, -1, "DeviceN has no suitable colorant");
+ gfree(mapping);
+ mapping = NULL;
+ overprintMask = 0xffffffff;
+ return;
+ }
+ }
+ }
+ }
+ }
+ overprintMask = newOverprintMask;
+}
+
//------------------------------------------------------------------------
// GfxPatternColorSpace
//------------------------------------------------------------------------
@@ -2474,6 +2770,12 @@
cmyk->k = 1;
}
+void GfxPatternColorSpace::getDeviceN(GfxColor *color, GfxColor *deviceN) {
+ for (int i = 0; i < gfxColorMaxComps; i++)
+ deviceN->c[i] = 0;
+ deviceN->c[3] = 1;
+}
+
void GfxPatternColorSpace::getDefaultColor(GfxColor *color) {
color->c[0]=0;
}
@@ -5305,6 +5607,23 @@
}
}
+void GfxImageColorMap::getDeviceN(Guchar *x, GfxColor *deviceN) {
+ GfxColor color;
+ int i;
+
+ if (colorSpace2) {
+ for (i = 0; i < nComps2; ++i) {
+ color.c[i] = lookup2[i][x[0]];
+ }
+ colorSpace2->getDeviceN(&color, deviceN);
+ } else {
+ for (i = 0; i < nComps; ++i) {
+ color.c[i] = lookup[i][x[i]];
+ }
+ colorSpace->getDeviceN(&color, deviceN);
+ }
+}
+
void GfxImageColorMap::getColor(Guchar *x, GfxColor *color) {
int maxPixel, i;
diff --git a/poppler/GfxState.h b/poppler/GfxState.h
index 856ec3f..f2ce6b2 100644
--- a/poppler/GfxState.h
+++ b/poppler/GfxState.h
@@ -20,7 +20,7 @@
// Copyright (C) 2009-2011 Albert Astals Cid <aacid@kde.org>
// Copyright (C) 2010 Christian Feuersänger <cfeuersaenger@googlemail.com>
// Copyright (C) 2011 Andrea Canciani <ranma42@gmail.com>
-// Copyright (C) 2011 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2011, 2012 Thomas Freitag <Thomas.Freitag@alfa.de>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
@@ -48,6 +48,7 @@
class PDFRectangle;
class GfxShading;
class PopplerCache;
+class GooList;
class Matrix {
public:
@@ -202,11 +203,15 @@
virtual void getGray(GfxColor *color, GfxGray *gray) = 0;
virtual void getRGB(GfxColor *color, GfxRGB *rgb) = 0;
virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk) = 0;
+ virtual void getDeviceN(GfxColor *color, GfxColor *deviceN) = 0;
virtual void getGrayLine(Guchar * /*in*/, Guchar * /*out*/, int /*length*/) { error(errInternal, -1, "GfxColorSpace::getGrayLine this should not happen"); }
virtual void getRGBLine(Guchar * /*in*/, unsigned int * /*out*/, int /*length*/) { error(errInternal, -1, "GfxColorSpace::getRGBLine (first variant) this should not happen"); }
virtual void getRGBLine(Guchar * /*in*/, Guchar * /*out*/, int /*length*/) { error(errInternal, -1, "GfxColorSpace::getRGBLine (second variant) this should not happen"); }
virtual void getRGBXLine(Guchar * /*in*/, Guchar * /*out*/, int /*length*/) { error(errInternal, -1, "GfxColorSpace::getRGBXLine this should not happen"); }
+ // create mapping for spot colorants
+ virtual void createMapping(GooList *separationList, int maxSepComps);
+
// Does this ColorSpace support getRGBLine?
virtual GBool useGetRGBLine() { return gFalse; }
// Does this ColorSpace support getGrayLine?
@@ -249,6 +254,7 @@
protected:
Guint overprintMask;
+ int *mapping;
};
//------------------------------------------------------------------------
@@ -266,6 +272,7 @@
virtual void getGray(GfxColor *color, GfxGray *gray);
virtual void getRGB(GfxColor *color, GfxRGB *rgb);
virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+ virtual void getDeviceN(GfxColor *color, GfxColor *deviceN);
virtual void getGrayLine(Guchar *in, Guchar *out, int length);
virtual void getRGBLine(Guchar *in, unsigned int *out, int length);
virtual void getRGBLine(Guchar *in, Guchar *out, int length);
@@ -298,6 +305,7 @@
virtual void getGray(GfxColor *color, GfxGray *gray);
virtual void getRGB(GfxColor *color, GfxRGB *rgb);
virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+ virtual void getDeviceN(GfxColor *color, GfxColor *deviceN);
virtual int getNComps() { return 1; }
virtual void getDefaultColor(GfxColor *color);
@@ -335,6 +343,7 @@
virtual void getGray(GfxColor *color, GfxGray *gray);
virtual void getRGB(GfxColor *color, GfxRGB *rgb);
virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+ virtual void getDeviceN(GfxColor *color, GfxColor *deviceN);
virtual void getGrayLine(Guchar *in, Guchar *out, int length);
virtual void getRGBLine(Guchar *in, unsigned int *out, int length);
virtual void getRGBLine(Guchar *in, Guchar *out, int length);
@@ -367,6 +376,7 @@
virtual void getGray(GfxColor *color, GfxGray *gray);
virtual void getRGB(GfxColor *color, GfxRGB *rgb);
virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+ virtual void getDeviceN(GfxColor *color, GfxColor *deviceN);
virtual int getNComps() { return 3; }
virtual void getDefaultColor(GfxColor *color);
@@ -408,6 +418,7 @@
virtual void getGray(GfxColor *color, GfxGray *gray);
virtual void getRGB(GfxColor *color, GfxRGB *rgb);
virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+ virtual void getDeviceN(GfxColor *color, GfxColor *deviceN);
virtual void getRGBLine(Guchar *in, unsigned int *out, int length);
virtual void getRGBLine(Guchar *, Guchar *out, int length);
virtual void getRGBXLine(Guchar *in, Guchar *out, int length);
@@ -437,6 +448,7 @@
virtual void getGray(GfxColor *color, GfxGray *gray);
virtual void getRGB(GfxColor *color, GfxRGB *rgb);
virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+ virtual void getDeviceN(GfxColor *color, GfxColor *deviceN);
virtual int getNComps() { return 3; }
virtual void getDefaultColor(GfxColor *color);
@@ -484,6 +496,7 @@
virtual void getGray(GfxColor *color, GfxGray *gray);
virtual void getRGB(GfxColor *color, GfxRGB *rgb);
virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+ virtual void getDeviceN(GfxColor *color, GfxColor *deviceN);
virtual void getRGBLine(Guchar *in, unsigned int *out, int length);
virtual void getRGBLine(Guchar *in, Guchar *out, int length);
virtual void getRGBXLine(Guchar *in, Guchar *out, int length);
@@ -529,6 +542,7 @@
virtual void getGray(GfxColor *color, GfxGray *gray);
virtual void getRGB(GfxColor *color, GfxRGB *rgb);
virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+ virtual void getDeviceN(GfxColor *color, GfxColor *deviceN);
virtual void getRGBLine(Guchar *in, unsigned int *out, int length);
virtual void getRGBLine(Guchar *in, Guchar *out, int length);
virtual void getRGBXLine(Guchar *in, Guchar *out, int length);
@@ -546,6 +560,10 @@
int getIndexHigh() { return indexHigh; }
Guchar *getLookup() { return lookup; }
GfxColor *mapColorToBase(GfxColor *color, GfxColor *baseColor);
+ Guint getOverprintMask() { return base->getOverprintMask(); }
+ virtual void createMapping(GooList *separationList, int maxSepComps)
+ { base->createMapping(separationList, maxSepComps); }
+
private:
@@ -573,6 +591,9 @@
virtual void getGray(GfxColor *color, GfxGray *gray);
virtual void getRGB(GfxColor *color, GfxRGB *rgb);
virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+ virtual void getDeviceN(GfxColor *color, GfxColor *deviceN);
+
+ virtual void createMapping(GooList *separationList, int maxSepComps);
virtual int getNComps() { return 1; }
virtual void getDefaultColor(GfxColor *color);
@@ -588,7 +609,7 @@
GfxSeparationColorSpace(GooString *nameA, GfxColorSpace *altA,
Function *funcA, GBool nonMarkingA,
- Guint overprintMaskA);
+ Guint overprintMaskA, int *mappingA);
GooString *name; // colorant name
GfxColorSpace *alt; // alternate color space
@@ -604,7 +625,7 @@
public:
GfxDeviceNColorSpace(int nCompsA, GooString **namesA,
- GfxColorSpace *alt, Function *func);
+ GfxColorSpace *alt, Function *func, GooList *sepsCS);
virtual ~GfxDeviceNColorSpace();
virtual GfxColorSpace *copy();
virtual GfxColorSpaceMode getMode() { return csDeviceN; }
@@ -615,6 +636,9 @@
virtual void getGray(GfxColor *color, GfxGray *gray);
virtual void getRGB(GfxColor *color, GfxRGB *rgb);
virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+ virtual void getDeviceN(GfxColor *color, GfxColor *deviceN);
+
+ virtual void createMapping(GooList *separationList, int maxSepComps);
virtual int getNComps() { return nComps; }
virtual void getDefaultColor(GfxColor *color);
@@ -629,8 +653,8 @@
private:
GfxDeviceNColorSpace(int nCompsA, GooString **namesA,
- GfxColorSpace *alt, Function *func,
- GBool nonMarkingA, Guint overprintMaskA);
+ GfxColorSpace *alt, Function *func, GooList *sepsCSA,
+ int *mappingA, GBool nonMarkingA, Guint overprintMaskA);
int nComps; // number of components
GooString // colorant names
@@ -638,6 +662,7 @@
GfxColorSpace *alt; // alternate color space
Function *func; // tint transform (into alternate color space)
GBool nonMarking;
+ GooList *sepsCS; // list of separation cs for spot colorants;
};
//------------------------------------------------------------------------
@@ -658,6 +683,7 @@
virtual void getGray(GfxColor *color, GfxGray *gray);
virtual void getRGB(GfxColor *color, GfxRGB *rgb);
virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+ virtual void getDeviceN(GfxColor *color, GfxColor *deviceN);
virtual int getNComps() { return 0; }
virtual void getDefaultColor(GfxColor *color);
@@ -1107,6 +1133,7 @@
void getRGBXLine(Guchar *in, Guchar *out, int length);
void getGrayLine(Guchar *in, Guchar *out, int length);
void getCMYK(Guchar *x, GfxCMYK *cmyk);
+ void getDeviceN(Guchar *x, GfxColor *deviceN);
void getColor(Guchar *x, GfxColor *color);
private:
@@ -1342,8 +1369,12 @@
{ strokeColorSpace->getRGB(&strokeColor, rgb); }
void getFillCMYK(GfxCMYK *cmyk)
{ fillColorSpace->getCMYK(&fillColor, cmyk); }
+ void getFillDeviceN(GfxColor *deviceN)
+ { fillColorSpace->getDeviceN(&fillColor, deviceN); }
void getStrokeCMYK(GfxCMYK *cmyk)
{ strokeColorSpace->getCMYK(&strokeColor, cmyk); }
+ void getStrokeDeviceN(GfxColor *deviceN)
+ { strokeColorSpace->getDeviceN(&strokeColor, deviceN); }
GfxColorSpace *getFillColorSpace() { return fillColorSpace; }
GfxColorSpace *getStrokeColorSpace() { return strokeColorSpace; }
GfxPattern *getFillPattern() { return fillPattern; }
diff --git a/poppler/GlobalParams.cc b/poppler/GlobalParams.cc
index 76394ca..098e4a4 100644
--- a/poppler/GlobalParams.cc
+++ b/poppler/GlobalParams.cc
@@ -439,7 +439,7 @@
void *dlA;
#endif
- path = globalParams->getBaseDir();
+ path = new GooString(POPPLER_DATADIR);
appendToPath(path, "plugins");
appendToPath(path, type);
appendToPath(path, name);
@@ -574,11 +574,7 @@
}
#ifdef _WIN32
- // baseDir will be set by a call to setBaseDir
- baseDir = new GooString();
substFiles = new GooHash(gTrue);
-#else
- baseDir = appendToPath(getHomeDir(), ".xpdf");
#endif
nameToUnicode = new NameToCharCode();
cidToUnicodes = new GooHash(gTrue);
@@ -800,7 +796,6 @@
delete macRomanReverseMap;
- delete baseDir;
delete nameToUnicode;
deleteGooHash(cidToUnicodes, GooString);
deleteGooHash(unicodeToUnicodes, GooString);
@@ -850,13 +845,6 @@
}
//------------------------------------------------------------------------
-
-void GlobalParams::setBaseDir(const char *dir) {
- delete baseDir;
- baseDir = new GooString(dir);
-}
-
-//------------------------------------------------------------------------
// accessors
//------------------------------------------------------------------------
@@ -865,15 +853,6 @@
return macRomanReverseMap->lookup(charName);
}
-GooString *GlobalParams::getBaseDir() {
- GooString *s;
-
- lockGlobalParams;
- s = baseDir->copy();
- unlockGlobalParams;
- return s;
-}
-
Unicode GlobalParams::mapNameToUnicode(const char *charName) {
// no need to lock - nameToUnicode is constant
return nameToUnicode->lookup(charName);
diff --git a/poppler/GlobalParams.h b/poppler/GlobalParams.h
index 375ac2c..bc11684 100644
--- a/poppler/GlobalParams.h
+++ b/poppler/GlobalParams.h
@@ -13,7 +13,7 @@
// All changes made under the Poppler project to this file are licensed
// under GPL version 2 or later
//
-// Copyright (C) 2005, 2007-2010 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2005, 2007-2010, 2012 Albert Astals Cid <aacid@kde.org>
// Copyright (C) 2005 Jonathan Blandford <jrb@redhat.com>
// Copyright (C) 2006 Takashi Iwai <tiwai@suse.de>
// Copyright (C) 2006 Kristian Høgsberg <krh@redhat.com>
@@ -133,14 +133,12 @@
~GlobalParams();
- void setBaseDir(const char *dir);
void setupBaseFonts(char *dir);
//----- accessors
CharCode getMacRomanCharCode(char *charName);
- GooString *getBaseDir();
Unicode mapNameToUnicode(const char *charName);
UnicodeMap *getResidentUnicodeMap(GooString *encodingName);
FILE *getUnicodeMapFile(GooString *encodingName);
@@ -273,7 +271,6 @@
//----- user-modifiable settings
- GooString *baseDir; // base directory - for plugins, etc.
NameToCharCode * // mapping from char name to Unicode
nameToUnicode;
GooHash *cidToUnicodes; // files for mappings from char collections
diff --git a/poppler/Link.cc b/poppler/Link.cc
index b90b1c1..b5b2bd3 100644
--- a/poppler/Link.cc
+++ b/poppler/Link.cc
@@ -19,6 +19,7 @@
// Copyright (C) 2008-2010, 2012 Albert Astals Cid <aacid@kde.org>
// Copyright (C) 2009 Kovid Goyal <kovid@kovidgoyal.net>
// Copyright (C) 2009 Ilya Gorenbein <igorenbein@finjan.com>
+// Copyright (C) 2012 Tobias Koening <tobias.koenig@kdab.com>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
@@ -700,9 +701,10 @@
//------------------------------------------------------------------------
LinkRendition::LinkRendition(Object *obj) {
- operation = -1;
+ operation = NoRendition;
media = NULL;
js = NULL;
+ int operationCode = -1;
if (obj->isDict()) {
Object tmp;
@@ -721,25 +723,43 @@
tmp.free();
if (obj->dictLookup("OP", &tmp)->isInt()) {
- operation = tmp.getInt();
- if (!js && (operation < 0 || operation > 4)) {
- error(errSyntaxWarning, -1, "Invalid Rendition Action: unrecognized operation valued: {0:d}", operation);
+ operationCode = tmp.getInt();
+ if (!js && (operationCode < 0 || operationCode > 4)) {
+ error(errSyntaxWarning, -1, "Invalid Rendition Action: unrecognized operation valued: {0:d}", operationCode);
} else {
Object obj1;
// retrieve rendition object
if (obj->dictLookup("R", &renditionObj)->isDict()) {
media = new MediaRendition(&renditionObj);
- } else if (operation == 0 || operation == 4) {
- error(errSyntaxWarning, -1, "Invalid Rendition Action: no R field with op = {0:d}", operation);
+ } else if (operationCode == 0 || operationCode == 4) {
+ error(errSyntaxWarning, -1, "Invalid Rendition Action: no R field with op = {0:d}", operationCode);
renditionObj.free();
}
if (!obj->dictLookupNF("AN", &screenRef)->isRef() && operation >= 0 && operation <= 4) {
- error(errSyntaxWarning, -1, "Invalid Rendition Action: no AN field with op = {0:d}", operation);
+ error(errSyntaxWarning, -1, "Invalid Rendition Action: no AN field with op = {0:d}", operationCode);
screenRef.free();
}
}
+
+ switch (operationCode) {
+ case 0:
+ operation = PlayRendition;
+ break;
+ case 1:
+ operation = StopRendition;
+ break;
+ case 2:
+ operation = PauseRendition;
+ break;
+ case 3:
+ operation = ResumeRendition;
+ break;
+ case 4:
+ operation = PlayRendition;
+ break;
+ }
} else if (!js) {
error(errSyntaxWarning, -1, "Invalid Rendition action: no OP or JS field defined");
}
diff --git a/poppler/Link.h b/poppler/Link.h
index 8e2df24..fc2abe6 100644
--- a/poppler/Link.h
+++ b/poppler/Link.h
@@ -16,6 +16,7 @@
// Copyright (C) 2006, 2008 Pino Toscano <pino@kde.org>
// Copyright (C) 2008 Hugo Mercier <hmercier31@gmail.com>
// Copyright (C) 2010, 2011 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright (C) 2012 Tobias Koening <tobias.koenig@kdab.com>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
@@ -51,7 +52,7 @@
actionURI, // URI
actionNamed, // named action
actionMovie, // movie action
- actionRendition,
+ actionRendition, // rendition action
actionSound, // sound action
actionJavaScript, // JavaScript action
actionOCGState, // Set-OCG-State action
@@ -319,6 +320,16 @@
class LinkRendition: public LinkAction {
public:
+ /**
+ * Describes the possible rendition operations.
+ */
+ enum RenditionOperation {
+ NoRendition,
+ PlayRendition,
+ StopRendition,
+ PauseRendition,
+ ResumeRendition
+ };
LinkRendition(Object *Obj);
@@ -334,7 +345,7 @@
GBool hasScreenAnnot() { return screenRef.isRef(); }
Ref getScreenAnnot() { return screenRef.getRef(); }
- int getOperation() { return operation; }
+ RenditionOperation getOperation() { return operation; }
MediaRendition* getMedia() { return media; }
@@ -344,7 +355,7 @@
Object screenRef;
Object renditionObj;
- int operation;
+ RenditionOperation operation;
MediaRendition* media;
diff --git a/poppler/Makefile.am b/poppler/Makefile.am
index c2e81d9..e10d19d 100644
--- a/poppler/Makefile.am
+++ b/poppler/Makefile.am
@@ -177,7 +177,7 @@
$(PTHREAD_LIBS) \
$(win32_libs)
-libpoppler_la_LDFLAGS = -version-info 28:0:0 @create_shared_lib@ @auto_import_flags@
+libpoppler_la_LDFLAGS = -version-info 29:0:0 @create_shared_lib@ @auto_import_flags@
if ENABLE_XPDF_HEADERS
@@ -251,6 +251,7 @@
PSOutputDev.h \
TextOutputDev.h \
SecurityHandler.h \
+ UTF.h \
UTF8.h \
XpdfPluginAPI.h \
Sound.h
@@ -317,6 +318,7 @@
strtok_r.cpp \
UnicodeMap.cc \
UnicodeTypeTable.cc \
+ UTF.cc \
ViewerPreferences.cc \
XRef.cc \
PSOutputDev.cc \
diff --git a/poppler/PDFDoc.cc b/poppler/PDFDoc.cc
index ce01ca3..f52d498 100644
--- a/poppler/PDFDoc.cc
+++ b/poppler/PDFDoc.cc
@@ -610,6 +610,15 @@
OutStream *outStr;
XRef *yRef, *countRef;
int rootNum = getXRef()->getNumObjects() + 1;
+
+ // Make sure that special flags are set, because we are going to read
+ // all objects, including Unencrypted ones.
+ xref->scanSpecialFlags();
+
+ Guchar *fileKey;
+ CryptAlgorithm encAlgorithm;
+ int keyLength;
+ xref->getEncryptionParameters(&fileKey, &encAlgorithm, &keyLength);
if (pageNo < 1 || pageNo > getNumPages()) {
error(errInternal, -1, "Illegal pageNo: {0:d}({1:d})", pageNo, getNumPages() );
@@ -634,7 +643,18 @@
outStr = new FileOutStream(f,0);
yRef = new XRef(getXRef()->getTrailerDict());
+ Object encrypt;
+ getXRef()->getTrailerDict()->dictLookup("Encrypt", &encrypt);
+
+ if (secHdlr != NULL && !secHdlr->isUnencrypted()) {
+ yRef->setEncryption(secHdlr->getPermissionFlags(),
+ secHdlr->getOwnerPasswordOk(), fileKey, keyLength, secHdlr->getEncVersion(), secHdlr->getEncRevision(), encAlgorithm);
+ }
countRef = new XRef();
+ Object *trailerObj = getXRef()->getTrailerDict();
+ if (trailerObj->isDict()) {
+ markPageObjects(trailerObj->getDict(), yRef, countRef, 0);
+ }
yRef->add(0, 65535, 0, gFalse);
writeHeader(outStr, getPDFMajorVersion(), getPDFMinorVersion());
@@ -644,7 +664,6 @@
if (infoObj.isDict()) {
Dict *infoDict = infoObj.getDict();
markPageObjects(infoDict, yRef, countRef, 0);
- Object *trailerObj = getXRef()->getTrailerDict();
if (trailerObj->isDict()) {
Dict *trailerDict = trailerObj->getDict();
Object ref;
@@ -673,6 +692,7 @@
Dict *pageDict = page.getDict();
markPageObjects(pageDict, yRef, countRef, 0);
+ yRef->markUnencrypted();
Guint objectsCount = writePageObjects(outStr, yRef, 0);
yRef->add(rootNum,0,outStr->getPos(),gTrue);
@@ -687,7 +707,7 @@
if (j > 0) outStr->printf(" ");
Object value; catDict->getValNF(j, &value);
outStr->printf("/%s ", key);
- writeObject(&value, NULL, outStr, getXRef(), 0);
+ writeObject(&value, outStr, getXRef(), 0, NULL, cryptRC4, 0, 0, 0);
value.free();
}
}
@@ -701,7 +721,7 @@
outStr->printf("<< /Type /Pages /Kids [ %d 0 R ] /Count 1 ", rootNum + 2);
if (resourcesObj.isDict()) {
outStr->printf("/Resources ");
- writeObject(&resourcesObj, NULL, outStr, getXRef(), 0);
+ writeObject(&resourcesObj, outStr, getXRef(), 0, NULL, cryptRC4, 0, 0, 0);
resourcesObj.free();
}
outStr->printf(">>\n");
@@ -719,7 +739,7 @@
outStr->printf("/Parent %d 0 R", rootNum + 1);
} else {
outStr->printf("/%s ", key);
- writeObject(&value, NULL, outStr, getXRef(), 0);
+ writeObject(&value, outStr, getXRef(), 0, NULL, cryptRC4, 0, 0, 0);
}
value.free();
}
@@ -766,41 +786,19 @@
// find if we have updated objects
GBool updated = gFalse;
for(int i=0; i<xref->getNumObjects(); i++) {
- if (xref->getEntry(i)->updated) {
+ if (xref->getEntry(i)->getFlag(XRefEntry::Updated)) {
updated = gTrue;
break;
}
}
- // we don't support rewriting files with Encrypt at the moment
- Object obj;
- xref->getTrailerDict()->getDict()->lookupNF("Encrypt", &obj);
- if (!obj.isNull())
- {
- obj.free();
- if (!updated && mode == writeStandard) {
- // simply copy the original file
- saveWithoutChangesAs (outStr);
- } else {
- return errEncrypted;
- }
- }
- else
- {
- obj.free();
-
- if (mode == writeForceRewrite) {
- saveCompleteRewrite(outStr);
- } else if (mode == writeForceIncremental) {
- saveIncrementalUpdate(outStr);
- } else { // let poppler decide
- if(updated) {
- saveIncrementalUpdate(outStr);
- } else {
- // simply copy the original file
- saveWithoutChangesAs (outStr);
- }
- }
+ if (!updated && mode == writeStandard) {
+ // simply copy the original file
+ saveWithoutChangesAs (outStr);
+ } if (mode == writeForceRewrite) {
+ saveCompleteRewrite(outStr);
+ } else {
+ saveIncrementalUpdate(outStr);
}
return errNone;
@@ -848,6 +846,11 @@
}
str->close();
+ Guchar *fileKey;
+ CryptAlgorithm encAlgorithm;
+ int keyLength;
+ xref->getEncryptionParameters(&fileKey, &encAlgorithm, &keyLength);
+
uxref = new XRef();
uxref->add(0, 65535, 0, gFalse);
for(int i=0; i<xref->getNumObjects(); i++) {
@@ -855,14 +858,16 @@
(xref->getEntry(i)->gen == 0)) //we skip the irrelevant free objects
continue;
- if (xref->getEntry(i)->updated) { //we have an updated object
+ if (xref->getEntry(i)->getFlag(XRefEntry::Updated)) { //we have an updated object
Ref ref;
ref.num = i;
ref.gen = xref->getEntry(i)->type == xrefEntryCompressed ? 0 : xref->getEntry(i)->gen;
if (xref->getEntry(i)->type != xrefEntryFree) {
Object obj1;
xref->fetch(ref.num, ref.gen, &obj1);
- Guint offset = writeObject(&obj1, &ref, outStr);
+ Guint offset = writeObjectHeader(&ref, outStr);
+ writeObject(&obj1, outStr, fileKey, encAlgorithm, keyLength, ref.num, ref.gen);
+ writeObjectFooter(outStr);
uxref->add(ref.num, ref.gen, offset, gTrue);
obj1.free();
} else {
@@ -905,6 +910,15 @@
void PDFDoc::saveCompleteRewrite (OutStream* outStr)
{
+ // Make sure that special flags are set, because we are going to read
+ // all objects, including Unencrypted ones.
+ xref->scanSpecialFlags();
+
+ Guchar *fileKey;
+ CryptAlgorithm encAlgorithm;
+ int keyLength;
+ xref->getEncryptionParameters(&fileKey, &encAlgorithm, &keyLength);
+
outStr->printf("%%PDF-%d.%d\r\n",pdfMajorVersion,pdfMinorVersion);
XRef *uxref = new XRef();
uxref->add(0, 65535, 0, gFalse);
@@ -919,18 +933,32 @@
and we don't want the one with num=0 because it has already been added (gen = 65535)*/
if (ref.gen > 0 && ref.num > 0)
uxref->add(ref.num, ref.gen, 0, gFalse);
+ } else if (xref->getEntry(i)->getFlag(XRefEntry::DontRewrite)) {
+ // This entry must not be written, put a free entry instead (with incremented gen)
+ ref.num = i;
+ ref.gen = xref->getEntry(i)->gen + 1;
+ uxref->add(ref.num, ref.gen, 0, gFalse);
} else if (type == xrefEntryUncompressed){
ref.num = i;
ref.gen = xref->getEntry(i)->gen;
xref->fetch(ref.num, ref.gen, &obj1);
- Guint offset = writeObject(&obj1, &ref, outStr);
+ Guint offset = writeObjectHeader(&ref, outStr);
+ // Write unencrypted objects in unencrypted form
+ if (xref->getEntry(i)->getFlag(XRefEntry::Unencrypted)) {
+ writeObject(&obj1, outStr, NULL, cryptRC4, 0, 0, 0);
+ } else {
+ writeObject(&obj1, outStr, fileKey, encAlgorithm, keyLength, ref.num, ref.gen);
+ }
+ writeObjectFooter(outStr);
uxref->add(ref.num, ref.gen, offset, gTrue);
obj1.free();
} else if (type == xrefEntryCompressed) {
ref.num = i;
ref.gen = 0; //compressed entries have gen == 0
xref->fetch(ref.num, ref.gen, &obj1);
- Guint offset = writeObject(&obj1, &ref, outStr);
+ Guint offset = writeObjectHeader(&ref, outStr);
+ writeObject(&obj1, outStr, fileKey, encAlgorithm, keyLength, ref.num, ref.gen);
+ writeObjectFooter(outStr);
uxref->add(ref.num, ref.gen, offset, gTrue);
obj1.free();
}
@@ -941,7 +969,8 @@
delete uxref;
}
-void PDFDoc::writeDictionnary (Dict* dict, OutStream* outStr, XRef *xRef, Guint numOffset)
+void PDFDoc::writeDictionnary (Dict* dict, OutStream* outStr, XRef *xRef, Guint numOffset, Guchar *fileKey,
+ CryptAlgorithm encAlgorithm, int keyLength, int objNum, int objGen)
{
Object obj1;
outStr->printf("<<");
@@ -950,7 +979,7 @@
GooString *keyNameToPrint = keyName.sanitizedName(gFalse /* non ps mode */);
outStr->printf("/%s ", keyNameToPrint->getCString());
delete keyNameToPrint;
- writeObject(dict->getValNF(i, &obj1), NULL, outStr, xRef, numOffset);
+ writeObject(dict->getValNF(i, &obj1), outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen);
obj1.free();
}
outStr->printf(">> ");
@@ -988,8 +1017,27 @@
outStr->printf("\r\nendstream\r\n");
}
-void PDFDoc::writeString (GooString* s, OutStream* outStr)
+void PDFDoc::writeString (GooString* s, OutStream* outStr, Guchar *fileKey,
+ CryptAlgorithm encAlgorithm, int keyLength, int objNum, int objGen)
{
+ // Encrypt string if encryption is enabled
+ GooString *sEnc = NULL;
+ if (fileKey) {
+ Object obj;
+ EncryptStream *enc = new EncryptStream(new MemStream(s->getCString(), 0, s->getLength(), obj.initNull()),
+ fileKey, encAlgorithm, keyLength, objNum, objGen);
+ sEnc = new GooString();
+ int c;
+ enc->reset();
+ while ((c = enc->getChar()) != EOF) {
+ sEnc->append((char)c);
+ }
+
+ delete enc;
+ s = sEnc;
+ }
+
+ // Write data
if (s->hasUnicodeMarker()) {
//unicode string don't necessary end with \0
const char* c = s->getCString();
@@ -1021,18 +1069,24 @@
}
outStr->printf(") ");
}
+
+ delete sEnc;
}
-Guint PDFDoc::writeObject (Object* obj, Ref* ref, OutStream* outStr, XRef *xRef, Guint numOffset)
+Guint PDFDoc::writeObjectHeader (Ref *ref, OutStream* outStr)
+{
+ Guint offset = outStr->getPos();
+ outStr->printf("%i %i obj ", ref->num, ref->gen);
+ return offset;
+}
+
+void PDFDoc::writeObject (Object* obj, OutStream* outStr, XRef *xRef, Guint numOffset, Guchar *fileKey,
+ CryptAlgorithm encAlgorithm, int keyLength, int objNum, int objGen)
{
Array *array;
Object obj1;
- Guint offset = outStr->getPos();
int tmp;
- if(ref)
- outStr->printf("%i %i obj ", ref->num, ref->gen);
-
switch (obj->getType()) {
case objBool:
outStr->printf("%s ", obj->getBool()?"true":"false");
@@ -1040,6 +1094,9 @@
case objInt:
outStr->printf("%i ", obj->getInt());
break;
+ case objUint:
+ outStr->printf("%u ", obj->getUint());
+ break;
case objReal:
{
GooString s;
@@ -1048,7 +1105,7 @@
break;
}
case objString:
- writeString(obj->getString(), outStr);
+ writeString(obj->getString(), outStr, fileKey, encAlgorithm, keyLength, objNum, objGen);
break;
case objName:
{
@@ -1065,13 +1122,13 @@
array = obj->getArray();
outStr->printf("[");
for (int i=0; i<array->getLength(); i++) {
- writeObject(array->getNF(i, &obj1), NULL,outStr, xRef, numOffset);
+ writeObject(array->getNF(i, &obj1), outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen);
obj1.free();
}
outStr->printf("] ");
break;
case objDict:
- writeDictionnary (obj->getDict(),outStr, xRef, numOffset);
+ writeDictionnary (obj->getDict(), outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen);
break;
case objStream:
{
@@ -1080,6 +1137,15 @@
Stream *stream = obj->getStream();
if (stream->getKind() == strWeird) {
//we write the stream unencoded => TODO: write stream encoder
+
+ // Encrypt stream
+ EncryptStream *encStream = NULL;
+ if (fileKey) {
+ encStream = new EncryptStream(stream, fileKey, encAlgorithm, keyLength, objNum, objGen);
+ encStream->setAutoDelete(gFalse);
+ stream = encStream;
+ }
+
stream->reset();
//recalculate stream length
tmp = 0;
@@ -1093,8 +1159,9 @@
stream->getDict()->remove("Filter");
stream->getDict()->remove("DecodeParms");
- writeDictionnary (stream->getDict(),outStr, xRef, numOffset);
+ writeDictionnary (stream->getDict(),outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen);
writeStream (stream,outStr);
+ delete encStream;
obj1.free();
} else {
//raw stream copy
@@ -1110,7 +1177,7 @@
}
}
}
- writeDictionnary (stream->getDict(), outStr, xRef, numOffset);
+ writeDictionnary (stream->getDict(), outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen);
writeRawStream (stream, outStr);
}
break;
@@ -1134,9 +1201,11 @@
error(errUnimplemented, -1,"Unhandled objType : {0:d}, please report a bug with a testcase\r\n", obj->getType());
break;
}
- if (ref)
- outStr->printf("endobj\r\n");
- return offset;
+}
+
+void PDFDoc::writeObjectFooter (OutStream* outStr)
+{
+ outStr->printf("endobj\r\n");
}
Dict *PDFDoc::createTrailerDict(int uxrefSize, GBool incrUpdate, Guint startxRef,
@@ -1177,6 +1246,17 @@
}
obj1.free();
+ GBool hasEncrypt = gFalse;
+ if (!xRef->getTrailerDict()->isNone()) {
+ Object obj2;
+ xRef->getTrailerDict()->dictLookupNF("Encrypt", &obj2);
+ if (!obj2.isNull()) {
+ trailerDict->set("Encrypt", &obj2);
+ hasEncrypt = gTrue;
+ obj2.free();
+ }
+ }
+
//calculate md5 digest
Guchar digest[16];
md5((Guchar*)message.getCString(), message.getLength(), digest);
@@ -1186,7 +1266,8 @@
Object obj2,obj3,obj5;
obj2.initArray(xRef);
- if (incrUpdate) {
+ // In case of encrypted files, the ID must not be changed because it's used to calculate the key
+ if (incrUpdate || hasEncrypt) {
Object obj4;
//only update the second part of the array
xRef->getTrailerDict()->getDict()->lookup("ID", &obj4);
@@ -1231,7 +1312,7 @@
{
uxref->writeTableToFile( outStr, writeAllEntries );
outStr->printf( "trailer\r\n");
- writeDictionnary(trailerDict, outStr, xRef, 0);
+ writeDictionnary(trailerDict, outStr, xRef, 0, NULL, cryptRC4, 0, 0, 0);
outStr->printf( "\r\nstartxref\r\n");
outStr->printf( "%i\r\n", uxrefOffset);
outStr->printf( "%%%%EOF\r\n");
@@ -1248,7 +1329,9 @@
Object obj1;
MemStream *mStream = new MemStream( stmData.getCString(), 0,
stmData.getLength(), obj1.initDict(trailerDict) );
- writeObject(obj1.initStream(mStream), uxrefStreamRef, outStr, xRef, 0);
+ writeObjectHeader(uxrefStreamRef, outStr);
+ writeObject(obj1.initStream(mStream), outStr, xRef, 0, NULL, cryptRC4, 0, 0, 0);
+ writeObjectFooter(outStr);
obj1.free();
outStr->printf( "startxref\r\n");
@@ -1435,7 +1518,8 @@
const char *key = pageDict->getKey(n);
Object value; pageDict->getValNF(n, &value);
if (strcmp(key, "Parent") != 0 &&
- strcmp(key, "Pages") != 0) {
+ strcmp(key, "Pages") != 0 &&
+ strcmp(key, "Root") != 0) {
markObject(&value, xRef, countRef, numOffset);
}
value.free();
@@ -1445,6 +1529,10 @@
Guint PDFDoc::writePageObjects(OutStream *outStr, XRef *xRef, Guint numOffset)
{
Guint objectsCount = 0; //count the number of objects in the XRef(s)
+ Guchar *fileKey;
+ CryptAlgorithm encAlgorithm;
+ int keyLength;
+ xRef->getEncryptionParameters(&fileKey, &encAlgorithm, &keyLength);
for (int n = numOffset; n < xRef->getNumObjects(); n++) {
if (xRef->getEntry(n)->type != xrefEntryFree) {
@@ -1454,7 +1542,13 @@
ref.gen = xRef->getEntry(n)->gen;
objectsCount++;
getXRef()->fetch(ref.num - numOffset, ref.gen, &obj);
- Guint offset = writeObject(&obj, &ref, outStr, xRef, numOffset);
+ Guint offset = writeObjectHeader(&ref, outStr);
+ if (xRef->getEntry(n)->getFlag(XRefEntry::Unencrypted)) {
+ writeObject(&obj, outStr, NULL, cryptRC4, 0, 0, 0);
+ } else {
+ writeObject(&obj, outStr, fileKey, encAlgorithm, keyLength, ref.num, ref.gen);
+ }
+ writeObjectFooter(outStr);
xRef->add(ref.num, ref.gen, offset, gTrue);
obj.free();
}
diff --git a/poppler/PDFDoc.h b/poppler/PDFDoc.h
index 468f698..f3e9f68 100644
--- a/poppler/PDFDoc.h
+++ b/poppler/PDFDoc.h
@@ -43,6 +43,7 @@
#include "Page.h"
#include "Annot.h"
#include "OptionalContent.h"
+#include "Stream.h"
class GooString;
class BaseStream;
@@ -243,7 +244,8 @@
void markPageObjects(Dict *pageDict, XRef *xRef, XRef *countRef, Guint numOffset);
// write all objects used by pageDict to outStr
Guint writePageObjects(OutStream *outStr, XRef *xRef, Guint numOffset);
- static Guint writeObject (Object *obj, Ref *ref, OutStream* outStr, XRef *xref, Guint numOffset);
+ static void writeObject (Object *obj, OutStream* outStr, XRef *xref, Guint numOffset, Guchar *fileKey,
+ CryptAlgorithm encAlgorithm, int keyLength, int objNum, int objGen);
static void writeHeader(OutStream *outStr, int major, int minor);
// Ownership goes to the caller
@@ -258,18 +260,25 @@
// insert referenced objects in XRef
void markDictionnary (Dict* dict, XRef *xRef, XRef *countRef, Guint numOffset);
void markObject (Object *obj, XRef *xRef, XRef *countRef, Guint numOffset);
- static void writeDictionnary (Dict* dict, OutStream* outStr, XRef *xRef, Guint numOffset);
+ static void writeDictionnary (Dict* dict, OutStream* outStr, XRef *xRef, Guint numOffset, Guchar *fileKey,
+ CryptAlgorithm encAlgorithm, int keyLength, int objNum, int objGen);
- // Add object to current file stream and return the offset of the beginning of the object
- Guint writeObject (Object *obj, Ref *ref, OutStream* outStr)
- { return writeObject(obj, ref, outStr, getXRef(), 0); }
- void writeDictionnary (Dict* dict, OutStream* outStr)
- { writeDictionnary(dict, outStr, getXRef(), 0); }
+ // Write object header to current file stream and return its offset
+ static Guint writeObjectHeader (Ref *ref, OutStream* outStr);
+ static void writeObjectFooter (OutStream* outStr);
+
+ void writeObject (Object *obj, OutStream* outStr, Guchar *fileKey, CryptAlgorithm encAlgorithm,
+ int keyLength, int objNum, int objGen)
+ { writeObject(obj, outStr, getXRef(), 0, fileKey, encAlgorithm, keyLength, objNum, objGen); }
+ void writeDictionnary (Dict* dict, OutStream* outStr, Guchar *fileKey, CryptAlgorithm encAlgorithm,
+ int keyLength, int objNum, int objGen)
+ { writeDictionnary(dict, outStr, getXRef(), 0, fileKey, encAlgorithm, keyLength, objNum, objGen); }
static void writeStream (Stream* str, OutStream* outStr);
static void writeRawStream (Stream* str, OutStream* outStr);
void writeXRefTableTrailer (Guint uxrefOffset, XRef *uxref, GBool writeAllEntries,
int uxrefSize, OutStream* outStr, GBool incrUpdate);
- static void writeString (GooString* s, OutStream* outStr);
+ static void writeString (GooString* s, OutStream* outStr, Guchar *fileKey,
+ CryptAlgorithm encAlgorithm, int keyLength, int objNum, int objGen);
void saveIncrementalUpdate (OutStream* outStr);
void saveCompleteRewrite (OutStream* outStr);
diff --git a/poppler/PSOutputDev.cc b/poppler/PSOutputDev.cc
index e4c925c..95be97f 100644
--- a/poppler/PSOutputDev.cc
+++ b/poppler/PSOutputDev.cc
@@ -15,7 +15,7 @@
//
// Copyright (C) 2005 Martin Kretzschmar <martink@gnome.org>
// Copyright (C) 2005, 2006 Kristian Høgsberg <krh@redhat.com>
-// Copyright (C) 2006-2009, 2011 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2006-2009, 2011, 2012 Albert Astals Cid <aacid@kde.org>
// Copyright (C) 2006 Jeff Muizelaar <jeff@infidigm.net>
// Copyright (C) 2007, 2008 Brad Hards <bradh@kde.org>
// Copyright (C) 2008, 2009 Koji Otani <sho@bbr.jp>
@@ -1470,11 +1470,8 @@
}
writePSFmt("%%BoundingBox: {0:d} {1:d} {2:d} {3:d}\n",
(int)floor(x1), (int)floor(y1), (int)ceil(x2), (int)ceil(y2));
- if (floor(x1) != ceil(x1) || floor(y1) != ceil(y1) ||
- floor(x2) != ceil(x2) || floor(y2) != ceil(y2)) {
- writePSFmt("%%HiResBoundingBox: {0:.6g} {1:.6g} {2:.6g} {3:.6g}\n",
+ writePSFmt("%%HiResBoundingBox: {0:.6g} {1:.6g} {2:.6g} {3:.6g}\n",
x1, y1, x2, y2);
- }
writePS("%%DocumentSuppliedResources: (atend)\n");
writePS("%%EndComments\n");
break;
diff --git a/poppler/Page.cc b/poppler/Page.cc
index eccc198..87bc3a4 100644
--- a/poppler/Page.cc
+++ b/poppler/Page.cc
@@ -348,7 +348,7 @@
Annots *Page::getAnnots() {
if (!annots) {
Object obj;
- annots = new Annots(doc, getAnnots(&obj));
+ annots = new Annots(doc, num, getAnnots(&obj));
obj.free();
}
@@ -391,8 +391,7 @@
}
annots->appendAnnot(annot);
-
- annot->setPage(&pageRef, num);
+ annot->setPage(num, gTrue);
}
void Page::removeAnnot(Annot *annot) {
@@ -428,6 +427,8 @@
}
}
annArray.free();
+ annot->removeReferencedObjects(); // Note: Might recurse in removeAnnot again
+ annot->setPage(0, gFalse);
}
Links *Page::getLinks() {
diff --git a/poppler/Page.h b/poppler/Page.h
index e2e666c..78cedc4 100644
--- a/poppler/Page.h
+++ b/poppler/Page.h
@@ -164,6 +164,7 @@
Dict *getPieceInfo() { return attrs->getPieceInfo(); }
Dict *getSeparationInfo() { return attrs->getSeparationInfo(); }
PDFDoc *getDoc() { return doc; }
+ Ref getRef() { return pageRef; }
// Get resource dictionary.
Dict *getResourceDict() { return attrs->getResourceDict(); }
@@ -173,7 +174,6 @@
// Add a new annotation to the page
void addAnnot(Annot *annot);
// Remove an existing annotation from the page
- // Note: Caller is responsible for deleting popup and appearance streams too
void removeAnnot(Annot *annot);
// Return a list of links.
diff --git a/poppler/SplashOutputDev.cc b/poppler/SplashOutputDev.cc
index 79c4900..de09f49 100644
--- a/poppler/SplashOutputDev.cc
+++ b/poppler/SplashOutputDev.cc
@@ -94,6 +94,7 @@
GfxRGB rgb;
#if SPLASH_CMYK
GfxCMYK cmyk;
+ GfxColor deviceN;
#endif
// make gcc happy
@@ -124,6 +125,11 @@
color[2] = colToByte(cmyk.y);
color[3] = colToByte(cmyk.k);
break;
+ case splashModeDeviceN8:
+ colorSpace->getDeviceN(src, &deviceN);
+ for (int i = 0; i < SPOT_NCOMPS + 4; i++)
+ color[i] = colToByte(deviceN.c[i]);
+ break;
#endif
}
splashColorCopy(dest, color);
@@ -154,6 +160,8 @@
#if SPLASH_CMYK
if (mode == splashModeCMYK8)
colorComps=4;
+ else if (mode == splashModeDeviceN8)
+ colorComps=4 + SPOT_NCOMPS;
#endif
shading->getParameterizedColor(colorinterp, &src);
@@ -436,7 +444,7 @@
int i;
#if SPLASH_CMYK
- if (cm == splashModeCMYK8) {
+ if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
SplashColor rgbSrc;
SplashColor rgbDest;
SplashColor rgbBlend;
@@ -460,7 +468,7 @@
int i;
#if SPLASH_CMYK
- if (cm == splashModeCMYK8) {
+ if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
SplashColor rgbSrc;
SplashColor rgbDest;
SplashColor rgbBlend;
@@ -484,7 +492,7 @@
int i;
#if SPLASH_CMYK
- if (cm == splashModeCMYK8) {
+ if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
SplashColor rgbSrc;
SplashColor rgbDest;
SplashColor rgbBlend;
@@ -512,7 +520,7 @@
int i;
#if SPLASH_CMYK
- if (cm == splashModeCMYK8) {
+ if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
SplashColor rgbSrc;
SplashColor rgbDest;
SplashColor rgbBlend;
@@ -536,7 +544,7 @@
int i;
#if SPLASH_CMYK
- if (cm == splashModeCMYK8) {
+ if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
SplashColor rgbSrc;
SplashColor rgbDest;
SplashColor rgbBlend;
@@ -561,7 +569,7 @@
int i, x;
#if SPLASH_CMYK
- if (cm == splashModeCMYK8) {
+ if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
SplashColor rgbSrc;
SplashColor rgbDest;
SplashColor rgbBlend;
@@ -595,7 +603,7 @@
int i, x;
#if SPLASH_CMYK
- if (cm == splashModeCMYK8) {
+ if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
SplashColor rgbSrc;
SplashColor rgbDest;
SplashColor rgbBlend;
@@ -629,7 +637,7 @@
int i;
#if SPLASH_CMYK
- if (cm == splashModeCMYK8) {
+ if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
SplashColor rgbSrc;
SplashColor rgbDest;
SplashColor rgbBlend;
@@ -657,7 +665,7 @@
int i, x;
#if SPLASH_CMYK
- if (cm == splashModeCMYK8) {
+ if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
SplashColor rgbSrc;
SplashColor rgbDest;
SplashColor rgbBlend;
@@ -700,7 +708,7 @@
int i;
#if SPLASH_CMYK
- if (cm == splashModeCMYK8) {
+ if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
SplashColor rgbSrc;
SplashColor rgbDest;
SplashColor rgbBlend;
@@ -724,7 +732,7 @@
int i;
#if SPLASH_CMYK
- if (cm == splashModeCMYK8) {
+ if (cm == splashModeCMYK8 || cm == splashModeDeviceN8) {
SplashColor rgbSrc;
SplashColor rgbDest;
SplashColor rgbBlend;
@@ -859,6 +867,7 @@
break;
#if SPLASH_CMYK
case splashModeCMYK8:
+ case splashModeDeviceN8:
for (i = 0; i < 4; i++) {
// convert to additive
src2[i] = 0xff - src[i];
@@ -908,6 +917,7 @@
break;
#if SPLASH_CMYK
case splashModeCMYK8:
+ case splashModeDeviceN8:
for (i = 0; i < 4; i++) {
// convert to additive
src2[i] = 0xff - src[i];
@@ -952,6 +962,7 @@
break;
#if SPLASH_CMYK
case splashModeCMYK8:
+ case splashModeDeviceN8:
for (i = 0; i < 4; i++) {
// convert to additive
src2[i] = 0xff - src[i];
@@ -995,6 +1006,7 @@
break;
#if SPLASH_CMYK
case splashModeCMYK8:
+ case splashModeDeviceN8:
for (i = 0; i < 4; i++) {
// convert to additive
src2[i] = 0xff - src[i];
@@ -1391,6 +1403,10 @@
case splashModeCMYK8:
color[0] = color[1] = color[2] = color[3] = 0;
break;
+ case splashModeDeviceN8:
+ for (int i = 0; i < 4 + SPOT_NCOMPS; i++)
+ color[i] = 0;
+ break;
#endif
}
splash->setStrokePattern(new SplashSolidColor(color));
@@ -1429,7 +1445,9 @@
updateFlatness(state);
updateMiterLimit(state);
updateStrokeAdjust(state);
+ updateFillColorSpace(state);
updateFillColor(state);
+ updateStrokeColorSpace(state);
updateStrokeColor(state);
needFontUpdate = gTrue;
}
@@ -1500,11 +1518,26 @@
#endif
}
+void SplashOutputDev::updateFillColorSpace(GfxState *state) {
+#if SPLASH_CMYK
+ if (colorMode == splashModeDeviceN8)
+ state->getFillColorSpace()->createMapping(bitmap->getSeparationList(), SPOT_NCOMPS);
+#endif
+}
+
+void SplashOutputDev::updateStrokeColorSpace(GfxState *state) {
+#if SPLASH_CMYK
+ if (colorMode == splashModeDeviceN8)
+ state->getStrokeColorSpace()->createMapping(bitmap->getSeparationList(), SPOT_NCOMPS);
+#endif
+}
+
void SplashOutputDev::updateFillColor(GfxState *state) {
GfxGray gray;
GfxRGB rgb;
#if SPLASH_CMYK
GfxCMYK cmyk;
+ GfxColor deviceN;
#endif
switch (colorMode) {
@@ -1524,6 +1557,10 @@
state->getFillCMYK(&cmyk);
splash->setFillPattern(getColor(&cmyk));
break;
+ case splashModeDeviceN8:
+ state->getFillDeviceN(&deviceN);
+ splash->setFillPattern(getColor(&deviceN));
+ break;
#endif
}
}
@@ -1533,6 +1570,7 @@
GfxRGB rgb;
#if SPLASH_CMYK
GfxCMYK cmyk;
+ GfxColor deviceN;
#endif
switch (colorMode) {
@@ -1552,6 +1590,10 @@
state->getStrokeCMYK(&cmyk);
splash->setStrokePattern(getColor(&cmyk));
break;
+ case splashModeDeviceN8:
+ state->getStrokeDeviceN(&deviceN);
+ splash->setStrokePattern(getColor(&deviceN));
+ break;
#endif
}
}
@@ -1596,6 +1638,14 @@
color[3] = colToByte(cmyk->k);
return new SplashSolidColor(color);
}
+
+SplashPattern *SplashOutputDev::getColor(GfxColor *deviceN) {
+ SplashColor color;
+
+ for (int i = 0; i < 4 + SPOT_NCOMPS; i++)
+ color[i] = colToByte(deviceN->c[i]);
+ return new SplashSolidColor(color);
+}
#endif
void SplashOutputDev::setOverprintMask(GfxColorSpace *colorSpace,
@@ -2725,6 +2775,7 @@
GfxGray gray;
#if SPLASH_CMYK
GfxCMYK cmyk;
+ GfxColor deviceN;
#endif
int nComps, x;
@@ -2773,6 +2824,13 @@
*q++ = col[3];
}
break;
+ case splashModeDeviceN8:
+ for (x = 0, q = colorLine; x < imgData->width; ++x, ++p) {
+ col = &imgData->lookup[(SPOT_NCOMPS+4) * *p];
+ for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+ *q++ = col[cp];
+ }
+ break;
#endif
}
} else {
@@ -2812,6 +2870,13 @@
*q++ = colToByte(cmyk.k);
}
break;
+ case splashModeDeviceN8:
+ for (x = 0, q = colorLine; x < imgData->width; ++x, p += nComps) {
+ imgData->colorMap->getDeviceN(p, &deviceN);
+ for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+ *q++ = colToByte(deviceN.c[cp]);
+ }
+ break;
#endif
}
}
@@ -2829,6 +2894,7 @@
GfxGray gray;
#if SPLASH_CMYK
GfxCMYK cmyk;
+ GfxColor deviceN;
#endif
Guchar alpha;
int nComps, x, i;
@@ -2881,6 +2947,11 @@
*q++ = col[2];
*q++ = col[3];
break;
+ case splashModeDeviceN8:
+ col = &imgData->lookup[(SPOT_NCOMPS+4) * *p];
+ for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+ *q++ = col[cp];
+ break;
#endif
}
*aq++ = alpha;
@@ -2908,6 +2979,11 @@
*q++ = colToByte(cmyk.y);
*q++ = colToByte(cmyk.k);
break;
+ case splashModeDeviceN8:
+ imgData->colorMap->getDeviceN(p, &deviceN);
+ for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+ *q++ = colToByte(deviceN.c[cp]);
+ break;
#endif
}
*aq++ = alpha;
@@ -2984,7 +3060,7 @@
imgData->pattern->getColor(x, imgData->y, pat);
for (int i = 0; i < splashColorModeNComps[imgData->colorMode]; ++i) {
#if SPLASH_CMYK
- if (imgData->colorMode == splashModeCMYK8)
+ if (imgData->colorMode == splashModeCMYK8 || imgData->colorMode == splashModeDeviceN8)
dest[i] = div255(pat[i] * (255 - col[0]));
else
#endif
@@ -3025,6 +3101,7 @@
#if SPLASH_CMYK
GfxCMYK cmyk;
GBool grayIndexed = gFalse;
+ GfxColor deviceN;
#endif
Guchar pix;
int n, i;
@@ -3104,6 +3181,21 @@
imgData.lookup[4*i+3] = colToByte(cmyk.k);
}
break;
+ case splashModeDeviceN8:
+ colorMap->getColorSpace()->createMapping(bitmap->getSeparationList(), SPOT_NCOMPS);
+ grayIndexed = colorMap->getColorSpace()->getMode() != csDeviceGray;
+ imgData.lookup = (SplashColorPtr)gmallocn(n, SPOT_NCOMPS+4);
+ for (i = 0; i < n; ++i) {
+ pix = (Guchar)i;
+ colorMap->getCMYK(&pix, &cmyk);
+ if (cmyk.c != 0 || cmyk.m != 0 || cmyk.y != 0) {
+ grayIndexed = gFalse;
+ }
+ colorMap->getDeviceN(&pix, &deviceN);
+ for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+ imgData.lookup[(SPOT_NCOMPS+4)*i +cp] = colToByte(deviceN.c[cp]);
+ }
+ break;
#endif
}
}
@@ -3154,6 +3246,7 @@
GfxGray gray;
#if SPLASH_CMYK
GfxCMYK cmyk;
+ GfxColor deviceN;
#endif
Guchar alpha;
Guchar *maskPtr;
@@ -3208,6 +3301,11 @@
*q++ = col[2];
*q++ = col[3];
break;
+ case splashModeDeviceN8:
+ col = &imgData->lookup[(SPOT_NCOMPS+4) * *p];
+ for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+ *q++ = col[cp];
+ break;
#endif
}
*aq++ = alpha;
@@ -3235,6 +3333,11 @@
*q++ = colToByte(cmyk.y);
*q++ = colToByte(cmyk.k);
break;
+ case splashModeDeviceN8:
+ imgData->colorMap->getDeviceN(p, &deviceN);
+ for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+ *q++ = colToByte(deviceN.c[cp]);
+ break;
#endif
}
*aq++ = alpha;
@@ -3266,10 +3369,14 @@
GfxRGB rgb;
#if SPLASH_CMYK
GfxCMYK cmyk;
+ GfxColor deviceN;
#endif
Guchar pix;
int n, i;
+#if SPLASH_CMYK
+ colorMap->getColorSpace()->createMapping(bitmap->getSeparationList(), SPOT_NCOMPS);
+#endif
setOverprintMask(colorMap->getColorSpace(), state->getFillOverprint(),
state->getOverprintMode(), NULL);
@@ -3391,6 +3498,15 @@
imgData.lookup[4*i+3] = colToByte(cmyk.k);
}
break;
+ case splashModeDeviceN8:
+ imgData.lookup = (SplashColorPtr)gmallocn(n, SPOT_NCOMPS+4);
+ for (i = 0; i < n; ++i) {
+ pix = (Guchar)i;
+ colorMap->getDeviceN(&pix, &deviceN);
+ for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+ imgData.lookup[(SPOT_NCOMPS+4)*i + cp] = colToByte(deviceN.c[cp]);
+ }
+ break;
#endif
}
}
@@ -3429,10 +3545,14 @@
GfxRGB rgb;
#if SPLASH_CMYK
GfxCMYK cmyk;
+ GfxColor deviceN;
#endif
Guchar pix;
int n, i;
+#if SPLASH_CMYK
+ colorMap->getColorSpace()->createMapping(bitmap->getSeparationList(), SPOT_NCOMPS);
+#endif
setOverprintMask(colorMap->getColorSpace(), state->getFillOverprint(),
state->getOverprintMode(), NULL);
@@ -3541,6 +3661,15 @@
imgData.lookup[4*i+3] = colToByte(cmyk.k);
}
break;
+ case splashModeDeviceN8:
+ imgData.lookup = (SplashColorPtr)gmallocn(n, SPOT_NCOMPS+4);
+ for (i = 0; i < n; ++i) {
+ pix = (Guchar)i;
+ colorMap->getDeviceN(&pix, &deviceN);
+ for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+ imgData.lookup[(SPOT_NCOMPS+4)*i + cp] = colToByte(deviceN.c[cp]);
+ }
+ break;
#endif
}
}
@@ -3684,7 +3813,7 @@
// create the temporary bitmap
bitmap = new SplashBitmap(w, h, bitmapRowPad, colorMode, gTrue,
- bitmapTopDown);
+ bitmapTopDown, bitmap->getSeparationList());
splash = new Splash(bitmap, vectorAntialias,
transpGroup->origSplash->getScreen());
splash->setMinLineWidth(globalParams->getMinLineWidth());
@@ -3773,6 +3902,7 @@
GfxRGB rgb;
#if SPLASH_CMYK
GfxCMYK cmyk;
+ GfxColor deviceN;
#endif
double lum, lum2;
int tx, ty, x, y;
@@ -3816,6 +3946,12 @@
color[3] = colToByte(cmyk.k);
tSplash->compositeBackground(color);
break;
+ case splashModeDeviceN8:
+ transpGroupStack->blendingColorSpace->getDeviceN(backdropColor, &deviceN);
+ for (int cp=0; cp < SPOT_NCOMPS+4; cp++)
+ color[cp] = colToByte(deviceN.c[cp]);
+ tSplash->compositeBackground(color);
+ break;
#endif
}
delete tSplash;
@@ -3857,6 +3993,7 @@
break;
#if SPLASH_CMYK
case splashModeCMYK8:
+ case splashModeDeviceN8:
lum = (1 - color[3] / 255.0)
- (0.3 / 255.0) * color[0]
- (0.59 / 255.0) * color[1]
@@ -3955,6 +4092,7 @@
Matrix m1;
double *ctm, savedCTM[6];
double kx, ky, sx, sy;
+ GBool retValue = gFalse;
width = bbox[2] - bbox[0];
height = bbox[3] - bbox[1];
@@ -4014,6 +4152,8 @@
repeatX = x1 - x0;
repeatY = y1 - y0;
} else {
+ if ((unsigned long) result_width * result_height > 0x800000L)
+ return gFalse;
while(fabs(kx) > 16384 || fabs(ky) > 16384) {
// limit pattern bitmap size
m1.m[0] /= 2;
@@ -4055,7 +4195,9 @@
memset(bitmap->getAlphaPtr(), 0, bitmap->getWidth() * bitmap->getHeight());
if (paintType == 2) {
#if SPLASH_CMYK
- memset(bitmap->getDataPtr(), (colorMode == splashModeCMYK8) ? 0x00 : 0xFF, bitmap->getRowSize() * bitmap->getHeight());
+ memset(bitmap->getDataPtr(),
+ (colorMode == splashModeCMYK8 || colorMode == splashModeDeviceN8) ? 0x00 : 0xFF,
+ bitmap->getRowSize() * bitmap->getHeight());
#else
memset(bitmap->getDataPtr(), 0xFF, bitmap->getRowSize() * bitmap->getHeight());
#endif
@@ -4099,10 +4241,10 @@
matc[1] = ctm[1];
matc[2] = ctm[2];
matc[3] = ctm[3];
- splash->drawImage(&tilingBitmapSrc, &imgData, colorMode, gTrue, result_width, result_height, matc, gTrue);
+ retValue = splash->drawImage(&tilingBitmapSrc, &imgData, colorMode, gTrue, result_width, result_height, matc, gTrue) == splashOk;
delete tBitmap;
delete gfx;
- return gTrue;
+ return retValue;
}
GBool SplashOutputDev::gouraudTriangleShadedFill(GfxState *state, GfxGouraudTriangleShading *shading)
@@ -4115,7 +4257,8 @@
break;
#if SPLASH_CMYK
case splashModeCMYK8:
- bDirectColorTranslation = (shadingMode == csDeviceCMYK);
+ case splashModeDeviceN8:
+ bDirectColorTranslation = (shadingMode == csDeviceCMYK || shadingMode == csDeviceN);
break;
#endif
default:
@@ -4185,6 +4328,9 @@
state->closePath();
path = convertPath(state, state->getPath(), gTrue);
+#if SPLASH_CMYK
+ pattern->getShading()->getColorSpace()->createMapping(bitmap->getSeparationList(), SPOT_NCOMPS);
+#endif
setOverprintMask(pattern->getShading()->getColorSpace(), state->getFillOverprint(),
state->getOverprintMode(), state->getFillColor());
retVal = (splash->shadedFill(path, pattern->getShading()->getHasBBox(), pattern) == splashOk);
diff --git a/poppler/SplashOutputDev.h b/poppler/SplashOutputDev.h
index f1c87ec..de7934d 100644
--- a/poppler/SplashOutputDev.h
+++ b/poppler/SplashOutputDev.h
@@ -215,6 +215,8 @@
virtual void updateMiterLimit(GfxState *state);
virtual void updateLineWidth(GfxState *state);
virtual void updateStrokeAdjust(GfxState *state);
+ virtual void updateFillColorSpace(GfxState *state);
+ virtual void updateStrokeColorSpace(GfxState *state);
virtual void updateFillColor(GfxState *state);
virtual void updateStrokeColor(GfxState *state);
virtual void updateBlendMode(GfxState *state);
@@ -362,6 +364,7 @@
SplashPattern *getColor(GfxRGB *rgb);
#if SPLASH_CMYK
SplashPattern *getColor(GfxCMYK *cmyk);
+ SplashPattern *getColor(GfxColor *deviceN);
#endif
void setOverprintMask(GfxColorSpace *colorSpace, GBool overprintFlag,
int overprintMode, GfxColor *singleColor, GBool grayIndexed = gFalse);
diff --git a/poppler/Stream.cc b/poppler/Stream.cc
index f287406..842f0c6 100644
--- a/poppler/Stream.cc
+++ b/poppler/Stream.cc
@@ -25,6 +25,7 @@
// Copyright (C) 2011, 2012 William Bader <williambader@hotmail.com>
// Copyright (C) 2012 Thomas Freitag <Thomas.Freitag@alfa.de>
// Copyright (C) 2012 Oliver Sander <sander@mi.fu-berlin.de>
+// Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
@@ -4495,7 +4496,12 @@
delete str;
}
-void FlateStream::unfilteredReset() {
+void FlateStream::flateReset(GBool unfiltered) {
+ if (unfiltered)
+ str->unfilteredReset();
+ else
+ str->reset();
+
index = 0;
remain = 0;
codeBuf = 0;
@@ -4503,14 +4509,16 @@
compressedBlock = gFalse;
endOfBlock = gTrue;
eof = gTrue;
+}
- str->reset();
+void FlateStream::unfilteredReset() {
+ flateReset(gTrue);
}
void FlateStream::reset() {
int cmf, flg;
- unfilteredReset();
+ flateReset(gFalse);
// read header
//~ need to look at window size?
diff --git a/poppler/Stream.h b/poppler/Stream.h
index a270fdf..20b5fd6 100644
--- a/poppler/Stream.h
+++ b/poppler/Stream.h
@@ -21,6 +21,7 @@
// Copyright (C) 2010 Hib Eris <hib@hiberis.nl>
// Copyright (C) 2011, 2012 William Bader <williambader@hotmail.com>
// Copyright (C) 2012 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
@@ -970,6 +971,7 @@
virtual void unfilteredReset ();
private:
+ void flateReset(GBool unfiltered);
inline int doGetRawChar() {
int c;
diff --git a/poppler/TextOutputDev.cc b/poppler/TextOutputDev.cc
index a9c9d70..2be0b42 100644
--- a/poppler/TextOutputDev.cc
+++ b/poppler/TextOutputDev.cc
@@ -15,10 +15,10 @@
//
// Copyright (C) 2005-2007 Kristian Høgsberg <krh@redhat.com>
// Copyright (C) 2005 Nickolay V. Shmyrev <nshmyrev@yandex.ru>
-// Copyright (C) 2006-2008, 2011 Carlos Garcia Campos <carlosgc@gnome.org>
+// Copyright (C) 2006-2008, 2011, 2012 Carlos Garcia Campos <carlosgc@gnome.org>
// Copyright (C) 2006, 2007 Ed Catmur <ed@catmur.co.uk>
// Copyright (C) 2006 Jeff Muizelaar <jeff@infidigm.net>
-// Copyright (C) 2007, 2008 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2007, 2008, 2012 Adrian Johnson <ajohnson@redneon.com>
// Copyright (C) 2008 Koji Otani <sho@bbr.jp>
// Copyright (C) 2008, 2010-2012 Albert Astals Cid <aacid@kde.org>
// Copyright (C) 2008 Pino Toscano <pino@kde.org>
@@ -64,7 +64,7 @@
#include "TextOutputDev.h"
#include "Page.h"
#include "Annot.h"
-#include "PDFDocEncoding.h"
+#include "UTF.h"
#ifdef MACOS
// needed for setting type/creator of MacOS files
@@ -128,7 +128,7 @@
// Minimum spacing between characters within a word, as a fraction of
// the font size.
-#define minCharSpacing -0.2
+#define minCharSpacing -0.5
// Maximum spacing between characters within a word, as a fraction of
// the font size, when there is no obvious extra-wide character
@@ -235,104 +235,14 @@
// TextWord
//------------------------------------------------------------------------
-TextWord::TextWord(GfxState *state, int rotA, double x0, double y0,
- TextFontInfo *fontA, double fontSizeA) {
- GfxFont *gfxFont;
- double x, y, ascent, descent;
- int wMode;
-
+TextWord::TextWord(GfxState *state, int rotA, double fontSizeA) {
rot = rotA;
- font = fontA;
fontSize = fontSizeA;
- state->transform(x0, y0, &x, &y);
- if ((gfxFont = font->gfxFont)) {
- ascent = gfxFont->getAscent() * fontSize;
- descent = gfxFont->getDescent() * fontSize;
- wMode = gfxFont->getWMode();
- } else {
- // this means that the PDF file draws text without a current font,
- // which should never happen
- ascent = 0.95 * fontSize;
- descent = -0.35 * fontSize;
- wMode = 0;
- }
- if (wMode) { // vertical writing mode
- // NB: the rotation value has been incremented by 1 (in
- // TextPage::beginWord()) for vertical writing mode
- switch (rot) {
- case 0:
- yMin = y - fontSize;
- yMax = y;
- base = y;
- break;
- case 1:
- xMin = x;
- xMax = x + fontSize;
- base = x;
- break;
- case 2:
- yMin = y;
- yMax = y + fontSize;
- base = y;
- break;
- case 3:
- xMin = x - fontSize;
- xMax = x;
- base = x;
- break;
- }
- } else { // horizontal writing mode
- switch (rot) {
- case 0:
- yMin = y - ascent;
- yMax = y - descent;
- if (yMin == yMax) {
- // this is a sanity check for a case that shouldn't happen -- but
- // if it does happen, we want to avoid dividing by zero later
- yMin = y;
- yMax = y + 1;
- }
- base = y;
- break;
- case 1:
- xMin = x + descent;
- xMax = x + ascent;
- if (xMin == xMax) {
- // this is a sanity check for a case that shouldn't happen -- but
- // if it does happen, we want to avoid dividing by zero later
- xMin = x;
- xMax = x + 1;
- }
- base = x;
- break;
- case 2:
- yMin = y + descent;
- yMax = y + ascent;
- if (yMin == yMax) {
- // this is a sanity check for a case that shouldn't happen -- but
- // if it does happen, we want to avoid dividing by zero later
- yMin = y;
- yMax = y + 1;
- }
- base = y;
- break;
- case 3:
- xMin = x - ascent;
- xMax = x - descent;
- if (xMin == xMax) {
- // this is a sanity check for a case that shouldn't happen -- but
- // if it does happen, we want to avoid dividing by zero later
- xMin = x;
- xMax = x + 1;
- }
- base = x;
- break;
- }
- }
text = NULL;
charcode = NULL;
edge = NULL;
charPos = NULL;
+ font = NULL;
len = size = 0;
spaceAfter = gFalse;
next = NULL;
@@ -359,12 +269,15 @@
gfree(charcode);
gfree(edge);
gfree(charPos);
+ gfree(font);
}
-void TextWord::addChar(GfxState *state, double x, double y,
+void TextWord::addChar(GfxState *state, TextFontInfo *fontA, double x, double y,
double dx, double dy, int charPosA, int charLen,
CharCode c, Unicode u) {
- int wMode;
+ GfxFont *gfxFont;
+ double ascent, descent;
+ ascent = descent = 0; // make gcc happy
if (len == size) {
size += 16;
@@ -372,12 +285,28 @@
charcode = (Unicode *)greallocn(charcode, size, sizeof(CharCode));
edge = (double *)greallocn(edge, (size + 1), sizeof(double));
charPos = (int *)greallocn(charPos, size + 1, sizeof(int));
+ font = (TextFontInfo **)greallocn(font, size, sizeof(TextFontInfo *));
}
text[len] = u;
charcode[len] = c;
charPos[len] = charPosA;
charPos[len + 1] = charPosA + charLen;
- wMode = font->gfxFont ? font->gfxFont->getWMode() : 0;
+ font[len] = fontA;
+
+ if (len == 0) {
+ if ((gfxFont = fontA->gfxFont)) {
+ ascent = gfxFont->getAscent() * fontSize;
+ descent = gfxFont->getDescent() * fontSize;
+ wMode = gfxFont->getWMode();
+ } else {
+ // this means that the PDF file draws text without a current font,
+ // which should never happen
+ ascent = 0.95 * fontSize;
+ descent = -0.35 * fontSize;
+ wMode = 0;
+ }
+ }
+
if (wMode) { // vertical writing mode
// NB: the rotation value has been incremented by 1 (in
// TextPage::beginWord()) for vertical writing mode
@@ -385,27 +314,39 @@
case 0:
if (len == 0) {
xMin = x - fontSize;
+ yMin = y - fontSize;
+ yMax = y;
+ base = y;
}
edge[len] = x - fontSize;
xMax = edge[len+1] = x;
break;
case 1:
if (len == 0) {
+ xMin = x;
yMin = y - fontSize;
+ xMax = x + fontSize;
+ base = x;
}
edge[len] = y - fontSize;
yMax = edge[len+1] = y;
break;
case 2:
if (len == 0) {
+ yMin = y;
xMax = x + fontSize;
+ yMax = y + fontSize;
+ base = y;
}
edge[len] = x + fontSize;
xMin = edge[len+1] = x;
break;
case 3:
if (len == 0) {
+ xMin = x - fontSize;
+ xMax = x;
yMax = y + fontSize;
+ base = x;
}
edge[len] = y + fontSize;
yMin = edge[len+1] = y;
@@ -416,27 +357,63 @@
case 0:
if (len == 0) {
xMin = x;
+ yMin = y - ascent;
+ yMax = y - descent;
+ if (yMin == yMax) {
+ // this is a sanity check for a case that shouldn't happen -- but
+ // if it does happen, we want to avoid dividing by zero later
+ yMin = y;
+ yMax = y + 1;
+ }
+ base = y;
}
edge[len] = x;
xMax = edge[len+1] = x + dx;
break;
case 1:
if (len == 0) {
+ xMin = x + descent;
yMin = y;
+ xMax = x + ascent;
+ if (xMin == xMax) {
+ // this is a sanity check for a case that shouldn't happen -- but
+ // if it does happen, we want to avoid dividing by zero later
+ xMin = x;
+ xMax = x + 1;
+ }
+ base = x;
}
edge[len] = y;
yMax = edge[len+1] = y + dy;
break;
case 2:
if (len == 0) {
+ yMin = y + descent;
xMax = x;
+ yMax = y + ascent;
+ if (yMin == yMax) {
+ // this is a sanity check for a case that shouldn't happen -- but
+ // if it does happen, we want to avoid dividing by zero later
+ yMin = y;
+ yMax = y + 1;
+ }
+ base = y;
}
edge[len] = x;
xMin = edge[len+1] = x + dx;
break;
case 3:
if (len == 0) {
+ xMin = x - ascent;
+ xMax = x - descent;
yMax = y;
+ if (xMin == xMax) {
+ // this is a sanity check for a case that shouldn't happen -- but
+ // if it does happen, we want to avoid dividing by zero later
+ xMin = x;
+ xMax = x + 1;
+ }
+ base = x;
}
edge[len] = y;
yMin = edge[len+1] = y + dy;
@@ -467,12 +444,14 @@
charcode = (CharCode *)greallocn(charcode, (size + 1), sizeof(CharCode));
edge = (double *)greallocn(edge, (size + 1), sizeof(double));
charPos = (int *)greallocn(charPos, size + 1, sizeof(int));
+ font = (TextFontInfo **)greallocn(font, size, sizeof(TextFontInfo *));
}
for (i = 0; i < word->len; ++i) {
text[len + i] = word->text[i];
charcode[len + i] = word->charcode[i];
edge[len + i] = word->edge[i];
charPos[len + i] = word->charPos[i];
+ font[len + i] = word->font[i];
}
edge[len + word->len] = word->edge[word->len];
charPos[len + word->len] = word->charPos[word->len];
@@ -864,7 +843,7 @@
word0->spaceAfter = gTrue;
word0 = word1;
word1 = word1->next;
- } else if (word0->font == word1->font &&
+ } else if (word0->font[word0->len - 1] == word1->font[0] &&
word0->underlined == word1->underlined &&
fabs(word0->fontSize - word1->fontSize) <
maxWordFontSizeDelta * words->fontSize &&
@@ -2235,7 +2214,7 @@
}
}
-void TextPage::beginWord(GfxState *state, double x0, double y0) {
+void TextPage::beginWord(GfxState *state) {
GfxFont *gfxFont;
double *fontm;
double m[4], m2[4];
@@ -2275,7 +2254,7 @@
rot = (rot + 1) & 3;
}
- curWord = new TextWord(state, rot, x0, y0, curFont, curFontSize);
+ curWord = new TextWord(state, rot, curFontSize);
}
void TextPage::addChar(GfxState *state, double x, double y,
@@ -2284,6 +2263,7 @@
double x1, y1, w1, h1, dx2, dy2, base, sp, delta;
GBool overlap;
int i;
+ int wMode;
// subtract char and word spacing from the dx,dy values
sp = state->getCharSpace();
@@ -2332,6 +2312,7 @@
// (3) the previous character was an overlap (we want each duplicated
// character to be in a word by itself at this stage),
// (4) the font size has changed
+ // (5) the WMode changed
if (curWord && curWord->len > 0) {
base = sp = delta = 0; // make gcc happy
switch (curWord->rot) {
@@ -2358,11 +2339,13 @@
}
overlap = fabs(delta) < dupMaxPriDelta * curWord->fontSize &&
fabs(base - curWord->base) < dupMaxSecDelta * curWord->fontSize;
+ wMode = curFont->gfxFont ? curFont->gfxFont->getWMode() : 0;
if (overlap || lastCharOverlap ||
sp < -minDupBreakOverlap * curWord->fontSize ||
sp > minWordBreakSpace * curWord->fontSize ||
fabs(base - curWord->base) > 0.5 ||
- curFontSize != curWord->fontSize) {
+ curFontSize != curWord->fontSize ||
+ wMode != curWord->wMode) {
endWord();
}
lastCharOverlap = overlap;
@@ -2373,7 +2356,7 @@
if (uLen != 0) {
// start a new word if needed
if (!curWord) {
- beginWord(state, x, y);
+ beginWord(state);
}
// page rotation and/or transform matrices can cause text to be
@@ -2384,7 +2367,7 @@
(curWord->rot == 2 && w1 > 0) ||
(curWord->rot == 3 && h1 > 0)) {
endWord();
- beginWord(state, x + dx, y + dy);
+ beginWord(state);
x1 += w1;
y1 += h1;
w1 = -w1;
@@ -2395,24 +2378,7 @@
w1 /= uLen;
h1 /= uLen;
for (i = 0; i < uLen; ++i) {
- if (u[i] >= 0xd800 && u[i] < 0xdc00) { /* surrogate pair */
- if (i + 1 < uLen && u[i+1] >= 0xdc00 && u[i+1] < 0xe000) {
- /* next code is a low surrogate */
- Unicode uu = (((u[i] & 0x3ff) << 10) | (u[i+1] & 0x3ff)) + 0x10000;
- i++;
- curWord->addChar(state, x1 + i*w1, y1 + i*h1, w1, h1, charPos, nBytes, c, uu);
- } else {
- /* missing low surrogate
- replace it with REPLACEMENT CHARACTER (U+FFFD) */
- curWord->addChar(state, x1 + i*w1, y1 + i*h1, w1, h1, charPos, nBytes, c, 0xfffd);
- }
- } else if (u[i] >= 0xdc00 && u[i] < 0xe000) {
- /* invalid low surrogate
- replace it with REPLACEMENT CHARACTER (U+FFFD) */
- curWord->addChar(state, x1 + i*w1, y1 + i*h1, w1, h1, charPos, nBytes, c, 0xfffd);
- } else {
- curWord->addChar(state, x1 + i*w1, y1 + i*h1, w1, h1, charPos, nBytes, c, u[i]);
- }
+ curWord->addChar(state, curFont, x1 + i*w1, y1 + i*h1, w1, h1, charPos, nBytes, c, u[i]);
}
}
charPos += nBytes;
@@ -3656,76 +3622,80 @@
j = backward ? m - len : 0;
p = txt + j;
while (backward ? j >= 0 : j <= m - len) {
+ if (!wholeWord ||
+ ((j == 0 || !unicodeTypeAlphaNum(txt[j - 1])) &&
+ (j + len == m || !unicodeTypeAlphaNum(txt[j + len])))) {
- // compare the strings
- for (k = 0; k < len; ++k) {
- if (p[k] != s2[k]) {
- break;
- }
- }
+ // compare the strings
+ for (k = 0; k < len; ++k) {
+ if (p[k] != s2[k]) {
+ break;
+ }
+ }
- // found it
- if (k == len) {
- // where s2 matches a subsequence of a compatibility equivalence
- // decomposition, highlight the entire glyph, since we don't know
- // the internal layout of subglyph components
- int normStart = line->normalized_idx[j];
- int normAfterEnd = line->normalized_idx[j + len - 1] + 1;
- switch (line->rot) {
- case 0:
- xMin1 = line->edge[normStart];
- xMax1 = line->edge[normAfterEnd];
- yMin1 = line->yMin;
- yMax1 = line->yMax;
- break;
- case 1:
- xMin1 = line->xMin;
- xMax1 = line->xMax;
- yMin1 = line->edge[normStart];
- yMax1 = line->edge[normAfterEnd];
- break;
- case 2:
- xMin1 = line->edge[normAfterEnd];
- xMax1 = line->edge[normStart];
- yMin1 = line->yMin;
- yMax1 = line->yMax;
- break;
- case 3:
- xMin1 = line->xMin;
- xMax1 = line->xMax;
- yMin1 = line->edge[normAfterEnd];
- yMax1 = line->edge[normStart];
- break;
- }
- if (backward) {
- if ((startAtTop ||
- yMin1 < yStart || (yMin1 == yStart && xMin1 < xStart)) &&
- (stopAtBottom ||
- yMin1 > yStop || (yMin1 == yStop && xMin1 > xStop))) {
- if (!found ||
- yMin1 > yMin0 || (yMin1 == yMin0 && xMin1 > xMin0)) {
- xMin0 = xMin1;
- xMax0 = xMax1;
- yMin0 = yMin1;
- yMax0 = yMax1;
- found = gTrue;
- }
- }
- } else {
- if ((startAtTop ||
- yMin1 > yStart || (yMin1 == yStart && xMin1 > xStart)) &&
- (stopAtBottom ||
- yMin1 < yStop || (yMin1 == yStop && xMin1 < xStop))) {
- if (!found ||
- yMin1 < yMin0 || (yMin1 == yMin0 && xMin1 < xMin0)) {
- xMin0 = xMin1;
- xMax0 = xMax1;
- yMin0 = yMin1;
- yMax0 = yMax1;
- found = gTrue;
- }
- }
- }
+ // found it
+ if (k == len) {
+ // where s2 matches a subsequence of a compatibility equivalence
+ // decomposition, highlight the entire glyph, since we don't know
+ // the internal layout of subglyph components
+ int normStart = line->normalized_idx[j];
+ int normAfterEnd = line->normalized_idx[j + len - 1] + 1;
+ switch (line->rot) {
+ case 0:
+ xMin1 = line->edge[normStart];
+ xMax1 = line->edge[normAfterEnd];
+ yMin1 = line->yMin;
+ yMax1 = line->yMax;
+ break;
+ case 1:
+ xMin1 = line->xMin;
+ xMax1 = line->xMax;
+ yMin1 = line->edge[normStart];
+ yMax1 = line->edge[normAfterEnd];
+ break;
+ case 2:
+ xMin1 = line->edge[normAfterEnd];
+ xMax1 = line->edge[normStart];
+ yMin1 = line->yMin;
+ yMax1 = line->yMax;
+ break;
+ case 3:
+ xMin1 = line->xMin;
+ xMax1 = line->xMax;
+ yMin1 = line->edge[normAfterEnd];
+ yMax1 = line->edge[normStart];
+ break;
+ }
+ if (backward) {
+ if ((startAtTop ||
+ yMin1 < yStart || (yMin1 == yStart && xMin1 < xStart)) &&
+ (stopAtBottom ||
+ yMin1 > yStop || (yMin1 == yStop && xMin1 > xStop))) {
+ if (!found ||
+ yMin1 > yMin0 || (yMin1 == yMin0 && xMin1 > xMin0)) {
+ xMin0 = xMin1;
+ xMax0 = xMax1;
+ yMin0 = yMin1;
+ yMax0 = yMax1;
+ found = gTrue;
+ }
+ }
+ } else {
+ if ((startAtTop ||
+ yMin1 > yStart || (yMin1 == yStart && xMin1 > xStart)) &&
+ (stopAtBottom ||
+ yMin1 < yStop || (yMin1 == yStop && xMin1 < xStop))) {
+ if (!found ||
+ yMin1 < yMin0 || (yMin1 == yMin0 && xMin1 < xMin0)) {
+ xMin0 = xMin1;
+ xMax0 = xMax1;
+ yMin0 = yMin1;
+ yMax0 = yMax1;
+ found = gTrue;
+ }
+ }
+ }
+ }
}
if (backward) {
--j;
@@ -3736,7 +3706,7 @@
}
}
}
- }
+ }
gfree(s2);
if (!caseSensitive) {
@@ -4355,29 +4325,32 @@
void TextSelectionPainter::visitWord (TextWord *word, int begin, int end,
PDFRectangle *selection)
{
- GooString *string;
- int i;
-
state->setFillColor(glyph_color);
out->updateFillColor(state);
- word->font->gfxFont->incRefCnt();
- state->setFont(word->font->gfxFont, word->fontSize);
- out->updateFont(state);
- /* The only purpose of this string is to let the output device query
- * it's length. Might want to change this interface later. */
+ while (begin < end) {
+ TextFontInfo *font = word->font[begin];
+ font->gfxFont->incRefCnt();
+ state->setFont(font->gfxFont, word->fontSize);
+ out->updateFont(state);
- string = new GooString ((char *) word->charcode, end - begin);
+ int fEnd = begin + 1;
+ while (fEnd < end && font->matches(word->font[fEnd]))
+ fEnd++;
- out->beginString(state, string);
+ /* The only purpose of this string is to let the output device query
+ * it's length. Might want to change this interface later. */
+ GooString *string = new GooString ((char *) word->charcode, fEnd - begin);
+ out->beginString(state, string);
- for (i = begin; i < end; i++)
- out->drawChar(state, word->edge[i], word->base, 0, 0, 0, 0,
- word->charcode[i], 1, NULL, 0);
-
- out->endString(state);
-
- delete string;
+ for (int i = begin; i < fEnd; i++) {
+ out->drawChar(state, word->edge[i], word->base, 0, 0, 0, 0,
+ word->charcode[i], 1, NULL, 0);
+ }
+ out->endString(state);
+ delete string;
+ begin = fEnd;
+ }
}
void TextWord::visitSelection(TextSelectionVisitor *visitor,
@@ -5246,41 +5219,17 @@
// extents of all the glyphs inside the span
if (actualTextNBytes) {
- char *uniString = NULL;
Unicode *uni;
- int length, i;
-
- if (!actualText->hasUnicodeMarker()) {
- if (actualText->getLength() > 0) {
- //non-unicode string -- assume pdfDocEncoding and
- //try to convert to UTF16BE
- uniString = pdfDocEncodingToUTF16(actualText, &length);
- } else {
- length = 0;
- }
- } else {
- uniString = actualText->getCString();
- length = actualText->getLength();
- }
-
- if (length < 3)
- length = 0;
- else
- length = length/2 - 1;
- uni = new Unicode[length];
- for (i = 0 ; i < length; i++)
- uni[i] = ((uniString[2 + i*2] & 0xff)<<8)|(uniString[3 + i*2] & 0xff);
+ int length;
// now that we have the position info for all of the text inside
// the marked content span, we feed the "ActualText" back through
// text->addChar()
+ length = TextStringToUCS4(actualText, &uni);
text->addChar(state, actualTextX0, actualTextY0,
actualTextX1 - actualTextX0, actualTextY1 - actualTextY0,
0, actualTextNBytes, uni, length);
-
- delete [] uni;
- if (!actualText->hasUnicodeMarker())
- delete [] uniString;
+ gfree(uni);
}
delete actualText;
diff --git a/poppler/TextOutputDev.h b/poppler/TextOutputDev.h
index e31876b..100f23e 100644
--- a/poppler/TextOutputDev.h
+++ b/poppler/TextOutputDev.h
@@ -19,6 +19,7 @@
// Copyright (C) 2007 Adrian Johnson <ajohnson@redneon.com>
// Copyright (C) 2008, 2010 Albert Astals Cid <aacid@kde.org>
// Copyright (C) 2010 Brian Ewins <brian.ewins@gmail.com>
+// Copyright (C) 2012 Jason Crain <jason@aquaticape.us>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
@@ -113,14 +114,13 @@
public:
// Constructor.
- TextWord(GfxState *state, int rotA, double x0, double y0,
- TextFontInfo *fontA, double fontSize);
+ TextWord(GfxState *state, int rotA, double fontSize);
// Destructor.
~TextWord();
// Add a character to the word.
- void addChar(GfxState *state, double x, double y,
+ void addChar(GfxState *state, TextFontInfo *fontA, double x, double y,
double dx, double dy, int charPosA, int charLen,
CharCode c, Unicode u);
@@ -141,8 +141,8 @@
PDFRectangle *selection,
SelectionStyle style);
- // Get the TextFontInfo object associated with this word.
- TextFontInfo *getFontInfo() { return font; }
+ // Get the TextFontInfo object associated with a character.
+ TextFontInfo *getFontInfo(int idx) { return font[idx]; }
// Get the next TextWord on the linked list.
TextWord *getNext() { return next; }
@@ -151,7 +151,7 @@
int getLength() { return len; }
const Unicode *getChar(int idx) { return &text[idx]; }
GooString *getText();
- GooString *getFontName() { return font->fontName; }
+ GooString *getFontName(int idx) { return font[idx]->fontName; }
void getColor(double *r, double *g, double *b)
{ *r = colorR; *g = colorG; *b = colorB; }
void getBBox(double *xMinA, double *yMinA, double *xMaxA, double *yMaxA)
@@ -184,13 +184,14 @@
int *charPos; // character position (within content stream)
// of each char (plus one extra entry for
// the last char)
- int len; // length of text/edge/charPos arrays
- int size; // size of text/edge/charPos arrays
- TextFontInfo *font; // font information
+ int len; // length of text/edge/charPos/font arrays
+ int size; // size of text/edge/charPos/font arrays
+ TextFontInfo **font; // font information for each char
double fontSize; // font size
GBool spaceAfter; // set if there is a space between this
// word and the next word on the line
TextWord *next; // next word in line
+ int wMode; // horizontal (0) or vertical (1) writing mode
#if TEXTOUT_WORD_LIST
double colorR, // word color
@@ -498,7 +499,7 @@
void updateFont(GfxState *state);
// Begin a new word.
- void beginWord(GfxState *state, double x0, double y0);
+ void beginWord(GfxState *state);
// Add a character to the current word.
void addChar(GfxState *state, double x, double y,
diff --git a/poppler/UTF.cc b/poppler/UTF.cc
new file mode 100644
index 0000000..42c7836
--- /dev/null
+++ b/poppler/UTF.cc
@@ -0,0 +1,116 @@
+//========================================================================
+//
+// UTF.h
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+//========================================================================
+//
+// Modified under the Poppler project - http://poppler.freedesktop.org
+//
+// All changes made under the Poppler project to this file are licensed
+// under GPL version 2 or later
+//
+// Copyright (C) 2008 Koji Otani <sho@bbr.jp>
+// Copyright (C) 2012 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2012 Hib Eris <hib@hiberis.nl>
+//
+// To see a description of the changes please see the Changelog file that
+// came with your tarball or type make ChangeLog if you are building from git
+//
+//========================================================================
+
+#include "goo/gmem.h"
+#include "PDFDocEncoding.h"
+#include "UTF.h"
+
+bool UnicodeIsValid(Unicode ucs4)
+{
+ return (ucs4 < 0x110000) &&
+ ((ucs4 & 0xfffff800) != 0xd800) &&
+ (ucs4 < 0xfdd0 || ucs4 > 0xfdef) &&
+ ((ucs4 & 0xfffe) != 0xfffe);
+}
+
+int UTF16toUCS4(const Unicode *utf16, int utf16Len, Unicode **ucs4)
+{
+ int i, n, len;
+ Unicode *u;
+
+ // count characters
+ len = 0;
+ for (i = 0; i < utf16Len; i++) {
+ if (utf16[i] >= 0xd800 && utf16[i] < 0xdc00 && i + 1 < utf16Len &&
+ utf16[i+1] >= 0xdc00 && utf16[i+1] < 0xe000) {
+ i++; /* surrogate pair */
+ }
+ len++;
+ }
+ if (ucs4 == NULL)
+ return len;
+
+ u = (Unicode*)gmallocn(len, sizeof(Unicode));
+ n = 0;
+ // convert string
+ for (i = 0; i < utf16Len; i++) {
+ if (utf16[i] >= 0xd800 && utf16[i] < 0xdc00) { /* surrogate pair */
+ if (i + 1 < utf16Len && utf16[i+1] >= 0xdc00 && utf16[i+1] < 0xe000) {
+ /* next code is a low surrogate */
+ u[n] = (((utf16[i] & 0x3ff) << 10) | (utf16[i+1] & 0x3ff)) + 0x10000;
+ ++i;
+ } else {
+ /* missing low surrogate
+ replace it with REPLACEMENT CHARACTER (U+FFFD) */
+ u[n] = 0xfffd;
+ }
+ } else if (utf16[i] >= 0xdc00 && utf16[i] < 0xe000) {
+ /* invalid low surrogate
+ replace it with REPLACEMENT CHARACTER (U+FFFD) */
+ u[n] = 0xfffd;
+ } else {
+ u[n] = utf16[i];
+ }
+ if (!UnicodeIsValid(u[n])) {
+ u[n] = 0xfffd;
+ }
+ n++;
+ }
+ *ucs4 = u;
+ return len;
+}
+
+int TextStringToUCS4(GooString *textStr, Unicode **ucs4)
+{
+ int i, len;
+ const char *s;
+ Unicode *u;
+
+ len = textStr->getLength();
+ s = textStr->getCString();
+ if (len == 0)
+ return 0;
+
+ if (textStr->hasUnicodeMarker()) {
+ Unicode *utf16;
+ len = len/2 - 1;
+ if (len > 0) {
+ utf16 = new Unicode[len];
+ for (i = 0 ; i < len; i++) {
+ utf16[i] = (s[2 + i*2] & 0xff) << 8 | (s[3 + i*2] & 0xff);
+ }
+ len = UTF16toUCS4(utf16, len, &u);
+ delete utf16;
+ } else {
+ u = NULL;
+ }
+ } else {
+ u = (Unicode*)gmallocn(len, sizeof(Unicode));
+ for (i = 0 ; i < len; i++) {
+ u[i] = pdfDocEncoding[s[i] & 0xff];
+ }
+ }
+ *ucs4 = u;
+ return len;
+}
diff --git a/poppler/UTF.h b/poppler/UTF.h
new file mode 100644
index 0000000..248c168
--- /dev/null
+++ b/poppler/UTF.h
@@ -0,0 +1,39 @@
+//========================================================================
+//
+// UTF.h
+//
+// This file is licensed under the GPLv2 or later
+//
+// Copyright (C) 2012 Adrian Johnson <ajohnson@redneon.com>
+//
+//========================================================================
+
+#ifndef UTF_H
+#define UTF_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include "goo/GooString.h"
+#include "CharTypes.h"
+
+// Convert a UTF-16 string to a UCS-4
+// utf16 - utf16 bytes
+// utf16_len - number of UTF-16 characters
+// ucs4_out - if not NULL, allocates and returns UCS-4 string. Free with gfree.
+// returns number of UCS-4 characters
+int UTF16toUCS4(const Unicode *utf16, int utf16_len, Unicode **ucs4_out);
+
+// Convert a PDF Text String to UCS-4
+// s - PDF text string
+// ucs4 - if the number of UCS-4 characters is > 0, allocates and
+// returns UCS-4 string. Free with gfree.
+// returns number of UCS-4 characters
+int TextStringToUCS4(GooString *textStr, Unicode **ucs4);
+
+// check if UCS-4 character is valid
+bool UnicodeIsValid(Unicode ucs4);
+
+
+#endif
diff --git a/poppler/XRef.cc b/poppler/XRef.cc
index b516a0f..81e939a 100644
--- a/poppler/XRef.cc
+++ b/poppler/XRef.cc
@@ -267,6 +267,10 @@
objStrs = new PopplerCache(5);
mainXRefEntriesOffset = 0;
xRefStream = gFalse;
+ scannedSpecialFlags = gFalse;
+ encrypted = gFalse;
+ permFlags = defPermFlags;
+ ownerPasswordOk = gFalse;
rootNum = -1;
}
@@ -276,6 +280,7 @@
XRef::XRef(Object *trailerDictA) {
init();
+
if (trailerDictA->isDict())
trailerDict.initDict(trailerDictA->getDict());
}
@@ -286,14 +291,10 @@
init();
mainXRefEntriesOffset = mainXRefEntriesOffsetA;
- encrypted = gFalse;
- permFlags = defPermFlags;
- ownerPasswordOk = gFalse;
-
// read the trailer
str = strA;
start = str->getStart();
- prevXRefOffset = pos;
+ prevXRefOffset = mainXRefOffset = pos;
if (reconstruct && !(ok = constructXRef(wasReconstructed)))
{
@@ -313,7 +314,7 @@
// read the xref table
} else {
std::vector<Guint> followedXRefStm;
- readXRef(&prevXRefOffset, &followedXRefStm);
+ readXRef(&prevXRefOffset, &followedXRefStm, NULL);
// if there was a problem with the xref table,
// try to reconstruct it
@@ -412,7 +413,7 @@
entries[i].offset = 0xffffffff;
entries[i].type = xrefEntryNone;
entries[i].obj.initNull ();
- entries[i].updated = false;
+ entries[i].flags = 0;
entries[i].gen = 0;
}
} else {
@@ -426,9 +427,20 @@
return size;
}
-// Read one xref table section. Also reads the associated trailer
-// dictionary, and returns the prev pointer (if any).
-GBool XRef::readXRef(Guint *pos, std::vector<Guint> *followedXRefStm) {
+/* Read one xref table section. Also reads the associated trailer
+ * dictionary, and returns the prev pointer (if any).
+ * Arguments:
+ * pos Points to a Guint containing the offset of the XRef
+ * section to be read. If a prev pointer is found, *pos is
+ * updated with its value
+ * followedXRefStm Used in case of nested readXRef calls to spot circular
+ * references in XRefStm pointers
+ * xrefStreamObjsNum If not NULL, every time a XRef stream is encountered,
+ * its object number is appended
+ * Return value:
+ * gTrue if a prev pointer is found, otherwise gFalse
+ */
+GBool XRef::readXRef(Guint *pos, std::vector<Guint> *followedXRefStm, std::vector<int> *xrefStreamObjsNum) {
Parser *parser;
Object obj;
GBool more;
@@ -444,10 +456,11 @@
// parse an old-style xref table
if (obj.isCmd("xref")) {
obj.free();
- more = readXRefTable(parser, pos, followedXRefStm);
+ more = readXRefTable(parser, pos, followedXRefStm, xrefStreamObjsNum);
// parse an xref stream
} else if (obj.isInt()) {
+ const int objNum = obj.getInt();
obj.free();
if (!parser->getObj(&obj, gTrue)->isInt()) {
goto err1;
@@ -463,6 +476,9 @@
if (trailerDict.isNone()) {
xRefStream = gTrue;
}
+ if (xrefStreamObjsNum) {
+ xrefStreamObjsNum->push_back(objNum);
+ }
more = readXRefStream(obj.getStream(), pos);
obj.free();
@@ -480,7 +496,7 @@
return gFalse;
}
-GBool XRef::readXRefTable(Parser *parser, Guint *pos, std::vector<Guint> *followedXRefStm) {
+GBool XRef::readXRefTable(Parser *parser, Guint *pos, std::vector<Guint> *followedXRefStm, std::vector<int> *xrefStreamObjsNum) {
XRefEntry entry;
GBool more;
Object obj, obj2;
@@ -523,7 +539,7 @@
}
entry.gen = obj.getInt();
entry.obj.initNull ();
- entry.updated = false;
+ entry.flags = 0;
obj.free();
parser->getObj(&obj, gTrue);
if (obj.isCmd("n")) {
@@ -597,7 +613,7 @@
}
if (ok) {
followedXRefStm->push_back(pos2);
- readXRef(&pos2, followedXRefStm);
+ readXRef(&pos2, followedXRefStm, xrefStreamObjsNum);
}
if (!ok) {
obj2.free();
@@ -945,6 +961,20 @@
encAlgorithm = encAlgorithmA;
}
+void XRef::getEncryptionParameters(Guchar **fileKeyA, CryptAlgorithm *encAlgorithmA,
+ int *keyLengthA) {
+ if (encrypted) {
+ *fileKeyA = fileKey;
+ *encAlgorithmA = encAlgorithm;
+ *keyLengthA = keyLength;
+ } else {
+ // null encryption parameters
+ *fileKeyA = NULL;
+ *encAlgorithmA = cryptRC4;
+ *keyLengthA = 0;
+ }
+}
+
GBool XRef::okToPrint(GBool ignoreOwnerPW) {
return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permPrint);
}
@@ -1064,7 +1094,7 @@
delete parser;
goto err;
}
- parser->getObj(obj, gFalse, encrypted ? fileKey : (Guchar *)NULL,
+ parser->getObj(obj, gFalse, (encrypted && !e->getFlag(XRefEntry::Unencrypted)) ? fileKey : NULL,
encAlgorithm, keyLength, num, gen, recursion);
obj1.free();
obj2.free();
@@ -1184,7 +1214,7 @@
entries[i].offset = 0xffffffff;
entries[i].type = xrefEntryFree;
entries[i].obj.initNull ();
- entries[i].updated = false;
+ entries[i].flags = 0;
entries[i].gen = 0;
}
size = num + 1;
@@ -1192,7 +1222,7 @@
XRefEntry *e = getEntry(num);
e->gen = gen;
e->obj.initNull ();
- e->updated = false;
+ e->flags = 0;
if (used) {
e->type = xrefEntryUncompressed;
e->offset = offs;
@@ -1210,7 +1240,7 @@
XRefEntry *e = getEntry(r.num);
e->obj.free();
o->copy(&(e->obj));
- e->updated = true;
+ e->setFlag(XRefEntry::Updated, gTrue);
}
Ref XRef::addIndirectObject (Object* o) {
@@ -1235,7 +1265,7 @@
}
e->type = xrefEntryUncompressed;
o->copy(&e->obj);
- e->updated = true;
+ e->setFlag(XRefEntry::Updated, gTrue);
Ref r;
r.num = entryIndexToUse;
@@ -1254,7 +1284,7 @@
e->obj.free();
e->type = xrefEntryFree;
e->gen++;
- e->updated = true;
+ e->setFlag(XRefEntry::Updated, gTrue);
}
void XRef::writeXRef(XRef::XRefWriter *writer, GBool writeAllEntries) {
@@ -1377,7 +1407,7 @@
entry->gen = obj2.getInt();
entry->type = obj3.isCmd("n") ? xrefEntryUncompressed : xrefEntryFree;
entry->obj.initNull ();
- entry->updated = false;
+ entry->flags = 0;
r = gTrue;
} else {
r = gFalse;
@@ -1389,6 +1419,50 @@
return r;
}
+/* Traverse all XRef tables and, if untilEntryNum != -1, stop as soon as
+ * untilEntryNum is found, or try to reconstruct the xref table if it's not
+ * present in any xref.
+ * If xrefStreamObjsNum is not NULL, it is filled with the list of the object
+ * numbers of the XRef streams that have been traversed */
+void XRef::readXRefUntil(int untilEntryNum, std::vector<int> *xrefStreamObjsNum)
+{
+ std::vector<Guint> followedPrev;
+ while (prevXRefOffset && (untilEntryNum == -1 || entries[untilEntryNum].type == xrefEntryNone)) {
+ bool followed = false;
+ for (size_t j = 0; j < followedPrev.size(); j++) {
+ if (followedPrev.at(j) == prevXRefOffset) {
+ followed = true;
+ break;
+ }
+ }
+ if (followed) {
+ error(errSyntaxError, -1, "Circular XRef");
+ if (!(ok = constructXRef(NULL))) {
+ errCode = errDamaged;
+ }
+ break;
+ }
+
+ followedPrev.push_back (prevXRefOffset);
+
+ std::vector<Guint> followedXRefStm;
+ if (!readXRef(&prevXRefOffset, &followedXRefStm, xrefStreamObjsNum)) {
+ prevXRefOffset = 0;
+ }
+
+ // if there was a problem with the xref table, or we haven't found the entry
+ // we were looking for, try to reconstruct the xref
+ if (!ok || (!prevXRefOffset && untilEntryNum != -1 && entries[untilEntryNum].type == xrefEntryNone)) {
+ GBool wasReconstructed = false;
+ if (!(ok = constructXRef(&wasReconstructed))) {
+ errCode = errDamaged;
+ break;
+ }
+ break;
+ }
+ }
+}
+
XRefEntry *XRef::getEntry(int i, GBool complainIfMissing)
{
if (entries[i].type == xrefEntryNone) {
@@ -1398,41 +1472,8 @@
error(errSyntaxError, -1, "Failed to parse XRef entry [{0:d}].", i);
}
} else {
- std::vector<Guint> followedPrev;
- while (prevXRefOffset && entries[i].type == xrefEntryNone) {
- bool followed = false;
- for (size_t j = 0; j < followedPrev.size(); j++) {
- if (followedPrev.at(j) == prevXRefOffset) {
- followed = true;
- break;
- }
- }
- if (followed) {
- error(errSyntaxError, -1, "Circular XRef");
- if (!(ok = constructXRef(NULL))) {
- errCode = errDamaged;
- }
- break;
- }
-
- followedPrev.push_back (prevXRefOffset);
-
- std::vector<Guint> followedXRefStm;
- if (!readXRef(&prevXRefOffset, &followedXRefStm)) {
- prevXRefOffset = 0;
- }
-
- // if there was a problem with the xref table,
- // try to reconstruct it
- if (!ok || (!prevXRefOffset && entries[i].type == xrefEntryNone)) {
- GBool wasReconstructed = false;
- if (!(ok = constructXRef(&wasReconstructed))) {
- errCode = errDamaged;
- break;
- }
- break;
- }
- }
+ // Read XRef tables until the entry we're looking for is found
+ readXRefUntil(i);
// We might have reconstructed the xref
// Check again i is in bounds
@@ -1441,7 +1482,7 @@
dummy.offset = 0;
dummy.gen = -1;
dummy.type = xrefEntryNone;
- dummy.updated = false;
+ dummy.flags = 0;
return &dummy;
}
@@ -1457,4 +1498,100 @@
return &entries[i];
}
+// Recursively sets the Unencrypted flag in all referenced xref entries
+void XRef::markUnencrypted(Object *obj) {
+ Object obj1;
+
+ switch (obj->getType()) {
+ case objArray:
+ {
+ Array *array = obj->getArray();
+ for (int i = 0; i < array->getLength(); i++) {
+ markUnencrypted(array->getNF(i, &obj1));
+ obj1.free();
+ }
+ break;
+ }
+ case objStream:
+ case objDict:
+ {
+ Dict *dict;
+ if (obj->getType() == objStream) {
+ Stream *stream = obj->getStream();
+ dict = stream->getDict();
+ } else {
+ dict = obj->getDict();
+ }
+ for (int i = 0; i < dict->getLength(); i++) {
+ markUnencrypted(dict->getValNF(i, &obj1));
+ obj1.free();
+ }
+ break;
+ }
+ case objRef:
+ {
+ Ref ref = obj->getRef();
+ XRefEntry *e = getEntry(ref.num);
+ if (e->getFlag(XRefEntry::Unencrypted))
+ return; // We've already been here: prevent infinite recursion
+ e->setFlag(XRefEntry::Unencrypted, gTrue);
+ fetch(ref.num, ref.gen, &obj1);
+ markUnencrypted(&obj1);
+ obj1.free();
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+void XRef::scanSpecialFlags() {
+ if (scannedSpecialFlags) {
+ return;
+ }
+ scannedSpecialFlags = gTrue;
+
+ // "Rewind" the XRef linked list, so that readXRefUntil re-reads all XRef
+ // tables/streams, even those that had already been parsed
+ prevXRefOffset = mainXRefOffset;
+
+ std::vector<int> xrefStreamObjNums;
+ readXRefUntil(-1 /* read all xref sections */, &xrefStreamObjNums);
+
+ // Mark object streams as DontRewrite, because we write each object
+ // individually in full rewrite mode.
+ for (int i = 0; i < size; ++i) {
+ if (entries[i].type == xrefEntryCompressed) {
+ const int objStmNum = entries[i].offset;
+ if (unlikely(objStmNum < 0 || objStmNum >= size)) {
+ error(errSyntaxError, -1, "Compressed object offset out of xref bounds");
+ } else {
+ getEntry(objStmNum)->setFlag(XRefEntry::DontRewrite, gTrue);
+ }
+ }
+ }
+
+ // Mark XRef streams objects as Unencrypted and DontRewrite
+ for (size_t i = 0; i < xrefStreamObjNums.size(); ++i) {
+ const int objNum = xrefStreamObjNums.at(i);
+ getEntry(objNum)->setFlag(XRefEntry::Unencrypted, gTrue);
+ getEntry(objNum)->setFlag(XRefEntry::DontRewrite, gTrue);
+ }
+
+ // Mark objects referred from the Encrypt dict as Unencrypted
+ Object obj;
+ markUnencrypted(trailerDict.dictLookupNF("Encrypt", &obj));
+ obj.free();
+}
+
+void XRef::markUnencrypted() {
+ // Mark objects referred from the Encrypt dict as Unencrypted
+ Object obj;
+ trailerDict.dictLookupNF("Encrypt", &obj);
+ if (obj.isRef()) {
+ XRefEntry *e = getEntry(obj.getRefNum());
+ e->setFlag(XRefEntry::Unencrypted, gTrue);
+ }
+ obj.free();
+}
diff --git a/poppler/XRef.h b/poppler/XRef.h
index 2add0a1..9af4a13 100644
--- a/poppler/XRef.h
+++ b/poppler/XRef.h
@@ -36,6 +36,7 @@
#include "goo/gtypes.h"
#include "Object.h"
+#include "Stream.h"
#include <vector>
@@ -59,8 +60,31 @@
Guint offset;
int gen;
XRefEntryType type;
- bool updated;
+ int flags;
Object obj; //if this entry was updated, obj will contains the updated object
+
+ enum Flag {
+ // Regular flags
+ Updated, // Entry was modified
+
+ // Special flags -- available only after xref->scanSpecialFlags() is run
+ Unencrypted, // Entry is stored in unencrypted form (meaningless in unencrypted documents)
+ DontRewrite // Entry must not be written back in case of full rewrite
+ };
+
+ inline GBool getFlag(Flag flag) {
+ const int mask = (1 << (int)flag);
+ return (flags & mask) != 0;
+ }
+
+ inline void setFlag(Flag flag, GBool value) {
+ const int mask = (1 << (int)flag);
+ if (value) {
+ flags |= mask;
+ } else {
+ flags &= ~mask;
+ }
+ }
};
class XRef {
@@ -90,6 +114,10 @@
Guchar *fileKeyA, int keyLengthA,
int encVersionA, int encRevisionA,
CryptAlgorithm encAlgorithmA);
+ // Mark Encrypt entry as Unencrypted
+ void markUnencrypted();
+
+ void getEncryptionParameters(Guchar **fileKeyA, CryptAlgorithm *encAlgorithmA, int *keyLengthA);
// Is the file encrypted?
GBool isEncrypted() { return encrypted; }
@@ -129,6 +157,14 @@
// Retuns the entry that belongs to the offset
int getNumEntry(Guint offset);
+ // Scans the document and sets special flags in all xref entries. One of those
+ // flags is Unencrypted, which affects how the object is fetched. Therefore,
+ // this function must be called before fetching unencrypted objects (e.g.
+ // Encrypt dictionary, XRef streams). Note that the code that initializes
+ // decryption doesn't need to call this function, because it runs before
+ // decryption is enabled, and therefore the Unencrypted flag is ignored.
+ void scanSpecialFlags();
+
// Direct access.
XRefEntry *getEntry(int i, GBool complainIfMissing = gTrue);
Object *getTrailerDict() { return &trailerDict; }
@@ -171,16 +207,20 @@
Guint prevXRefOffset; // position of prev XRef section (= next to read)
Guint mainXRefEntriesOffset; // offset of entries in main XRef table
GBool xRefStream; // true if last XRef section is a stream
+ Guint mainXRefOffset; // position of the main XRef table/stream
+ GBool scannedSpecialFlags; // true if scanSpecialFlags has been called
void init();
int reserve(int newSize);
int resize(int newSize);
- GBool readXRef(Guint *pos, std::vector<Guint> *followedXRefStm);
- GBool readXRefTable(Parser *parser, Guint *pos, std::vector<Guint> *followedXRefStm);
+ GBool readXRef(Guint *pos, std::vector<Guint> *followedXRefStm, std::vector<int> *xrefStreamObjsNum);
+ GBool readXRefTable(Parser *parser, Guint *pos, std::vector<Guint> *followedXRefStm, std::vector<int> *xrefStreamObjsNum);
GBool readXRefStreamSection(Stream *xrefStr, int *w, int first, int n);
GBool readXRefStream(Stream *xrefStr, Guint *pos);
GBool constructXRef(GBool *wasReconstructed, GBool needCatalogDict = gFalse);
GBool parseEntry(Guint offset, XRefEntry *entry);
+ void readXRefUntil(int untilEntryNum, std::vector<int> *xrefStreamObjsNum = NULL);
+ void markUnencrypted(Object *obj);
class XRefWriter {
public:
diff --git a/poppler/poppler-config.h.cmake b/poppler/poppler-config.h.cmake
index 382ca45..2425f6a 100644
--- a/poppler/poppler-config.h.cmake
+++ b/poppler/poppler-config.h.cmake
@@ -44,16 +44,6 @@
#cmakedefine TEXTOUT_WORD_LIST 1
#endif
-/* Use fontconfig font configuration backend */
-#ifndef WITH_FONTCONFIGURATION_FONTCONFIG
-#cmakedefine WITH_FONTCONFIGURATION_FONTCONFIG 1
-#endif
-
-/* Use win32 font configuration backend */
-#ifndef WITH_FONTCONFIGURATION_WIN32
-#cmakedefine WITH_FONTCONFIGURATION_WIN32 1
-#endif
-
/* Support for curl is compiled in. */
#ifndef POPPLER_HAS_CURL_SUPPORT
#cmakedefine POPPLER_HAS_CURL_SUPPORT 1
diff --git a/poppler/poppler-config.h.in b/poppler/poppler-config.h.in
index 0d8b379..5c56ea4 100644
--- a/poppler/poppler-config.h.in
+++ b/poppler/poppler-config.h.in
@@ -44,16 +44,6 @@
#undef TEXTOUT_WORD_LIST
#endif
-/* Use fontconfig font configuration backend */
-#ifndef WITH_FONTCONFIGURATION_FONTCONFIG
-#undef WITH_FONTCONFIGURATION_FONTCONFIG
-#endif
-
-/* Use win32 font configuration backend */
-#ifndef WITH_FONTCONFIGURATION_WIN32
-#undef WITH_FONTCONFIGURATION_WIN32
-#endif
-
/* Support for curl is compiled in. */
#ifndef POPPLER_HAS_CURL_SUPPORT
#undef POPPLER_HAS_CURL_SUPPORT
diff --git a/qt4/demos/Makefile.am b/qt4/demos/Makefile.am
index 155fc1c..3cadda9 100644
--- a/qt4/demos/Makefile.am
+++ b/qt4/demos/Makefile.am
@@ -4,13 +4,11 @@
-I$(top_srcdir) \
-I$(top_srcdir)/poppler \
-I$(top_srcdir)/qt4/src \
- $(FONTCONFIG_CFLAGS) \
$(POPPLER_QT4_CFLAGS)
LDADDS = \
$(top_builddir)/poppler/libpoppler.la \
$(top_builddir)/qt4/src/libpoppler-qt4.la \
- $(FONTCONFIG_LIBS) \
$(POPPLER_QT4_LIBS)
SUFFIXES: .moc
diff --git a/qt4/src/CMakeLists.txt b/qt4/src/CMakeLists.txt
index 8b6edaa..c06730b 100644
--- a/qt4/src/CMakeLists.txt
+++ b/qt4/src/CMakeLists.txt
@@ -30,7 +30,7 @@
)
qt4_automoc(${poppler_qt4_SRCS})
add_library(poppler-qt4 SHARED ${poppler_qt4_SRCS})
-set_target_properties(poppler-qt4 PROPERTIES VERSION 4.0.0 SOVERSION 4)
+set_target_properties(poppler-qt4 PROPERTIES VERSION 4.1.0 SOVERSION 4)
target_link_libraries(poppler-qt4 poppler ${QT4_QTCORE_LIBRARY} ${QT4_QTGUI_LIBRARY} ${QT4_QTXML_LIBRARY})
if(MSVC)
target_link_libraries(poppler-qt4 poppler ${poppler_LIBS})
diff --git a/qt4/src/Doxyfile b/qt4/src/Doxyfile
index c356ebd..85673f4 100644
--- a/qt4/src/Doxyfile
+++ b/qt4/src/Doxyfile
@@ -31,7 +31,7 @@
# This could be handy for archiving the generated documentation or
# if some version control system is used.
-PROJECT_NUMBER = 0.20.5
+PROJECT_NUMBER = 0.21.0
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
# base path where the generated documentation will be put.
diff --git a/qt4/src/Makefile.am b/qt4/src/Makefile.am
index 22033e3..b91daf0 100644
--- a/qt4/src/Makefile.am
+++ b/qt4/src/Makefile.am
@@ -1,7 +1,6 @@
INCLUDES = \
-I$(top_srcdir) \
-I$(top_srcdir)/poppler \
- $(FONTCONFIG_CFLAGS) \
$(POPPLER_QT4_CFLAGS) \
$(LCMS_CFLAGS)
@@ -60,10 +59,9 @@
libpoppler_qt4_la_LIBADD = \
$(top_builddir)/poppler/libpoppler.la \
$(top_builddir)/poppler/libpoppler-arthur.la \
- $(FONTCONFIG_LIBS) \
$(POPPLER_QT4_LIBS)
-libpoppler_qt4_la_LDFLAGS = -version-info 4:0:0 @create_shared_lib@ @auto_import_flags@
+libpoppler_qt4_la_LDFLAGS = -version-info 5:0:1 @create_shared_lib@ @auto_import_flags@
# This rule lets GNU make create any *.moc from the equivalent *.h
.h.moc:
diff --git a/qt4/src/poppler-annotation-private.h b/qt4/src/poppler-annotation-private.h
index 2ee7d77..3bfb5da 100644
--- a/qt4/src/poppler-annotation-private.h
+++ b/qt4/src/poppler-annotation-private.h
@@ -1,7 +1,8 @@
-/* poppler-link-extractor-private.h: qt interface to poppler
+/* poppler-annotation-private.h: qt interface to poppler
* Copyright (C) 2007, Pino Toscano <pino@kde.org>
* Copyright (C) 2012, Tobias Koenig <tokoe@kdab.com>
* Copyright (C) 2012, Fabio D'Urso <fabiodurso@hotmail.it>
+ * Copyright (C) 2012, Albert Astals Cid <aacid@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -31,6 +32,7 @@
class Annot;
class AnnotPath;
+class Link;
class Page;
class PDFRectangle;
@@ -100,6 +102,8 @@
static void removeAnnotationFromPage(::Page *pdfPage, const Annotation * ann);
Ref pdfObjectReference() const;
+
+ Link* additionalAction( Annotation::AdditionalActionType type ) const;
};
}
diff --git a/qt4/src/poppler-annotation.cc b/qt4/src/poppler-annotation.cc
index 67dbbae..5ecea80 100644
--- a/qt4/src/poppler-annotation.cc
+++ b/qt4/src/poppler-annotation.cc
@@ -3,6 +3,7 @@
* Copyright (C) 2006, 2008, 2010 Pino Toscano <pino@kde.org>
* Copyright (C) 2012, Guillermo A. Amaral B. <gamaral@kde.org>
* Copyright (C) 2012, Fabio D'Urso <fabiodurso@hotmail.it>
+ * Copyright (C) 2012, Tobias Koenig <tokoe@kdab.com>
* Adapting code from
* Copyright (C) 2004 by Enrico Ros <eros.kde@email.it>
*
@@ -42,6 +43,7 @@
#include <Gfx.h>
#include <Error.h>
#include <FileSpec.h>
+#include <Link.h>
/* Almost all getters directly query the underlying poppler annotation, with
* the exceptions of link, file attachment, sound, movie and screen annotations,
@@ -455,7 +457,8 @@
case Annot::typeUnknown:
continue; // special case for ignoring unknown annotations
case Annot::typeWidget:
- continue; // handled as forms or some other way
+ annotation = new WidgetAnnotation();
+ break;
default:
{
#define CASE_FOR_TYPE( thetype ) \
@@ -493,6 +496,40 @@
return pdfAnnot->getRef();
}
+Link* AnnotationPrivate::additionalAction( Annotation::AdditionalActionType type ) const
+{
+ if ( pdfAnnot->getType() != Annot::typeScreen && pdfAnnot->getType() != Annot::typeWidget )
+ return 0;
+
+ Annot::AdditionalActionsType actionType = Annot::actionCursorEntering;
+ switch ( type )
+ {
+ case Annotation::CursorEnteringAction: actionType = Annot::actionCursorEntering; break;
+ case Annotation::CursorLeavingAction: actionType = Annot::actionCursorLeaving; break;
+ case Annotation::MousePressedAction: actionType = Annot::actionMousePressed; break;
+ case Annotation::MouseReleasedAction: actionType = Annot::actionMouseReleased; break;
+ case Annotation::FocusInAction: actionType = Annot::actionFocusIn; break;
+ case Annotation::FocusOutAction: actionType = Annot::actionFocusOut; break;
+ case Annotation::PageOpeningAction: actionType = Annot::actionPageOpening; break;
+ case Annotation::PageClosingAction: actionType = Annot::actionPageClosing; break;
+ case Annotation::PageVisibleAction: actionType = Annot::actionPageVisible; break;
+ case Annotation::PageInvisibleAction: actionType = Annot::actionPageInvisible; break;
+ }
+
+ ::LinkAction *linkAction = 0;
+ if ( pdfAnnot->getType() == Annot::typeScreen )
+ linkAction = static_cast<AnnotScreen*>( pdfAnnot )->getAdditionalAction( actionType );
+ else
+ linkAction = static_cast<AnnotWidget*>( pdfAnnot )->getAdditionalAction( actionType );
+
+ Link *link = 0;
+
+ if ( linkAction )
+ link = PageData::convertLinkActionToLink( linkAction, parentDoc, QRectF() );
+
+ return link;
+}
+
void AnnotationPrivate::addAnnotationToPage(::Page *pdfPage, DocumentData *doc, const Annotation * ann)
{
if (ann->d_ptr->pdfAnnot != 0)
@@ -522,14 +559,6 @@
return;
}
- // Remove popup window
- AnnotMarkup *markupann = dynamic_cast<AnnotMarkup*>(ann->d_ptr->pdfAnnot);
- if (markupann && markupann->getPopup())
- pdfPage->removeAnnot(markupann->getPopup());
-
- // Remove appearance streams (if any)
- ann->d_ptr->pdfAnnot->invalidateAppearance();
-
// Remove annotation
pdfPage->removeAnnot(ann->d_ptr->pdfAnnot);
@@ -4269,6 +4298,64 @@
d->title = title;
}
+Link* ScreenAnnotation::additionalAction( AdditionalActionType type ) const
+{
+ Q_D( const ScreenAnnotation );
+ return d->additionalAction( type );
+}
+
+/** WidgetAnnotation [Annotation] */
+class WidgetAnnotationPrivate : public AnnotationPrivate
+{
+ public:
+ Annotation * makeAlias();
+ Annot* createNativeAnnot(::Page *destPage, DocumentData *doc);
+};
+
+Annotation * WidgetAnnotationPrivate::makeAlias()
+{
+ return new WidgetAnnotation(*this);
+}
+
+Annot* WidgetAnnotationPrivate::createNativeAnnot(::Page *destPage, DocumentData *doc)
+{
+ return 0; // Not implemented
+}
+
+WidgetAnnotation::WidgetAnnotation(WidgetAnnotationPrivate &dd)
+ : Annotation( dd )
+{}
+
+WidgetAnnotation::WidgetAnnotation()
+ : Annotation( *new WidgetAnnotationPrivate() )
+{
+}
+
+WidgetAnnotation::~WidgetAnnotation()
+{
+}
+
+void WidgetAnnotation::store( QDomNode & node, QDomDocument & document ) const
+{
+ // store base annotation properties
+ storeBaseAnnotationProperties( node, document );
+
+ // create [widget] element
+ QDomElement widgetElement = document.createElement( "widget" );
+ node.appendChild( widgetElement );
+}
+
+Annotation::SubType WidgetAnnotation::subType() const
+{
+ return AWidget;
+}
+
+Link* WidgetAnnotation::additionalAction( AdditionalActionType type ) const
+{
+ Q_D( const WidgetAnnotation );
+ return d->additionalAction( type );
+}
+
//BEGIN utility annotation functions
QColor convertAnnotColor( AnnotColor *color )
{
diff --git a/qt4/src/poppler-annotation.h b/qt4/src/poppler-annotation.h
index e511ec0..9208ca7 100644
--- a/qt4/src/poppler-annotation.h
+++ b/qt4/src/poppler-annotation.h
@@ -55,6 +55,7 @@
class SoundAnnotationPrivate;
class MovieAnnotationPrivate;
class ScreenAnnotationPrivate;
+class WidgetAnnotationPrivate;
class EmbeddedFile;
class Link;
class SoundObject;
@@ -106,13 +107,14 @@
{
friend class AnnotationUtils;
friend class LinkMovie;
+ friend class LinkRendition;
public:
// enum definitions
// WARNING!!! oKular uses that very same values so if you change them notify the author!
enum SubType { AText = 1, ALine = 2, AGeom = 3, AHighlight = 4, AStamp = 5,
AInk = 6, ALink = 7, ACaret = 8, AFileAttachment = 9, ASound = 10,
- AMovie = 11, AScreen = 12 /** \since 0.20 */, A_BASE = 0 };
+ AMovie = 11, AScreen = 12 /** \since 0.20 */, AWidget = 13 /** \since 0.22 */, A_BASE = 0 };
enum Flag { Hidden = 1, FixedSize = 2, FixedRotation = 4, DenyPrint = 8,
DenyWrite = 16, DenyDelete = 32, ToggleHidingOnMouse = 64, External = 128 };
enum LineStyle { Solid = 1, Dashed = 2, Beveled = 4, Inset = 8, Underline = 16 };
@@ -272,6 +274,28 @@
*/
virtual ~Annotation();
+ /**
+ * Describes the flags from an annotations 'AA' dictionary.
+ *
+ * This flag is used by the additionalAction() method for ScreenAnnotation
+ * and WidgetAnnotation.
+ *
+ * \since 0.22
+ */
+ enum AdditionalActionType
+ {
+ CursorEnteringAction, ///< Performed when the cursor enters the annotation's active area
+ CursorLeavingAction, ///< Performed when the cursor exists the annotation's active area
+ MousePressedAction, ///< Performed when the mouse button is pressed inside the annotation's active area
+ MouseReleasedAction, ///< Performed when the mouse button is released inside the annotation's active area
+ FocusInAction, ///< Performed when the annotation receives the input focus
+ FocusOutAction, ///< Performed when the annotation loses the input focus
+ PageOpeningAction, ///< Performed when the page containing the annotation is opened
+ PageClosingAction, ///< Performed when the page containing the annotation is closed
+ PageVisibleAction, ///< Performed when the page containing the annotation becomes visible
+ PageInvisibleAction ///< Performed when the page containing the annotation becomes invisible
+ };
+
protected:
/// \cond PRIVATE
Annotation( AnnotationPrivate &dd );
@@ -840,6 +864,14 @@
*/
void setScreenTitle( const QString &title );
+ /**
+ * Returns the additional action of the given @p type fo the annotation or
+ * @c 0 if no action has been defined.
+ *
+ * \since 0.22
+ */
+ Link* additionalAction( AdditionalActionType type ) const;
+
private:
ScreenAnnotation();
ScreenAnnotation( ScreenAnnotationPrivate &dd );
@@ -848,6 +880,41 @@
Q_DISABLE_COPY( ScreenAnnotation )
};
+/**
+ * \short Widget annotation.
+ *
+ * The widget annotation represents a widget (form field) on a page.
+ *
+ * \note This class is just provided for consistency of the annotation API,
+ * use the FormField classes to get all the form-related information.
+ *
+ * \since 0.22
+ */
+class POPPLER_QT4_EXPORT WidgetAnnotation : public Annotation
+{
+ friend class AnnotationPrivate;
+
+ public:
+ virtual ~WidgetAnnotation();
+
+ virtual SubType subType() const;
+
+ /**
+ * Returns the additional action of the given @p type fo the annotation or
+ * @c 0 if no action has been defined.
+ *
+ * \since 0.22
+ */
+ Link* additionalAction( AdditionalActionType type ) const;
+
+ private:
+ WidgetAnnotation();
+ WidgetAnnotation( WidgetAnnotationPrivate &dd );
+ virtual void store( QDomNode &parentNode, QDomDocument &document ) const; // stub
+ Q_DECLARE_PRIVATE( WidgetAnnotation )
+ Q_DISABLE_COPY( WidgetAnnotation )
+};
+
}
#endif
diff --git a/qt4/src/poppler-document.cc b/qt4/src/poppler-document.cc
index e89b51e..ee56ed6 100644
--- a/qt4/src/poppler-document.cc
+++ b/qt4/src/poppler-document.cc
@@ -5,6 +5,8 @@
* Copyright (C) 2006-2010, Pino Toscano <pino@kde.org>
* Copyright (C) 2010, 2011 Hib Eris <hib@hiberis.nl>
* Copyright (C) 2012 Koji Otani <sho@bbr.jp>
+ * Copyright (C) 2012 Thomas Freitag <Thomas.Freitag@alfa.de>
+ * Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -519,14 +521,20 @@
void Document::setRenderHint( Document::RenderHint hint, bool on )
{
+ const bool touchesAntialias = hint & ( Document::Antialiasing | Document::TextAntialiasing | Document::TextHinting );
+ const bool touchesOverprinting = hint & Document::OverprintPreview;
+
+ int hintForOperation = hint;
+ if (touchesOverprinting && !isOverprintPreviewAvailable())
+ hintForOperation = hintForOperation & ~(int)Document::OverprintPreview;
+
if ( on )
- m_doc->m_hints |= hint;
+ m_doc->m_hints |= hintForOperation;
else
- m_doc->m_hints &= ~(int)hint;
+ m_doc->m_hints &= ~hintForOperation;
// the only way to set antialiasing for Splash is on creation
- if ( m_doc->m_backend == Document::SplashBackend &&
- ( hint & ( Document::Antialiasing | Document::TextAntialiasing | Document::TextHinting ) ) )
+ if ( m_doc->m_backend == Document::SplashBackend && (touchesAntialias || touchesOverprinting) )
{
delete m_doc->m_outputDev;
m_doc->m_outputDev = NULL;
@@ -605,6 +613,21 @@
return true;
}
+ Document::FormType Document::formType() const
+ {
+ switch ( m_doc->doc->getCatalog()->getFormType() )
+ {
+ case Catalog::NoForm:
+ return Document::NoForm;
+ case Catalog::AcroForm:
+ return Document::AcroForm;
+ case Catalog::XfaForm:
+ return Document::XfaForm;
+ }
+
+ return Document::NoForm; // make gcc happy
+ }
+
QDateTime convertDate( char *dateString )
{
int year, mon, day, hour, min, sec, tzHours, tzMins;
@@ -645,4 +668,12 @@
#endif
}
+ bool isOverprintPreviewAvailable() {
+#if defined(SPLASH_CMYK)
+ return true;
+#else
+ return false;
+#endif
+ }
+
}
diff --git a/qt4/src/poppler-form.cc b/qt4/src/poppler-form.cc
index 82309ff..a5e5adf 100644
--- a/qt4/src/poppler-form.cc
+++ b/qt4/src/poppler-form.cc
@@ -2,6 +2,7 @@
* Copyright (C) 2007-2008, 2011, Pino Toscano <pino@kde.org>
* Copyright (C) 2008, 2011, 2012 Albert Astals Cid <aacid@kde.org>
* Copyright (C) 2011 Carlos Garcia Campos <carlosgc@gnome.org>
+ * Copyright (C) 2012, Adam Reichold <adamreichold@myopera.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -226,13 +227,20 @@
QList<int> FormFieldButton::siblings() const
{
FormWidgetButton* fwb = static_cast<FormWidgetButton*>(m_formData->fm);
+ ::FormFieldButton* ffb = static_cast< ::FormFieldButton* >(fwb->getField());
if (fwb->getButtonType() == formButtonPush)
return QList<int>();
QList<int> ret;
- unsigned *sibls = fwb->getSiblingsID();
- for (int i = 0; i < fwb->getNumSiblingsID(); ++i)
- ret.append(sibls[i]);
+ for (int i = 0; i < ffb->getNumSiblings(); ++i)
+ {
+ ::FormFieldButton* sibling = static_cast< ::FormFieldButton* >(ffb->getSibling(i));
+ for (int j = 0; j < sibling->getNumWidgets(); ++j)
+ {
+ FormWidget *w = sibling->getWidget(j);
+ if (w) ret.append(w->getID());
+ }
+ }
return ret;
}
@@ -372,6 +380,28 @@
fwc->select( choice.at( i ) );
}
+QString FormFieldChoice::editChoice() const
+{
+ FormWidgetChoice* fwc = static_cast<FormWidgetChoice*>(m_formData->fm);
+
+ if ( fwc->isCombo() && fwc->hasEdit() )
+ return UnicodeParsedString(fwc->getEditChoice());
+ else
+ return QString();
+}
+
+void FormFieldChoice::setEditChoice(const QString& text)
+{
+ FormWidgetChoice* fwc = static_cast<FormWidgetChoice*>(m_formData->fm);
+
+ if ( fwc->isCombo() && fwc->hasEdit() )
+ {
+ GooString* goo = QStringToUnicodeGooString( text );
+ fwc->setEditChoice( goo );
+ delete goo;
+ }
+}
+
Qt::Alignment FormFieldChoice::textAlignment() const
{
return formTextAlignment(m_formData->fm);
diff --git a/qt4/src/poppler-form.h b/qt4/src/poppler-form.h
index 9af367b..79ed393 100644
--- a/qt4/src/poppler-form.h
+++ b/qt4/src/poppler-form.h
@@ -1,6 +1,7 @@
/* poppler-form.h: qt4 interface to poppler
* Copyright (C) 2007-2008, Pino Toscano <pino@kde.org>
* Copyright (C) 2008, 2011, Albert Astals Cid <aacid@kde.org>
+ * Copyright (C) 2012, Adam Reichold <adamreichold@myopera.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -305,6 +306,20 @@
Sets the selected choices to \p choice.
*/
void setCurrentChoices( const QList<int> &choice );
+
+ /**
+ The text entered into an editable combo box choice field. Otherwise a null string.
+
+ \since 0.22
+ */
+ QString editChoice() const;
+
+ /**
+ Sets the text entered into an editable combo box choice field. Otherwise does nothing.
+
+ \since 0.22
+ */
+ void setEditChoice(const QString& text);
/**
The horizontal alignment for the text of this text field.
diff --git a/qt4/src/poppler-link.cc b/qt4/src/poppler-link.cc
index a4bc55b..199e2db 100644
--- a/qt4/src/poppler-link.cc
+++ b/qt4/src/poppler-link.cc
@@ -168,16 +168,40 @@
class LinkRenditionPrivate : public LinkPrivate
{
public:
- LinkRenditionPrivate( const QRectF &area, ::MediaRendition *rendition );
+ LinkRenditionPrivate( const QRectF &area, ::MediaRendition *rendition, ::LinkRendition::RenditionOperation operation, const QString &script, const Ref &annotationReference );
~LinkRenditionPrivate();
MediaRendition *rendition;
+ LinkRendition::RenditionAction action;
+ QString script;
+ Ref annotationReference;
};
- LinkRenditionPrivate::LinkRenditionPrivate( const QRectF &area, ::MediaRendition *r )
+ LinkRenditionPrivate::LinkRenditionPrivate( const QRectF &area, ::MediaRendition *r, ::LinkRendition::RenditionOperation operation, const QString &javaScript, const Ref &ref )
: LinkPrivate( area )
- , rendition( new MediaRendition( r ) )
+ , rendition( r ? new MediaRendition( r ) : 0 )
+ , action( LinkRendition::PlayRendition )
+ , script( javaScript )
+ , annotationReference( ref )
{
+ switch ( operation )
+ {
+ case ::LinkRendition::NoRendition:
+ action = LinkRendition::NoRendition;
+ break;
+ case ::LinkRendition::PlayRendition:
+ action = LinkRendition::PlayRendition;
+ break;
+ case ::LinkRendition::StopRendition:
+ action = LinkRendition::StopRendition;
+ break;
+ case ::LinkRendition::PauseRendition:
+ action = LinkRendition::PauseRendition;
+ break;
+ case ::LinkRendition::ResumeRendition:
+ action = LinkRendition::ResumeRendition;
+ break;
+ }
}
LinkRenditionPrivate::~LinkRenditionPrivate()
@@ -579,10 +603,15 @@
// LinkRendition
LinkRendition::LinkRendition( const QRectF &linkArea, ::MediaRendition *rendition )
- : Link( *new LinkRenditionPrivate( linkArea, rendition ) )
+ : Link( *new LinkRenditionPrivate( linkArea, rendition, ::LinkRendition::NoRendition, QString(), Ref() ) )
{
}
+ LinkRendition::LinkRendition( const QRectF &linkArea, ::MediaRendition *rendition, int operation, const QString &script, const Ref &annotationReference )
+ : Link( *new LinkRenditionPrivate( linkArea, rendition, static_cast<enum ::LinkRendition::RenditionOperation>(operation), script, annotationReference ) )
+ {
+ }
+
LinkRendition::~LinkRendition()
{
}
@@ -598,6 +627,29 @@
return d->rendition;
}
+ LinkRendition::RenditionAction LinkRendition::action() const
+ {
+ Q_D( const LinkRendition );
+ return d->action;
+ }
+
+ QString LinkRendition::script() const
+ {
+ Q_D( const LinkRendition );
+ return d->script;
+ }
+
+ bool LinkRendition::isReferencedAnnotation( const ScreenAnnotation *annotation ) const
+ {
+ Q_D( const LinkRendition );
+ if ( d->annotationReference.num != -1 && d->annotationReference == annotation->d_ptr->pdfObjectReference() )
+ {
+ return true;
+ }
+
+ return false;
+ }
+
// LinkJavaScript
LinkJavaScript::LinkJavaScript( const QRectF &linkArea, const QString &js )
: Link( *new LinkJavaScriptPrivate( linkArea ) )
diff --git a/qt4/src/poppler-link.h b/qt4/src/poppler-link.h
index a2ef2d3..ef93bf0 100644
--- a/qt4/src/poppler-link.h
+++ b/qt4/src/poppler-link.h
@@ -455,12 +455,40 @@
{
public:
/**
- * Create a new media rendition link.
+ * Describes the possible rendition actions.
+ *
+ * \since 0.22
+ */
+ enum RenditionAction {
+ NoRendition,
+ PlayRendition,
+ StopRendition,
+ PauseRendition,
+ ResumeRendition
+ };
+
+ /**
+ * Create a new rendition link.
*
* \param linkArea the active area of the link
- * \param rendition
+ * \param rendition the media rendition object
+ *
+ * \deprecated Use the constructor that takes all parameter instead
*/
- LinkRendition( const QRectF &linkArea, ::MediaRendition *rendition );
+ Q_DECL_DEPRECATED LinkRendition( const QRectF &linkArea, ::MediaRendition *rendition );
+
+ /**
+ * Create a new rendition link.
+ *
+ * \param linkArea the active area of the link
+ * \param rendition the media rendition object
+ * \param operation the numeric operation (action) (@see ::LinkRendition::RenditionOperation)
+ * \param script the java script code
+ * \param annotationReference the object reference of the screen annotation associated with this rendition action
+ * \since 0.22
+ */
+ LinkRendition( const QRectF &linkArea, ::MediaRendition *rendition, int operation, const QString &script, const Ref &annotationReference );
+
/**
* Destructor.
*/
@@ -469,10 +497,31 @@
LinkType linkType() const;
/**
- *
+ * Returns the media rendition object if the redition provides one, @c 0 otherwise
*/
MediaRendition *rendition() const;
+ /**
+ * Returns the action that should be executed if a rendition object is provided.
+ *
+ * \since 0.22
+ */
+ RenditionAction action() const;
+
+ /**
+ * The JS code that shall be executed or an empty string.
+ *
+ * \since 0.22
+ */
+ QString script() const;
+
+ /**
+ * Returns whether the given @p annotation is the referenced screen annotation for this rendition @p link.
+ *
+ * \since 0.22
+ */
+ bool isReferencedAnnotation( const ScreenAnnotation *annotation ) const;
+
private:
Q_DECLARE_PRIVATE( LinkRendition )
Q_DISABLE_COPY( LinkRendition )
diff --git a/qt4/src/poppler-movie.cc b/qt4/src/poppler-movie.cc
index 869e381..a64847c 100644
--- a/qt4/src/poppler-movie.cc
+++ b/qt4/src/poppler-movie.cc
@@ -2,6 +2,7 @@
* Copyright (C) 2008, 2010, Pino Toscano <pino@kde.org>
* Copyright (C) 2008, Albert Astals Cid <aacid@kde.org>
* Copyright (C) 2010, Carlos Garcia Campos <carlosgc@gnome.org>
+ * Copyright (C) 2012, Tobias Koenig <tobias.koenig@kdab.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,6 +25,8 @@
#include "Annot.h"
#include "Movie.h"
+#include <QtGui/QImage>
+
namespace Poppler
{
@@ -43,6 +46,7 @@
Movie *m_movieObj;
QSize m_size;
int m_rotation;
+ QImage m_posterImage;
MovieObject::PlayMode m_playMode : 3;
bool m_showControls : 1;
};
@@ -51,6 +55,7 @@
{
m_movieData = new MovieData();
m_movieData->m_movieObj = ann->getMovie()->copy();
+ //TODO: copy poster image
MovieActivationParameters *mp = m_movieData->m_movieObj->getActivationParameters();
int width, height;
@@ -92,4 +97,14 @@
return m_movieData->m_playMode;
}
+bool MovieObject::showPosterImage() const
+{
+ return (m_movieData->m_movieObj->getShowPoster() == gTrue);
+}
+
+QImage MovieObject::posterImage() const
+{
+ return m_movieData->m_posterImage;
+}
+
}
diff --git a/qt4/src/poppler-page-private.h b/qt4/src/poppler-page-private.h
index ecdca17..91955e0 100644
--- a/qt4/src/poppler-page-private.h
+++ b/qt4/src/poppler-page-private.h
@@ -1,6 +1,6 @@
/* poppler-page.cc: qt interface to poppler
* Copyright (C) 2005, Net Integration Technologies, Inc.
- * Copyright (C) 2007, Albert Astals Cid <aacid@kde.org>
+ * Copyright (C) 2007, 2012, Albert Astals Cid <aacid@kde.org>
* Copyright (C) 2008, Pino Toscano <pino@kde.org>
*
* This program is free software; you can redistribute it and/or modify
@@ -21,10 +21,13 @@
#ifndef _POPPLER_PAGE_PRIVATE_H_
#define _POPPLER_PAGE_PRIVATE_H_
+#include "CharTypes.h"
+
class QRectF;
class LinkAction;
class Page;
+class TextPage;
namespace Poppler
{
@@ -42,6 +45,8 @@
PageTransition *transition;
static Link* convertLinkActionToLink(::LinkAction * a, DocumentData *parentDoc, const QRectF &linkArea);
+
+ TextPage *prepareTextSearch(const QString &text, Page::SearchMode caseSensitive, Page::Rotation rotate, GBool *sCase, QVector<Unicode> *u);
};
}
diff --git a/qt4/src/poppler-page.cc b/qt4/src/poppler-page.cc
index 6a16d03..5475614 100644
--- a/qt4/src/poppler-page.cc
+++ b/qt4/src/poppler-page.cc
@@ -1,7 +1,7 @@
/* poppler-page.cc: qt interface to poppler
* Copyright (C) 2005, Net Integration Technologies, Inc.
* Copyright (C) 2005, Brad Hards <bradh@frogmouth.net>
- * Copyright (C) 2005-2011, Albert Astals Cid <aacid@kde.org>
+ * Copyright (C) 2005-2012, Albert Astals Cid <aacid@kde.org>
* Copyright (C) 2005, Stefan Kebekus <stefan.kebekus@math.uni-koeln.de>
* Copyright (C) 2006-2011, Pino Toscano <pino@kde.org>
* Copyright (C) 2008 Carlos Garcia Campos <carlosgc@gnome.org>
@@ -12,6 +12,8 @@
* Copyright (C) 2010 Hib Eris <hib@hiberis.nl>
* Copyright (C) 2012 Tobias Koenig <tokoe@kdab.com>
* Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
+ * Copyright (C) 2012 Adam Reichold <adamreichold@myopera.com>
+ * Copyright (C) 2012 Thomas Freitag <Thomas.Freitag@alfa.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -196,7 +198,13 @@
case actionRendition:
{
::LinkRendition *lrn = (::LinkRendition *)a;
- popplerLink = new LinkRendition( linkArea, lrn->getMedia() );
+
+ Ref reference;
+ reference.num = reference.gen = -1;
+ if ( lrn->hasScreenAnnot() )
+ reference = lrn->getScreenAnnot();
+
+ popplerLink = new LinkRendition( linkArea, lrn->getMedia(), lrn->getOperation(), UnicodeParsedString( lrn->getScript() ), reference );
}
break;
@@ -207,6 +215,25 @@
return popplerLink;
}
+TextPage *PageData::prepareTextSearch(const QString &text, Page::SearchMode caseSensitive, Page::Rotation rotate, GBool *sCase, QVector<Unicode> *u)
+{
+ const QChar * str = text.unicode();
+ const int len = text.length();
+ u->resize(len);
+ for (int i = 0; i < len; ++i) (*u)[i] = str[i].unicode();
+
+ if (caseSensitive == Page::CaseSensitive) *sCase = gTrue;
+ else *sCase = gFalse;
+
+ const int rotation = (int)rotate * 90;
+
+ // fetch ourselves a textpage
+ TextOutputDev td(NULL, gTrue, 0, gFalse, gFalse);
+ parentDoc->doc->displayPage( &td, index + 1, 72, 72, rotation, false, true, false );
+ TextPage *textPage=td.takeText();
+
+ return textPage;
+}
Page::Page(DocumentData *doc, int index) {
m_page = new PageData();
@@ -240,27 +267,30 @@
int bw = bitmap->getWidth();
int bh = bitmap->getHeight();
- SplashColorPtr dataPtr = splash_output->getBitmap()->getDataPtr();
-
- if (QSysInfo::BigEndian == QSysInfo::ByteOrder)
+ if (bitmap->convertToXBGR())
{
- uchar c;
- int count = bw * bh * 4;
- for (int k = 0; k < count; k += 4)
+ SplashColorPtr dataPtr = bitmap->getDataPtr();
+
+ if (QSysInfo::BigEndian == QSysInfo::ByteOrder)
{
- c = dataPtr[k];
- dataPtr[k] = dataPtr[k+3];
- dataPtr[k+3] = c;
+ uchar c;
+ int count = bw * bh * 4;
+ for (int k = 0; k < count; k += 4)
+ {
+ c = dataPtr[k];
+ dataPtr[k] = dataPtr[k+3];
+ dataPtr[k+3] = c;
- c = dataPtr[k+1];
- dataPtr[k+1] = dataPtr[k+2];
- dataPtr[k+2] = c;
+ c = dataPtr[k+1];
+ dataPtr[k+1] = dataPtr[k+2];
+ dataPtr[k+2] = c;
+ }
}
- }
- // construct a qimage SHARING the raw bitmap data in memory
- QImage tmpimg( dataPtr, bw, bh, QImage::Format_ARGB32 );
- img = tmpimg.copy();
+ // construct a qimage SHARING the raw bitmap data in memory
+ QImage tmpimg( dataPtr, bw, bh, QImage::Format_ARGB32 );
+ img = tmpimg.copy();
+ }
// unload underlying xpdf bitmap
splash_output->startPage( 0, NULL );
#endif
@@ -376,32 +406,19 @@
bool Page::search(const QString &text, double &sLeft, double &sTop, double &sRight, double &sBottom, SearchDirection direction, SearchMode caseSensitive, Rotation rotate) const
{
- const QChar * str = text.unicode();
- int len = text.length();
- QVector<Unicode> u(len);
- for (int i = 0; i < len; ++i) u[i] = str[i].unicode();
-
GBool sCase;
- if (caseSensitive == CaseSensitive) sCase = gTrue;
- else sCase = gFalse;
+ QVector<Unicode> u;
+ TextPage *textPage = m_page->prepareTextSearch(text, caseSensitive, rotate, &sCase, &u);
bool found = false;
-
- int rotation = (int)rotate * 90;
-
- // fetch ourselves a textpage
- TextOutputDev td(NULL, gTrue, 0, gFalse, gFalse);
- m_page->parentDoc->doc->displayPage( &td, m_page->index + 1, 72, 72, rotation, false, true, false );
- TextPage *textPage=td.takeText();
-
if (direction == FromTop)
- found = textPage->findText( u.data(), len,
+ found = textPage->findText( u.data(), u.size(),
gTrue, gTrue, gFalse, gFalse, sCase, gFalse, gFalse, &sLeft, &sTop, &sRight, &sBottom );
else if ( direction == NextResult )
- found = textPage->findText( u.data(), len,
+ found = textPage->findText( u.data(), u.size(),
gFalse, gTrue, gTrue, gFalse, sCase, gFalse, gFalse, &sLeft, &sTop, &sRight, &sBottom );
else if ( direction == PreviousResult )
- found = textPage->findText( u.data(), len,
+ found = textPage->findText( u.data(), u.size(),
gFalse, gTrue, gTrue, gFalse, sCase, gTrue, gFalse, &sLeft, &sTop, &sRight, &sBottom );
textPage->decRefCnt();
@@ -427,6 +444,33 @@
return found;
}
+QList<QRectF> Page::search(const QString &text, SearchMode caseSensitive, Rotation rotate) const
+{
+ GBool sCase;
+ QVector<Unicode> u;
+ TextPage *textPage = m_page->prepareTextSearch(text, caseSensitive, rotate, &sCase, &u);
+
+ QList<QRectF> results;
+ double sLeft = 0.0, sTop = 0.0, sRight = 0.0, sBottom = 0.0;
+
+ while(textPage->findText( u.data(), u.size(),
+ gFalse, gTrue, gTrue, gFalse, sCase, gFalse, gFalse, &sLeft, &sTop, &sRight, &sBottom ))
+ {
+ QRectF result;
+
+ result.setLeft(sLeft);
+ result.setTop(sTop);
+ result.setRight(sRight);
+ result.setBottom(sBottom);
+
+ results.append(result);
+ }
+
+ textPage->decRefCnt();
+
+ return results;
+}
+
QList<TextBox*> Page::textList(Rotation rotate) const
{
TextOutputDev *output_dev;
diff --git a/qt4/src/poppler-private.h b/qt4/src/poppler-private.h
index 6d2ef2a..5a9e1b8 100644
--- a/qt4/src/poppler-private.h
+++ b/qt4/src/poppler-private.h
@@ -1,10 +1,11 @@
/* poppler-private.h: qt interface to poppler
* Copyright (C) 2005, Net Integration Technologies, Inc.
* Copyright (C) 2005, 2008, Brad Hards <bradh@frogmouth.net>
- * Copyright (C) 2006-2009, 2011 by Albert Astals Cid <aacid@kde.org>
+ * Copyright (C) 2006-2009, 2011, 2012 by Albert Astals Cid <aacid@kde.org>
* Copyright (C) 2007-2009, 2011 by Pino Toscano <pino@kde.org>
* Copyright (C) 2011 Andreas Hartmetz <ahartmetz@gmail.com>
* Copyright (C) 2011 Hib Eris <hib@hiberis.nl>
+ * Copyright (C) 2012 Thomas Freitag <Thomas.Freitag@alfa.de>
* Inspired on code by
* Copyright (C) 2004 by Albert Astals Cid <tsdgeos@terra.es>
* Copyright (C) 2004 by Enrico Ros <eros.kde@email.it>
@@ -124,11 +125,46 @@
{
#if defined(HAVE_SPLASH)
SplashColor bgColor;
- bgColor[0] = paperColor.blue();
- bgColor[1] = paperColor.green();
- bgColor[2] = paperColor.red();
+ GBool overprint = m_hints & Document::OverprintPreview ? gTrue : gFalse;
+ globalParams->setOverprintPreview(overprint);
+#if defined(SPLASH_CMYK)
+ if (overprint)
+ {
+ Guchar c, m, y, k;
+
+ c = 255 - paperColor.blue();
+ m = 255 - paperColor.red();
+ y = 255 - paperColor.green();
+ k = c;
+ if (m < k) {
+ k = m;
+ }
+ if (y < k) {
+ k = y;
+ }
+ bgColor[0] = c - k;
+ bgColor[1] = m - k;
+ bgColor[2] = y - k;
+ bgColor[3] = k;
+ for (int i = 4; i < SPOT_NCOMPS + 4; i++) {
+ bgColor[i] = 0;
+ }
+ }
+ else
+#endif
+ {
+ bgColor[0] = paperColor.blue();
+ bgColor[1] = paperColor.green();
+ bgColor[2] = paperColor.red();
+ }
GBool AA = m_hints & Document::TextAntialiasing ? gTrue : gFalse;
- SplashOutputDev * splashOutputDev = new SplashOutputDev(splashModeXBGR8, 4, gFalse, bgColor, gTrue, AA);
+ SplashOutputDev * splashOutputDev = new SplashOutputDev(
+#if defined(SPLASH_CMYK)
+ (overprint) ? splashModeDeviceN8 : splashModeXBGR8,
+#else
+ splashModeXBGR8,
+#endif
+ 4, gFalse, bgColor, gTrue, AA);
splashOutputDev->setVectorAntialias(m_hints & Document::Antialiasing ? gTrue : gFalse);
splashOutputDev->setFreeTypeHinting(m_hints & Document::TextHinting ? gTrue : gFalse, m_hints & Document::TextSlightHinting ? gTrue : gFalse);
splashOutputDev->startDoc(doc);
@@ -149,25 +185,10 @@
return;
paperColor = color;
- if ( m_outputDev == NULL )
- return;
-
- switch ( m_backend )
- {
- case Document::SplashBackend:
- {
-#if defined(HAVE_SPLASH)
- SplashOutputDev *splash_output = static_cast<SplashOutputDev *>( m_outputDev );
- SplashColor bgColor;
- bgColor[0] = paperColor.blue();
- bgColor[1] = paperColor.green();
- bgColor[2] = paperColor.red();
- splash_output->setPaperColor(bgColor);
-#endif
- break;
- }
- default: ;
- }
+
+ // Make sure the new paper color will be picked up for the next rendering
+ delete m_outputDev;
+ m_outputDev = NULL;
}
void fillMembers()
diff --git a/qt4/src/poppler-qt4.h b/qt4/src/poppler-qt4.h
index f314108..f4f6fc6 100644
--- a/qt4/src/poppler-qt4.h
+++ b/qt4/src/poppler-qt4.h
@@ -11,6 +11,9 @@
* Copyright (C) 2011 Glad Deschrijver <glad.deschrijver@gmail.com>
* Copyright (C) 2012, Guillermo A. Amaral B. <gamaral@kde.org>
* Copyright (C) 2012, Fabio D'Urso <fabiodurso@hotmail.it>
+ * Copyright (C) 2012, Tobias Koenig <tobias.koenig@kdab.com>
+ * Copyright (C) 2012 Adam Reichold <adamreichold@myopera.com>
+ * Copyright (C) 2012 Thomas Freitag <Thomas.Freitag@alfa.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -601,6 +604,19 @@
\since 0.14
**/
bool search(const QString &text, double &rectLeft, double &rectTop, double &rectRight, double &rectBottom, SearchDirection direction, SearchMode caseSensitive, Rotation rotate = Rotate0) const;
+
+ /**
+ Returns a list of all occurrences of the specified text on the page.
+
+ \param text the text to search
+ \param caseSensitive whether to be case sensitive
+ \param rotate the rotation to apply for the search order
+
+ \warning Do not use the returned QRectF as arguments of another search call because of truncation issues if qreal is defined as float.
+
+ \since 0.22
+ **/
+ QList<QRectF> search(const QString &text, SearchMode caseSensitive, Rotation rotate = Rotate0) const;
/**
Returns a list of text of the page
@@ -831,11 +847,23 @@
Antialiasing = 0x00000001, ///< Antialiasing for graphics
TextAntialiasing = 0x00000002, ///< Antialiasing for text
TextHinting = 0x00000004, ///< Hinting for text \since 0.12.1
- TextSlightHinting = 0x00000008 ///< Lighter hinting for text when combined with TextHinting \since 0.18
+ TextSlightHinting = 0x00000008, ///< Lighter hinting for text when combined with TextHinting \since 0.18
+ OverprintPreview = 0x00000010 ///< Overprint preview \since 0.22
};
Q_DECLARE_FLAGS( RenderHints, RenderHint )
/**
+ Form types
+
+ \since 0.22
+ */
+ enum FormType {
+ NoForm, ///< Document doesn't contain forms
+ AcroForm, ///< AcroForm
+ XfaForm ///< Adobe XML Forms Architecture (XFA), currently unsupported
+ };
+
+ /**
Set a color display profile for the current document.
\param outputProfileA is a \c cmsHPROFILE of the LCMS library.
@@ -1347,6 +1375,13 @@
bool getPdfId(QByteArray *permanentId, QByteArray *updateId) const;
/**
+ Returns the type of forms contained in the document
+
+ \since 0.22
+ */
+ FormType formType() const;
+
+ /**
Destructor.
*/
~Document();
@@ -1609,6 +1644,13 @@
\since 0.12
*/
POPPLER_QT4_EXPORT bool isCmsAvailable();
+
+ /**
+ Whether the overprint preview functionality is available.
+
+ \since 0.22
+ */
+ POPPLER_QT4_EXPORT bool isOverprintPreviewAvailable();
class SoundData;
/**
@@ -1733,6 +1775,20 @@
*/
PlayMode playMode() const;
+ /**
+ Returns whether a poster image should be shown if the movie is not playing.
+ \since 0.22
+ */
+ bool showPosterImage() const;
+
+ /**
+ Returns the poster image that should be shown if the movie is not playing.
+ If the image is null but showImagePoster() returns @c true, the first frame of the movie
+ should be used as poster image.
+ \since 0.22
+ */
+ QImage posterImage() const;
+
private:
/// \cond PRIVATE
MovieObject( AnnotMovie *ann );
diff --git a/qt4/tests/.gitignore b/qt4/tests/.gitignore
index de8b3b4..05b2dbf 100644
--- a/qt4/tests/.gitignore
+++ b/qt4/tests/.gitignore
@@ -12,9 +12,11 @@
poppler-attachments
poppler-fonts
poppler-texts
+check_actualtext
check_attachments
check_dateConversion
check_fonts
+check_links
check_metadata
check_optcontent
check_permissions
@@ -22,4 +24,5 @@
check_pagemode
check_password
check_search
+check_strings
diff --git a/qt4/tests/Makefile.am b/qt4/tests/Makefile.am
index 6286d8c..ed38d17 100644
--- a/qt4/tests/Makefile.am
+++ b/qt4/tests/Makefile.am
@@ -5,13 +5,11 @@
-I$(top_srcdir)/poppler \
-I$(top_srcdir)/qt4/src \
-DTESTDATADIR=\"$(TESTDATADIR)\" \
- $(FONTCONFIG_CFLAGS) \
$(POPPLER_QT4_CFLAGS)
LDADDS = \
$(top_builddir)/poppler/libpoppler.la \
$(top_builddir)/qt4/src/libpoppler-qt4.la \
- $(FONTCONFIG_LIBS) \
$(POPPLER_QT4_LIBS)
SUFFIXES: .moc
diff --git a/qt4/tests/check_fonts.cpp b/qt4/tests/check_fonts.cpp
index c57b6da..267595d 100644
--- a/qt4/tests/check_fonts.cpp
+++ b/qt4/tests/check_fonts.cpp
@@ -19,7 +19,7 @@
};
-QList<Poppler::FontInfo> loadFontsViaIterator( Poppler::Document *doc, int from = 0, int count = -1 )
+static QList<Poppler::FontInfo> loadFontsViaIterator( Poppler::Document *doc, int from = 0, int count = -1 )
{
int num = count == -1 ? doc->numPages() - from : count;
QList<Poppler::FontInfo> list;
@@ -32,7 +32,9 @@
return list;
}
-bool operator==( const Poppler::FontInfo &f1, const Poppler::FontInfo &f2 )
+namespace Poppler
+{
+static bool operator==( const FontInfo &f1, const FontInfo &f2 )
{
if ( f1.name() != f2.name() )
return false;
@@ -48,7 +50,7 @@
return false;
return true;
}
-
+}
void TestFontsData::checkNoFonts()
{
diff --git a/qt4/tests/test-poppler-qt4.cpp b/qt4/tests/test-poppler-qt4.cpp
index 503b35a..46875ef 100644
--- a/qt4/tests/test-poppler-qt4.cpp
+++ b/qt4/tests/test-poppler-qt4.cpp
@@ -186,10 +186,6 @@
qDebug() << "OK to add notes: " << doc->okToAddNotes();
qDebug() << " Page mode: " << doc->pageMode();
qDebug() << " Metadata: " << doc->metadata();
- QStringList fontNameList;
- foreach( const Poppler::FontInfo &font, doc->fonts() )
- fontNameList += font.name();
- qDebug() << " Fonts: " << fontNameList.join( ", " );
if ( doc->hasEmbeddedFiles() ) {
qDebug() << "Embedded files:";
diff --git a/regtest/Printer.py b/regtest/Printer.py
new file mode 100644
index 0000000..008f46b
--- /dev/null
+++ b/regtest/Printer.py
@@ -0,0 +1,99 @@
+# Printer.py
+#
+# Copyright (C) 2012 Carlos Garcia Campos <carlosgc@gnome.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+import sys
+from Config import Config
+
+class Printer:
+
+ __single = None
+
+ def __init__(self):
+ if Printer.__single is not None:
+ raise Printer.__single
+
+ self._verbose = Config().verbose
+ self._stream = sys.stdout
+ self._rewrite = self._stream.isatty() and not self._verbose
+ self._current_line = None
+
+ Printer.__single = self
+
+ def _erase_current_line(self):
+ if not self._rewrite or self._current_line is None:
+ return
+
+ line_len = len(self._current_line)
+ self._stream.write('\b' * line_len + ' ' * line_len + '\b' * line_len)
+ self._current_line = None
+
+ def _ensure_new_line(self, msg):
+ if not msg.endswith('\n'):
+ msg += '\n'
+ return msg
+
+ def _print(self, msg):
+ self._stream.write(msg)
+ self._stream.flush()
+
+ def printout(self, msg):
+ self._erase_current_line()
+ self._print(msg)
+ self._current_line = msg[msg.rfind('\n') + 1:]
+
+ def printout_update(self, msg):
+ if self._rewrite and self._current_line is not None:
+ msg = self._current_line + msg
+ elif not self._rewrite:
+ msg = self._ensure_new_line(msg)
+ self.printout(msg)
+
+ def printout_ln(self, msg):
+ if self._current_line is not None:
+ self._current_line = None
+ msg = '\n' + msg
+
+ self._print(self._ensure_new_line(msg))
+
+ def printerr(self, msg):
+ self.stderr.write(self._ensure_new_line(msg))
+ self.stderr.flush()
+
+ def print_test_start(self, msg):
+ self.printout(msg)
+
+ def print_test_result(self, msg):
+ self.printout_update(msg)
+
+ def print_test_result_ln(self, msg):
+ self.printout_update(self._ensure_new_line(msg))
+
+ def print_default(self, msg):
+ if self._verbose:
+ self.printout_ln(msg)
+
+def get_printer():
+ try:
+ instance = Printer()
+ except Printer, i:
+ instance = i
+
+ return instance
+
+
+
diff --git a/regtest/TestReferences.py b/regtest/TestReferences.py
index d65d30d..9a9e923 100644
--- a/regtest/TestReferences.py
+++ b/regtest/TestReferences.py
@@ -20,6 +20,7 @@
import errno
from backends import get_backend, get_all_backends
from Config import Config
+from Printer import get_printer
from Utils import get_document_paths_from_dir, get_skipped_tests
class TestReferences:
@@ -29,6 +30,7 @@
self._refsdir = refsdir
self._skipped = get_skipped_tests(docsdir)
self.config = Config()
+ self.printer = get_printer()
try:
os.makedirs(self._refsdir)
@@ -40,7 +42,7 @@
def create_refs_for_file(self, filename, n_doc = 1, total_docs = 1):
if filename in self._skipped:
- print("Skipping test '%s' (%d/%d)" % (os.path.join(self._docsdir, filename), n_doc, total_docs))
+ self.printer.print_default("Skipping test '%s' (%d/%d)" % (os.path.join(self._docsdir, filename), n_doc, total_docs))
return
refs_path = os.path.join(self._refsdir, filename)
@@ -60,9 +62,9 @@
for backend in backends:
if not self.config.force and backend.has_results(refs_path):
- print("Results found, skipping '%s' for %s backend (%d/%d)" % (doc_path, backend.get_name(), n_doc, total_docs))
+ self.printer.print_default("Results found, skipping '%s' for %s backend (%d/%d)" % (doc_path, backend.get_name(), n_doc, total_docs))
continue
- print("Creating refs for '%s' using %s backend (%d/%d)" % (doc_path, backend.get_name(), n_doc, total_docs))
+ self.printer.printout_ln("Creating refs for '%s' using %s backend (%d/%d)" % (doc_path, backend.get_name(), n_doc, total_docs))
if backend.create_refs(doc_path, refs_path):
backend.create_checksums(refs_path, self.config.checksums_only)
diff --git a/regtest/TestRun.py b/regtest/TestRun.py
index cffd00b..f4e5051 100644
--- a/regtest/TestRun.py
+++ b/regtest/TestRun.py
@@ -19,6 +19,7 @@
from backends import get_backend, get_all_backends
from Config import Config
from Utils import get_document_paths_from_dir, get_skipped_tests
+from Printer import get_printer
import sys
import os
import errno
@@ -31,6 +32,7 @@
self._outdir = outdir
self._skip = get_skipped_tests(docsdir)
self.config = Config()
+ self.printer = get_printer()
# Results
self._n_tests = 0
@@ -56,12 +58,11 @@
ref_is_failed = backend.is_failed(refs_path)
if not ref_has_md5 and not ref_is_crashed and not ref_is_failed:
self._skipped.append("%s (%s)" % (doc_path, backend.get_name()))
- print("Reference files not found, skipping '%s' for %s backend" % (doc_path, backend.get_name()))
+ self.printer.print_default("Reference files not found, skipping '%s' for %s backend" % (doc_path, backend.get_name()))
return
self._n_tests += 1
- sys.stdout.write("Testing '%s' using %s backend (%d/%d): " % (doc_path, backend.get_name(), n_doc, total_docs))
- sys.stdout.flush()
+ self.printer.print_test_start("Testing '%s' using %s backend (%d/%d): " % (doc_path, backend.get_name(), n_doc, total_docs))
test_has_md5 = backend.create_refs(doc_path, test_path)
if backend.has_stderr(test_path):
@@ -70,40 +71,39 @@
if ref_has_md5 and test_has_md5:
if backend.compare_checksums(refs_path, test_path, not self.config.keep_results, self.config.create_diffs, self.config.update_refs):
# FIXME: remove dir if it's empty?
- print("PASS")
+ self.printer.print_test_result("PASS")
self._n_passed += 1
else:
- print("FAIL")
+ self.printer.print_test_result_ln("FAIL")
self._failed.append("%s (%s)" % (doc_path, backend.get_name()))
return
elif test_has_md5:
if ref_is_crashed:
- print("DOES NOT CRASH")
+ self.printer.print_test_result_ln("DOES NOT CRASH")
elif ref_is_failed:
- print("DOES NOT FAIL")
-
+ self.printer.print_test_result_ln("DOES NOT FAIL")
return
test_is_crashed = backend.is_crashed(test_path)
if ref_is_crashed and test_is_crashed:
- print("PASS (Expected crash)")
+ self.printer.print_test_result("PASS (Expected crash)")
self._n_passed += 1
return
test_is_failed = backend.is_failed(test_path)
if ref_is_failed and test_is_failed:
# FIXME: compare status errors
- print("PASS (Expected fail with status error %d)" % (test_is_failed))
+ self.printer.print_test_result("PASS (Expected fail with status error %d)" % (test_is_failed))
self._n_passed += 1
return
if test_is_crashed:
- print("CRASH")
+ self.printer.print_test_result_ln("CRASH")
self._crashed.append("%s (%s)" % (doc_path, backend.get_name()))
return
if test_is_failed:
- print("FAIL (status error %d)" % (test_is_failed))
+ self.printer.print_test_result_ln("FAIL (status error %d)" % (test_is_failed))
self._failed_status_error("%s (%s)" % (doc_path, backend.get_name()))
return
@@ -111,7 +111,7 @@
if filename in self._skip:
doc_path = os.path.join(self._docsdir, filename)
self._skipped.append("%s" % (doc_path))
- print("Skipping test '%s' (%d/%d)" % (doc_path, n_doc, total_docs))
+ self.printer.print_default("Skipping test '%s' (%d/%d)" % (doc_path, n_doc, total_docs))
return
out_path = os.path.join(self._outdir, filename)
@@ -127,7 +127,7 @@
if not os.path.isdir(refs_path):
self._skipped.append("%s" % (doc_path))
- print("Reference dir not found for %s, skipping (%d/%d)" % (doc_path, n_doc, total_docs))
+ self.printer.print_default("Reference dir not found for %s, skipping (%d/%d)" % (doc_path, n_doc, total_docs))
return
if self.config.backends:
@@ -147,16 +147,17 @@
def summary(self):
if not self._n_tests:
- print("No tests run")
+ self.printer.printout_ln("No tests run")
return
- print("Total %d tests" % (self._n_tests))
- print("%d tests passed (%.2f%%)" % (self._n_passed, (self._n_passed * 100.) / self._n_tests))
+ self.printer.printout_ln("Total %d tests" % (self._n_tests))
+ self.printer.printout_ln("%d tests passed (%.2f%%)" % (self._n_passed, (self._n_passed * 100.) / self._n_tests))
def report_tests(test_list, test_type):
n_tests = len(test_list)
if not n_tests:
return
- print("%d tests %s (%.2f%%): %s" % (n_tests, test_type, (n_tests * 100.) / self._n_tests, ", ".join(test_list)))
+ self.printer.printout_ln("%d tests %s (%.2f%%): %s" % (n_tests, test_type, (n_tests * 100.) / self._n_tests, ", ".join(test_list)))
+
report_tests(self._failed, "failed")
report_tests(self._crashed, "crashed")
report_tests(self._failed_status_error, "failed to run")
diff --git a/regtest/backends/__init__.py b/regtest/backends/__init__.py
index 26be0b0..ff6ef84 100644
--- a/regtest/backends/__init__.py
+++ b/regtest/backends/__init__.py
@@ -21,6 +21,7 @@
import shutil
import errno
from Config import Config
+from Printer import get_printer
__all__ = [ 'register_backend',
'get_backend',
@@ -38,6 +39,8 @@
self._diff_ext = diff_ext
self._utilsdir = Config().utils_dir
+ self.printer = get_printer()
+
def get_name(self):
return self._name
@@ -83,7 +86,7 @@
if not basename in tests:
retval = False
- print("%s found in md5 ref file but missing in output dir %s" % (basename, out_path))
+ self.printer.print_default("%s found in md5 ref file but missing in output dir %s" % (basename, out_path))
continue
result_path = os.path.join(out_path, basename)
@@ -99,10 +102,10 @@
if remove_results:
os.remove(result_path)
else:
- print("Differences found in %s" % (basename))
+ self.printer.print_default("Differences found in %s" % (basename))
if create_diffs:
if not os.path.exists(ref_path):
- print("Reference file %s not found, skipping diff for %s" % (ref_path, result_path))
+ self.printer.print_default("Reference file %s not found, skipping diff for %s" % (ref_path, result_path))
else:
try:
self._create_diff(ref_path, result_path)
@@ -112,14 +115,14 @@
if update_refs:
if os.path.exists(ref_path):
- print("Updating image reference %s" % (ref_path))
+ self.printer.print_default("Updating image reference %s" % (ref_path))
shutil.copyfile(result_path, ref_path)
retval = False
md5_file.close()
if update_refs and not retval:
- print("Updating md5 reference %s" % (md5_path))
+ self.printer.print_default("Updating md5 reference %s" % (md5_path))
f = open(md5_path + '.md5.tmp', 'wb')
f.writelines(result_md5)
f.close()
diff --git a/regtest/commands/create-refs.py b/regtest/commands/create-refs.py
index b055703..d559fb3 100644
--- a/regtest/commands/create-refs.py
+++ b/regtest/commands/create-refs.py
@@ -20,6 +20,7 @@
from TestReferences import TestReferences
from Timer import Timer
from Config import Config
+from Printer import get_printer
import os
import tempfile
@@ -60,6 +61,6 @@
refs.create_refs()
else:
refs.create_refs_for_file(os.path.basename(doc))
- print("Refs created in %s" % (t.elapsed_str()))
+ get_printer().printout_ln("Refs created in %s" % (t.elapsed_str()))
register_command('create-refs', CreateRefs)
diff --git a/regtest/commands/find-regression.py b/regtest/commands/find-regression.py
index 1a46eee..8f5f811 100644
--- a/regtest/commands/find-regression.py
+++ b/regtest/commands/find-regression.py
@@ -20,6 +20,7 @@
from Bisect import Bisect
from Timer import Timer
from Config import Config
+from Printer import get_printer
import os
import tempfile
@@ -66,12 +67,12 @@
doc = options['test']
if not os.path.isfile(doc):
- print("Invalid test %s: not a regulat file" % (doc))
+ get_printer().printerr("Invalid test %s: not a regulat file" % (doc))
return
t = Timer()
bisect = Bisect(options['test'], options['refs_dir'], options['out_dir'])
bisect.run()
- print("Tests run in %s" % (t.elapsed_str()))
+ get_printer().printout_ln("Tests run in %s" % (t.elapsed_str()))
register_command('find-regression', FindRegression)
diff --git a/regtest/commands/run-tests.py b/regtest/commands/run-tests.py
index d05d815..c5d87f9 100644
--- a/regtest/commands/run-tests.py
+++ b/regtest/commands/run-tests.py
@@ -20,6 +20,7 @@
from TestRun import TestRun
from Timer import Timer
from Config import Config
+from Printer import get_printer
import os
import tempfile
@@ -68,6 +69,6 @@
else:
tests.run_test(os.path.basename(doc))
tests.summary()
- print("Tests run in %s" % (t.elapsed_str()))
+ get_printer().printout_ln("Tests run in %s" % (t.elapsed_str()))
register_command('run-tests', RunTests)
diff --git a/regtest/main.py b/regtest/main.py
index a46a64c..290c8bc 100644
--- a/regtest/main.py
+++ b/regtest/main.py
@@ -49,6 +49,9 @@
parser.add_argument('--help-command', metavar = 'COMMAND',
action = HelpAction,
help = 'Show help for a given command')
+ parser.add_argument('-v', '--verbose',
+ action = 'store_true', dest = 'verbose', default = False,
+ help = 'Run in verbose mode')
parser.add_argument('--utils-dir',
action = 'store', dest = 'utils_dir', default = os.path.abspath("../utils"),
help = 'Directory of poppler utils used for the tests')
diff --git a/splash/Splash.cc b/splash/Splash.cc
index e6559f4..e46a496 100644
--- a/splash/Splash.cc
+++ b/splash/Splash.cc
@@ -36,6 +36,7 @@
#include <math.h>
#include "goo/gmem.h"
#include "goo/GooLikely.h"
+#include "goo/GooList.h"
#include "poppler/Error.h"
#include "SplashErrorCodes.h"
#include "SplashMath.h"
@@ -170,7 +171,8 @@
splashPipeResultColorNoAlphaBlendRGB
#if SPLASH_CMYK
,
- splashPipeResultColorNoAlphaBlendCMYK
+ splashPipeResultColorNoAlphaBlendCMYK,
+ splashPipeResultColorNoAlphaBlendDeviceN
#endif
};
@@ -182,7 +184,8 @@
splashPipeResultColorAlphaNoBlendRGB
#if SPLASH_CMYK
,
- splashPipeResultColorAlphaNoBlendCMYK
+ splashPipeResultColorAlphaNoBlendCMYK,
+ splashPipeResultColorAlphaNoBlendDeviceN
#endif
};
@@ -194,7 +197,8 @@
splashPipeResultColorAlphaBlendRGB
#if SPLASH_CMYK
,
- splashPipeResultColorAlphaBlendCMYK
+ splashPipeResultColorAlphaBlendCMYK,
+ splashPipeResultColorAlphaBlendDeviceN
#endif
};
@@ -307,6 +311,8 @@
#if SPLASH_CMYK
} else if (bitmap->mode == splashModeCMYK8 && pipe->destAlphaPtr) {
pipe->run = &Splash::pipeRunSimpleCMYK8;
+ } else if (bitmap->mode == splashModeDeviceN8 && pipe->destAlphaPtr) {
+ pipe->run = &Splash::pipeRunSimpleDeviceN8;
#endif
}
} else if (!pipe->pattern && !pipe->noTransparency && !state->softMask &&
@@ -326,6 +332,8 @@
#if SPLASH_CMYK
} else if (bitmap->mode == splashModeCMYK8 && pipe->destAlphaPtr) {
pipe->run = &Splash::pipeRunAACMYK8;
+ } else if (bitmap->mode == splashModeDeviceN8 && pipe->destAlphaPtr) {
+ pipe->run = &Splash::pipeRunAADeviceN8;
#endif
}
}
@@ -338,6 +346,10 @@
SplashColorPtr cSrc;
Guchar cResult0, cResult1, cResult2, cResult3;
int t;
+#if SPLASH_CMYK
+ int cp, mask;
+ Guchar cResult[SPOT_NCOMPS+4];
+#endif
//----- source color
@@ -412,6 +424,16 @@
}
pipe->destColorPtr += 4;
break;
+ case splashModeDeviceN8:
+ mask = 1;
+ for (cp = 0; cp < SPOT_NCOMPS + 4; cp ++) {
+ if (state->overprintMask & mask) {
+ pipe->destColorPtr[cp] = state->deviceNTransfer[cp][pipe->cSrc[cp]];
+ }
+ mask <<= 1;
+ }
+ pipe->destColorPtr += (SPOT_NCOMPS+4);
+ break;
#endif
}
if (pipe->destAlphaPtr) {
@@ -452,6 +474,10 @@
cDest[2] = pipe->destColorPtr[2];
cDest[3] = pipe->destColorPtr[3];
break;
+ case splashModeDeviceN8:
+ for (cp = 0; cp < SPOT_NCOMPS + 4; cp++)
+ cDest[cp] = pipe->destColorPtr[cp];
+ break;
#endif
}
if (pipe->destAlphaPtr) {
@@ -489,6 +515,10 @@
t = (aDest * 255) / pipe->shape - aDest;
switch (bitmap->mode) {
#if SPLASH_CMYK
+ case splashModeDeviceN8:
+ for (cp = 4; cp < SPOT_NCOMPS + 4; cp++)
+ cSrcNonIso[cp] = clip255(pipe->cSrc[cp] +
+ ((pipe->cSrc[cp] - cDest[cp]) * t) / 255);
case splashModeCMYK8:
cSrcNonIso[3] = clip255(pipe->cSrc[3] +
((pipe->cSrc[3] - cDest[3]) * t) / 255);
@@ -570,6 +600,11 @@
cResult3 = state->cmykTransferK[div255((255 - aDest) * cSrc[3] +
aDest * cBlend[3])];
break;
+ case splashPipeResultColorNoAlphaBlendDeviceN:
+ for (cp = 0; cp < SPOT_NCOMPS+4; cp++)
+ cResult[cp] = state->deviceNTransfer[cp][div255((255 - aDest) * cSrc[cp] +
+ aDest * cBlend[cp])];
+ break;
#endif
case splashPipeResultColorAlphaNoBlendMono:
@@ -612,6 +647,16 @@
aSrc * cSrc[3]) / alphaI];
}
break;
+ case splashPipeResultColorAlphaNoBlendDeviceN:
+ if (alphaI == 0) {
+ for (cp = 0; cp < SPOT_NCOMPS+4; cp++)
+ cResult[cp] = 0;
+ } else {
+ for (cp = 0; cp < SPOT_NCOMPS+4; cp++)
+ cResult[cp] = state->deviceNTransfer[cp][((alphaI - aSrc) * cDest[cp] +
+ aSrc * cSrc[cp]) / alphaI];
+ }
+ break;
#endif
case splashPipeResultColorAlphaBlendMono:
@@ -670,6 +715,18 @@
alphaI];
}
break;
+ case splashPipeResultColorAlphaBlendDeviceN:
+ if (alphaI == 0) {
+ for (cp = 0; cp < SPOT_NCOMPS+4; cp++)
+ cResult[cp] = 0;
+ } else {
+ for (cp = 0; cp < SPOT_NCOMPS+4; cp++)
+ cResult[cp] = state->deviceNTransfer[cp][((alphaI - aSrc) * cDest[cp] +
+ aSrc * ((255 - alphaIm1) * cSrc[cp] +
+ alphaIm1 * cBlend[cp]) / 255) /
+ alphaI];
+ }
+ break;
#endif
}
@@ -730,6 +787,16 @@
}
pipe->destColorPtr += 4;
break;
+ case splashModeDeviceN8:
+ mask = 1;
+ for (cp = 0; cp < SPOT_NCOMPS+4; cp++) {
+ if (state->overprintMask & mask) {
+ pipe->destColorPtr[cp] = cResult[cp];
+ }
+ mask <<=1;
+ }
+ pipe->destColorPtr += (SPOT_NCOMPS+4);
+ break;
#endif
}
if (pipe->destAlphaPtr) {
@@ -844,8 +911,25 @@
++pipe->x;
}
-#endif
+// special case:
+// !pipe->pattern && pipe->noTransparency && !state->blendFunc &&
+// bitmap->mode == splashModeDeviceN8 && pipe->destAlphaPtr) {
+void Splash::pipeRunSimpleDeviceN8(SplashPipe *pipe) {
+ //----- write destination pixel
+ int mask = 1;
+ for (int cp = 0; cp < SPOT_NCOMPS+4; cp++) {
+ if (state->overprintMask & mask) {
+ pipe->destColorPtr[cp] = state->deviceNTransfer[cp][pipe->cSrc[cp]];
+ }
+ mask <<=1;
+ }
+ pipe->destColorPtr += (SPOT_NCOMPS+4);
+ *pipe->destAlphaPtr++ = 255;
+
+ ++pipe->x;
+}
+#endif
// special case:
// !pipe->pattern && !pipe->noTransparency && !state->softMask &&
@@ -1125,6 +1209,53 @@
++pipe->x;
}
+
+// special case:
+// !pipe->pattern && !pipe->noTransparency && !state->softMask &&
+// pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc &&
+// !pipe->nonIsolatedGroup &&
+// bitmap->mode == splashModeDeviceN8 && pipe->destAlphaPtr
+void Splash::pipeRunAADeviceN8(SplashPipe *pipe) {
+ Guchar aSrc, aDest, alpha2, aResult;
+ SplashColor cDest;
+ Guchar cResult[SPOT_NCOMPS+4];
+ int cp, mask;
+
+ //----- read destination pixel
+ for (cp=0; cp < SPOT_NCOMPS+4; cp++)
+ cDest[cp] = pipe->destColorPtr[cp];
+ aDest = *pipe->destAlphaPtr;
+
+ //----- source alpha
+ aSrc = div255(pipe->aInput * pipe->shape);
+
+ //----- result alpha and non-isolated group element correction
+ aResult = aSrc + aDest - div255(aSrc * aDest);
+ alpha2 = aResult;
+
+ //----- result color
+ if (alpha2 == 0) {
+ for (cp=0; cp < SPOT_NCOMPS+4; cp++)
+ cResult[cp] = 0;
+ } else {
+ for (cp=0; cp < SPOT_NCOMPS+4; cp++)
+ cResult[cp] = state->deviceNTransfer[cp][(Guchar)(((alpha2 - aSrc) * cDest[cp] +
+ aSrc * pipe->cSrc[cp]) / alpha2)];
+ }
+
+ //----- write destination pixel
+ mask = 1;
+ for (cp=0; cp < SPOT_NCOMPS+4; cp++) {
+ if (state->overprintMask & mask) {
+ pipe->destColorPtr[cp] = cResult[cp];
+ }
+ mask <<= 1;
+ }
+ pipe->destColorPtr += (SPOT_NCOMPS+4);
+ *pipe->destAlphaPtr++ = aResult;
+
+ ++pipe->x;
+}
#endif
inline void Splash::pipeSetXY(SplashPipe *pipe, int x, int y) {
@@ -1153,6 +1284,9 @@
case splashModeCMYK8:
pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x];
break;
+ case splashModeDeviceN8:
+ pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + (SPOT_NCOMPS + 4) * x];
+ break;
#endif
}
if (bitmap->alpha) {
@@ -1195,6 +1329,9 @@
case splashModeCMYK8:
pipe->destColorPtr += 4;
break;
+ case splashModeDeviceN8:
+ pipe->destColorPtr += (SPOT_NCOMPS+4);
+ break;
#endif
}
if (pipe->destAlphaPtr) {
@@ -1774,6 +1911,17 @@
}
}
break;
+ case splashModeDeviceN8:
+ row = bitmap->data;
+ for (y = 0; y < bitmap->height; ++y) {
+ p = row;
+ for (x = 0; x < bitmap->width; ++x) {
+ for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+ *p++ = color[cp];
+ }
+ row += bitmap->rowSize;
+ }
+ break;
#endif
}
@@ -3355,7 +3503,7 @@
SplashError Splash::drawImage(SplashImageSource src, void *srcData,
SplashColorMode srcMode, GBool srcAlpha,
int w, int h, SplashCoord *mat,
- GBool tilingPattern) {
+ GBool tilingPattern) {
GBool ok;
SplashBitmap *scaledImg;
SplashClipResult clipRes;
@@ -3396,6 +3544,10 @@
ok = srcMode == splashModeCMYK8;
nComps = 4;
break;
+ case splashModeDeviceN8:
+ ok = srcMode == splashModeDeviceN8;
+ nComps = SPOT_NCOMPS+4;
+ break;
#endif
default:
ok = gFalse;
@@ -3496,7 +3648,7 @@
GBool srcAlpha,
int srcWidth, int srcHeight,
SplashCoord *mat,
- GBool tilingPattern) {
+ GBool tilingPattern) {
SplashBitmap *scaledImg;
SplashClipResult clipRes, clipRes2;
SplashPipe pipe;
@@ -3621,7 +3773,7 @@
}
scaledImg = scaleImage(src, srcData, srcMode, nComps, srcAlpha,
srcWidth, srcHeight, scaledWidth, scaledHeight);
-
+
if (scaledImg == NULL) {
return splashErrBadArg;
}
@@ -3802,7 +3954,7 @@
int scaledWidth, int scaledHeight) {
SplashBitmap *dest;
- dest = new SplashBitmap(scaledWidth, scaledHeight, 1, srcMode, srcAlpha);
+ dest = new SplashBitmap(scaledWidth, scaledHeight, 1, srcMode, srcAlpha, gTrue, bitmap->getSeparationList());
if (dest->getDataPtr() != NULL) {
if (scaledHeight < srcHeight) {
if (scaledWidth < srcWidth) {
@@ -3838,6 +3990,7 @@
Guint pix0, pix1, pix2;
#if SPLASH_CMYK
Guint pix3;
+ Guint pix[SPOT_NCOMPS+4], cp;
#endif
Guint alpha;
Guchar *destPtr, *destAlphaPtr;
@@ -4017,6 +4170,25 @@
*destPtr++ = (Guchar)pix2;
*destPtr++ = (Guchar)pix3;
break;
+ case splashModeDeviceN8:
+
+ // compute the final pixel
+ for (cp = 0; cp < SPOT_NCOMPS+4; cp++)
+ pix[cp] = 0;
+ for (i = 0; i < xStep; ++i) {
+ for (cp = 0; cp < SPOT_NCOMPS+4; cp++) {
+ pix[cp] += pixBuf[xx + cp];
+ }
+ xx += (SPOT_NCOMPS+4);
+ }
+ // pix / xStep * yStep
+ for (cp = 0; cp < SPOT_NCOMPS+4; cp++)
+ pix[cp] = (pix[cp] * d) >> 23;
+
+ // store the pixel
+ for (cp = 0; cp < SPOT_NCOMPS+4; cp++)
+ *destPtr++ = (Guchar)pix[cp];
+ break;
#endif
@@ -4168,6 +4340,12 @@
*destPtr++ = (Guchar)pix[3];
}
break;
+ case splashModeDeviceN8:
+ for (i = 0; i < xStep; ++i) {
+ for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+ *destPtr++ = (Guchar)pix[cp];
+ }
+ break;
#endif
}
@@ -4311,6 +4489,13 @@
*destPtr++ = (Guchar)pix[3];
}
break;
+ case splashModeDeviceN8:
+ for (i = 0; i < yStep; ++i) {
+ destPtr = destPtr0 + (i * scaledWidth + x) * nComps;
+ for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+ *destPtr++ = (Guchar)pix[cp];
+ }
+ break;
#endif
}
@@ -4459,6 +4644,15 @@
}
}
break;
+ case splashModeDeviceN8:
+ for (i = 0; i < yStep; ++i) {
+ for (j = 0; j < xStep; ++j) {
+ destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps;
+ for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+ *destPtr++ = (Guchar)pix[cp];
+ }
+ }
+ break;
#endif
}
@@ -4681,6 +4875,10 @@
return splashErrModeMismatch;
}
+ if(src->getSeparationList()->getLength() > bitmap->getSeparationList()->getLength()) {
+ for (x = bitmap->getSeparationList()->getLength(); x < src->getSeparationList()->getLength(); x++)
+ bitmap->getSeparationList()->append(((GfxSeparationColorSpace *)src->getSeparationList()->get(x))->copy());
+ }
if (src->alpha) {
pipeInit(&pipe, xDest, yDest, NULL, pixel,
(Guchar)splashRound(state->fillAlpha * 255), gTrue, nonIsolated,
@@ -4694,7 +4892,7 @@
alpha = *ap++;
// this uses shape instead of alpha, which isn't technically
// correct, but works out the same
- pipe.shape = alpha;
+ pipe.shape = alpha;
(this->*pipe.run)(&pipe);
}
}
@@ -4712,7 +4910,7 @@
if (state->clip->test(xDest + x, yDest + y)) {
// this uses shape instead of alpha, which isn't technically
// correct, but works out the same
- pipe.shape = alpha;
+ pipe.shape = alpha;
(this->*pipe.run)(&pipe);
updateModX(xDest + x);
updateModY(yDest + y);
@@ -4763,6 +4961,7 @@
Guchar alpha, alpha1, c, color0, color1, color2;
#if SPLASH_CMYK
Guchar color3;
+ Guchar colorsp[SPOT_NCOMPS+4], cp;
#endif
int x, y, mask;
@@ -4892,6 +5091,29 @@
}
}
break;
+ case splashModeDeviceN8:
+ for (cp = 0; cp < SPOT_NCOMPS+4; cp++)
+ colorsp[cp] = color[cp];
+ for (y = 0; y < bitmap->height; ++y) {
+ p = &bitmap->data[y * bitmap->rowSize];
+ q = &bitmap->alpha[y * bitmap->width];
+ for (x = 0; x < bitmap->width; ++x) {
+ alpha = *q++;
+ if (alpha == 0)
+ {
+ for (cp = 0; cp < SPOT_NCOMPS+4; cp++)
+ p[cp] = colorsp[cp];
+ }
+ else if (alpha != 255)
+ {
+ alpha1 = 255 - alpha;
+ for (cp = 0; cp < SPOT_NCOMPS+4; cp++)
+ p[cp] = div255(alpha1 * colorsp[cp] + alpha * p[cp]);
+ }
+ p += (SPOT_NCOMPS+4);
+ }
+ }
+ break;
#endif
}
memset(bitmap->alpha, 255, bitmap->width * bitmap->height);
@@ -4951,6 +5173,9 @@
case splashModeCMYK8:
colorComps=4;
break;
+ case splashModeDeviceN8:
+ colorComps=SPOT_NCOMPS+4;
+ break;
#endif
}
@@ -5289,6 +5514,16 @@
}
}
break;
+ case splashModeDeviceN8:
+ for (y = 0; y < h; ++y) {
+ p = &bitmap->data[(yDest + y) * bitmap->rowSize + (SPOT_NCOMPS+4) * xDest];
+ sp = &src->data[(ySrc + y) * src->rowSize + (SPOT_NCOMPS+4) * xSrc];
+ for (x = 0; x < w; ++x) {
+ for (int cp=0; cp < SPOT_NCOMPS+4; cp++)
+ *p++ = *sp++;
+ }
+ }
+ break;
#endif
}
diff --git a/splash/Splash.h b/splash/Splash.h
index f4fb542..223afdd 100644
--- a/splash/Splash.h
+++ b/splash/Splash.h
@@ -60,6 +60,7 @@
enum SplashPipeResultColorCtrl {
#if SPLASH_CMYK
splashPipeResultColorNoAlphaBlendCMYK,
+ splashPipeResultColorNoAlphaBlendDeviceN,
#endif
splashPipeResultColorNoAlphaBlendRGB,
splashPipeResultColorNoAlphaBlendMono,
@@ -67,12 +68,14 @@
splashPipeResultColorAlphaNoBlendRGB,
#if SPLASH_CMYK
splashPipeResultColorAlphaNoBlendCMYK,
+ splashPipeResultColorAlphaNoBlendDeviceN,
#endif
splashPipeResultColorAlphaBlendMono,
splashPipeResultColorAlphaBlendRGB
#if SPLASH_CMYK
,
- splashPipeResultColorAlphaBlendCMYK
+ splashPipeResultColorAlphaBlendCMYK,
+ splashPipeResultColorAlphaBlendDeviceN
#endif
};
@@ -285,6 +288,7 @@
void pipeRunSimpleBGR8(SplashPipe *pipe);
#if SPLASH_CMYK
void pipeRunSimpleCMYK8(SplashPipe *pipe);
+ void pipeRunSimpleDeviceN8(SplashPipe *pipe);
#endif
void pipeRunAAMono1(SplashPipe *pipe);
void pipeRunAAMono8(SplashPipe *pipe);
@@ -293,6 +297,7 @@
void pipeRunAABGR8(SplashPipe *pipe);
#if SPLASH_CMYK
void pipeRunAACMYK8(SplashPipe *pipe);
+ void pipeRunAADeviceN8(SplashPipe *pipe);
#endif
void pipeSetXY(SplashPipe *pipe, int x, int y);
void pipeIncX(SplashPipe *pipe);
diff --git a/splash/SplashBitmap.cc b/splash/SplashBitmap.cc
index cd85543..996f0aa 100644
--- a/splash/SplashBitmap.cc
+++ b/splash/SplashBitmap.cc
@@ -45,6 +45,7 @@
#include "goo/PNGWriter.h"
#include "goo/TiffWriter.h"
#include "goo/ImgWriter.h"
+#include "goo/GooList.h"
//------------------------------------------------------------------------
// SplashBitmap
@@ -52,7 +53,7 @@
SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPadA,
SplashColorMode modeA, GBool alphaA,
- GBool topDown) {
+ GBool topDown, GooList *separationListA) {
width = widthA;
height = heightA;
mode = modeA;
@@ -95,6 +96,13 @@
rowSize = -1;
}
break;
+ case splashModeDeviceN8:
+ if (width > 0 && width <= INT_MAX / 4) {
+ rowSize = width * (SPOT_NCOMPS + 4);
+ } else {
+ rowSize = -1;
+ }
+ break;
#endif
}
if (rowSize > 0) {
@@ -115,11 +123,15 @@
} else {
alpha = NULL;
}
+ separationList = new GooList();
+ if (separationListA != NULL)
+ for (int i = 0; i < separationListA->getLength(); i++)
+ separationList->append(((GfxSeparationColorSpace *) separationListA->get(i))->copy());
}
SplashBitmap *SplashBitmap::copy(SplashBitmap *src) {
SplashBitmap *result = new SplashBitmap(src->getWidth(), src->getHeight(), src->getRowPad(),
- src->getMode(), src->getAlphaPtr() != NULL, src->getRowSize() >= 0);
+ src->getMode(), src->getAlphaPtr() != NULL, src->getRowSize() >= 0, src->getSeparationList());
Guchar *dataSource = src->getDataPtr();
Guchar *dataDest = result->getDataPtr();
int amount = src->getRowSize();
@@ -146,6 +158,7 @@
}
}
gfree(alpha);
+ deleteGooList(separationList, GfxSeparationColorSpace);
}
@@ -234,6 +247,7 @@
#if SPLASH_CMYK
case splashModeCMYK8:
+ case splashModeDeviceN8:
// PNM doesn't support CMYK
error(errInternal, -1, "unsupported SplashBitmap mode");
return splashErrGeneric;
@@ -300,6 +314,11 @@
pixel[2] = p[2];
pixel[3] = p[3];
break;
+ case splashModeDeviceN8:
+ p = &data[y * rowSize + (SPOT_NCOMPS + 4) * x];
+ for (int cp = 0; cp < SPOT_NCOMPS + 4; cp++)
+ pixel[cp] = p[cp];
+ break;
#endif
}
}
@@ -386,6 +405,31 @@
m = byteToDbl(col[1]);
y = byteToDbl(col[2]);
k = byteToDbl(col[3]);
+#if SPLASH_CMYK
+ if (separationList->getLength() > 0) {
+ for (int i = 0; i < separationList->getLength(); i++) {
+ if (col[i+4] > 0) {
+ GfxCMYK cmyk;
+ GfxColor input;
+ input.c[0] = byteToCol(col[i+4]);
+ GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)separationList->get(i);
+ sepCS->getCMYK(&input, &cmyk);
+ col[0] = colToByte(cmyk.c);
+ col[1] = colToByte(cmyk.m);
+ col[2] = colToByte(cmyk.y);
+ col[3] = colToByte(cmyk.k);
+ c += byteToDbl(col[0]);
+ m += byteToDbl(col[1]);
+ y += byteToDbl(col[2]);
+ k += byteToDbl(col[3]);
+ }
+ }
+ if (c > 1) c = 1;
+ if (m > 1) m = 1;
+ if (y > 1) y = 1;
+ if (k > 1) k = 1;
+ }
+#endif
c1 = 1 - c;
m1 = 1 - m;
y1 = 1 - y;
@@ -397,10 +441,122 @@
}
}
+void SplashBitmap::getXBGRLine(int yl, SplashColorPtr line) {
+ SplashColor col;
+ double c, m, y, k, c1, m1, y1, k1, r, g, b;
+
+ for (int x = 0; x < width; x++) {
+ getPixel(x, yl, col);
+ c = byteToDbl(col[0]);
+ m = byteToDbl(col[1]);
+ y = byteToDbl(col[2]);
+ k = byteToDbl(col[3]);
+#if SPLASH_CMYK
+ if (separationList->getLength() > 0) {
+ for (int i = 0; i < separationList->getLength(); i++) {
+ if (col[i+4] > 0) {
+ GfxCMYK cmyk;
+ GfxColor input;
+ input.c[0] = byteToCol(col[i+4]);
+ GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)separationList->get(i);
+ sepCS->getCMYK(&input, &cmyk);
+ col[0] = colToByte(cmyk.c);
+ col[1] = colToByte(cmyk.m);
+ col[2] = colToByte(cmyk.y);
+ col[3] = colToByte(cmyk.k);
+ c += byteToDbl(col[0]);
+ m += byteToDbl(col[1]);
+ y += byteToDbl(col[2]);
+ k += byteToDbl(col[3]);
+ }
+ }
+ if (c > 1) c = 1;
+ if (m > 1) m = 1;
+ if (y > 1) y = 1;
+ if (k > 1) k = 1;
+ }
+#endif
+ c1 = 1 - c;
+ m1 = 1 - m;
+ y1 = 1 - y;
+ k1 = 1 - k;
+ cmykToRGBMatrixMultiplication(c, m, y, k, c1, m1, y1, k1, r, g, b);
+ *line++ = dblToByte(clip01(b));
+ *line++ = dblToByte(clip01(g));
+ *line++ = dblToByte(clip01(r));
+ *line++ = 255;
+ }
+}
+
+GBool SplashBitmap::convertToXBGR() {
+ if (mode == splashModeXBGR8)
+ return gTrue;
+
+ int newrowSize = width * 4;
+ SplashColorPtr newdata = (SplashColorPtr)gmallocn_checkoverflow(newrowSize, height);
+ if (newdata != NULL) {
+ for (int y = 0; y < height; y++) {
+ unsigned char *row = newdata + y * newrowSize;
+ getXBGRLine(y, row);
+ }
+ if (rowSize < 0) {
+ gfree(data + (height - 1) * rowSize);
+ } else {
+ gfree(data);
+ }
+ data = newdata;
+ rowSize = newrowSize;
+ mode = splashModeXBGR8;
+ }
+ return newdata != NULL;
+}
+
+#if SPLASH_CMYK
+void SplashBitmap::getCMYKLine(int yl, SplashColorPtr line) {
+ SplashColor col;
+
+ for (int x = 0; x < width; x++) {
+ getPixel(x, yl, col);
+ if (separationList->getLength() > 0) {
+ double c, m, y, k;
+ c = byteToDbl(col[0]);
+ m = byteToDbl(col[1]);
+ y = byteToDbl(col[2]);
+ k = byteToDbl(col[3]);
+ for (int i = 0; i < separationList->getLength(); i++) {
+ if (col[i+4] > 0) {
+ GfxCMYK cmyk;
+ GfxColor input;
+ input.c[0] = byteToCol(col[i+4]);
+ GfxSeparationColorSpace *sepCS = (GfxSeparationColorSpace *)separationList->get(i);
+ sepCS->getCMYK(&input, &cmyk);
+ col[0] = colToByte(cmyk.c);
+ col[1] = colToByte(cmyk.m);
+ col[2] = colToByte(cmyk.y);
+ col[3] = colToByte(cmyk.k);
+ c += byteToDbl(col[0]);
+ m += byteToDbl(col[1]);
+ y += byteToDbl(col[2]);
+ k += byteToDbl(col[3]);
+ }
+ }
+ col[0] = dblToByte(clip01(c));
+ col[1] = dblToByte(clip01(m));
+ col[2] = dblToByte(clip01(y));
+ col[3] = dblToByte(clip01(k));
+ }
+ *line++ = col[0];
+ *line++ = col[1];
+ *line++ = col[2];
+ *line++ = col[3];
+ }
+}
+#endif
+
SplashError SplashBitmap::writeImgFile(ImgWriter *writer, FILE *f, int hDPI, int vDPI) {
if (mode != splashModeRGB8 && mode != splashModeMono8 && mode != splashModeMono1 && mode != splashModeXBGR8
#if SPLASH_CMYK
- && mode != splashModeCMYK8
+ && mode != splashModeCMYK8 && mode != splashModeDeviceN8
#endif
) {
error(errInternal, -1, "unsupported SplashBitmap mode");
@@ -440,6 +596,29 @@
delete[] row;
}
break;
+ case splashModeDeviceN8:
+ if (writer->supportCMYK()) {
+ unsigned char *row = new unsigned char[4 * width];
+ for (int y = 0; y < height; y++) {
+ getCMYKLine(y, row);
+ if (!writer->writeRow(&row)) {
+ delete[] row;
+ return splashErrGeneric;
+ }
+ }
+ delete[] row;
+ } else {
+ unsigned char *row = new unsigned char[3 * width];
+ for (int y = 0; y < height; y++) {
+ getRGBLine(y, row);
+ if (!writer->writeRow(&row)) {
+ delete[] row;
+ return splashErrGeneric;
+ }
+ }
+ delete[] row;
+ }
+ break;
#endif
case splashModeRGB8:
{
diff --git a/splash/SplashBitmap.h b/splash/SplashBitmap.h
index 5ef5573..70509ab 100644
--- a/splash/SplashBitmap.h
+++ b/splash/SplashBitmap.h
@@ -13,7 +13,7 @@
//
// Copyright (C) 2007 Ilmari Heikkinen <ilmari.heikkinen@gmail.com>
// Copyright (C) 2009 Shen Liang <shenzhuxi@gmail.com>
-// Copyright (C) 2009 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2009, 2012 Albert Astals Cid <aacid@kde.org>
// Copyright (C) 2009 Stefan Thomas <thomas@eload24.com>
// Copyright (C) 2010 Adrian Johnson <ajohnson@redneon.com>
// Copyright (C) 2010 Harry Roberts <harry.roberts@midnight-labs.org>
@@ -34,6 +34,7 @@
#endif
#include "SplashTypes.h"
+#include "poppler/GfxState.h"
#include <stdio.h>
class ImgWriter;
@@ -51,7 +52,7 @@
// upside-down, i.e., with the last row first in memory.
SplashBitmap(int widthA, int heightA, int rowPad,
SplashColorMode modeA, GBool alphaA,
- GBool topDown = gTrue);
+ GBool topDown = gTrue, GooList *separationList = NULL);
static SplashBitmap *copy(SplashBitmap *src);
~SplashBitmap();
@@ -64,6 +65,7 @@
SplashColorMode getMode() { return mode; }
SplashColorPtr getDataPtr() { return data; }
Guchar *getAlphaPtr() { return alpha; }
+ GooList *getSeparationList() { return separationList; }
SplashError writePNMFile(char *fileName);
SplashError writePNMFile(FILE *f);
@@ -73,8 +75,14 @@
SplashError writeImgFile(SplashImageFileFormat format, FILE *f, int hDPI, int vDPI, const char *compressionString = "");
SplashError writeImgFile(ImgWriter *writer, FILE *f, int hDPI, int vDPI);
+ GBool convertToXBGR();
+
void getPixel(int x, int y, SplashColorPtr pixel);
void getRGBLine(int y, SplashColorPtr line);
+ void getXBGRLine(int y, SplashColorPtr line);
+#if SPLASH_CMYK
+ void getCMYKLine(int y, SplashColorPtr line);
+#endif
Guchar getAlpha(int x, int y);
// Caller takes ownership of the bitmap data. The SplashBitmap
@@ -92,6 +100,7 @@
SplashColorPtr data; // pointer to row zero of the color data
Guchar *alpha; // pointer to row zero of the alpha data
// (always top-down)
+ GooList *separationList; // list of spot colorants and their mapping functions
friend class Splash;
};
diff --git a/splash/SplashScreen.cc b/splash/SplashScreen.cc
index d741246..68ccd7d 100644
--- a/splash/SplashScreen.cc
+++ b/splash/SplashScreen.cc
@@ -12,6 +12,7 @@
// under GPL version 2 or later
//
// Copyright (C) 2009 Albert Astals Cid <aacid@kde.org>
+// Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
@@ -28,6 +29,7 @@
#include <string.h>
#include <algorithm>
#include "goo/gmem.h"
+#include "goo/grandom.h"
#include "SplashMath.h"
#include "SplashScreen.h"
@@ -253,9 +255,6 @@
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;
@@ -267,8 +266,7 @@
}
}
for (i = 0; i < size * size; ++i) {
- j = i + (int)((double)(size * size - i) *
- (double)rand() / ((double)RAND_MAX + 1.0));
+ j = i + (int)((double)(size * size - i) * grandom_double());
x = pts[i].x;
y = pts[i].y;
pts[i].x = pts[j].x;
diff --git a/splash/SplashState.cc b/splash/SplashState.cc
index e258f66..fd2789d 100644
--- a/splash/SplashState.cc
+++ b/splash/SplashState.cc
@@ -40,7 +40,7 @@
int splashColorModeNComps[] = {
1, 1, 3, 3, 4
#if SPLASH_CMYK
- ,4
+ , 4, 4 + SPOT_NCOMPS
#endif
};
@@ -80,10 +80,14 @@
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;
+ for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+ deviceNTransfer[cp][i] = (Guchar)i;
+#endif
}
overprintMask = 0xffffffff;
overprintAdditive = gFalse;
@@ -126,10 +130,14 @@
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;
+ for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+ deviceNTransfer[cp][i] = (Guchar)i;
+#endif
}
overprintMask = 0xffffffff;
overprintAdditive = gFalse;
@@ -170,10 +178,14 @@
memcpy(rgbTransferG, state->rgbTransferG, 256);
memcpy(rgbTransferB, state->rgbTransferB, 256);
memcpy(grayTransfer, state->grayTransfer, 256);
+#if SPLASH_CMYK
memcpy(cmykTransferC, state->cmykTransferC, 256);
memcpy(cmykTransferM, state->cmykTransferM, 256);
memcpy(cmykTransferY, state->cmykTransferY, 256);
memcpy(cmykTransferK, state->cmykTransferK, 256);
+ for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+ memcpy(deviceNTransfer[cp], state->deviceNTransfer[cp], 256);
+#endif
overprintMask = state->overprintMask;
overprintAdditive = state->overprintAdditive;
next = NULL;
@@ -228,16 +240,24 @@
void SplashState::setTransfer(Guchar *red, Guchar *green, Guchar *blue,
Guchar *gray) {
+#if SPLASH_CMYK
int i;
- memcpy(rgbTransferR, red, 256);
- memcpy(rgbTransferG, green, 256);
- memcpy(rgbTransferB, blue, 256);
- memcpy(grayTransfer, gray, 256);
for (i = 0; i < 256; ++i) {
cmykTransferC[i] = 255 - rgbTransferR[255 - i];
cmykTransferM[i] = 255 - rgbTransferG[255 - i];
cmykTransferY[i] = 255 - rgbTransferB[255 - i];
cmykTransferK[i] = 255 - grayTransfer[255 - i];
}
+ for (i = 0; i < 256; ++i) {
+ deviceNTransfer[0][i] = 255 - rgbTransferR[255 - i];
+ deviceNTransfer[1][i] = 255 - rgbTransferG[255 - i];
+ deviceNTransfer[2][i] = 255 - rgbTransferB[255 - i];
+ deviceNTransfer[3][i] = 255 - grayTransfer[255 - i];
+ }
+#endif
+ memcpy(rgbTransferR, red, 256);
+ memcpy(rgbTransferG, green, 256);
+ memcpy(rgbTransferB, blue, 256);
+ memcpy(grayTransfer, gray, 256);
}
diff --git a/splash/SplashState.h b/splash/SplashState.h
index 01e7772..13d5478 100644
--- a/splash/SplashState.h
+++ b/splash/SplashState.h
@@ -121,10 +121,13 @@
rgbTransferG[256],
rgbTransferB[256];
Guchar grayTransfer[256];
+#if SPLASH_CMYK
Guchar cmykTransferC[256],
cmykTransferM[256],
cmykTransferY[256],
cmykTransferK[256];
+ Guchar deviceNTransfer[SPOT_NCOMPS+4][256];
+#endif
Guint overprintMask;
GBool overprintAdditive;
diff --git a/splash/SplashTypes.h b/splash/SplashTypes.h
index 65525b1..531b945 100644
--- a/splash/SplashTypes.h
+++ b/splash/SplashTypes.h
@@ -13,7 +13,7 @@
//
// Copyright (C) 2006, 2010 Albert Astals Cid <aacid@kde.org>
// Copyright (C) 2008 Tomas Are Haavet <tomasare@gmail.com>
-// Copyright (C) 2009, 2011 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2009, 2011, 2012 Thomas Freitag <Thomas.Freitag@alfa.de>
// Copyright (C) 2009 Stefan Thomas <thomas@eload24.com>
// Copyright (C) 2010 William Bader <williambader@hotmail.com>
//
@@ -46,6 +46,12 @@
#define splashAASize 4
+#ifdef SPLASH_CMYK
+#ifndef SPOT_NCOMPS
+#define SPOT_NCOMPS 4
+#endif
+#endif
+
//------------------------------------------------------------------------
// colors
//------------------------------------------------------------------------
@@ -62,8 +68,11 @@
// XBGRXBGR...
#if SPLASH_CMYK
,
- splashModeCMYK8 // 1 byte per component, 4 bytes per pixel:
+ splashModeCMYK8, // 1 byte per component, 4 bytes per pixel:
// CMYKCMYK...
+ splashModeDeviceN8 // 1 byte per component,
+ // 4 bytes + n bytes spot colors per pixel:
+ // CMYKSSSSCMYKSSSS...
#endif
};
@@ -72,7 +81,11 @@
extern int splashColorModeNComps[];
// max number of components in any SplashColor
+#if SPLASH_CMYK
+#define splashMaxColorComps SPOT_NCOMPS+4
+#else
#define splashMaxColorComps 4
+#endif
typedef Guchar SplashColor[splashMaxColorComps];
typedef Guchar *SplashColorPtr;
@@ -93,6 +106,13 @@
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]; }
+
+// DEVICEN8
+static inline Guchar splashDeviceN8C(SplashColorPtr deviceN8) { return deviceN8[0]; }
+static inline Guchar splashDeviceN8M(SplashColorPtr deviceN8) { return deviceN8[1]; }
+static inline Guchar splashDeviceN8Y(SplashColorPtr deviceN8) { return deviceN8[2]; }
+static inline Guchar splashDeviceN8K(SplashColorPtr deviceN8) { return deviceN8[3]; }
+static inline Guchar splashDeviceN8S(SplashColorPtr deviceN8, int nSpot) { return deviceN8[4 + nSpot]; }
#endif
static inline void splashClearColor(SplashColorPtr dest) {
@@ -101,6 +121,8 @@
dest[2] = 0;
#if SPLASH_CMYK
dest[3] = 0;
+ for (int i = SPOT_NCOMPS; i < SPOT_NCOMPS + 4; i++)
+ dest[i] = 0;
#endif
}
@@ -110,6 +132,8 @@
dest[2] = src[2];
#if SPLASH_CMYK
dest[3] = src[3];
+ for (int i = SPOT_NCOMPS; i < SPOT_NCOMPS + 4; i++)
+ dest[i] = src[i];
#endif
}
@@ -119,6 +143,8 @@
dest[2] ^= src[2];
#if SPLASH_CMYK
dest[3] ^= src[3];
+ for (int i = SPOT_NCOMPS; i < SPOT_NCOMPS + 4; i++)
+ dest[i] ^= src[i];
#endif
}
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index cff715c..a89a4cf 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -17,7 +17,7 @@
if (GTK_FOUND)
- add_definitions(${GTK2_CFLAGS})
+ add_definitions(${GTK3_CFLAGS})
include_directories(
${CMAKE_SOURCE_DIR}/glib
@@ -28,7 +28,7 @@
gtk-test.cc
)
poppler_add_test(gtk-test BUILD_GTK_TESTS ${gtk_splash_test_SRCS})
- target_link_libraries(gtk-test poppler-glib ${GTK2_LIBRARIES})
+ target_link_libraries(gtk-test poppler-glib ${GTK3_LIBRARIES})
if (HAVE_CAIRO)
@@ -36,7 +36,7 @@
pdf-inspector.cc
)
poppler_add_test(pdf-inspector BUILD_GTK_TESTS ${pdf_inspector_SRCS})
- target_link_libraries(pdf-inspector poppler-glib ${GTK2_LIBRARIES})
+ target_link_libraries(pdf-inspector poppler-glib ${GTK3_LIBRARIES})
endif (HAVE_CAIRO)
@@ -44,6 +44,7 @@
set (pdf_fullrewrite_SRCS
pdf-fullrewrite.cc
+ ../utils/parseargs.cc
)
add_executable(pdf-fullrewrite ${pdf_fullrewrite_SRCS})
target_link_libraries(pdf-fullrewrite poppler)
diff --git a/test/Makefile.am b/test/Makefile.am
index 0252911..b3289c7 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -39,8 +39,7 @@
-I$(top_srcdir)/glib \
-I$(top_builddir)/glib \
$(cairo_includes) \
- $(GTK_TEST_CFLAGS) \
- $(FONTCONFIG_CFLAGS)
+ $(GTK_TEST_CFLAGS)
noinst_PROGRAMS = $(pdf_inspector) $(perf_test) $(pdf_fullrewrite) $(gtk_test)
@@ -53,8 +52,7 @@
$(top_builddir)/poppler/libpoppler.la \
$(top_builddir)/glib/libpoppler-glib.la \
$(CAIRO_LIBS) \
- $(GTK_TEST_LIBS) \
- $(FONTCONFIG_LIBS)
+ $(GTK_TEST_LIBS)
pdf_inspector_SOURCES = \
@@ -78,7 +76,8 @@
$(X_EXTRA_LIBS)
pdf_fullrewrite_SOURCES = \
- pdf-fullrewrite.cc
+ pdf-fullrewrite.cc \
+ ../utils/parseargs.cc
pdf_fullrewrite_LDADD = \
$(top_builddir)/poppler/libpoppler.la
diff --git a/test/gtk-test.cc b/test/gtk-test.cc
index dd339fb..a5759d7 100644
--- a/test/gtk-test.cc
+++ b/test/gtk-test.cc
@@ -156,16 +156,14 @@
}
static gboolean
-drawing_area_expose (GtkWidget *drawing_area,
- GdkEventExpose *event,
- View *view)
+drawing_area_draw (GtkWidget *drawing_area,
+ cairo_t *cr,
+ View *view)
{
- cairo_t *cr;
GdkRectangle document;
+ GdkRectangle clip;
GdkRectangle draw;
- gdk_window_clear (drawing_area->window);
-
document.x = 0;
document.y = 0;
if (cairo_output) {
@@ -176,8 +174,10 @@
document.height = view->out->getBitmapHeight();
}
- cr = gdk_cairo_create (drawing_area->window);
- if (!gdk_rectangle_intersect (&document, &event->area, &draw))
+ if (!gdk_cairo_get_clip_rectangle (cr, &clip))
+ return FALSE;
+
+ if (!gdk_rectangle_intersect (&document, &clip, &draw))
return FALSE;
if (cairo_output) {
@@ -190,8 +190,6 @@
draw.width, draw.height);
}
- cairo_destroy (cr);
-
return TRUE;
}
@@ -281,6 +279,7 @@
GtkWidget *sw;
GtkWidget *vbox, *hbox;
guint n_pages;
+ PopplerPage *page;
view = g_slice_new0 (View);
@@ -291,7 +290,16 @@
G_CALLBACK (destroy_window_callback),
view);
- vbox = gtk_vbox_new (FALSE, 5);
+ page = poppler_document_get_page (doc, 0);
+ if (page) {
+ double width, height;
+
+ poppler_page_get_size (page, &width, &height);
+ gtk_window_set_default_size (GTK_WINDOW (window), (gint)width, (gint)height);
+ g_object_unref (page);
+ }
+
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
view->drawing_area = gtk_drawing_area_new ();
sw = gtk_scrolled_window_new (NULL, NULL);
@@ -305,7 +313,7 @@
gtk_box_pack_end (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
gtk_widget_show (sw);
- hbox = gtk_hbox_new (FALSE, 5);
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
n_pages = poppler_document_get_n_pages (doc);
view->spin_button = gtk_spin_button_new_with_range (0, n_pages - 1, 1);
@@ -333,8 +341,8 @@
}
g_signal_connect (view->drawing_area,
- "expose_event",
- G_CALLBACK (drawing_area_expose),
+ "draw",
+ G_CALLBACK (drawing_area_draw),
view);
return view;
@@ -366,27 +374,27 @@
for (int i = 0; file_arguments[i]; i++) {
View *view;
GFile *file;
- gchar *uri;
PopplerDocument *doc;
GError *error = NULL;
file = g_file_new_for_commandline_arg (file_arguments[i]);
- uri = g_file_get_uri (file);
- g_object_unref (file);
-
- doc = poppler_document_new_from_file (uri, NULL, &error);
+ doc = poppler_document_new_from_gfile (file, NULL, NULL, &error);
if (!doc) {
+ gchar *uri;
+
+ uri = g_file_get_uri (file);
g_printerr ("Error opening document %s: %s\n", uri, error->message);
g_error_free (error);
g_free (uri);
+ g_object_unref (file);
continue;
}
+ g_object_unref (file);
view = view_new (doc);
view_list = g_list_prepend (view_list, view);
view_set_page (view, CLAMP (page, 0, poppler_document_get_n_pages (doc) - 1));
- g_free (uri);
}
gtk_main ();
diff --git a/test/pdf-fullrewrite.cc b/test/pdf-fullrewrite.cc
index 9658e55..2b912f7 100644
--- a/test/pdf-fullrewrite.cc
+++ b/test/pdf-fullrewrite.cc
@@ -3,44 +3,368 @@
// pdf-fullrewrite.cc
//
// Copyright 2007 Julien Rebetez
+// Copyright 2012 Fabio D'Urso
//
//========================================================================
-#include "config.h"
-#include <poppler-config.h>
+
#include "GlobalParams.h"
#include "Error.h"
+#include "Object.h"
#include "PDFDoc.h"
+#include "XRef.h"
#include "goo/GooString.h"
+#include "utils/parseargs.h"
+
+static GBool compareDocuments(PDFDoc *origDoc, PDFDoc *newDoc);
+static GBool compareObjects(Object *objA, Object *objB);
+
+static char ownerPassword[33] = "\001";
+static char userPassword[33] = "\001";
+static GBool forceIncremental = gFalse;
+static GBool checkOutput = gFalse;
+static GBool printHelp = gFalse;
+
+static const ArgDesc argDesc[] = {
+ {"-opw", argString, ownerPassword, sizeof(ownerPassword),
+ "owner password (for encrypted files)"},
+ {"-upw", argString, userPassword, sizeof(userPassword),
+ "user password (for encrypted files)"},
+ {"-i", argFlag, &forceIncremental,0,
+ "incremental update mode"},
+ {"-check", argFlag, &checkOutput, 0,
+ "verify the generated document"},
+ {"-h", argFlag, &printHelp, 0,
+ "print usage information"},
+ {"-help", argFlag, &printHelp, 0,
+ "print usage information"},
+ {"--help", argFlag, &printHelp, 0,
+ "print usage information"},
+ {"-?", argFlag, &printHelp, 0,
+ "print usage information"},
+ {NULL}
+};
int main (int argc, char *argv[])
{
- PDFDoc *doc;
- GooString *inputName, *outputName;
+ PDFDoc *doc = NULL;
+ PDFDoc *docOut = NULL;
+ GooString *inputName = NULL;
+ GooString *outputName = NULL;
+ GooString *ownerPW = NULL;
+ GooString *userPW = NULL;
+ int res = 0;
// parse args
- if (argc < 3) {
- fprintf(stderr, "usage: %s INPUT-FILE OUTPUT-FILE\n", argv[0]);
- return 1;
+ GBool ok = parseArgs(argDesc, &argc, argv);
+ if (!ok || (argc < 3) || printHelp) {
+ printUsage(argv[0], "INPUT-FILE OUTPUT-FILE", argDesc);
+ if (!printHelp) {
+ res = 1;
+ }
+ goto done;
}
inputName = new GooString(argv[1]);
outputName = new GooString(argv[2]);
- globalParams = new GlobalParams();
-
- doc = new PDFDoc(inputName);
-
- if (!doc->isOk()) {
- delete doc;
- fprintf(stderr, "Error loading document !\n");
- return 1;
+ if (ownerPassword[0] != '\001') {
+ ownerPW = new GooString(ownerPassword);
+ }
+ if (userPassword[0] != '\001') {
+ userPW = new GooString(userPassword);
}
+ // load input document
+ globalParams = new GlobalParams();
+ doc = new PDFDoc(inputName, ownerPW, userPW);
+ if (!doc->isOk()) {
+ fprintf(stderr, "Error loading input document\n");
+ res = 1;
+ goto done;
+ }
- int res = doc->saveAs(outputName, writeForceRewrite);
+ // save it back (in rewrite or incremental update mode)
+ if (doc->saveAs(outputName, forceIncremental ? writeForceIncremental : writeForceRewrite) != 0) {
+ fprintf(stderr, "Error saving document\n");
+ res = 1;
+ goto done;
+ }
+ if (checkOutput) {
+ // open the generated document to verify it
+ docOut = new PDFDoc(outputName, ownerPW, userPW);
+ if (!docOut->isOk()) {
+ fprintf(stderr, "Error loading generated document\n");
+ res = 1;
+ } else if (!compareDocuments(doc, docOut)) {
+ fprintf(stderr, "Verification failed\n");
+ res = 1;
+ }
+ } else {
+ delete outputName;
+ }
+
+done:
+ delete docOut;
delete doc;
delete globalParams;
- delete outputName;
+ delete userPW;
+ delete ownerPW;
return res;
}
+
+static GBool compareDictionaries(Dict *dictA, Dict *dictB)
+{
+ const int length = dictA->getLength();
+ if (dictB->getLength() != length)
+ return gFalse;
+
+ /* Check that every key in dictA is contained in dictB.
+ * Since keys are unique and we've already checked that dictA and dictB
+ * contain the same number of entries, we don't need to check that every key
+ * in dictB is also contained in dictA */
+ for (int i = 0; i < length; ++i) {
+ Object valA, valB;
+ const char *key = dictA->getKey(i);
+ dictA->getValNF(i, &valA);
+ dictB->lookupNF(key, &valB);
+ if (!compareObjects(&valA, &valB))
+ return gFalse;
+ valA.free();
+ valB.free();
+ }
+
+ return gTrue;
+}
+
+static GBool compareObjects(Object *objA, Object *objB)
+{
+ switch (objA->getType()) {
+ case objBool:
+ {
+ if (objB->getType() != objBool) {
+ return gFalse;
+ } else {
+ return (objA->getBool() == objB->getBool());
+ }
+ }
+ case objInt:
+ case objReal:
+ {
+ if (!objB->isNum()) {
+ return gFalse;
+ } else {
+ // Fuzzy comparison
+ const double diff = objA->getNum() - objB->getNum();
+ return (-0.01 < diff) && (diff < 0.01);
+ }
+ }
+ case objUint:
+ {
+ if (objB->getType() != objUint) {
+ return gFalse;
+ } else {
+ return (objA->getUint() == objB->getUint());
+ }
+ }
+ case objString:
+ {
+ if (objB->getType() != objString) {
+ return gFalse;
+ } else {
+ GooString *strA = objA->getString();
+ GooString *strB = objB->getString();
+ return (strA->cmp(strB) == 0);
+ }
+ }
+ case objName:
+ {
+ if (objB->getType() != objName) {
+ return gFalse;
+ } else {
+ GooString nameA(objA->getName());
+ GooString nameB(objB->getName());
+ return (nameA.cmp(&nameB) == 0);
+ }
+ }
+ case objNull:
+ {
+ if (objB->getType() != objNull) {
+ return gFalse;
+ } else {
+ return gTrue;
+ }
+ }
+ case objArray:
+ {
+ if (objB->getType() != objArray) {
+ return gFalse;
+ } else {
+ Array *arrayA = objA->getArray();
+ Array *arrayB = objB->getArray();
+ const int length = arrayA->getLength();
+ if (arrayB->getLength() != length) {
+ return gFalse;
+ } else {
+ for (int i = 0; i < length; ++i) {
+ Object elemA, elemB;
+ arrayA->getNF(i, &elemA);
+ arrayB->getNF(i, &elemB);
+ if (!compareObjects(&elemA, &elemB)) {
+ return gFalse;
+ }
+ elemA.free();
+ elemB.free();
+ }
+ return gTrue;
+ }
+ }
+ }
+ case objDict:
+ {
+ if (objB->getType() != objDict) {
+ return gFalse;
+ } else {
+ Dict *dictA = objA->getDict();
+ Dict *dictB = objB->getDict();
+ return compareDictionaries(dictA, dictB);
+ }
+ }
+ case objStream:
+ {
+ if (objB->getType() != objStream) {
+ return gFalse;
+ } else {
+ Stream *streamA = objA->getStream();
+ Stream *streamB = objB->getStream();
+ if (!compareDictionaries(streamA->getDict(), streamB->getDict())) {
+ return gFalse;
+ } else {
+ int c;
+ streamA->reset();
+ streamB->reset();
+ do
+ {
+ c = streamA->getChar();
+ if (c != streamB->getChar()) {
+ return gFalse;
+ }
+ } while (c != EOF);
+ return gTrue;
+ }
+ }
+ return gTrue;
+ }
+ case objRef:
+ {
+ if (objB->getType() != objRef) {
+ return gFalse;
+ } else {
+ Ref refA = objA->getRef();
+ Ref refB = objB->getRef();
+ return (refA.num == refB.num) && (refA.gen == refB.gen);
+ }
+ }
+ default:
+ {
+ fprintf(stderr, "compareObjects failed: unexpected object type %u\n", objA->getType());
+ return gFalse;
+ }
+ }
+}
+
+static GBool compareDocuments(PDFDoc *origDoc, PDFDoc *newDoc)
+{
+ GBool result = gTrue;
+ XRef *origXRef = origDoc->getXRef();
+ XRef *newXRef = newDoc->getXRef();
+
+ // Make sure that special flags are set in both documents
+ origXRef->scanSpecialFlags();
+ newXRef->scanSpecialFlags();
+
+ // Compare XRef tables' size
+ const int origNumObjects = origXRef->getNumObjects();
+ const int newNumObjects = newXRef->getNumObjects();
+ if (forceIncremental && origXRef->isXRefStream()) {
+ // In case of incremental update, expect a new entry to be appended to store the new XRef stream
+ if (origNumObjects+1 != newNumObjects) {
+ fprintf(stderr, "XRef table: Unexpected number of entries (%d+1 != %d)\n", origNumObjects, newNumObjects);
+ result = gFalse;
+ }
+ } else {
+ // In all other cases the number of entries must be the same
+ if (origNumObjects != newNumObjects) {
+ fprintf(stderr, "XRef table: Different number of entries (%d != %d)\n", origNumObjects, newNumObjects);
+ result = gFalse;
+ }
+ }
+
+ // Compare each XRef entry
+ const int numObjects = (origNumObjects < newNumObjects) ? origNumObjects : newNumObjects;
+ for (int i = 0; i < numObjects; ++i) {
+ XRefEntryType origType = origXRef->getEntry(i)->type;
+ XRefEntryType newType = newXRef->getEntry(i)->type;
+ const int origGenNum = (origType != xrefEntryCompressed) ? origXRef->getEntry(i)->gen : 0;
+ const int newGenNum = (newType != xrefEntryCompressed) ? newXRef->getEntry(i)->gen : 0;
+
+ // Check that DontRewrite entries are freed in full rewrite mode
+ if (!forceIncremental && origXRef->getEntry(i)->getFlag(XRefEntry::DontRewrite)) {
+ if (newType != xrefEntryFree || origGenNum+1 != newGenNum) {
+ fprintf(stderr, "XRef entry %u: DontRewrite entry was not freed correctly\n", i);
+ result = gFalse;
+ }
+ continue; // There's nothing left to check for this entry
+ }
+
+ // Compare generation numbers
+ // Object num 0 should always have gen 65535 according to specs, but some
+ // documents have it set to 0. We always write 65535 in output
+ if (i != 0) {
+ if (origGenNum != newGenNum) {
+ fprintf(stderr, "XRef entry %u: generation numbers differ (%d != %d)\n", i, origGenNum, newGenNum);
+ result = gFalse;
+ continue;
+ }
+ } else {
+ if (newGenNum != 65535) {
+ fprintf(stderr, "XRef entry %u: generation number was expected to be 65535 (%d != 65535)\n", i, newGenNum);
+ result = gFalse;
+ continue;
+ }
+ }
+
+ // Compare object flags. A failure shows that there's some error in XRef::scanSpecialFlags()
+ if (origXRef->getEntry(i)->flags != newXRef->getEntry(i)->flags) {
+ fprintf(stderr, "XRef entry %u: flags detected by scanSpecialFlags differ (%d != %d)\n", i, origXRef->getEntry(i)->flags, newXRef->getEntry(i)->flags);
+ result = gFalse;
+ }
+
+ // Check that either both are free or both are in use
+ if ((origType == xrefEntryFree) != (newType == xrefEntryFree)) {
+ const char *origStatus = (origType == xrefEntryFree) ? "free" : "in use";
+ const char *newStatus = (newType == xrefEntryFree) ? "free" : "in use";
+ fprintf(stderr, "XRef entry %u: usage status differs (%s != %s)\n", i, origStatus, newStatus);
+ result = gFalse;
+ continue;
+ }
+
+ // Skip free entries
+ if (origType == xrefEntryFree) {
+ continue;
+ }
+
+ // Compare contents
+ Object origObj, newObj;
+ origXRef->fetch(i, origGenNum, &origObj);
+ newXRef->fetch(i, newGenNum, &newObj);
+ if (!compareObjects(&origObj, &newObj)) {
+ fprintf(stderr, "XRef entry %u: contents differ\n", i);
+ result = gFalse;
+ }
+ origObj.free();
+ newObj.free();
+ }
+
+ return result;
+}
diff --git a/test/perf-test.cc b/test/perf-test.cc
index 6bdda97..21fbdee 100644
--- a/test/perf-test.cc
+++ b/test/perf-test.cc
@@ -1242,7 +1242,6 @@
if (!globalParams)
return 1;
globalParams->setErrQuiet(gFalse);
- globalParams->setBaseDir("");
FILE * outFile = NULL;
if (gOutFileName) {
diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt
index 4a29841..06378bd 100644
--- a/utils/CMakeLists.txt
+++ b/utils/CMakeLists.txt
@@ -5,9 +5,6 @@
set(common_libs
poppler
)
-if (FONTCONFIG_FOUND)
- set(common_libs ${common_libs} ${FONTCONFIG_LIBRARIES})
-endif (FONTCONFIG_FOUND)
if (ENABLE_SPLASH)
# pdftoppm
diff --git a/utils/HtmlFonts.cc b/utils/HtmlFonts.cc
index be02c5f..e0ea8a7 100644
--- a/utils/HtmlFonts.cc
+++ b/utils/HtmlFonts.cc
@@ -24,6 +24,7 @@
// Copyright (C) 2011 Joshua Richardson <jric@chegg.com>
// Copyright (C) 2011 Stephen Reichling <sreichling@chegg.com>
// Copyright (C) 2012 Igor Slepchin <igor.slepchin@gmail.com>
+// Copyright (C) 2012 Luis Parravicini <lparravi@gmail.com>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
@@ -63,6 +64,7 @@
#define xoutRound(x) ((int)(x + 0.5))
extern GBool xml;
+extern GBool fontFullName;
GooString* HtmlFont::DefaultFont=new GooString("Times"); // Arial,Helvetica,sans-serif
@@ -318,7 +320,7 @@
HtmlFont font=*g;
GooString *Size=GooString::fromInt(font.getSize());
GooString *colorStr=font.getColor().toString();
- GooString *fontName=font.getFontName();
+ GooString *fontName=(fontFullName ? font.getFullName() : font.getFontName());
GooString *lSize;
if(!xml){
diff --git a/utils/HtmlOutputDev.cc b/utils/HtmlOutputDev.cc
index 1d1b628..e4bd0b1 100644
--- a/utils/HtmlOutputDev.cc
+++ b/utils/HtmlOutputDev.cc
@@ -25,13 +25,14 @@
// Copyright (C) 2009 Warren Toomey <wkt@tuhs.org>
// Copyright (C) 2009, 2011 Carlos Garcia Campos <carlosgc@gnome.org>
// Copyright (C) 2009 Reece Dunn <msclrhd@gmail.com>
-// Copyright (C) 2010 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2010, 2012 Adrian Johnson <ajohnson@redneon.com>
// Copyright (C) 2010 Hib Eris <hib@hiberis.nl>
// Copyright (C) 2010 OSSD CDAC Mumbai by Leena Chourey (leenac@cdacmumbai.in) and Onkar Potdar (onkar@cdacmumbai.in)
// Copyright (C) 2011 Joshua Richardson <jric@chegg.com>
// Copyright (C) 2011 Stephen Reichling <sreichling@chegg.com>
// Copyright (C) 2011, 2012 Igor Slepchin <igor.slepchin@gmail.com>
// Copyright (C) 2012 Ihar Filipau <thephilips@gmail.com>
+// Copyright (C) 2012 Gerald Schmidt <solahcin@gmail.com>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
@@ -399,19 +400,7 @@
h1 /= uLen;
}
for (i = 0; i < uLen; ++i) {
- Unicode u1 = u[i];
- if (u1 >= 0xd800 && u1 <= 0xdbff && i < uLen) {
- // surrogate pair
- const Unicode u2 = u[i + 1];
- if (u2 >= 0xdc00 && u2 <= 0xdfff) {
- u1 = 0x10000 + ((u1 - 0xd800) << 10) + (u2 - 0xdc00);
-
- curStr->addChar(state, x1 + i*w1, y1 + i*h1, w1, h1, u1);
- }
- ++i;
- } else {
- curStr->addChar(state, x1 + i*w1, y1 + i*h1, w1, h1, u1);
- }
+ curStr->addChar(state, x1 + i*w1, y1 + i*h1, w1, h1, u[i]);
}
}
@@ -782,7 +771,7 @@
// http://stackoverflow.com/questions/1309055/cross-browser-way-to-flip-html-image-via-javascript-css
// tested in Chrome, Fx (Linux) and IE9 (W7)
static const char css[] =
- "<STYLE type=\"text/css\">" "\n"
+ "<style type=\"text/css\">" "\n"
"<!--" "\n"
".xflip {" "\n"
" -moz-transform: scaleX(-1);" "\n"
@@ -806,7 +795,7 @@
" filter: fliph + flipv;" "\n"
"}" "\n"
"-->" "\n"
- "</STYLE>" "\n";
+ "</style>" "\n";
fwrite( css, sizeof(css)-1, 1, f );
}
@@ -833,17 +822,17 @@
}
if (!singleHtml)
- fprintf(pageFile,"%s\n<HTML xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n<HEAD>\n<TITLE>Page %d</TITLE>\n\n", DOCTYPE, page);
+ fprintf(pageFile,"%s\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n<head>\n<title>Page %d</title>\n\n", DOCTYPE, page);
else
- fprintf(pageFile,"%s\n<HTML xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n<HEAD>\n<TITLE>%s</TITLE>\n\n", DOCTYPE, tmp->getCString());
+ fprintf(pageFile,"%s\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n<head>\n<title>%s</title>\n\n", DOCTYPE, tmp->getCString());
delete tmp;
GooString *htmlEncoding = HtmlOutputDev::mapEncodingToHtml(globalParams->getTextEncodingName());
if (!singleHtml)
- fprintf(pageFile, "<META http-equiv=\"Content-Type\" content=\"text/html; charset=%s\"/>\n", htmlEncoding->getCString());
+ fprintf(pageFile, "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\"/>\n", htmlEncoding->getCString());
else
- fprintf(pageFile, "<META http-equiv=\"Content-Type\" content=\"text/html; charset=%s\"/>\n <br/>\n", htmlEncoding->getCString());
+ fprintf(pageFile, "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\"/>\n <br/>\n", htmlEncoding->getCString());
delete htmlEncoding;
}
else
@@ -866,7 +855,7 @@
tmp=basename(DocName);
- fputs("<STYLE type=\"text/css\">\n<!--\n",pageFile);
+ fputs("<style type=\"text/css\">\n<!--\n",pageFile);
fputs("\tp {margin: 0; padding: 0;}",pageFile);
for(int i=fontsPageMarker;i!=fonts->size();i++) {
GooString *fontCSStyle;
@@ -878,20 +867,20 @@
delete fontCSStyle;
}
- fputs("-->\n</STYLE>\n",pageFile);
+ fputs("-->\n</style>\n",pageFile);
if( !noframes )
{
- fputs("</HEAD>\n<BODY bgcolor=\"#A0A0A0\" vlink=\"blue\" link=\"blue\">\n",pageFile);
+ fputs("</head>\n<body bgcolor=\"#A0A0A0\" vlink=\"blue\" link=\"blue\">\n",pageFile);
}
- fprintf(pageFile,"<DIV id=\"page%d-div\" style=\"position:relative;width:%dpx;height:%dpx;\">\n",
+ fprintf(pageFile,"<div id=\"page%d-div\" style=\"position:relative;width:%dpx;height:%dpx;\">\n",
page, pageWidth, pageHeight);
if( !ignore )
{
fprintf(pageFile,
- "<IMG width=\"%d\" height=\"%d\" src=\"%s%03d.%s\" alt=\"background image\"/>\n",
+ "<img width=\"%d\" height=\"%d\" src=\"%s%03d.%s\" alt=\"background image\"/>\n",
pageWidth, pageHeight, tmp->getCString(),
(page-firstPage+1), imgExt->getCString());
}
@@ -901,7 +890,7 @@
for(HtmlString *tmp1=yxStrings;tmp1;tmp1=tmp1->yxNext){
if (tmp1->htext){
fprintf(pageFile,
- "<P style=\"position:absolute;top:%dpx;left:%dpx;white-space:nowrap\" class=\"ft",
+ "<p style=\"position:absolute;top:%dpx;left:%dpx;white-space:nowrap\" class=\"ft",
xoutRound(tmp1->yMin),
xoutRound(tmp1->xMin));
if (!singleHtml) {
@@ -911,15 +900,15 @@
}
fprintf(pageFile,"%d\">", tmp1->fontpos);
fputs(tmp1->htext->getCString(), pageFile);
- fputs("</P>\n", pageFile);
+ fputs("</p>\n", pageFile);
}
}
- fputs("</DIV>\n", pageFile);
+ fputs("</div>\n", pageFile);
if( !noframes )
{
- fputs("</BODY>\n</HTML>\n",pageFile);
+ fputs("</body>\n</html>\n",pageFile);
fclose(pageFile);
}
}
@@ -934,7 +923,7 @@
}
else
{
- fprintf(f,"<A name=%d></a>",pageNum);
+ fprintf(f,"<a name=%d></a>",pageNum);
// Loop over the list of image names on this page
int listlen=imgList->getLength();
for (int i = 0; i < listlen; i++) {
@@ -946,7 +935,7 @@
if (img->xMin > img->xMax) style_index += 1; // xFlip
if (img->yMin > img->yMax) style_index += 2; // yFlip
- fprintf(f,"<IMG%s src=\"%s\"/><br/>\n",styles[style_index],img->fName->getCString());
+ fprintf(f,"<img%s src=\"%s\"/><br/>\n",styles[style_index],img->fName->getCString());
delete img;
}
@@ -959,7 +948,7 @@
fputs("<br/>\n",f);
}
}
- fputs("<hr>\n",f);
+ fputs("<hr/>\n",f);
}
}
@@ -1024,7 +1013,7 @@
GooString* HtmlMetaVar::toString()
{
- GooString *result = new GooString("<META name=\"");
+ GooString *result = new GooString("<meta name=\"");
result->append(name);
result->append("\" content=\"");
result->append(content);
@@ -1070,22 +1059,22 @@
fName=basename(Docname);
fputs(DOCTYPE, fContentsFrame);
- fputs("\n<HTML>",fContentsFrame);
- fputs("\n<HEAD>",fContentsFrame);
- fprintf(fContentsFrame,"\n<TITLE>%s</TITLE>",docTitle->getCString());
+ fputs("\n<html>",fContentsFrame);
+ fputs("\n<head>",fContentsFrame);
+ fprintf(fContentsFrame,"\n<title>%s</title>",docTitle->getCString());
htmlEncoding = mapEncodingToHtml(globalParams->getTextEncodingName());
- fprintf(fContentsFrame, "\n<META http-equiv=\"Content-Type\" content=\"text/html; charset=%s\"/>\n", htmlEncoding->getCString());
+ fprintf(fContentsFrame, "\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\"/>\n", htmlEncoding->getCString());
dumpMetaVars(fContentsFrame);
- fprintf(fContentsFrame, "</HEAD>\n");
- fputs("<FRAMESET cols=\"100,*\">\n",fContentsFrame);
- fprintf(fContentsFrame,"<FRAME name=\"links\" src=\"%s_ind.html\">\n",fName->getCString());
- fputs("<FRAME name=\"contents\" src=",fContentsFrame);
+ fprintf(fContentsFrame, "</head>\n");
+ fputs("<frameset cols=\"100,*\">\n",fContentsFrame);
+ fprintf(fContentsFrame,"<frame name=\"links\" src=\"%s_ind.html\"/>\n",fName->getCString());
+ fputs("<frame name=\"contents\" src=",fContentsFrame);
if (complexMode)
fprintf(fContentsFrame,"\"%s-%d.html\"",fName->getCString(), firstPage);
else
fprintf(fContentsFrame,"\"%ss.html\"",fName->getCString());
- fputs(">\n</FRAMESET>\n</HTML>\n",fContentsFrame);
+ fputs("/>\n</frameset>\n</html>\n",fContentsFrame);
delete fName;
delete htmlEncoding;
@@ -1143,12 +1132,12 @@
}
delete left;
fputs(DOCTYPE, fContentsFrame);
- fputs("<HTML xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n<HEAD>\n<TITLE></TITLE>\n</HEAD>\n<BODY>\n", fContentsFrame);
+ fputs("<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n<head>\n<title></title>\n</head>\n<body>\n", fContentsFrame);
if (doOutline)
{
GooString *str = basename(Docname);
- fprintf(fContentsFrame, "<A href=\"%s%s\" target=\"contents\">Outline</a><br/>", str->getCString(), complexMode ? "-outline.html" : "s.html#outline");
+ fprintf(fContentsFrame, "<a href=\"%s%s\" target=\"contents\">Outline</a><br/>", str->getCString(), complexMode ? "-outline.html" : "s.html#outline");
delete str;
}
}
@@ -1165,9 +1154,9 @@
}
delete right;
fputs(DOCTYPE, page);
- fputs("<HTML>\n<HEAD>\n<TITLE></TITLE>\n",page);
+ fputs("<html>\n<head>\n<title></title>\n",page);
printCSS(page);
- fputs("</HEAD>\n<BODY>\n",page);
+ fputs("</head>\n<body>\n",page);
}
}
@@ -1194,14 +1183,14 @@
}
else
{
- fprintf(page,"%s\n<HTML xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n<HEAD>\n<TITLE>%s</TITLE>\n", DOCTYPE, docTitle->getCString());
+ fprintf(page,"%s\n<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"\" xml:lang=\"\">\n<head>\n<title>%s</title>\n", DOCTYPE, docTitle->getCString());
- fprintf(page, "<META http-equiv=\"Content-Type\" content=\"text/html; charset=%s\"/>\n", htmlEncoding->getCString());
+ fprintf(page, "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\"/>\n", htmlEncoding->getCString());
dumpMetaVars(page);
printCSS(page);
- fprintf(page,"</HEAD>\n");
- fprintf(page,"<BODY bgcolor=\"#A0A0A0\" vlink=\"blue\" link=\"blue\">\n");
+ fprintf(page,"</head>\n");
+ fprintf(page,"<body bgcolor=\"#A0A0A0\" vlink=\"blue\" link=\"blue\">\n");
}
delete htmlEncoding;
}
@@ -1217,7 +1206,7 @@
deleteGooList(glMetaVars, HtmlMetaVar);
if (fContentsFrame){
- fputs("</BODY>\n</HTML>\n",fContentsFrame);
+ fputs("</body>\n</html>\n",fContentsFrame);
fclose(fContentsFrame);
}
if (page != NULL) {
@@ -1227,7 +1216,7 @@
} else
if ( !complexMode || xml || noframes )
{
- fputs("</BODY>\n</HTML>\n",page);
+ fputs("</body>\n</html>\n",page);
fclose(page);
}
}
@@ -1263,9 +1252,9 @@
if (fContentsFrame)
{
if (complexMode)
- fprintf(fContentsFrame,"<A href=\"%s-%d.html\"",str->getCString(),pageNum);
+ fprintf(fContentsFrame,"<a href=\"%s-%d.html\"",str->getCString(),pageNum);
else
- fprintf(fContentsFrame,"<A href=\"%ss.html#%d\"",str->getCString(),pageNum);
+ fprintf(fContentsFrame,"<a href=\"%ss.html#%d\"",str->getCString(),pageNum);
fprintf(fContentsFrame," target=\"contents\" >Page %d</a><br/>\n",pageNum);
}
}
@@ -1295,7 +1284,7 @@
maxPageWidth = pages->pageWidth;
maxPageHeight = pages->pageHeight;
- //if(!noframes&&!xml) fputs("<br>\n", fContentsFrame);
+ //if(!noframes&&!xml) fputs("<br/>\n", fContentsFrame);
if(!stout && !globalParams->getErrQuiet()) printf("Page-%d\n",(pageNum));
}
@@ -1698,7 +1687,7 @@
if (noframes)
{
output = page;
- fputs("<hr>\n", output);
+ fputs("<hr/>\n", output);
}
else
{
@@ -1713,13 +1702,13 @@
GooString *htmlEncoding =
HtmlOutputDev::mapEncodingToHtml(globalParams->getTextEncodingName());
- fprintf(output, "<HTML xmlns=\"http://www.w3.org/1999/xhtml\" " \
+ fprintf(output, "<html xmlns=\"http://www.w3.org/1999/xhtml\" " \
"lang=\"\" xml:lang=\"\">\n" \
- "<HEAD>\n" \
- "<TITLE>Document Outline</TITLE>\n" \
- "<META http-equiv=\"Content-Type\" content=\"text/html; " \
+ "<head>\n" \
+ "<title>Document Outline</title>\n" \
+ "<meta http-equiv=\"Content-Type\" content=\"text/html; " \
"charset=%s\"/>\n" \
- "</HEAD>\n<BODY>\n", htmlEncoding->getCString());
+ "</head>\n<body>\n", htmlEncoding->getCString());
delete htmlEncoding;
}
}
@@ -1728,11 +1717,11 @@
{
GBool done = newHtmlOutlineLevel(output, outlines, catalog);
if (done && !complexMode)
- fputs("<hr>\n", output);
+ fputs("<hr/>\n", output);
if (bClose)
{
- fputs("</BODY>\n</HTML>\n", output);
+ fputs("</body>\n</html>\n", output);
fclose(output);
}
}
@@ -1752,7 +1741,7 @@
if (level == 1)
{
- fputs("<A name=\"outline\"></a>", output);
+ fputs("<a name=\"outline\"></a>", output);
fputs("<h1>Document Outline</h1>\n", output);
}
fputs("<ul>\n",output);
@@ -1791,10 +1780,10 @@
fputs("<li>",output);
if (linkName)
- fprintf(output,"<A href=\"%s\">", linkName->getCString());
+ fprintf(output,"<a href=\"%s\">", linkName->getCString());
fputs(titleStr->getCString(),output);
if (linkName) {
- fputs("</A>",output);
+ fputs("</a>",output);
delete linkName;
}
delete titleStr;
diff --git a/utils/Makefile.am b/utils/Makefile.am
index ad845c1..d56cc9c 100644
--- a/utils/Makefile.am
+++ b/utils/Makefile.am
@@ -16,13 +16,11 @@
-I$(top_srcdir)/utils \
-I$(top_srcdir)/poppler \
$(UTILS_CFLAGS) \
- $(FONTCONFIG_CFLAGS) \
$(PDFTOCAIRO_CFLAGS)
LDADD = \
$(top_builddir)/poppler/libpoppler.la \
- $(UTILS_LIBS) \
- $(FONTCONFIG_LIBS)
+ $(UTILS_LIBS)
if BUILD_CAIRO_OUTPUT
diff --git a/utils/pdfinfo.cc b/utils/pdfinfo.cc
index cdc5375..bd8b56d 100644
--- a/utils/pdfinfo.cc
+++ b/utils/pdfinfo.cc
@@ -18,6 +18,7 @@
// Copyright (C) 2010 Hib Eris <hib@hiberis.nl>
// Copyright (C) 2011 Vittal Aithal <vittal.aithal@cognidox.com>
// Copyright (C) 2012 Adrian Johnson <ajohnson@redneon.com>
+// Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
@@ -48,7 +49,7 @@
#include "PDFDocFactory.h"
#include "CharTypes.h"
#include "UnicodeMap.h"
-#include "PDFDocEncoding.h"
+#include "UTF.h"
#include "Error.h"
#include "DateInfo.h"
@@ -228,16 +229,17 @@
doc->getStructTreeRoot()->isDict() ? "yes" : "no");
// print form info
- if ((acroForm = doc->getCatalog()->getAcroForm())->isDict()) {
- acroForm->dictLookup("XFA", &xfa);
- if (xfa.isStream() || xfa.isArray()) {
- printf("Form: XFA\n");
- } else {
+ switch (doc->getCatalog()->getFormType())
+ {
+ case Catalog::NoForm:
+ printf("Form: none\n");
+ break;
+ case Catalog::AcroForm:
printf("Form: AcroForm\n");
- }
- xfa.free();
- } else {
- printf("Form: none\n");
+ break;
+ case Catalog::XfaForm:
+ printf("Form: XFA\n");
+ break;
}
// print page count
@@ -246,11 +248,31 @@
// print encryption info
printf("Encrypted: ");
if (doc->isEncrypted()) {
- printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
+ Guchar *fileKey;
+ CryptAlgorithm encAlgorithm;
+ int keyLength;
+ doc->getXRef()->getEncryptionParameters(&fileKey, &encAlgorithm, &keyLength);
+
+ const char *encAlgorithmName = "unknown";
+ switch (encAlgorithm)
+ {
+ case cryptRC4:
+ encAlgorithmName = "RC4";
+ break;
+ case cryptAES:
+ encAlgorithmName = "AES";
+ break;
+ case cryptAES256:
+ encAlgorithmName = "AES-256";
+ break;
+ }
+
+ printf("yes (print:%s copy:%s change:%s addNotes:%s algorithm:%s)\n",
doc->okToPrint(gTrue) ? "yes" : "no",
doc->okToCopy(gTrue) ? "yes" : "no",
doc->okToChange(gTrue) ? "yes" : "no",
- doc->okToAddNotes(gTrue) ? "yes" : "no");
+ doc->okToAddNotes(gTrue) ? "yes" : "no",
+ encAlgorithmName);
} else {
printf("no\n");
}
@@ -379,41 +401,16 @@
UnicodeMap *uMap) {
Object obj;
GooString *s1;
- GBool isUnicode;
- Unicode u, u2;
+ Unicode *u;
char buf[8];
- int i, n;
+ int i, n, len;
if (infoDict->lookup(key, &obj)->isString()) {
fputs(text, stdout);
s1 = obj.getString();
- if ((s1->getChar(0) & 0xff) == 0xfe &&
- (s1->getChar(1) & 0xff) == 0xff) {
- isUnicode = gTrue;
- i = 2;
- } else {
- isUnicode = gFalse;
- i = 0;
- }
- while (i < obj.getString()->getLength()) {
- if (isUnicode) {
- u = ((s1->getChar(i) & 0xff) << 8) |
- (s1->getChar(i+1) & 0xff);
- i += 2;
- if (u >= 0xd800 && u <= 0xdbff && i < obj.getString()->getLength()) {
- // surrogate pair
- u2 = ((s1->getChar(i) & 0xff) << 8) |
- (s1->getChar(i+1) & 0xff);
- i += 2;
- if (u2 >= 0xdc00 && u2 <= 0xdfff) {
- u = 0x10000 + ((u - 0xd800) << 10) + (u2 - 0xdc00);
- }
- }
- } else {
- u = pdfDocEncoding[s1->getChar(i) & 0xff];
- ++i;
- }
- n = uMap->mapUnicode(u, buf, sizeof(buf));
+ len = TextStringToUCS4(s1, &u);
+ for (i = 0; i < len; i++) {
+ n = uMap->mapUnicode(u[i], buf, sizeof(buf));
fwrite(buf, 1, n, stdout);
}
fputc('\n', stdout);
diff --git a/utils/pdfseparate.cc b/utils/pdfseparate.cc
index 25fac5a..35ae020 100644
--- a/utils/pdfseparate.cc
+++ b/utils/pdfseparate.cc
@@ -52,10 +52,6 @@
error(errSyntaxError, -1, "Could not extract page(s) from damaged file ('{0:s}')", srcFileName);
return false;
}
- if (doc->isEncrypted()) {
- error(errSyntaxError, -1, "Could not extract page(s) from encrypted file ('{0:s}')", srcFileName);
- return false;
- }
if (firstPage == 0 && lastPage == 0) {
firstPage = 1;
diff --git a/utils/pdftohtml.1 b/utils/pdftohtml.1
index 44137e4..f08fccb 100644
--- a/utils/pdftohtml.1
+++ b/utils/pdftohtml.1
@@ -70,13 +70,9 @@
.B \-hidden
force hidden text extraction
.TP
-.B \-dev
-output device name for Ghostscript (png16m, jpeg etc).
-Unless this option is specified, Splash will be used
-.TP
-.B \-fmt
+3.B \-fmt
image file format for Splash output (png or jpg).
-If complex is selected, but neither \-fmt or \-dev are specified,
+If complex is selected, but \-fmt is not specified,
\-fmt png will be assumed
.TP
.B \-nomerge
@@ -89,6 +85,9 @@
adjust the word break threshold percent. Default is 10.
Word break occurs when distance between two adjacent characters is
greater than this percent of character height.
+.TP
+.B \-fontfullname
+outputs the font name without any substitutions.
.SH AUTHOR
diff --git a/utils/pdftohtml.cc b/utils/pdftohtml.cc
index d6475b0..97372be 100644
--- a/utils/pdftohtml.cc
+++ b/utils/pdftohtml.cc
@@ -21,6 +21,7 @@
// Copyright (C) 2011 Steven Murdoch <Steven.Murdoch@cl.cam.ac.uk>
// Copyright (C) 2012 Igor Slepchin <igor.redhat@gmail.com>
// Copyright (C) 2012 Ihar Filipau <thephilips@gmail.com>
+// Copyright (C) 2012 Luis Parravicini <lparravi@gmail.com>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
@@ -62,10 +63,6 @@
#include "DateInfo.h"
#include "goo/gfile.h"
-#ifndef GHOSTSCRIPT
-# define GHOSTSCRIPT "gs"
-#endif
-
static int firstPage = 1;
static int lastPage = 0;
static GBool rawOrder = gTrue;
@@ -75,7 +72,6 @@
GBool complexMode=gFalse;
GBool singleHtml=gFalse; // singleHtml
GBool ignore=gFalse;
-static GBool useSplash=gTrue;
static char extension[5]="png";
static double scale=1.5;
GBool noframes=gFalse;
@@ -87,9 +83,9 @@
GBool showHidden = gFalse;
GBool noMerge = gFalse;
+GBool fontFullName = gFalse;
static char ownerPassword[33] = "";
static char userPassword[33] = "";
-static char gsDevice[33] = "none";
static GBool printVersion = gFalse;
static GooString* getInfoString(Dict *infoDict, const char *key);
@@ -132,8 +128,6 @@
"do not merge paragraphs"},
{"-enc", argString, textEncName, sizeof(textEncName),
"output text encoding name"},
- {"-dev", argString, gsDevice, sizeof(gsDevice),
- "output device name for Ghostscript (png16m, jpeg etc)"},
{"-fmt", argString, extension, sizeof(extension),
"image file format for Splash output (png or jpg)"},
{"-v", argFlag, &printVersion, 0,
@@ -146,6 +140,8 @@
"override document DRM settings"},
{"-wbt", argFP, &wordBreakThreshold, 0,
"word break threshold (default 10 percent)"},
+ {"-fontfullname", argFlag, &fontFullName, 0,
+ "outputs font full name"},
{NULL}
};
@@ -181,18 +177,15 @@
GooString *docTitle = NULL;
GooString *author = NULL, *keywords = NULL, *subject = NULL, *date = NULL;
GooString *htmlFileName = NULL;
- GooString *psFileName = NULL;
HtmlOutputDev *htmlOut = NULL;
#ifdef HAVE_SPLASH
SplashOutputDev *splashOut = NULL;
#endif
- PSOutputDev *psOut = NULL;
GBool doOutline;
GBool ok;
char *p;
GooString *ownerPW, *userPW;
Object info;
- const char * extsList[] = {"png", "jpeg", "bmp", "pcx", "tiff", "pbm", NULL};
// parse args
ok = parseArgs(argDesc, &argc, argv);
@@ -344,36 +337,6 @@
info.free();
if( !docTitle ) docTitle = new GooString(htmlFileName);
- if( strcmp("none", gsDevice) ) {
- useSplash = gFalse;
- /* determine extensions of output background images */
- int i;
- for(i = 0; extsList[i]; i++)
- {
- if( strstr(gsDevice, extsList[i]) != (char *) NULL )
- {
- strncpy(extension, extsList[i], sizeof(extension));
- break;
- }
- }
- }
-
-#ifndef HAVE_SPLASH
- if( useSplash ) {
- fprintf(stderr, "You are trying to use the -fmt option but your pdftohtml was built without support for it. Please use the -dev option\n");
- delete docTitle;
- delete author;
- delete keywords;
- delete subject;
- delete date;
- delete htmlFileName;
- delete globalParams;
- delete fileName;
- delete doc;
- return -1;
- }
-#endif
-
if (!singleHtml)
rawOrder = complexMode; // todo: figure out what exactly rawOrder do :)
else
@@ -421,87 +384,43 @@
}
if ((complexMode || singleHtml) && !xml && !ignore) {
- if(useSplash) {
#ifdef HAVE_SPLASH
- GooString *imgFileName = NULL;
- // White paper color
- SplashColor color;
- color[0] = color[1] = color[2] = 255;
- // If the user specified "jpg" use JPEG, otherwise PNG
- SplashImageFileFormat format = strcmp(extension, "jpg") ?
- splashFormatPng : splashFormatJpeg;
+ GooString *imgFileName = NULL;
+ // White paper color
+ SplashColor color;
+ color[0] = color[1] = color[2] = 255;
+ // If the user specified "jpg" use JPEG, otherwise PNG
+ SplashImageFileFormat format = strcmp(extension, "jpg") ?
+ splashFormatPng : splashFormatJpeg;
- splashOut = new SplashOutputDevNoText(splashModeRGB8, 4, gFalse, color);
- splashOut->startDoc(doc);
+ splashOut = new SplashOutputDevNoText(splashModeRGB8, 4, gFalse, color);
+ splashOut->startDoc(doc);
- for (int pg = firstPage; pg <= lastPage; ++pg) {
- doc->displayPage(splashOut, pg,
- 72 * scale, 72 * scale,
- 0, gTrue, gFalse, gFalse);
- SplashBitmap *bitmap = splashOut->getBitmap();
+ for (int pg = firstPage; pg <= lastPage; ++pg) {
+ doc->displayPage(splashOut, pg,
+ 72 * scale, 72 * scale,
+ 0, gTrue, gFalse, gFalse);
+ SplashBitmap *bitmap = splashOut->getBitmap();
- imgFileName = GooString::format("{0:s}{1:03d}.{2:s}",
- htmlFileName->getCString(), pg, extension);
+ imgFileName = GooString::format("{0:s}{1:03d}.{2:s}",
+ htmlFileName->getCString(), pg, extension);
- bitmap->writeImgFile(format, imgFileName->getCString(),
- 72 * scale, 72 * scale);
+ bitmap->writeImgFile(format, imgFileName->getCString(),
+ 72 * scale, 72 * scale);
- delete imgFileName;
- }
-
- delete splashOut;
-#endif
- } else {
- int h=xoutRound(htmlOut->getPageHeight()/scale);
- int w=xoutRound(htmlOut->getPageWidth()/scale);
- //int h=xoutRound(doc->getPageHeight(1)/scale);
- //int w=xoutRound(doc->getPageWidth(1)/scale);
-
- psFileName = new GooString(htmlFileName->getCString());
- psFileName->append(".ps");
-
- psOut = new PSOutputDev(psFileName->getCString(), doc,
- NULL, firstPage, lastPage, psModePS, w, h);
- psOut->setDisplayText(gFalse);
- doc->displayPages(psOut, firstPage, lastPage, 72, 72, 0,
- gTrue, gFalse, gFalse);
- delete psOut;
-
- /*sprintf(buf, "%s -sDEVICE=png16m -dBATCH -dNOPROMPT -dNOPAUSE -r%d -sOutputFile=%s%%03d.png -g%dx%d -q %s", GHOSTSCRIPT, resolution, htmlFileName->getCString(), w, h,
- psFileName->getCString());*/
-
- GooString *gsCmd = new GooString(GHOSTSCRIPT);
- GooString *tw, *th, *sc;
- gsCmd->append(" -sDEVICE=");
- gsCmd->append(gsDevice);
- gsCmd->append(" -dBATCH -dNOPROMPT -dNOPAUSE -r");
- sc = GooString::fromInt(static_cast<int>(72*scale));
- gsCmd->append(sc);
- gsCmd->append(" -sOutputFile=");
- gsCmd->append("\"");
- gsCmd->append(htmlFileName);
- gsCmd->append("%03d.");
- gsCmd->append(extension);
- gsCmd->append("\" -g");
- tw = GooString::fromInt(static_cast<int>(scale*w));
- gsCmd->append(tw);
- gsCmd->append("x");
- th = GooString::fromInt(static_cast<int>(scale*h));
- gsCmd->append(th);
- gsCmd->append(" -q \"");
- gsCmd->append(psFileName);
- gsCmd->append("\"");
- // printf("running: %s\n", gsCmd->getCString());
- if( !executeCommand(gsCmd->getCString()) && !errQuiet) {
- error(errIO, -1, "Failed to launch Ghostscript!\n");
- }
- unlink(psFileName->getCString());
- delete tw;
- delete th;
- delete sc;
- delete gsCmd;
- delete psFileName;
+ delete imgFileName;
}
+
+ delete splashOut;
+#else
+ fprintf(stderr, "Your pdftohtml was built without splash backend support. It is needed for the option you want to use.\n");
+ delete htmlOut;
+ delete htmlFileName;
+ delete globalParams;
+ delete fileName;
+ delete doc;
+ return -1;
+#endif
}
delete htmlOut;
diff --git a/utils/pdftoppm.cc b/utils/pdftoppm.cc
index 04a0dfb..cebb12a 100644
--- a/utils/pdftoppm.cc
+++ b/utils/pdftoppm.cc
@@ -23,7 +23,7 @@
// Copyright (C) 2010 Hib Eris <hib@hiberis.nl>
// Copyright (C) 2010 Jonathan Liu <net147@gmail.com>
// Copyright (C) 2010 William Bader <williambader@hotmail.com>
-// Copyright (C) 2011 Thomas Freitag <Thomas.Freitag@alfa.de>
+// Copyright (C) 2011, 2012 Thomas Freitag <Thomas.Freitag@alfa.de>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
@@ -353,10 +353,8 @@
#if SPLASH_CMYK
if (jpegcmyk || overprint) {
globalParams->setOverprintPreview(gTrue);
- paperColor[0] = 0;
- paperColor[1] = 0;
- paperColor[2] = 0;
- paperColor[3] = 0;
+ for (int cp = 0; cp < SPOT_NCOMPS+4; cp++)
+ paperColor[cp] = 0;
} else
#endif
{
@@ -367,7 +365,7 @@
splashOut = new SplashOutputDev(mono ? splashModeMono1 :
gray ? splashModeMono8 :
#if SPLASH_CMYK
- (jpegcmyk || overprint) ? splashModeCMYK8 :
+ (jpegcmyk || overprint) ? splashModeDeviceN8 :
#endif
splashModeRGB8, 4,
gFalse, paperColor);
diff --git a/utils/pdfunite.cc b/utils/pdfunite.cc
index 212f89b..a16f4dd 100644
--- a/utils/pdfunite.cc
+++ b/utils/pdfunite.cc
@@ -154,7 +154,7 @@
outStr->printf("/Parent %d 0 R", rootNum + 1);
} else {
outStr->printf("/%s ", key);
- PDFDoc::writeObject(&value, NULL, outStr, yRef, offsets[i]);
+ PDFDoc::writeObject(&value, outStr, yRef, offsets[i], NULL, cryptRC4, 0, 0, 0);
}
value.free();
}