[poppler] 8 commits - glib/demo glib/Makefile.am glib/poppler-document.cc glib/poppler-document.h glib/poppler.h glib/poppler-layer.cc glib/poppler-layer.h glib/poppler-private.h glib/test-poppler-glib.cc poppler/Annot.cc poppler/Annot.h poppler/Catalog.cc poppler/Gfx.cc poppler/Gfx.h poppler/OptionalContent.cc poppler/OptionalContent.h qt4/src qt4/tests
Carlos Garcia Campos
carlosgc at kemper.freedesktop.org
Sat Nov 8 12:01:09 PST 2008
glib/Makefile.am | 2
glib/demo/Makefile.am | 2
glib/demo/layers.c | 511 +++++++++++++++++++++++++++++++++++++++++
glib/demo/layers.h | 31 ++
glib/demo/main.c | 4
glib/poppler-document.cc | 377 ++++++++++++++++++++++++++++++
glib/poppler-document.h | 12
glib/poppler-layer.cc | 201 ++++++++++++++++
glib/poppler-layer.h | 43 +++
glib/poppler-private.h | 21 +
glib/poppler.h | 3
glib/test-poppler-glib.cc | 63 ++++-
poppler/Annot.cc | 20 -
poppler/Annot.h | 4
poppler/Catalog.cc | 4
poppler/Gfx.cc | 113 ++++++---
poppler/Gfx.h | 7
poppler/OptionalContent.cc | 38 +--
poppler/OptionalContent.h | 23 +
qt4/src/poppler-optcontent.cc | 6
qt4/tests/check_optcontent.cpp | 8
21 files changed, 1405 insertions(+), 88 deletions(-)
New commits:
commit 471255c5a3850984997d91c7850759eb0c7e8a9c
Author: Carlos Garcia Campos <carlosgc at gnome.org>
Date: Sat Nov 8 20:58:57 2008 +0100
[glib-demo] Add Optional Content demo
diff --git a/glib/demo/Makefile.am b/glib/demo/Makefile.am
index a79dbec..781c974 100644
--- a/glib/demo/Makefile.am
+++ b/glib/demo/Makefile.am
@@ -24,6 +24,8 @@ poppler_glib_demo_SOURCES = \
images.c \
info.h \
info.cc \
+ layers.h \
+ layers.c \
links.h \
links.c \
outline.h \
diff --git a/glib/demo/layers.c b/glib/demo/layers.c
new file mode 100644
index 0000000..ac93376
--- /dev/null
+++ b/glib/demo/layers.c
@@ -0,0 +1,511 @@
+/*
+ * Copyright (C) 2008 Carlos Garcia Campos <carlosgc at 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 <gtk/gtk.h>
+
+#include "layers.h"
+
+enum {
+ LAYERS_TITLE_COLUMN,
+ LAYERS_VISIBILITY_COLUMN,
+ LAYERS_ENABLE_COLUMN,
+ LAYERS_SHOWTOGGLE_COLUMN,
+ LAYERS_RB_GROUP_COLUMN,
+ LAYERS_LAYER_COLUMN,
+ N_COLUMNS
+};
+
+typedef struct {
+ PopplerDocument *doc;
+ guint page;
+ GtkWidget *treeview;
+ GtkWidget *darea;
+
+#if defined (HAVE_CAIRO)
+ cairo_surface_t *surface;
+#else
+ GdkPixbuf *pixbuf;
+#endif
+} PgdLayersDemo;
+
+static void
+pgd_layers_free (PgdLayersDemo *demo)
+{
+ if (!demo)
+ return;
+
+ if (demo->doc) {
+ g_object_unref (demo->doc);
+ demo->doc = NULL;
+ }
+
+#if defined (HAVE_CAIRO)
+ if (demo->surface) {
+ cairo_surface_destroy (demo->surface);
+ demo->surface = NULL;
+ }
+#else
+ if (demo->pixbuf) {
+ g_object_unref (demo->pixbuf);
+ demo->pixbuf = NULL;
+ }
+#endif
+
+ g_free (demo);
+}
+
+static void
+build_tree (PopplerDocument *document,
+ GtkTreeModel *model,
+ GtkTreeIter *parent,
+ PopplerLayersIter *iter)
+{
+
+ do {
+ GtkTreeIter tree_iter;
+ PopplerLayersIter *child;
+ PopplerLayer *layer;
+ gboolean visible;
+ gchar *markup;
+ gint rb_group = 0;
+
+ layer = poppler_layers_iter_get_layer (iter);
+ if (layer) {
+ markup = g_markup_escape_text (poppler_layer_get_title (layer), -1);
+ visible = poppler_layer_is_visible (layer);
+ rb_group = poppler_layer_get_radio_button_group_id (layer);
+ } else {
+ gchar *title;
+
+ title = poppler_layers_iter_get_title (iter);
+ markup = g_markup_escape_text (title, -1);
+ g_free (title);
+
+ visible = FALSE;
+ layer = NULL;
+ }
+
+ gtk_tree_store_append (GTK_TREE_STORE (model), &tree_iter, parent);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &tree_iter,
+ LAYERS_TITLE_COLUMN, markup,
+ LAYERS_VISIBILITY_COLUMN, visible,
+ LAYERS_ENABLE_COLUMN, TRUE, /* FIXME */
+ LAYERS_SHOWTOGGLE_COLUMN, (layer != NULL),
+ LAYERS_RB_GROUP_COLUMN, rb_group,
+ LAYERS_LAYER_COLUMN, layer,
+ -1);
+ if (layer)
+ g_object_unref (layer);
+ g_free (markup);
+
+ child = poppler_layers_iter_get_child (iter);
+ if (child)
+ build_tree (document, model, &tree_iter, child);
+ poppler_layers_iter_free (child);
+ } while (poppler_layers_iter_next (iter));
+}
+
+GtkTreeModel *
+pgd_layers_create_model (PopplerDocument *document)
+{
+ GtkTreeModel *model;
+ PopplerLayersIter *iter;
+
+ iter = poppler_layers_iter_new (document);
+ if (iter) {
+ model = GTK_TREE_MODEL (
+ gtk_tree_store_new (N_COLUMNS,
+ G_TYPE_STRING,
+ G_TYPE_BOOLEAN,
+ G_TYPE_BOOLEAN,
+ G_TYPE_BOOLEAN,
+ G_TYPE_INT,
+ G_TYPE_OBJECT));
+ build_tree (document, model, NULL, iter);
+ poppler_layers_iter_free (iter);
+ } else {
+ GtkTreeIter tree_iter;
+ gchar *markup;
+
+ model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING));
+ gtk_list_store_append (GTK_LIST_STORE (model), &tree_iter);
+ markup = g_strdup_printf ("<span size=\"larger\" style=\"italic\">%s</span>",
+ "The document doesn't contain layers");
+ gtk_list_store_set (GTK_LIST_STORE (model), &tree_iter,
+ 0, markup, -1);
+ g_free (markup);
+ }
+
+ return model;
+}
+
+#if defined (HAVE_CAIRO)
+static cairo_surface_t *
+pgd_layers_render_page (PgdLayersDemo *demo)
+{
+ cairo_t *cr;
+ PopplerPage *page;
+ gdouble width, height;
+ cairo_surface_t *surface = NULL;
+
+ page = poppler_document_get_page (demo->doc, demo->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;
+}
+#else
+static GdkPixbuf *
+pgd_layers_render_page (PgdLayersDemo *demo)
+{
+ PopplerPage *page;
+ gdouble width, height;
+ GdkPixbuf *pixbuf = NULL;
+
+ page = poppler_document_get_page (demo->doc, demo->page);
+ if (!page)
+ return NULL;
+
+ poppler_page_get_size (page, &width, &height);
+ gtk_widget_set_size_request (demo->darea, width, height);
+
+ pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
+ FALSE, 8, width, height);
+ gdk_pixbuf_fill (pixbuf, 0xffffff);
+ poppler_page_render_to_pixbuf (page, 0, 0,
+ width, height,
+ 1.0, 0, pixbuf);
+ g_object_unref (page);
+
+ return pixbuf;
+}
+#endif
+
+static gboolean
+pgd_layers_viewer_drawing_area_expose (GtkWidget *area,
+ GdkEventExpose *event,
+ PgdLayersDemo *demo)
+{
+#if defined (HAVE_CAIRO)
+ cairo_t *cr;
+
+ if (!demo->surface) {
+ demo->surface = pgd_layers_render_page (demo);
+ if (!demo->surface)
+ return FALSE;
+ }
+#else
+
+ if (!demo->pixbuf) {
+ demo->pixbuf = pgd_layers_render_page (demo);
+ if (!demo->pixbuf)
+ return FALSE;
+ }
+#endif
+
+ gdk_window_clear (area->window);
+
+#if defined (HAVE_CAIRO)
+ cr = gdk_cairo_create (area->window);
+ cairo_set_source_surface (cr, demo->surface, 0, 0);
+ cairo_paint (cr);
+ cairo_destroy (cr);
+#else
+ gdk_draw_pixbuf (area->window,
+ area->style->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);
+#endif
+
+ return TRUE;
+}
+
+static gboolean
+pgd_layers_viewer_redraw (PgdLayersDemo *demo)
+{
+#if defined (HAVE_CAIRO)
+ cairo_surface_destroy (demo->surface);
+ demo->surface = NULL;
+#else
+ g_object_unref (demo->pixbuf);
+ demo->pixbuf = NULL;
+#endif
+ gtk_widget_queue_draw (demo->darea);
+
+ return FALSE;
+}
+
+static void
+pgd_layers_viewer_queue_redraw (PgdLayersDemo *demo)
+{
+ g_idle_add ((GSourceFunc)pgd_layers_viewer_redraw, demo);
+}
+
+static void
+pgd_layers_page_selector_value_changed (GtkSpinButton *spinbutton,
+ PgdLayersDemo *demo)
+{
+ demo->page = (gint)gtk_spin_button_get_value (spinbutton) - 1;
+ pgd_layers_viewer_queue_redraw (demo);
+}
+
+static GtkWidget *
+pgd_layers_create_viewer (PgdLayersDemo *demo)
+{
+ GtkWidget *vbox, *hbox;
+ GtkWidget *label;
+ GtkWidget *swindow;
+ GtkWidget *page_selector;
+ guint n_pages;
+ gchar *str;
+
+ vbox = gtk_vbox_new (FALSE, 6);
+
+ hbox = gtk_hbox_new (FALSE, 6);
+
+ label = gtk_label_new ("Page:");
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
+ gtk_widget_show (label);
+
+ n_pages = poppler_document_get_n_pages (demo->doc);
+ page_selector = gtk_spin_button_new_with_range (1, n_pages, 1);
+ g_signal_connect (G_OBJECT (page_selector), "value-changed",
+ G_CALLBACK (pgd_layers_page_selector_value_changed),
+ (gpointer)demo);
+ gtk_box_pack_start (GTK_BOX (hbox), page_selector, FALSE, TRUE, 0);
+ gtk_widget_show (page_selector);
+
+ str = g_strdup_printf ("of %d", n_pages);
+ label = gtk_label_new (str);
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
+ gtk_widget_show (label);
+ g_free (str);
+
+ gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
+ 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),
+ (gpointer)demo);
+
+ swindow = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (swindow), demo->darea);
+ gtk_widget_show (demo->darea);
+
+ gtk_box_pack_start (GTK_BOX (vbox), swindow, TRUE, TRUE, 0);
+ gtk_widget_show (swindow);
+
+ return vbox;
+}
+
+static gboolean
+update_kids (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ GtkTreeIter *parent)
+{
+ if (gtk_tree_store_is_ancestor (GTK_TREE_STORE (model), parent, iter)) {
+ gboolean visible;
+
+ gtk_tree_model_get (model, parent,
+ LAYERS_VISIBILITY_COLUMN, &visible,
+ -1);
+ gtk_tree_store_set (GTK_TREE_STORE (model), iter,
+ LAYERS_ENABLE_COLUMN, visible,
+ -1);
+ }
+
+ return FALSE;
+}
+
+static gboolean
+clear_rb_group (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gint *rb_group)
+{
+ gint group;
+
+ gtk_tree_model_get (model, iter,
+ LAYERS_RB_GROUP_COLUMN, &group,
+ -1);
+
+ if (group == *rb_group) {
+ gtk_tree_store_set (GTK_TREE_STORE (model), iter,
+ LAYERS_VISIBILITY_COLUMN, FALSE,
+ -1);
+ }
+
+ return FALSE;
+}
+
+static void
+pgd_layers_visibility_changed (GtkCellRendererToggle *cell,
+ gchar *path_str,
+ PgdLayersDemo *demo)
+{
+ GtkTreeModel *model;
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ gboolean visible;
+ PopplerLayer *layer;
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (demo->treeview));
+
+ path = gtk_tree_path_new_from_string (path_str);
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_get (model, &iter,
+ LAYERS_VISIBILITY_COLUMN, &visible,
+ LAYERS_LAYER_COLUMN, &layer,
+ -1);
+
+ visible = !visible;
+ visible ? poppler_layer_show (layer) : poppler_layer_hide (layer);
+
+ if (visible) {
+ gint rb_group;
+
+ rb_group = poppler_layer_get_radio_button_group_id (layer);
+ if (rb_group) {
+ gtk_tree_model_foreach (model,
+ (GtkTreeModelForeachFunc)clear_rb_group,
+ &rb_group);
+ }
+ }
+
+ gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
+ LAYERS_VISIBILITY_COLUMN, visible,
+ -1);
+
+ if (poppler_layer_is_parent (layer)) {
+ gtk_tree_model_foreach (model,
+ (GtkTreeModelForeachFunc)update_kids,
+ &iter);
+ }
+
+ pgd_layers_viewer_queue_redraw (demo);
+
+ gtk_tree_path_free (path);
+ g_object_unref (layer);
+}
+
+GtkWidget *
+pgd_layers_create_widget (PopplerDocument *document)
+{
+ PgdLayersDemo *demo;
+ GtkWidget *swindow;
+ GtkWidget *treeview;
+ GtkTreeModel *model;
+ GtkCellRenderer *renderer;
+ GtkTreeSelection *selection;
+ GtkWidget *hpaned, *viewer;
+
+ demo = g_new0 (PgdLayersDemo, 1);
+ demo->doc = g_object_ref (document);
+
+ hpaned = gtk_hpaned_new ();
+
+ viewer = pgd_layers_create_viewer (demo);
+
+ swindow = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+
+ model = pgd_layers_create_model (document);
+ treeview = gtk_tree_view_new_with_model (model);
+ demo->treeview = treeview;
+ g_object_unref (model);
+
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
+ 0, "Layer",
+ renderer,
+ "markup", LAYERS_TITLE_COLUMN,
+ NULL);
+ g_object_set (G_OBJECT (renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
+ g_object_set (G_OBJECT (gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), 0)),
+ "expand", TRUE, NULL);
+
+ if (GTK_IS_TREE_STORE (model)) {
+ renderer = gtk_cell_renderer_toggle_new ();
+ gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
+ 1, "Show/Hide",
+ renderer,
+ "active", LAYERS_VISIBILITY_COLUMN,
+ "activatable", LAYERS_ENABLE_COLUMN,
+ "visible", LAYERS_SHOWTOGGLE_COLUMN,
+ NULL);
+
+ g_signal_connect (renderer, "toggled",
+ G_CALLBACK (pgd_layers_visibility_changed),
+ (gpointer)demo);
+ gtk_tree_view_column_set_clickable (gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), 1),
+ TRUE);
+ }
+
+ gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)),
+ GTK_SELECTION_NONE);
+
+ gtk_container_add (GTK_CONTAINER (swindow), treeview);
+ gtk_widget_show (treeview);
+
+ gtk_paned_add1 (GTK_PANED (hpaned), swindow);
+ gtk_widget_show (swindow);
+
+ gtk_paned_add2 (GTK_PANED (hpaned), viewer);
+ gtk_widget_show (viewer);
+
+ gtk_paned_set_position (GTK_PANED (hpaned), 150);
+
+ g_object_weak_ref (G_OBJECT (hpaned),
+ (GWeakNotify)pgd_layers_free,
+ (gpointer)demo);
+
+ return hpaned;
+}
diff --git a/glib/demo/layers.h b/glib/demo/layers.h
new file mode 100644
index 0000000..88b43c3
--- /dev/null
+++ b/glib/demo/layers.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2008 Carlos Garcia Campos <carlosgc at 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 <gtk/gtk.h>
+#include <poppler.h>
+
+#ifndef _LAYERS_H_
+#define _LAYERS_H_
+
+G_BEGIN_DECLS
+
+GtkWidget *pgd_layers_create_widget (PopplerDocument *document);
+
+G_END_DECLS
+
+#endif /* _LAYERS_H_ */
diff --git a/glib/demo/main.c b/glib/demo/main.c
index 3c26e61..ebbb595 100644
--- a/glib/demo/main.c
+++ b/glib/demo/main.c
@@ -31,6 +31,7 @@
#include "images.h"
#include "annots.h"
#include "attachments.h"
+#include "layers.h"
enum {
PGD_TITLE_COLUMN,
@@ -55,7 +56,8 @@ static const PopplerGlibDemo demo_list[] = {
{ "Page Transitions", pgd_transitions_create_widget },
{ "Images", pgd_images_create_widget },
{ "Annots", pgd_annots_create_widget },
- { "Attachments", pgd_attachments_create_widget }
+ { "Attachments", pgd_attachments_create_widget },
+ { "Layers", pgd_layers_create_widget }
};
static void
commit 7363c25e1d83332932d9b4fe16d7fb4e364da628
Author: Carlos Garcia Campos <carlosgc at gnome.org>
Date: Sun Oct 26 19:47:35 2008 +0100
[glib] Add Optional Content support
diff --git a/glib/Makefile.am b/glib/Makefile.am
index 187caed..806a37a 100644
--- a/glib/Makefile.am
+++ b/glib/Makefile.am
@@ -67,6 +67,7 @@ poppler_glib_public_headers = \
poppler-attachment.h \
poppler-form-field.h \
poppler-annot.h \
+ poppler-layer.h \
poppler.h
poppler_glib_includedir = $(includedir)/poppler/glib
@@ -85,6 +86,7 @@ libpoppler_glib_la_SOURCES = \
poppler-attachment.cc \
poppler-form-field.cc \
poppler-annot.cc \
+ poppler-layer.cc \
poppler.cc \
poppler-private.h
diff --git a/glib/poppler-document.cc b/glib/poppler-document.cc
index ef5deb0..352149b 100644
--- a/glib/poppler-document.cc
+++ b/glib/poppler-document.cc
@@ -29,6 +29,7 @@
#include <FontInfo.h>
#include <PDFDocEncoding.h>
#include <DateInfo.h>
+#include <OptionalContent.h>
#include "poppler.h"
#include "poppler-private.h"
@@ -53,6 +54,8 @@ enum {
PROP_METADATA
};
+static void poppler_document_layers_free (PopplerDocument *document);
+
typedef struct _PopplerDocumentClass PopplerDocumentClass;
struct _PopplerDocumentClass
{
@@ -294,6 +297,7 @@ poppler_document_finalize (GObject *object)
{
PopplerDocument *document = POPPLER_DOCUMENT (object);
+ poppler_document_layers_free (document);
delete document->output_dev;
delete document->doc;
}
@@ -1353,6 +1357,379 @@ poppler_font_info_free (PopplerFontInfo *font_info)
}
+/* Optional content (layers) */
+static Layer *
+layer_new (OptionalContentGroup *oc)
+{
+ Layer *layer;
+
+ layer = g_new0 (Layer, 1);
+ layer->oc = oc;
+
+ return layer;
+}
+
+static void
+layer_free (Layer *layer)
+{
+ if (!layer)
+ return;
+
+ if (layer->kids) {
+ g_list_foreach (layer->kids, (GFunc)layer_free, NULL);
+ g_list_free (layer->kids);
+ }
+
+ if (layer->label) {
+ g_free (layer->label);
+ }
+
+ g_free (layer);
+}
+
+static GList *
+get_optional_content_rbgroups (OCGs *ocg)
+{
+ Array *rb;
+ GList *groups = NULL;
+
+ rb = ocg->getRBGroupsArray ();
+
+ if (rb) {
+ int i, j;
+
+ for (i = 0; i < rb->getLength (); ++i) {
+ Object obj;
+ Array *rb_array;
+ GList *group = NULL;
+
+ rb->get (i, &obj);
+ if (!obj.isArray ()) {
+ obj.free ();
+ continue;
+ }
+
+ rb_array = obj.getArray ();
+ for (j = 0; j < rb_array->getLength (); ++j) {
+ Object ref;
+ OptionalContentGroup *oc;
+
+ rb_array->getNF (j, &ref);
+ if (!ref.isRef ()) {
+ ref.free ();
+ continue;
+ }
+
+ oc = ocg->findOcgByRef (ref.getRef ());
+ group = g_list_prepend (group, oc);
+ ref.free ();
+ }
+ obj.free ();
+
+ groups = g_list_prepend (groups, group);
+ }
+ }
+
+ return groups;
+}
+
+static GList *
+poppler_document_get_layer_rbgroup (PopplerDocument *document,
+ Layer *layer)
+{
+ GList *l;
+
+ for (l = document->layers_rbgroups; l && l->data; l = g_list_next (l)) {
+ GList *group = (GList *)l->data;
+
+ if (g_list_find (group, layer->oc))
+ return group;
+ }
+
+ return NULL;
+}
+
+static GList *
+get_optional_content_items_sorted (OCGs *ocg, Layer *parent, Array *order)
+{
+ GList *items = NULL;
+ Layer *last_item = parent;
+ int i;
+
+ for (i = 0; i < order->getLength (); ++i) {
+ Object orderItem;
+
+ order->get (i, &orderItem);
+
+ if (orderItem.isDict ()) {
+ Object ref;
+
+ order->getNF (i, &ref);
+ if (ref.isRef ()) {
+ OptionalContentGroup *oc = ocg->findOcgByRef (ref.getRef ());
+ Layer *layer = layer_new (oc);
+
+ items = g_list_prepend (items, layer);
+ last_item = layer;
+ }
+ ref.free ();
+ } else if (orderItem.isArray () && orderItem.arrayGetLength () > 0) {
+ if (!last_item) {
+ last_item = layer_new (NULL);
+ items = g_list_prepend (items, last_item);
+ }
+ last_item->kids = get_optional_content_items_sorted (ocg, last_item, orderItem.getArray ());
+ } else if (orderItem.isString ()) {
+ last_item->label = _poppler_goo_string_to_utf8 (orderItem.getString ());
+ }
+ orderItem.free ();
+ }
+
+ return g_list_reverse (items);
+}
+
+static GList *
+get_optional_content_items (OCGs *ocg)
+{
+ Array *order;
+ GList *items = NULL;
+
+ order = ocg->getOrderArray ();
+
+ if (order) {
+ items = get_optional_content_items_sorted (ocg, NULL, order);
+ } else {
+ GooList *ocgs;
+ int i;
+
+ ocgs = ocg->getOCGs ();
+
+ for (i = 0; i < ocgs->getLength (); ++i) {
+ OptionalContentGroup *oc = (OptionalContentGroup *) ocgs->get (i);
+ Layer *layer = layer_new (oc);
+
+ items = g_list_prepend (items, layer);
+ }
+
+ items = g_list_reverse (items);
+ }
+
+ return items;
+}
+
+static GList *
+poppler_document_get_layers (PopplerDocument *document)
+{
+ if (!document->layers) {
+ Catalog *catalog = document->doc->getCatalog ();
+ OCGs *ocg = catalog->getOptContentConfig ();
+
+ if (!ocg)
+ return NULL;
+
+ document->layers = get_optional_content_items (ocg);
+ document->layers_rbgroups = get_optional_content_rbgroups (ocg);
+ }
+
+ return document->layers;
+}
+
+static void
+poppler_document_layers_free (PopplerDocument *document)
+{
+ if (!document->layers)
+ return;
+
+ g_list_foreach (document->layers, (GFunc)layer_free, NULL);
+ g_list_free (document->layers);
+
+ g_list_foreach (document->layers_rbgroups, (GFunc)g_list_free, NULL);
+ g_list_free (document->layers_rbgroups);
+
+ document->layers = NULL;
+ document->layers_rbgroups = NULL;
+}
+
+/* PopplerLayersIter */
+struct _PopplerLayersIter {
+ PopplerDocument *document;
+ GList *items;
+ int index;
+};
+
+GType
+poppler_layers_iter_get_type (void)
+{
+ static GType our_type = 0;
+
+ if (our_type == 0)
+ our_type = g_boxed_type_register_static ("PopplerLayersIter",
+ (GBoxedCopyFunc) poppler_layers_iter_copy,
+ (GBoxedFreeFunc) poppler_layers_iter_free);
+ return our_type;
+}
+
+/**
+ * poppler_layers_iter_copy:
+ * @iter: a #PopplerLayersIter
+ *
+ * Creates a new #PopplerLayersIter as a copy of @iter. This must be freed with
+ * poppler_layers_iter_free().
+ *
+ * Return value: a new #PopplerLayersIter
+ **/
+PopplerLayersIter *
+poppler_layers_iter_copy (PopplerLayersIter *iter)
+{
+ PopplerLayersIter *new_iter;
+
+ g_return_val_if_fail (iter != NULL, NULL);
+
+ new_iter = g_new0 (PopplerLayersIter, 1);
+ *new_iter = *iter;
+ new_iter->document = (PopplerDocument *) g_object_ref (new_iter->document);
+
+ return new_iter;
+}
+
+/**
+ * poppler_layers_iter_free:
+ * @iter: a #PopplerLayersIter
+ *
+ * Frees @iter.
+ **/
+void
+poppler_layers_iter_free (PopplerLayersIter *iter)
+{
+ if (iter == NULL)
+ return;
+
+ g_object_unref (iter->document);
+ g_free (iter);
+}
+
+/**
+ * poppler_layers_iter_new:
+ **/
+PopplerLayersIter *
+poppler_layers_iter_new (PopplerDocument *document)
+{
+ PopplerLayersIter *iter;
+ GList *items;
+
+ items = poppler_document_get_layers (document);
+
+ if (!items)
+ return NULL;
+
+ iter = g_new0 (PopplerLayersIter, 1);
+ iter->document = (PopplerDocument *)g_object_ref (document);
+ iter->items = items;
+
+ return iter;
+}
+
+/**
+ * poppler_layers_iter_get_child:
+ * @parent: a #PopplerLayersIter
+ *
+ * Returns a newly created child of @parent, or %NULL if the iter has no child.
+ * See poppler_layers_iter_new() for more information on this function.
+ *
+ * Return value: a new #PopplerLayersIter, or %NULL
+ **/
+PopplerLayersIter *
+poppler_layers_iter_get_child (PopplerLayersIter *parent)
+{
+ PopplerLayersIter *child;
+ Layer *layer;
+
+ g_return_val_if_fail (parent != NULL, NULL);
+
+ layer = (Layer *) g_list_nth_data (parent->items, parent->index);
+ if (!layer || !layer->kids)
+ return NULL;
+
+ child = g_new0 (PopplerLayersIter, 1);
+ child->document = (PopplerDocument *)g_object_ref (parent->document);
+ child->items = layer->kids;
+
+ g_assert (child->items);
+
+ return child;
+}
+
+/**
+ * poppler_layers_iter_get_title:
+ * @iter: a #PopplerLayersIter
+ *
+ * Returns the title associated with @iter. It must be freed with
+ * g_free().
+ *
+ * Return value: a new string containing the @iter's title or %NULL if @iter doesn't have a title.
+ * The returned string should be freed with g_free() when no longer needed.
+ **/
+gchar *
+poppler_layers_iter_get_title (PopplerLayersIter *iter)
+{
+ Layer *layer;
+
+ g_return_val_if_fail (iter != NULL, NULL);
+
+ layer = (Layer *)g_list_nth_data (iter->items, iter->index);
+
+ return layer->label ? g_strdup (layer->label) : NULL;
+}
+
+/**
+ * poppler_layers_iter_get_layer:
+ * @iter: a #PopplerLayersIter
+ *
+ * Returns the #PopplerLayer associated with @iter. It must be freed with
+ * poppler_layer_free().
+ *
+ * Return value: a new #PopplerLayer, or %NULL if there isn't any layer associated with @iter
+ **/
+PopplerLayer *
+poppler_layers_iter_get_layer (PopplerLayersIter *iter)
+{
+ Layer *layer;
+ PopplerLayer *poppler_layer = NULL;
+
+ g_return_val_if_fail (iter != NULL, NULL);
+
+ layer = (Layer *)g_list_nth_data (iter->items, iter->index);
+ if (layer->oc) {
+ GList *rb_group = NULL;
+
+ rb_group = poppler_document_get_layer_rbgroup (iter->document, layer);
+ poppler_layer = _poppler_layer_new (iter->document, layer, rb_group);
+ }
+
+ return poppler_layer;
+}
+
+/**
+ * poppler_layers_iter_next:
+ * @iter: a #PopplerLayersIter
+ *
+ * Sets @iter to point to the next action at the current level, if valid. See
+ * poppler_layers_iter_new() for more information.
+ *
+ * Return value: %TRUE, if @iter was set to the next action
+ **/
+gboolean
+poppler_layers_iter_next (PopplerLayersIter *iter)
+{
+ g_return_val_if_fail (iter != NULL, FALSE);
+
+ iter->index++;
+ if (iter->index >= (gint)g_list_length (iter->items))
+ return FALSE;
+
+ return TRUE;
+}
+
typedef struct _PopplerPSFileClass PopplerPSFileClass;
struct _PopplerPSFileClass
{
diff --git a/glib/poppler-document.h b/glib/poppler-document.h
index 4585425..2f4f50a 100644
--- a/glib/poppler-document.h
+++ b/glib/poppler-document.h
@@ -157,6 +157,18 @@ gboolean poppler_fonts_iter_is_embedded (PopplerFontsIter *iter);
gboolean poppler_fonts_iter_is_subset (PopplerFontsIter *iter);
gboolean poppler_fonts_iter_next (PopplerFontsIter *iter);
+/* Interface for getting the Layers of a poppler_document */
+#define POPPLER_TYPE_LAYERS_ITER (poppler_layers_iter_get_type ())
+GType poppler_layers_iter_get_type (void) G_GNUC_CONST;
+PopplerLayersIter *poppler_layers_iter_new (PopplerDocument *document);
+PopplerLayersIter *poppler_layers_iter_copy (PopplerLayersIter *iter);
+void poppler_layers_iter_free (PopplerLayersIter *iter);
+
+PopplerLayersIter *poppler_layers_iter_get_child (PopplerLayersIter *parent);
+gchar *poppler_layers_iter_get_title (PopplerLayersIter *iter);
+PopplerLayer *poppler_layers_iter_get_layer (PopplerLayersIter *iter);
+gboolean poppler_layers_iter_next (PopplerLayersIter *iter);
+
/* Export to ps */
#define POPPLER_TYPE_PS_FILE (poppler_ps_file_get_type ())
#define POPPLER_PS_FILE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), POPPLER_TYPE_PS_FILE, PopplerPSFile))
diff --git a/glib/poppler-layer.cc b/glib/poppler-layer.cc
new file mode 100644
index 0000000..2049dc7
--- /dev/null
+++ b/glib/poppler-layer.cc
@@ -0,0 +1,201 @@
+/* poppler-layer.cc: glib interface to poppler
+ *
+ * Copyright (C) 2008 Carlos Garcia Campos <carlosgc at 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 "poppler-layer.h"
+#include "poppler-private.h"
+
+typedef struct _PopplerLayerClass PopplerLayerClass;
+struct _PopplerLayerClass
+{
+ GObjectClass parent_class;
+};
+
+G_DEFINE_TYPE (PopplerLayer, poppler_layer, G_TYPE_OBJECT)
+
+static void
+poppler_layer_finalize (GObject *object)
+{
+ PopplerLayer *poppler_layer = POPPLER_LAYER (object);
+
+ if (poppler_layer->document)
+ {
+ g_object_unref (poppler_layer->document);
+ poppler_layer->document = NULL;
+ }
+
+ if (poppler_layer->title)
+ {
+ g_free (poppler_layer->title);
+ poppler_layer->title = NULL;
+ }
+ poppler_layer->layer = NULL;
+ poppler_layer->rbgroup = NULL;
+
+ G_OBJECT_CLASS (poppler_layer_parent_class)->finalize (object);
+}
+
+static void
+poppler_layer_init (PopplerLayer *layer)
+{
+}
+
+static void
+poppler_layer_class_init (PopplerLayerClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->finalize = poppler_layer_finalize;
+}
+
+PopplerLayer *
+_poppler_layer_new (PopplerDocument *document,
+ Layer *layer,
+ GList *rbgroup)
+{
+ PopplerLayer *poppler_layer;
+
+ g_return_val_if_fail (POPPLER_IS_DOCUMENT (document), NULL);
+ g_return_val_if_fail (layer != NULL, NULL);
+
+ poppler_layer = POPPLER_LAYER (g_object_new (POPPLER_TYPE_LAYER, NULL));
+
+ poppler_layer->document = (PopplerDocument *)g_object_ref (document);
+ poppler_layer->layer = layer;
+ poppler_layer->rbgroup = rbgroup;
+ poppler_layer->title = _poppler_goo_string_to_utf8 (layer->oc->getName ());
+
+ return poppler_layer;
+}
+
+/**
+ * poppler_layer_get_title
+ * @layer: a #PopplerLayer
+ *
+ * Returns the name of the layer suitable for
+ * presentation as a title in a viewer's GUI
+ *
+ * Return value: a string containing the title of the layer
+ **/
+const gchar *
+poppler_layer_get_title (PopplerLayer *poppler_layer)
+{
+ g_return_val_if_fail (POPPLER_IS_LAYER (poppler_layer), NULL);
+
+ return poppler_layer->title;
+}
+
+/**
+ * poppler_layer_is_visible
+ * @layer: a #PopplerLayer
+ *
+ * Returns whether @layer is visible
+ *
+ * Return value: %TRUE if @layer is visible
+ **/
+gboolean
+poppler_layer_is_visible (PopplerLayer *poppler_layer)
+{
+ g_return_val_if_fail (POPPLER_IS_LAYER (poppler_layer), FALSE);
+
+ return poppler_layer->layer->oc->getState () == OptionalContentGroup::On;
+}
+
+/**
+ * poppler_layer_show
+ * @layer: a #PopplerLayer
+ *
+ * Shows @layer
+ **/
+void
+poppler_layer_show (PopplerLayer *poppler_layer)
+{
+ GList *l;
+ Layer *layer;
+
+ g_return_if_fail (POPPLER_IS_LAYER (poppler_layer));
+
+ layer = poppler_layer->layer;
+
+ if (layer->oc->getState () == OptionalContentGroup::On)
+ return;
+
+ layer->oc->setState (OptionalContentGroup::On);
+
+ for (l = poppler_layer->rbgroup; l && l->data; l = g_list_next (l)) {
+ OptionalContentGroup *oc = (OptionalContentGroup *)l->data;
+
+ if (oc != layer->oc)
+ oc->setState (OptionalContentGroup::Off);
+ }
+}
+
+/**
+ * poppler_layer_hide
+ * @layer: a #PopplerLayer
+ *
+ * Hides @layer. If @layer is the parent of other nested layers,
+ * such layers will be also hidden and will be blocked until @layer
+ * is shown again
+ **/
+void
+poppler_layer_hide (PopplerLayer *poppler_layer)
+{
+ Layer *layer;
+
+ g_return_if_fail (POPPLER_IS_LAYER (poppler_layer));
+
+ layer = poppler_layer->layer;
+
+ if (layer->oc->getState () == OptionalContentGroup::Off)
+ return;
+
+ layer->oc->setState (OptionalContentGroup::Off);
+}
+
+
+/**
+ * poppler_layer_is_parent
+ *
+ * Returns whether @layer is parent of other nested layers.
+ *
+ * Return value: %TRUE if @layer is a parent layer
+ **/
+gboolean
+poppler_layer_is_parent (PopplerLayer *poppler_layer)
+{
+ g_return_val_if_fail (POPPLER_IS_LAYER (poppler_layer), FALSE);
+
+ return poppler_layer->layer->kids != NULL;
+}
+
+/**
+ * poppler_layer_get_radio_button_group_id
+ *
+ * Returns the numeric ID the radio button group associated with @layer.
+ *
+ * Return value: the ID of the radio button group associated with @layer,
+ * or 0 if the layer is not associated to any radio button group
+ **/
+gint
+poppler_layer_get_radio_button_group_id (PopplerLayer *poppler_layer)
+{
+ g_return_val_if_fail (POPPLER_IS_LAYER (poppler_layer), FALSE);
+
+ return GPOINTER_TO_INT (poppler_layer->rbgroup);
+}
diff --git a/glib/poppler-layer.h b/glib/poppler-layer.h
new file mode 100644
index 0000000..2434e27
--- /dev/null
+++ b/glib/poppler-layer.h
@@ -0,0 +1,43 @@
+/* poppler-layer.h: glib interface to poppler
+ *
+ * Copyright (C) 2008 Carlos Garcia Campos <carlosgc at 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_LAYER_H__
+#define __POPPLER_LAYER_H__
+
+#include <glib-object.h>
+#include "poppler.h"
+
+G_BEGIN_DECLS
+
+#define POPPLER_TYPE_LAYER (poppler_layer_get_type ())
+#define POPPLER_LAYER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), POPPLER_TYPE_LAYER, PopplerLayer))
+#define POPPLER_IS_LAYER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), POPPLER_TYPE_LAYER))
+
+GType poppler_layer_get_type (void) G_GNUC_CONST;
+
+const gchar *poppler_layer_get_title (PopplerLayer *layer);
+gboolean poppler_layer_is_visible (PopplerLayer *layer);
+void poppler_layer_show (PopplerLayer *layer);
+void poppler_layer_hide (PopplerLayer *layer);
+gboolean poppler_layer_is_parent (PopplerLayer *layer);
+gint poppler_layer_get_radio_button_group_id (PopplerLayer *layer);
+
+G_END_DECLS
+
+#endif /* __POPPLER_LAYER_H__ */
diff --git a/glib/poppler-private.h b/glib/poppler-private.h
index 539714c..663b8e8 100644
--- a/glib/poppler-private.h
+++ b/glib/poppler-private.h
@@ -10,6 +10,7 @@
#include <FontInfo.h>
#include <TextOutputDev.h>
#include <Catalog.h>
+#include <OptionalContent.h>
#if defined (HAVE_CAIRO)
#include <CairoOutputDev.h>
@@ -22,6 +23,8 @@ struct _PopplerDocument
GObject parent_instance;
PDFDoc *doc;
+ GList *layers;
+ GList *layers_rbgroups;
#if defined (HAVE_CAIRO)
CairoOutputDev *output_dev;
#elif defined (HAVE_SPLASH)
@@ -68,12 +71,30 @@ struct _PopplerFormField
FormWidget *widget;
};
+typedef struct _Layer {
+ GList *kids;
+ gchar *label;
+ OptionalContentGroup *oc;
+} Layer;
+
+struct _PopplerLayer
+{
+ GObject parent_instance;
+ PopplerDocument *document;
+ Layer *layer;
+ GList *rbgroup;
+ gchar *title;
+};
+
PopplerPage *_poppler_page_new (PopplerDocument *document,
Page *page,
int index);
PopplerAction *_poppler_action_new (PopplerDocument *document,
LinkAction *link,
const gchar *title);
+PopplerLayer *_poppler_layer_new (PopplerDocument *document,
+ Layer *layer,
+ GList *rbgroup);
PopplerDest *_poppler_dest_new_goto (PopplerDocument *document,
LinkDest *link_dest);
PopplerFormField *_poppler_form_field_new (PopplerDocument *document,
diff --git a/glib/poppler.h b/glib/poppler.h
index 88a330c..d554093 100644
--- a/glib/poppler.h
+++ b/glib/poppler.h
@@ -82,6 +82,7 @@ typedef enum
typedef struct _PopplerDocument PopplerDocument;
typedef struct _PopplerIndexIter PopplerIndexIter;
typedef struct _PopplerFontsIter PopplerFontsIter;
+typedef struct _PopplerLayersIter PopplerLayersIter;
typedef struct _PopplerRectangle PopplerRectangle;
typedef struct _PopplerColor PopplerColor;
typedef struct _PopplerLinkMapping PopplerLinkMapping;
@@ -91,6 +92,7 @@ typedef struct _PopplerFormFieldMapping PopplerFormFieldMapping;
typedef struct _PopplerAnnotMapping PopplerAnnotMapping;
typedef struct _PopplerPage PopplerPage;
typedef struct _PopplerFontInfo PopplerFontInfo;
+typedef struct _PopplerLayer PopplerLayer;
typedef struct _PopplerPSFile PopplerPSFile;
typedef union _PopplerAction PopplerAction;
typedef struct _PopplerDest PopplerDest;
@@ -117,6 +119,7 @@ G_END_DECLS
#include "poppler-features.h"
#include "poppler-document.h"
#include "poppler-page.h"
+#include "poppler-layer.h"
#include "poppler-action.h"
#include "poppler-form-field.h"
#include "poppler-enums.h"
diff --git a/glib/test-poppler-glib.cc b/glib/test-poppler-glib.cc
index 592a7c7..bd33f91 100644
--- a/glib/test-poppler-glib.cc
+++ b/glib/test-poppler-glib.cc
@@ -46,13 +46,52 @@ print_index (PopplerIndexIter *iter, gint deph)
poppler_action_free (action);
child = poppler_index_iter_get_child (iter);
if (child)
- print_index (child, deph + 1);
+ print_index (child, deph + 1);
poppler_index_iter_free (child);
}
while (poppler_index_iter_next (iter));
}
static void
+print_layers (PopplerLayersIter *iter, gint deph)
+{
+ do
+ {
+ PopplerLayersIter *child;
+ PopplerLayer *layer;
+ gint i;
+
+ for (i = 0; i < deph; i++)
+ g_print (" ");
+
+ layer = poppler_layers_iter_get_layer (iter);
+ if (layer)
+ {
+ g_print ("+ %s (%s)\n", poppler_layer_get_title (layer),
+ poppler_layer_is_visible (layer) ?
+ "Visible" : "Hidden");
+ g_object_unref (layer);
+ }
+
+ child = poppler_layers_iter_get_child (iter);
+ if (child)
+ {
+ gchar *title;
+
+ title = poppler_layers_iter_get_title (iter);
+ if (title)
+ {
+ g_print ("+ %s\n", title);
+ g_free (title);
+ }
+ print_layers (child, deph + 1);
+ }
+ poppler_layers_iter_free (child);
+ }
+ while (poppler_layers_iter_next (iter));
+}
+
+static void
print_document_info (PopplerDocument *document)
{
gchar *title, *format, *author, *subject, *keywords, *creator, *producer, *linearized;
@@ -344,6 +383,7 @@ int main (int argc, char *argv[])
gint num_images;
gint num_forms;
gint form_id = 0;
+ PopplerLayersIter *layers_iter;
if (argc != 3)
FAIL ("usage: test-poppler-glib file://FILE PAGE");
@@ -540,6 +580,16 @@ int main (int argc, char *argv[])
else
g_print ("\tNo attachments found\n");
+ layers_iter = poppler_layers_iter_new (document);
+ if (layers_iter)
+ {
+ g_print ("\tLayers:\n");
+ print_layers (layers_iter, 0);
+ poppler_layers_iter_free (layers_iter);
+ }
+ else
+ g_print ("\tNo layers found\n");
+
g_object_unref (G_OBJECT (page));
g_object_unref (G_OBJECT (document));
commit c674566f458b54097f21aae0d4bf8637146565c5
Author: Carlos Garcia Campos <carlosgc at gnome.org>
Date: Sun Oct 26 19:42:53 2008 +0100
Fix memory leaks in OptionalContent
diff --git a/poppler/OptionalContent.cc b/poppler/OptionalContent.cc
index 4a3d4a9..f59b16a 100644
--- a/poppler/OptionalContent.cc
+++ b/poppler/OptionalContent.cc
@@ -28,7 +28,7 @@
//------------------------------------------------------------------------
OCGs::OCGs(Object *ocgObject, XRef *xref) :
- m_orderArray(0), m_rBGroupsArray(), m_xref(xref)
+ m_xref(xref)
{
// we need to parse the dictionary here, and build optionalContentGroups
ok = gTrue;
@@ -126,17 +126,8 @@ OCGs::OCGs(Object *ocgObject, XRef *xref) :
}
off.free();
- Object order;
defaultOcgConfig.dictLookup("Order", &order);
- if ( (order.isArray()) && (order.arrayGetLength() > 0) ) {
- m_orderArray = order.getArray();
- }
-
- Object rbgroups;
defaultOcgConfig.dictLookup("RBGroups", &rbgroups);
- if ( (rbgroups.isArray()) && (rbgroups.arrayGetLength() > 0) ) {
- m_rBGroupsArray = rbgroups.getArray();
- }
ocgList.free();
defaultOcgConfig.free();
@@ -145,6 +136,8 @@ OCGs::OCGs(Object *ocgObject, XRef *xref) :
OCGs::~OCGs()
{
deleteGooList(optionalContentGroups, OptionalContentGroup);
+ order.free();
+ rbgroups.free();
}
diff --git a/poppler/OptionalContent.h b/poppler/OptionalContent.h
index b6136c3..90fded2 100644
--- a/poppler/OptionalContent.h
+++ b/poppler/OptionalContent.h
@@ -40,8 +40,10 @@ public:
OptionalContentGroup* findOcgByRef( const Ref &ref);
- Array* getOrderArray() const { return m_orderArray; }
- Array* getRBGroupsArray() const { return m_rBGroupsArray; }
+ Array* getOrderArray()
+ { return (order.isArray() && order.arrayGetLength() > 0) ? order.getArray() : NULL; }
+ Array* getRBGroupsArray()
+ { return (rbgroups.isArray() && rbgroups.arrayGetLength()) ? rbgroups.getArray() : NULL; }
bool optContentIsVisible( Object *dictRef );
@@ -55,8 +57,8 @@ private:
GooList *optionalContentGroups;
- Array *m_orderArray;
- Array *m_rBGroupsArray;
+ Object order;
+ Object rbgroups;
XRef *m_xref;
};
commit 06ca313b8ecb8abb8dec3b418d118525b7bb0fdf
Author: Carlos Garcia Campos <carlosgc at gnome.org>
Date: Sun Oct 26 19:11:45 2008 +0100
Check annotation optional content properties before drawing it
diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index 6e35b2a..76a7cb1 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -957,13 +957,12 @@ void Annot::initialize(XRef *xrefA, Dict *dict, Catalog *catalog) {
treeKey = 0;
}
obj1.free();
-
- if (dict->lookup("OC", &obj1)->isDict()) {
- optionalContent = new OCGs(&obj1, xrefA);
- } else {
- optionalContent = NULL;
+
+ optContentConfig = catalog->getOptContentConfig();
+ dict->lookupNF("OC", &oc);
+ if (!oc.isRef() && !oc.isNull()) {
+ error (-1, "Annotation OC value not null or dict: %i", oc.getType());
}
- obj1.free();
}
double Annot::getXMin() {
@@ -1013,8 +1012,7 @@ Annot::~Annot() {
if (color)
delete color;
- if (optionalContent)
- delete optionalContent;
+ oc.free();
}
// Set the current fill or stroke color, based on <a> (which should
@@ -1149,6 +1147,12 @@ void Annot::draw(Gfx *gfx, GBool printing) {
return;
}
+ // check the OC
+ if (optContentConfig && oc.isRef()) {
+ if (! optContentConfig->optContentIsVisible(&oc))
+ return;
+ }
+
// draw the appearance stream
appearance.fetch(xref, &obj);
gfx->drawAnnot(&obj, (type == typeLink) ? border : (AnnotBorder *)NULL, color,
diff --git a/poppler/Annot.h b/poppler/Annot.h
index ebd3e74..6dd7850 100644
--- a/poppler/Annot.h
+++ b/poppler/Annot.h
@@ -509,7 +509,6 @@ public:
AnnotBorder *getBorder() const { return border; }
AnnotColor *getColor() const { return color; }
int getTreeKey() const { return treeKey; }
- OCGs *getOptionalContent() const { return optionalContent; }
int getId() { return ref.num; }
@@ -542,7 +541,8 @@ protected:
// for the normal appearance
GooString *appearState; // AS
int treeKey; // Struct Parent;
- OCGs *optionalContent; // OC
+ OCGs *optContentConfig; // Optional content config
+ Object oc; // OC
XRef *xref; // the xref table for this PDF file
Ref ref; // object ref identifying this annotation
commit a6d58927b048aa043cb6b6ed3ee9aeb213578924
Author: Carlos Garcia Campos <carlosgc at gnome.org>
Date: Sat Nov 8 20:50:40 2008 +0100
Do not show hidden optional content
Before any draw operation we first check whether we are inside an
optional marked content element that is currently hidden.
diff --git a/poppler/Gfx.cc b/poppler/Gfx.cc
index be2f19a..871feb3 100644
--- a/poppler/Gfx.cc
+++ b/poppler/Gfx.cc
@@ -496,6 +496,7 @@ Gfx::Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, Catalog *cata
subPage = gFalse;
printCommands = globalParams->getPrintCommands();
profileCommands = globalParams->getProfileCommands();
+ mcStack = NULL;
// start the resource stack
res = new GfxResources(xref, resDict, NULL);
@@ -539,6 +540,7 @@ Gfx::Gfx(XRef *xrefA, OutputDev *outA, Dict *resDict, Catalog *catalogA,
catalog = catalogA;
subPage = gTrue;
printCommands = globalParams->getPrintCommands();
+ mcStack = NULL;
// start the resource stack
res = new GfxResources(xref, resDict, NULL);
@@ -582,6 +584,9 @@ Gfx::~Gfx() {
if (state) {
delete state;
}
+ while (mcStack) {
+ popMarkedContent();
+ }
}
void Gfx::display(Object *obj, GBool topLevel) {
@@ -1562,7 +1567,7 @@ void Gfx::opStroke(Object args[], int numArgs) {
//error(getPos(), "No path in stroke");
return;
}
- if (state->isPath()) {
+ if (state->isPath() && !contentIsHidden()) {
if (state->getStrokeColorSpace()->getMode() == csPattern) {
doPatternStroke();
} else {
@@ -1578,7 +1583,7 @@ void Gfx::opCloseStroke(Object * /*args[]*/, int /*numArgs*/) {
return;
}
state->closePath();
- if (state->isPath()) {
+ if (state->isPath() && !contentIsHidden()) {
if (state->getStrokeColorSpace()->getMode() == csPattern) {
doPatternStroke();
} else {
@@ -1593,7 +1598,7 @@ void Gfx::opFill(Object args[], int numArgs) {
//error(getPos(), "No path in fill");
return;
}
- if (state->isPath()) {
+ if (state->isPath() && !contentIsHidden()) {
if (state->getFillColorSpace()->getMode() == csPattern) {
doPatternFill(gFalse);
} else {
@@ -1608,7 +1613,7 @@ void Gfx::opEOFill(Object args[], int numArgs) {
//error(getPos(), "No path in eofill");
return;
}
- if (state->isPath()) {
+ if (state->isPath() && !contentIsHidden()) {
if (state->getFillColorSpace()->getMode() == csPattern) {
doPatternFill(gTrue);
} else {
@@ -1623,7 +1628,7 @@ void Gfx::opFillStroke(Object args[], int numArgs) {
//error(getPos(), "No path in fill/stroke");
return;
}
- if (state->isPath()) {
+ if (state->isPath() && !contentIsHidden()) {
if (state->getFillColorSpace()->getMode() == csPattern) {
doPatternFill(gFalse);
} else {
@@ -1643,7 +1648,7 @@ void Gfx::opCloseFillStroke(Object args[], int numArgs) {
//error(getPos(), "No path in closepath/fill/stroke");
return;
}
- if (state->isPath()) {
+ if (state->isPath() && !contentIsHidden()) {
state->closePath();
if (state->getFillColorSpace()->getMode() == csPattern) {
doPatternFill(gFalse);
@@ -1664,7 +1669,7 @@ void Gfx::opEOFillStroke(Object args[], int numArgs) {
//error(getPos(), "No path in eofill/stroke");
return;
}
- if (state->isPath()) {
+ if (state->isPath() && !contentIsHidden()) {
if (state->getFillColorSpace()->getMode() == csPattern) {
doPatternFill(gTrue);
} else {
@@ -1684,7 +1689,7 @@ void Gfx::opCloseEOFillStroke(Object args[], int numArgs) {
//error(getPos(), "No path in closepath/eofill/stroke");
return;
}
- if (state->isPath()) {
+ if (state->isPath() && !contentIsHidden()) {
state->closePath();
if (state->getFillColorSpace()->getMode() == csPattern) {
doPatternFill(gTrue);
@@ -1911,10 +1916,12 @@ void Gfx::doTilingPatternFill(GfxTilingPattern *tPat,
if (out->useTilingPatternFill()) {
m1[4] = m[4];
m1[5] = m[5];
- out->tilingPatternFill(state, tPat->getContentStream(),
- tPat->getPaintType(), tPat->getResDict(),
- m1, tPat->getBBox(),
- xi0, yi0, xi1, yi1, xstep, ystep);
+ if (!contentIsHidden()) {
+ out->tilingPatternFill(state, tPat->getContentStream(),
+ tPat->getPaintType(), tPat->getResDict(),
+ m1, tPat->getBBox(),
+ xi0, yi0, xi1, yi1, xstep, ystep);
+ }
} else {
for (yi = yi0; yi < yi1; ++yi) {
for (xi = xi0; xi < xi1; ++xi) {
@@ -1983,7 +1990,8 @@ void Gfx::doShadingPatternFill(GfxShadingPattern *sPat,
if (shading->getHasBackground()) {
state->setFillColor(shading->getBackground());
out->updateFillColor(state);
- out->fill(state);
+ if (!contentIsHidden())
+ out->fill(state);
}
state->clearPath();
@@ -2196,7 +2204,8 @@ void Gfx::doFunctionShFill1(GfxFunctionShading *shading,
state->lineTo(x0 * matrix[0] + y1 * matrix[2] + matrix[4],
x0 * matrix[1] + y1 * matrix[3] + matrix[5]);
state->closePath();
- out->fill(state);
+ if (!contentIsHidden())
+ out->fill(state);
state->clearPath();
// the four corner colors are not close enough -- subdivide the
@@ -2485,7 +2494,8 @@ void Gfx::doAxialShFill(GfxAxialShading *shading) {
state->lineTo(vx1, vy1);
state->lineTo(ux1, uy1);
state->closePath();
- out->fill(state);
+ if (!contentIsHidden())
+ out->fill(state);
state->clearPath();
// set up for next region
@@ -2761,7 +2771,8 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) {
}
// fill the path
- out->fill(state);
+ if (!contentIsHidden())
+ out->fill(state);
state->clearPath();
// step to the next value of t
@@ -2798,7 +2809,8 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) {
state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle));
}
state->closePath();
- out->fill(state);
+ if (!contentIsHidden())
+ out->fill(state);
state->clearPath();
}
@@ -2830,7 +2842,8 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) {
state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle));
}
state->closePath();
- out->fill(state);
+ if (!contentIsHidden())
+ out->fill(state);
state->clearPath();
}
}
@@ -2871,7 +2884,8 @@ void Gfx::gouraudFillTriangle(double x0, double y0, GfxColor *color0,
state->lineTo(x1, y1);
state->lineTo(x2, y2);
state->closePath();
- out->fill(state);
+ if (!contentIsHidden())
+ out->fill(state);
state->clearPath();
} else {
x01 = 0.5 * (x0 + x1);
@@ -2951,7 +2965,8 @@ void Gfx::fillPatch(GfxPatch *patch, int nComps, int depth) {
patch->x[1][0], patch->y[1][0],
patch->x[0][0], patch->y[0][0]);
state->closePath();
- out->fill(state);
+ if (!contentIsHidden())
+ out->fill(state);
state->clearPath();
} else {
for (i = 0; i < 4; ++i) {
@@ -3411,8 +3426,10 @@ void Gfx::doShowText(GooString *s) {
originX *= state->getFontSize();
originY *= state->getFontSize();
state->textTransformDelta(originX, originY, &tOriginX, &tOriginY);
- out->drawChar(state, state->getCurX() + riseX, state->getCurY() + riseY,
- tdx, tdy, tOriginX, tOriginY, code, n, u, uLen);
+ if (!contentIsHidden()) {
+ out->drawChar(state, state->getCurX() + riseX, state->getCurY() + riseY,
+ tdx, tdy, tOriginX, tOriginY, code, n, u, uLen);
+ }
state->shift(tdx, tdy);
p += n;
len -= n;
@@ -3449,7 +3466,8 @@ void Gfx::doShowText(GooString *s) {
dy *= state->getFontSize();
}
state->textTransformDelta(dx, dy, &tdx, &tdy);
- out->drawString(state, s);
+ if (!contentIsHidden())
+ out->drawString(state, s);
state->shift(tdx, tdy);
}
@@ -3643,7 +3661,8 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
obj1.free();
// draw it
- out->drawImageMask(state, ref, str, width, height, invert, inlineImg);
+ if (!contentIsHidden())
+ out->drawImageMask(state, ref, str, width, height, invert, inlineImg);
} else {
@@ -3833,13 +3852,15 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
// draw it
if (haveSoftMask) {
- out->drawSoftMaskedImage(state, ref, str, width, height, colorMap,
- maskStr, maskWidth, maskHeight, maskColorMap);
+ if (!contentIsHidden()) {
+ out->drawSoftMaskedImage(state, ref, str, width, height, colorMap,
+ maskStr, maskWidth, maskHeight, maskColorMap);
+ }
delete maskColorMap;
- } else if (haveExplicitMask) {
+ } else if (haveExplicitMask && !contentIsHidden ()) {
out->drawMaskedImage(state, ref, str, width, height, colorMap,
maskStr, maskWidth, maskHeight, maskInvert);
- } else {
+ } else if (!contentIsHidden()) {
out->drawImage(state, ref, str, width, height, colorMap,
haveColorKeyMask ? maskColors : (int *)NULL, inlineImg);
}
@@ -4153,10 +4174,33 @@ void Gfx::opEndIgnoreUndef(Object args[], int numArgs) {
// marked content operators
//------------------------------------------------------------------------
+struct MarkedContentStack {
+ GBool ocSuppressed; // are we ignoring content based on OptionalContent?
+ MarkedContentStack *next; // next object on stack
+};
+
+void Gfx::popMarkedContent() {
+ MarkedContentStack *mc = mcStack;
+ mcStack = mc->next;
+ delete mc;
+}
+
+void Gfx::pushMarkedContent() {
+ MarkedContentStack *mc = new MarkedContentStack();
+ mc->ocSuppressed = gFalse;
+ mc->next = mcStack;
+ mcStack = mc;
+}
+
+GBool Gfx::contentIsHidden() {
+ return mcStack && mcStack->ocSuppressed;
+}
+
void Gfx::opBeginMarkedContent(Object args[], int numArgs) {
- // TODO: we really need to be adding this to the markedContentStack
+ // push a new stack entry
+ pushMarkedContent();
+
OCGs *contentConfig = catalog->getOptContentConfig();
-
char* name0 = args[0].getName();
if ( strncmp( name0, "OC", 2) == 0 && contentConfig) {
if ( numArgs >= 2 ) {
@@ -4168,7 +4212,8 @@ void Gfx::opBeginMarkedContent(Object args[], int numArgs) {
if ( res->lookupMarkedContentNF( name1, &markedContent ) ) {
if ( markedContent.isRef() ) {
bool visible = contentConfig->optContentIsVisible( &markedContent );
- ocSuppressed = !(visible);
+ MarkedContentStack *mc = mcStack;
+ mc->ocSuppressed = !(visible);
}
} else {
error(getPos(), "DID NOT find %s", name1);
@@ -4178,7 +4223,6 @@ void Gfx::opBeginMarkedContent(Object args[], int numArgs) {
}
}
-
if (printCommands) {
printf(" marked content: %s ", args[0].getName());
if (numArgs == 2)
@@ -4195,8 +4239,9 @@ void Gfx::opBeginMarkedContent(Object args[], int numArgs) {
}
void Gfx::opEndMarkedContent(Object args[], int numArgs) {
- // TODO: we should turn this off based on the markedContentStack
- ocSuppressed = false;
+ // pop the stack
+ if (mcStack)
+ popMarkedContent();
out->endMarkedContent(state);
}
diff --git a/poppler/Gfx.h b/poppler/Gfx.h
index 2dc9315..b14c5a2 100644
--- a/poppler/Gfx.h
+++ b/poppler/Gfx.h
@@ -61,6 +61,7 @@ class PDFRectangle;
class AnnotBorder;
class AnnotColor;
class Catalog;
+struct MarkedContentStack;
//------------------------------------------------------------------------
@@ -171,7 +172,6 @@ private:
GBool profileCommands; // profile the drawing commands (for debugging)
GfxResources *res; // resource stack
int updateLevel;
- GBool ocSuppressed; // are we ignoring content based on OptionalContent?
GfxState *state; // current graphics state
GBool fontChanged; // set if font or text matrix has changed
@@ -181,7 +181,7 @@ private:
// page/form/pattern
int formDepth;
- GooList *markedContentStack; // current BMC/EMC stack
+ MarkedContentStack *mcStack; // current BMC/EMC stack
Parser *parser; // parser for page content stream(s)
@@ -329,6 +329,9 @@ private:
void opBeginMarkedContent(Object args[], int numArgs);
void opEndMarkedContent(Object args[], int numArgs);
void opMarkPoint(Object args[], int numArgs);
+ GBool contentIsHidden();
+ void pushMarkedContent();
+ void popMarkedContent();
void pushResources(Dict *resDict);
void popResources();
commit 5f168f991477e291290350a28f4a60a565e187b9
Author: Carlos Garcia Campos <carlosgc at gnome.org>
Date: Mon Oct 20 17:56:11 2008 +0200
[glib] Show action titles when printing the index in test program
diff --git a/glib/test-poppler-glib.cc b/glib/test-poppler-glib.cc
index 1e4f1cd..592a7c7 100644
--- a/glib/test-poppler-glib.cc
+++ b/glib/test-poppler-glib.cc
@@ -31,19 +31,22 @@ poppler_format_date (GTime utime)
}
static void
-print_index (PopplerIndexIter *iter)
+print_index (PopplerIndexIter *iter, gint deph)
{
do
{
- PopplerAction *action;
+ PopplerAction *action;
PopplerIndexIter *child;
+ int i;
action = poppler_index_iter_get_action (iter);
- g_print ("Action: %d\n", action->type);
+ for (i = 0; i < deph; i++)
+ g_print (" ");
+ g_print ("+ %s\n", action->any.title);
poppler_action_free (action);
child = poppler_index_iter_get_child (iter);
if (child)
- print_index (child);
+ print_index (child, deph + 1);
poppler_index_iter_free (child);
}
while (poppler_index_iter_next (iter));
@@ -127,7 +130,7 @@ print_document_info (PopplerDocument *document)
if (index_iter)
{
g_print ("\tindex:\n");
- print_index (index_iter);
+ print_index (index_iter, 0);
poppler_index_iter_free (index_iter);
}
commit a906d12e16748d9a40c0db4043a576fd3d004341
Author: Carlos Garcia Campos <carlosgc at gnome.org>
Date: Sat Nov 8 20:20:00 2008 +0100
Minor code cleanup and consistency issues
diff --git a/poppler/OptionalContent.cc b/poppler/OptionalContent.cc
index ffffd6f..4a3d4a9 100644
--- a/poppler/OptionalContent.cc
+++ b/poppler/OptionalContent.cc
@@ -51,7 +51,7 @@ OCGs::OCGs(Object *ocgObject, XRef *xref) :
ocg.free();
break;
}
- OptionalContentGroup *thisOptionalContentGroup = new OptionalContentGroup(ocg.getDict(), xref);
+ OptionalContentGroup *thisOptionalContentGroup = new OptionalContentGroup(ocg.getDict());
ocg.free();
ocgList.arrayGetNF(i, &ocg);
// TODO: we should create a lookup map from Ref to the OptionalContentGroup
@@ -159,7 +159,7 @@ OptionalContentGroup* OCGs::findOcgByRef( const Ref &ref)
OptionalContentGroup *ocg = NULL;
for (int i=0; i < optionalContentGroups->getLength(); ++i) {
ocg = (OptionalContentGroup*)optionalContentGroups->get(i);
- if ( (ocg->ref().num == ref.num) && (ocg->ref().gen == ref.gen) ) {
+ if ( (ocg->getRef().num == ref.num) && (ocg->getRef().gen == ref.gen) ) {
return ocg;
}
}
@@ -206,7 +206,7 @@ bool OCGs::optContentIsVisible( Object *dictRef )
}
} else if (ocg.isRef()) {
OptionalContentGroup* oc = findOcgByRef( ocg.getRef() );
- if ( !oc || oc->state() == OptionalContentGroup::Off ) {
+ if ( !oc || oc->getState() == OptionalContentGroup::Off ) {
result = false;
} else {
result = true ;
@@ -216,7 +216,7 @@ bool OCGs::optContentIsVisible( Object *dictRef )
policy.free();
} else if ( dictType.isName("OCG") ) {
OptionalContentGroup* oc = findOcgByRef( dictRef->getRef() );
- if ( !oc || oc->state() == OptionalContentGroup::Off ) {
+ if ( !oc || oc->getState() == OptionalContentGroup::Off ) {
result=false;
}
}
@@ -233,7 +233,7 @@ bool OCGs::allOn( Array *ocgArray )
ocgArray->getNF(i, &ocgItem);
if (ocgItem.isRef()) {
OptionalContentGroup* oc = findOcgByRef( ocgItem.getRef() );
- if ( oc && oc->state() == OptionalContentGroup::Off ) {
+ if ( oc && oc->getState() == OptionalContentGroup::Off ) {
return false;
}
}
@@ -248,7 +248,7 @@ bool OCGs::allOff( Array *ocgArray )
ocgArray->getNF(i, &ocgItem);
if (ocgItem.isRef()) {
OptionalContentGroup* oc = findOcgByRef( ocgItem.getRef() );
- if ( oc && oc->state() == OptionalContentGroup::On ) {
+ if ( oc && oc->getState() == OptionalContentGroup::On ) {
return false;
}
}
@@ -263,7 +263,7 @@ bool OCGs::anyOn( Array *ocgArray )
ocgArray->getNF(i, &ocgItem);
if (ocgItem.isRef()) {
OptionalContentGroup* oc = findOcgByRef( ocgItem.getRef() );
- if ( oc && oc->state() == OptionalContentGroup::On ) {
+ if ( oc && oc->getState() == OptionalContentGroup::On ) {
return true;
}
}
@@ -278,7 +278,7 @@ bool OCGs::anyOff( Array *ocgArray )
ocgArray->getNF(i, &ocgItem);
if (ocgItem.isRef()) {
OptionalContentGroup* oc = findOcgByRef( ocgItem.getRef() );
- if ( oc && oc->state() == OptionalContentGroup::Off ) {
+ if ( oc && oc->getState() == OptionalContentGroup::Off ) {
return true;
}
}
@@ -288,7 +288,7 @@ bool OCGs::anyOff( Array *ocgArray )
//------------------------------------------------------------------------
-OptionalContentGroup::OptionalContentGroup(Dict *ocgDict, XRef *xrefA) : m_name(NULL)
+OptionalContentGroup::OptionalContentGroup(Dict *ocgDict) : m_name(NULL)
{
Object ocgName;
ocgDict->lookup("Name", &ocgName);
@@ -306,7 +306,7 @@ OptionalContentGroup::OptionalContentGroup(GooString *label)
m_state = On;
}
-GooString* OptionalContentGroup::name() const
+GooString* OptionalContentGroup::getName() const
{
return m_name;
}
@@ -316,7 +316,7 @@ void OptionalContentGroup::setRef(const Ref ref)
m_ref = ref;
}
-Ref OptionalContentGroup::ref() const
+Ref OptionalContentGroup::getRef() const
{
return m_ref;
}
diff --git a/poppler/OptionalContent.h b/poppler/OptionalContent.h
index 0ffbc44..b6136c3 100644
--- a/poppler/OptionalContent.h
+++ b/poppler/OptionalContent.h
@@ -66,18 +66,18 @@ class OptionalContentGroup {
public:
enum State { On, Off };
- OptionalContentGroup(Dict *dict, XRef *xrefA);
+ OptionalContentGroup(Dict *dict);
OptionalContentGroup(GooString *label);
~OptionalContentGroup();
- GooString* name() const;
+ GooString* getName() const;
- Ref ref() const;
+ Ref getRef() const;
void setRef(const Ref ref);
- State state() { return m_state; };
+ State getState() { return m_state; };
void setState(State state) { m_state = state; };
private:
diff --git a/qt4/src/poppler-optcontent.cc b/qt4/src/poppler-optcontent.cc
index af916ab..ecbc23a 100644
--- a/qt4/src/poppler-optcontent.cc
+++ b/qt4/src/poppler-optcontent.cc
@@ -73,8 +73,8 @@ namespace Poppler
{
m_group = group;
m_parent = 0;
- m_name = UnicodeParsedString( group->name() );
- if ( group->state() == OptionalContentGroup::On ) {
+ m_name = UnicodeParsedString( group->getName() );
+ if ( group->getState() == OptionalContentGroup::On ) {
m_state = OptContentItem::On;
} else {
m_state = OptContentItem::Off;
@@ -162,7 +162,7 @@ namespace Poppler
for (int i = 0; i < ocgs->getLength(); ++i) {
OptionalContentGroup *ocg = static_cast<OptionalContentGroup*>(ocgs->get(i));
OptContentItem *node = new OptContentItem( ocg );
- m_optContentItems.insert( QString::number(ocg->ref().num), node);
+ m_optContentItems.insert( QString::number(ocg->getRef().num), node);
}
if ( optContent->getOrderArray() == 0 ) {
diff --git a/qt4/tests/check_optcontent.cpp b/qt4/tests/check_optcontent.cpp
index 247c67b..ec988b8 100644
--- a/qt4/tests/check_optcontent.cpp
+++ b/qt4/tests/check_optcontent.cpp
@@ -184,8 +184,8 @@ void TestOptionalContent::checkVisibilitySetting()
OptionalContentGroup *ocgA = ocgs->findOcgByRef( ref21 );
QVERIFY( ocgA );
- QVERIFY( (ocgA->name()->cmp("A")) == 0 );
- QCOMPARE( ocgA->state(), OptionalContentGroup::On );
+ QVERIFY( (ocgA->getName()->cmp("A")) == 0 );
+ QCOMPARE( ocgA->getState(), OptionalContentGroup::On );
Object ref28obj;
ref28obj.initRef( 28, 0 );
@@ -193,8 +193,8 @@ void TestOptionalContent::checkVisibilitySetting()
OptionalContentGroup *ocgB = ocgs->findOcgByRef( ref28 );
QVERIFY( ocgB );
- QVERIFY( (ocgB->name()->cmp("B")) == 0 );
- QCOMPARE( ocgB->state(), OptionalContentGroup::On );
+ QVERIFY( (ocgB->getName()->cmp("B")) == 0 );
+ QCOMPARE( ocgB->getState(), OptionalContentGroup::On );
// turn one Off
ocgA->setState( OptionalContentGroup::Off );
commit e73c2ce906b7e1f06d641f7e0733aad6336b4091
Author: Carlos Garcia Campos <carlosgc at gnome.org>
Date: Sun Oct 19 12:44:13 2008 +0200
Delete the optContent object if it's invalid
diff --git a/poppler/Catalog.cc b/poppler/Catalog.cc
index c5d473f..95476b5 100644
--- a/poppler/Catalog.cc
+++ b/poppler/Catalog.cc
@@ -202,6 +202,10 @@ Catalog::Catalog(XRef *xrefA) {
// get the Optional Content dictionary
if (catDict.dictLookup("OCProperties", &optContentProps)->isDict()) {
optContent = new OCGs(&optContentProps, xref);
+ if (!optContent->isOk ()) {
+ delete optContent;
+ optContent = NULL;
+ }
}
optContentProps.free();
diff --git a/poppler/OptionalContent.cc b/poppler/OptionalContent.cc
index 204872b..ffffd6f 100644
--- a/poppler/OptionalContent.cc
+++ b/poppler/OptionalContent.cc
@@ -31,6 +31,7 @@ OCGs::OCGs(Object *ocgObject, XRef *xref) :
m_orderArray(0), m_rBGroupsArray(), m_xref(xref)
{
// we need to parse the dictionary here, and build optionalContentGroups
+ ok = gTrue;
optionalContentGroups = new GooList();
Object ocgList;
@@ -38,6 +39,7 @@ OCGs::OCGs(Object *ocgObject, XRef *xref) :
if (!ocgList.isArray()) {
error(-1, "Expected the optional content group list, but wasn't able to find it, or it isn't an Array");
ocgList.free();
+ ok = gFalse;
return;
}
@@ -66,6 +68,7 @@ OCGs::OCGs(Object *ocgObject, XRef *xref) :
error(-1, "Expected the default config, but wasn't able to find it, or it isn't a Dictionary");
defaultOcgConfig.free();
ocgList.free();
+ ok = gFalse;
return;
}
#if 0
diff --git a/poppler/OptionalContent.h b/poppler/OptionalContent.h
index 6afa023..0ffbc44 100644
--- a/poppler/OptionalContent.h
+++ b/poppler/OptionalContent.h
@@ -32,6 +32,9 @@ public:
OCGs(Object *ocgObject, XRef *xref);
~OCGs();
+ // Is OCGS valid?
+ GBool isOk() { return ok; }
+
bool hasOCGs();
GooList *getOCGs() const { return optionalContentGroups; }
@@ -43,6 +46,8 @@ public:
bool optContentIsVisible( Object *dictRef );
private:
+ GBool ok;
+
bool allOn( Array *ocgArray );
bool allOff( Array *ocgArray );
bool anyOn( Array *ocgArray );
More information about the poppler
mailing list