[poppler] 7 commits - glib/demo glib/poppler-page.cc glib/poppler-private.h poppler/CairoOutputDev.cc poppler/CairoOutputDev.h poppler/TextOutputDev.cc poppler/TextOutputDev.h qt4/src
Carlos Garcia Campos
carlosgc at kemper.freedesktop.org
Sat Dec 20 10:30:45 PST 2008
glib/demo/Makefile.am | 4
glib/demo/find.c | 282 ++++++++++++++++++++++++++++++++++++++++++++++
glib/demo/find.h | 31 +++++
glib/demo/main.c | 6
glib/demo/text.c | 175 ++++++++++++++++++++++++++++
glib/demo/text.h | 31 +++++
glib/poppler-page.cc | 148 ++++++++++++++++--------
glib/poppler-private.h | 4
poppler/CairoOutputDev.cc | 64 +++++++++-
poppler/CairoOutputDev.h | 14 +-
poppler/TextOutputDev.cc | 218 +++++++++++++++++++++--------------
poppler/TextOutputDev.h | 45 +++++--
qt4/src/poppler-page.cc | 2
13 files changed, 870 insertions(+), 154 deletions(-)
New commits:
commit ba91b889c3b50239e339938f3c9d31fffcd87d44
Author: Carlos Garcia Campos <carlosgc at gnome.org>
Date: Sat Dec 20 19:29:40 2008 +0100
Make destructor private in TextPage
diff --git a/poppler/TextOutputDev.h b/poppler/TextOutputDev.h
index 2bb91c2..f2b7eab 100644
--- a/poppler/TextOutputDev.h
+++ b/poppler/TextOutputDev.h
@@ -466,9 +466,6 @@ public:
// Constructor.
TextPage(GBool rawOrderA);
- // Destructor.
- ~TextPage();
-
void incRefCnt();
void decRefCnt();
@@ -563,7 +560,10 @@ public:
#endif
private:
-
+
+ // Destructor.
+ ~TextPage();
+
void clear();
void assignColumns(TextLineFrag *frags, int nFrags, int rot);
int dumpFragment(Unicode *text, int len, UnicodeMap *uMap, GooString *s);
commit 0da16537aa83f6ed6d8895c7e54266263a71c1cf
Author: Carlos Garcia Campos <carlosgc at gnome.org>
Date: Fri Dec 19 19:08:21 2008 +0100
Refactor actual text code adding a new ActualText class
It's used by both Text and Cairo ouput devices avoiding duplicated code
in such classes.
diff --git a/poppler/CairoOutputDev.cc b/poppler/CairoOutputDev.cc
index 42bcaac..843b40b 100644
--- a/poppler/CairoOutputDev.cc
+++ b/poppler/CairoOutputDev.cc
@@ -138,7 +138,7 @@ CairoOutputDev::CairoOutputDev() {
knockoutCount = 0;
text = NULL;
- actualTextBMCLevel = 0;
+ actualText = NULL;
}
CairoOutputDev::~CairoOutputDev() {
@@ -157,7 +157,9 @@ CairoOutputDev::~CairoOutputDev() {
if (shape)
cairo_pattern_destroy (shape);
if (text)
- text->decRefCnt();
+ text->decRefCnt();
+ if (actualText)
+ delete actualText;
}
void CairoOutputDev::setCairo(cairo_t *cairo)
@@ -185,11 +187,15 @@ void CairoOutputDev::setTextPage(TextPage *text)
{
if (this->text)
this->text->decRefCnt();
+ if (actualText)
+ delete actualText;
if (text) {
this->text = text;
this->text->incRefCnt();
+ actualText = new ActualText(text);
} else {
this->text = NULL;
+ actualText = NULL;
}
}
@@ -608,28 +614,7 @@ void CairoOutputDev::drawChar(GfxState *state, double x, double y,
if (!text)
return;
-
- if (actualTextBMCLevel == 0) {
- text->addChar(state, x, y, dx, dy, code, nBytes, u, uLen);
- } else {
- // Inside ActualText span.
- if (newActualTextSpan) {
- actualText_x = x;
- actualText_y = y;
- actualText_dx = dx;
- actualText_dy = dy;
- newActualTextSpan = gFalse;
- } else {
- if (x < actualText_x)
- actualText_x = x;
- if (y < actualText_y)
- actualText_y = y;
- if (x + dx > actualText_x + actualText_dx)
- actualText_dx = x + dx - actualText_x;
- if (y + dy > actualText_y + actualText_dy)
- actualText_dy = y + dy - actualText_y;
- }
- }
+ actualText->addChar (state, x, y, dx, dy, code, nBytes, u, uLen);
}
void CairoOutputDev::endString(GfxState *state)
@@ -774,81 +759,14 @@ void CairoOutputDev::endTextObject(GfxState *state) {
void CairoOutputDev::beginMarkedContent(char *name, Dict *properties)
{
- Object obj;
-
- if (!text)
- return;
-
- if (actualTextBMCLevel > 0) {
- // Already inside a ActualText span.
- actualTextBMCLevel++;
- return;
- }
-
- if (properties->lookup("ActualText", &obj)) {
- if (obj.isString()) {
- actualText = obj.getString();
- actualTextBMCLevel = 1;
- newActualTextSpan = gTrue;
- }
- }
+ if (text)
+ actualText->beginMC(properties);
}
void CairoOutputDev::endMarkedContent(GfxState *state)
{
- char *uniString = NULL;
- Unicode *uni;
- int length, i;
-
- if (!text)
- return;
-
- if (actualTextBMCLevel > 0) {
- actualTextBMCLevel--;
- if (actualTextBMCLevel == 0) {
- // ActualText span closed. Output the span text and the
- // extents of all the glyphs inside the span
-
- if (newActualTextSpan) {
- // No content inside span.
- actualText_x = state->getCurX();
- actualText_y = state->getCurY();
- actualText_dx = 0;
- actualText_dy = 0;
- }
-
- 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]<<8) + uniString[2 + i*2+1];
-
- text->addChar(state,
- actualText_x, actualText_y,
- actualText_dx, actualText_dy,
- 0, 1, uni, length);
-
- delete [] uni;
- if (!actualText->hasUnicodeMarker())
- delete [] uniString;
- delete actualText;
- }
- }
+ if (text)
+ actualText->endMC(state);
}
static inline int splashRound(SplashCoord x) {
diff --git a/poppler/CairoOutputDev.h b/poppler/CairoOutputDev.h
index 3273d74..1e410c1 100644
--- a/poppler/CairoOutputDev.h
+++ b/poppler/CairoOutputDev.h
@@ -258,12 +258,7 @@ protected:
GBool prescaleImages;
TextPage *text; // text for the current page
- int actualTextBMCLevel; // > 0 when inside ActualText span. Incremented
- // for each nested BMC inside the span.
- GooString *actualText; // replacement text for the span
- GBool newActualTextSpan; // true at start of span. used to init the extent
- double actualText_x, actualText_y; // extent of the text inside the span
- double actualText_dx, actualText_dy;
+ ActualText *actualText;
cairo_pattern_t *group;
cairo_pattern_t *shape;
diff --git a/poppler/TextOutputDev.cc b/poppler/TextOutputDev.cc
index 1cf3319..816cc8c 100644
--- a/poppler/TextOutputDev.cc
+++ b/poppler/TextOutputDev.cc
@@ -4494,6 +4494,118 @@ TextWordList *TextPage::makeWordList(GBool physLayout) {
#endif
//------------------------------------------------------------------------
+// ActualText
+//------------------------------------------------------------------------
+ActualText::ActualText(TextPage *out) {
+ out->incRefCnt();
+ text = out;
+ actualText = NULL;
+ actualTextBMCLevel = 0;
+}
+
+ActualText::~ActualText() {
+ if (actualText)
+ delete actualText;
+ text->decRefCnt();
+}
+
+void ActualText::addChar(GfxState *state, double x, double y,
+ double dx, double dy,
+ CharCode c, int nBytes, Unicode *u, int uLen) {
+ if (actualTextBMCLevel == 0) {
+ text->addChar(state, x, y, dx, dy, c, nBytes, u, uLen);
+ } else {
+ // Inside ActualText span.
+ if (newActualTextSpan) {
+ actualText_x = x;
+ actualText_y = y;
+ actualText_dx = dx;
+ actualText_dy = dy;
+ newActualTextSpan = gFalse;
+ } else {
+ if (x < actualText_x)
+ actualText_x = x;
+ if (y < actualText_y)
+ actualText_y = y;
+ if (x + dx > actualText_x + actualText_dx)
+ actualText_dx = x + dx - actualText_x;
+ if (y + dy > actualText_y + actualText_dy)
+ actualText_dy = y + dy - actualText_y;
+ }
+ }
+}
+
+void ActualText::beginMC(Dict *properties) {
+ if (actualTextBMCLevel > 0) {
+ // Already inside a ActualText span.
+ actualTextBMCLevel++;
+ return;
+ }
+
+ Object obj;
+ if (properties->lookup("ActualText", &obj)) {
+ if (obj.isString()) {
+ actualText = obj.getString();
+ actualTextBMCLevel = 1;
+ newActualTextSpan = gTrue;
+ }
+ }
+}
+
+void ActualText::endMC(GfxState *state) {
+ char *uniString = NULL;
+ Unicode *uni;
+ int length, i;
+
+ if (actualTextBMCLevel > 0) {
+ actualTextBMCLevel--;
+ if (actualTextBMCLevel == 0) {
+ // ActualText span closed. Output the span text and the
+ // extents of all the glyphs inside the span
+
+ if (newActualTextSpan) {
+ // No content inside span.
+ actualText_x = state->getCurX();
+ actualText_y = state->getCurY();
+ actualText_dx = 0;
+ actualText_dy = 0;
+ }
+
+ 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]<<8) + uniString[2 + i*2+1];
+
+ text->addChar(state,
+ actualText_x, actualText_y,
+ actualText_dx, actualText_dy,
+ 0, 1, uni, length);
+
+ delete [] uni;
+ if (!actualText->hasUnicodeMarker())
+ delete [] uniString;
+ delete actualText;
+ }
+ }
+}
+
+//------------------------------------------------------------------------
// TextOutputDev
//------------------------------------------------------------------------
@@ -4532,7 +4644,7 @@ TextOutputDev::TextOutputDev(char *fileName, GBool physLayoutA,
// set up text object
text = new TextPage(rawOrderA);
- actualTextBMCLevel = 0;
+ actualText = new ActualText(text);
}
TextOutputDev::TextOutputDev(TextOutputFunc func, void *stream,
@@ -4544,8 +4656,8 @@ TextOutputDev::TextOutputDev(TextOutputFunc func, void *stream,
rawOrder = rawOrderA;
doHTML = gFalse;
text = new TextPage(rawOrderA);
+ actualText = new ActualText(text);
ok = gTrue;
- actualTextBMCLevel = 0;
}
TextOutputDev::~TextOutputDev() {
@@ -4558,6 +4670,7 @@ TextOutputDev::~TextOutputDev() {
if (text) {
text->decRefCnt();
}
+ delete actualText;
}
void TextOutputDev::startPage(int pageNum, GfxState *state) {
@@ -4586,100 +4699,17 @@ void TextOutputDev::drawChar(GfxState *state, double x, double y,
double dx, double dy,
double originX, double originY,
CharCode c, int nBytes, Unicode *u, int uLen) {
- if (actualTextBMCLevel == 0) {
- text->addChar(state, x, y, dx, dy, c, nBytes, u, uLen);
- } else {
- // Inside ActualText span.
- if (newActualTextSpan) {
- actualText_x = x;
- actualText_y = y;
- actualText_dx = dx;
- actualText_dy = dy;
- newActualTextSpan = gFalse;
- } else {
- if (x < actualText_x)
- actualText_x = x;
- if (y < actualText_y)
- actualText_y = y;
- if (x + dx > actualText_x + actualText_dx)
- actualText_dx = x + dx - actualText_x;
- if (y + dy > actualText_y + actualText_dy)
- actualText_dy = y + dy - actualText_y;
- }
- }
+ actualText->addChar(state, x, y, dx, dy, c, nBytes, u, uLen);
}
void TextOutputDev::beginMarkedContent(char *name, Dict *properties)
{
- Object obj;
-
- if (actualTextBMCLevel > 0) {
- // Already inside a ActualText span.
- actualTextBMCLevel++;
- return;
- }
-
- if (properties->lookup("ActualText", &obj)) {
- if (obj.isString()) {
- actualText = obj.getString();
- actualTextBMCLevel = 1;
- newActualTextSpan = gTrue;
- }
- }
+ actualText->beginMC(properties);
}
void TextOutputDev::endMarkedContent(GfxState *state)
{
- char *uniString = NULL;
- Unicode *uni;
- int length, i;
-
- if (actualTextBMCLevel > 0) {
- actualTextBMCLevel--;
- if (actualTextBMCLevel == 0) {
- // ActualText span closed. Output the span text and the
- // extents of all the glyphs inside the span
-
- if (newActualTextSpan) {
- // No content inside span.
- actualText_x = state->getCurX();
- actualText_y = state->getCurY();
- actualText_dx = 0;
- actualText_dy = 0;
- }
-
- 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]<<8) + uniString[2 + i*2+1];
-
- text->addChar(state,
- actualText_x, actualText_y,
- actualText_dx, actualText_dy,
- 0, 1, uni, length);
-
- delete [] uni;
- if (!actualText->hasUnicodeMarker())
- delete [] uniString;
- delete actualText;
- }
- }
+ actualText->endMC(state);
}
void TextOutputDev::stroke(GfxState *state) {
diff --git a/poppler/TextOutputDev.h b/poppler/TextOutputDev.h
index 2b019ff..2bb91c2 100644
--- a/poppler/TextOutputDev.h
+++ b/poppler/TextOutputDev.h
@@ -614,6 +614,33 @@ private:
};
//------------------------------------------------------------------------
+// ActualText
+//------------------------------------------------------------------------
+
+class ActualText {
+public:
+ // Create an ActualText
+ ActualText(TextPage *out);
+ ~ActualText();
+
+ void addChar(GfxState *state, double x, double y,
+ double dx, double dy,
+ CharCode c, int nBytes, Unicode *u, int uLen);
+ void beginMC(Dict *properties);
+ void endMC(GfxState *state);
+
+private:
+ TextPage *text;
+ int actualTextBMCLevel; // > 0 when inside ActualText span. Incremented
+ // for each nested BMC inside the span.
+ GooString *actualText; // replacement text for the span
+ GBool newActualTextSpan; // true at start of span. used to init the extent
+ double actualText_x, actualText_y; // extent of the text inside the span
+ double actualText_dx, actualText_dy;
+};
+
+
+//------------------------------------------------------------------------
// TextOutputDev
//------------------------------------------------------------------------
@@ -755,12 +782,7 @@ private:
GBool doHTML; // extra processing for HTML conversion
GBool ok; // set up ok?
- int actualTextBMCLevel; // > 0 when inside ActualText span. Incremented
- // for each nested BMC inside the span.
- GooString *actualText; // replacement text for the span
- GBool newActualTextSpan; // true at start of span. used to init the extent
- double actualText_x, actualText_y; // extent of the text inside the span
- double actualText_dx, actualText_dy;
+ ActualText *actualText;
};
#endif
commit 0f8ab301c633133eea3dbd4f2254f31c50e3c4a9
Author: Carlos Garcia Campos <carlosgc at gnome.org>
Date: Sun Dec 14 13:12:34 2008 +0100
[glib-demo] Add find demo
diff --git a/glib/demo/Makefile.am b/glib/demo/Makefile.am
index 958be90..13bccb3 100644
--- a/glib/demo/Makefile.am
+++ b/glib/demo/Makefile.am
@@ -16,6 +16,8 @@ poppler_glib_demo_SOURCES = \
annots.c \
attachments.c \
attachments.h \
+ find.h \
+ find.c \
fonts.h \
fonts.c \
forms.h \
diff --git a/glib/demo/find.c b/glib/demo/find.c
new file mode 100644
index 0000000..08e41e2
--- /dev/null
+++ b/glib/demo/find.c
@@ -0,0 +1,282 @@
+/*
+ * 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 "find.h"
+
+enum {
+ TITLE_COLUMN,
+ X1_COLUMN,
+ Y1_COLUMN,
+ X2_COLUMN,
+ Y2_COLUMN,
+
+ VISIBLE_COLUMN,
+ N_COLUMNS
+};
+
+typedef struct {
+ PopplerDocument *doc;
+
+ GtkTreeModel *model;
+ GtkWidget *entry;
+ GtkWidget *progress;
+
+ gint n_pages;
+ gint page_index;
+
+ guint idle_id;
+} PgdFindDemo;
+
+static void
+pgd_find_free (PgdFindDemo *demo)
+{
+ if (!demo)
+ return;
+
+ if (demo->idle_id > 0) {
+ g_source_remove (demo->idle_id);
+ demo->idle_id = 0;
+ }
+
+ if (demo->doc) {
+ g_object_unref (demo->doc);
+ demo->doc = NULL;
+ }
+
+ if (demo->model) {
+ g_object_unref (demo->model);
+ demo->model = NULL;
+ }
+
+ g_free (demo);
+}
+
+static void
+pgd_find_update_progress (PgdFindDemo *demo,
+ gint scanned)
+{
+ gchar *str;
+
+ str = g_strdup_printf ("Searching ... (%d%%)",
+ MIN (scanned * 100 / demo->n_pages, 100));
+ gtk_progress_bar_set_text (GTK_PROGRESS_BAR (demo->progress), str);
+ gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (demo->progress),
+ MIN ((gdouble)scanned / demo->n_pages, 1.0));
+ g_free (str);
+}
+
+static gboolean
+pgd_find_find_text (PgdFindDemo *demo)
+{
+ PopplerPage *page;
+ GList *matches;
+ GTimer *timer;
+
+ page = poppler_document_get_page (demo->doc, demo->page_index);
+ if (!page) {
+ demo->page_index++;
+ return demo->page_index < demo->n_pages;
+ }
+
+ timer = g_timer_new ();
+ matches = poppler_page_find_text (page, gtk_entry_get_text (GTK_ENTRY (demo->entry)));
+ g_timer_stop (timer);
+ if (matches) {
+ GtkTreeIter iter;
+ gchar *str;
+ GList *l;
+ 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,
+ TITLE_COLUMN, str,
+ VISIBLE_COLUMN, FALSE,
+ -1);
+ g_free (str);
+
+ for (l = matches; l && l->data; l = g_list_next (l)) {
+ PopplerRectangle *rect = (PopplerRectangle *)l->data;
+ GtkTreeIter iter_child;
+ gchar *x1, *y1, *x2, *y2;
+
+ 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,
+ TITLE_COLUMN, str,
+ X1_COLUMN, x1,
+ Y1_COLUMN, y1,
+ X2_COLUMN, x2,
+ Y2_COLUMN, y2,
+ VISIBLE_COLUMN, TRUE,
+ -1);
+ g_free (str);
+ g_free (x1);
+ g_free (y1);
+ g_free (x2);
+ g_free (y2);
+ g_free (rect);
+ }
+ g_list_free (matches);
+ }
+
+ g_timer_destroy (timer);
+ g_object_unref (page);
+
+ demo->page_index++;
+ pgd_find_update_progress (demo, demo->page_index);
+
+ return demo->page_index < demo->n_pages;
+}
+
+static void
+pgd_find_button_clicked (GtkButton *button,
+ PgdFindDemo *demo)
+{
+ gtk_tree_store_clear (GTK_TREE_STORE (demo->model));
+ demo->page_index = 0;
+ pgd_find_update_progress (demo, demo->page_index);
+ if (demo->idle_id > 0)
+ g_source_remove (demo->idle_id);
+ demo->idle_id = g_idle_add ((GSourceFunc)pgd_find_find_text, demo);
+}
+
+static void
+pgd_find_button_sensitivity_cb (GtkWidget *button,
+ GtkEntry *entry)
+{
+ const gchar *text;
+
+ text = gtk_entry_get_text (entry);
+ gtk_widget_set_sensitive (button, text != NULL && text[0] != '\0');
+}
+
+GtkWidget *
+pgd_find_create_widget (PopplerDocument *document)
+{
+ PgdFindDemo *demo;
+ GtkWidget *vbox, *hbox;
+ GtkWidget *button;
+ GtkWidget *swindow;
+ GtkWidget *treeview;
+ GtkCellRenderer *renderer;
+
+ demo = g_new0 (PgdFindDemo, 1);
+
+ demo->doc = g_object_ref (document);
+
+ demo->n_pages = poppler_document_get_n_pages (document);
+
+ vbox = gtk_vbox_new (FALSE, 12);
+
+ hbox = gtk_hbox_new (FALSE, 6);
+
+ demo->entry = gtk_entry_new ();
+ gtk_box_pack_start (GTK_BOX (hbox), demo->entry, FALSE, TRUE, 0);
+ gtk_widget_show (demo->entry);
+
+ demo->progress = gtk_progress_bar_new ();
+ gtk_progress_bar_set_ellipsize (GTK_PROGRESS_BAR (demo->progress),
+ PANGO_ELLIPSIZE_END);
+ gtk_box_pack_start (GTK_BOX (hbox), demo->progress, TRUE, TRUE, 0);
+ gtk_widget_show (demo->progress);
+
+ button = gtk_button_new_with_label ("Find");
+ gtk_widget_set_sensitive (button, FALSE);
+ g_signal_connect (G_OBJECT (button), "clicked",
+ G_CALLBACK (pgd_find_button_clicked),
+ (gpointer)demo);
+ g_signal_connect_swapped (G_OBJECT (demo->entry), "changed",
+ G_CALLBACK (pgd_find_button_sensitivity_cb),
+ (gpointer)button);
+ gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
+ gtk_widget_show (button);
+
+ gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 6);
+ 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));
+ 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);
+
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
+ TITLE_COLUMN, "Matches",
+ renderer,
+ "text", TITLE_COLUMN,
+ NULL);
+
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
+ X1_COLUMN, "X1",
+ renderer,
+ "text", X1_COLUMN,
+ "visible", VISIBLE_COLUMN,
+ NULL);
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
+ Y1_COLUMN, "Y1",
+ renderer,
+ "text", Y1_COLUMN,
+ "visible", VISIBLE_COLUMN,
+ NULL);
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
+ X2_COLUMN, "X2",
+ renderer,
+ "text", X2_COLUMN,
+ "visible", VISIBLE_COLUMN,
+ NULL);
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
+ Y2_COLUMN, "Y2",
+ renderer,
+ "text", Y2_COLUMN,
+ "visible", VISIBLE_COLUMN,
+ NULL);
+ 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);
+
+ g_object_weak_ref (G_OBJECT (vbox),
+ (GWeakNotify)pgd_find_free,
+ (gpointer)demo);
+
+ return vbox;
+}
diff --git a/glib/demo/find.h b/glib/demo/find.h
new file mode 100644
index 0000000..36f95c1
--- /dev/null
+++ b/glib/demo/find.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 _FIND_H_
+#define _FIND_H_
+
+G_BEGIN_DECLS
+
+GtkWidget *pgd_find_create_widget (PopplerDocument *document);
+
+G_END_DECLS
+
+#endif /* _FIND_H_ */
diff --git a/glib/demo/main.c b/glib/demo/main.c
index b272114..cf5cb75 100644
--- a/glib/demo/main.c
+++ b/glib/demo/main.c
@@ -33,6 +33,7 @@
#include "attachments.h"
#include "layers.h"
#include "text.h"
+#include "find.h"
enum {
PGD_TITLE_COLUMN,
@@ -59,7 +60,8 @@ static const PopplerGlibDemo demo_list[] = {
{ "Annots", pgd_annots_create_widget },
{ "Attachments", pgd_attachments_create_widget },
{ "Layers", pgd_layers_create_widget },
- { "Text", pgd_text_create_widget }
+ { "Text", pgd_text_create_widget },
+ { "Find", pgd_find_create_widget }
};
static void
commit 88df9e9aa9adb53f0a9714ea404d46f111495df3
Author: Carlos Garcia Campos <carlosgc at gnome.org>
Date: Sun Dec 14 11:54:35 2008 +0100
[glib-demo] Add Text demo
diff --git a/glib/demo/Makefile.am b/glib/demo/Makefile.am
index 781c974..958be90 100644
--- a/glib/demo/Makefile.am
+++ b/glib/demo/Makefile.am
@@ -34,6 +34,8 @@ poppler_glib_demo_SOURCES = \
page.c \
render.h \
render.c \
+ text.h \
+ text.c \
transitions.h \
transitions.c \
utils.h \
diff --git a/glib/demo/main.c b/glib/demo/main.c
index ebbb595..b272114 100644
--- a/glib/demo/main.c
+++ b/glib/demo/main.c
@@ -32,6 +32,7 @@
#include "annots.h"
#include "attachments.h"
#include "layers.h"
+#include "text.h"
enum {
PGD_TITLE_COLUMN,
@@ -57,7 +58,8 @@ static const PopplerGlibDemo demo_list[] = {
{ "Images", pgd_images_create_widget },
{ "Annots", pgd_annots_create_widget },
{ "Attachments", pgd_attachments_create_widget },
- { "Layers", pgd_layers_create_widget }
+ { "Layers", pgd_layers_create_widget },
+ { "Text", pgd_text_create_widget }
};
static void
diff --git a/glib/demo/text.c b/glib/demo/text.c
new file mode 100644
index 0000000..e119082
--- /dev/null
+++ b/glib/demo/text.c
@@ -0,0 +1,175 @@
+/*
+ * 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 <string.h>
+
+#include "text.h"
+
+typedef struct {
+ PopplerDocument *doc;
+
+ GtkWidget *timer_label;
+ GtkTextBuffer *buffer;
+
+ gint page;
+} PgdTextDemo;
+
+static void
+pgd_text_free (PgdTextDemo *demo)
+{
+ if (!demo)
+ return;
+
+ if (demo->doc) {
+ g_object_unref (demo->doc);
+ demo->doc = NULL;
+ }
+
+ if (demo->buffer) {
+ g_object_unref (demo->buffer);
+ demo->buffer = NULL;
+ }
+
+ g_free (demo);
+}
+
+static void
+pgd_text_get_text (GtkWidget *button,
+ PgdTextDemo *demo)
+{
+ PopplerPage *page;
+ PopplerRectangle rect;
+ gdouble width, height;
+ gchar *text;
+ GTimer *timer;
+
+ page = poppler_document_get_page (demo->doc, demo->page);
+ if (!page)
+ return;
+
+ poppler_page_get_size (page, &width, &height);
+ rect.x1 = rect.y1 = 0;
+ rect.x2 = width;
+ rect.y2 = height;
+
+ timer = g_timer_new ();
+ text = poppler_page_get_text (page, POPPLER_SELECTION_GLYPH, &rect);
+ g_timer_stop (timer);
+
+ if (text) {
+ gchar *str;
+
+ str = g_strdup_printf ("<i>got text in %.4f seconds</i>",
+ g_timer_elapsed (timer, NULL));
+ gtk_label_set_markup (GTK_LABEL (demo->timer_label), str);
+ g_free (str);
+ } else {
+ gtk_label_set_markup (GTK_LABEL (demo->timer_label), "<i>No text found</i>");
+ }
+
+ g_timer_destroy (timer);
+ g_object_unref (page);
+
+ if (text) {
+ gtk_text_buffer_set_text (demo->buffer, text, strlen (text));
+ g_free (text);
+ }
+}
+
+static void
+pgd_text_page_selector_value_changed (GtkSpinButton *spinbutton,
+ PgdTextDemo *demo)
+{
+ demo->page = (gint)gtk_spin_button_get_value (spinbutton) - 1;
+}
+
+GtkWidget *
+pgd_text_create_widget (PopplerDocument *document)
+{
+ PgdTextDemo *demo;
+ GtkWidget *label;
+ GtkWidget *vbox;
+ GtkWidget *hbox, *page_selector;
+ GtkWidget *button;
+ GtkWidget *swindow, *textview;
+ gchar *str;
+ gint n_pages;
+
+ demo = g_new0 (PgdTextDemo, 1);
+
+ demo->doc = g_object_ref (document);
+
+ n_pages = poppler_document_get_n_pages (document);
+
+ vbox = gtk_vbox_new (FALSE, 12);
+
+ 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);
+
+ page_selector = gtk_spin_button_new_with_range (1, n_pages, 1);
+ g_signal_connect (G_OBJECT (page_selector), "value-changed",
+ G_CALLBACK (pgd_text_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);
+
+ button = gtk_button_new_with_label ("Get Text");
+ g_signal_connect (G_OBJECT (button), "clicked",
+ G_CALLBACK (pgd_text_get_text),
+ (gpointer)demo);
+ gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
+ gtk_widget_show (button);
+
+ gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
+ gtk_widget_show (hbox);
+
+ demo->timer_label = gtk_label_new (NULL);
+ gtk_label_set_markup (GTK_LABEL (demo->timer_label), "<i>No text found</i>");
+ g_object_set (G_OBJECT (demo->timer_label), "xalign", 1.0, NULL);
+ gtk_box_pack_start (GTK_BOX (vbox), demo->timer_label, FALSE, TRUE, 0);
+ gtk_widget_show (demo->timer_label);
+
+ swindow = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+
+ demo->buffer = gtk_text_buffer_new (NULL);
+ textview = gtk_text_view_new_with_buffer (demo->buffer);
+
+ gtk_container_add (GTK_CONTAINER (swindow), textview);
+ gtk_widget_show (textview);
+
+ gtk_box_pack_start (GTK_BOX (vbox), swindow, TRUE, TRUE, 0);
+ gtk_widget_show (swindow);
+
+ g_object_weak_ref (G_OBJECT (vbox),
+ (GWeakNotify)pgd_text_free,
+ demo);
+
+ return vbox;
+}
diff --git a/glib/demo/text.h b/glib/demo/text.h
new file mode 100644
index 0000000..87a1143
--- /dev/null
+++ b/glib/demo/text.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 _TEXT_H_
+#define _TEXT_H_
+
+G_BEGIN_DECLS
+
+GtkWidget *pgd_text_create_widget (PopplerDocument *document);
+
+G_END_DECLS
+
+#endif /* _TEXT_H_ */
commit 5b0f2355d55a5104820fd0bf16b4e76b25959de4
Author: Carlos Garcia Campos <carlosgc at gnome.org>
Date: Sun Dec 14 11:49:00 2008 +0100
[glib] Use TextPage instead of TextOutputDev when cairo is enabled
diff --git a/glib/poppler-page.cc b/glib/poppler-page.cc
index 405e0e6..29d124d 100644
--- a/glib/poppler-page.cc
+++ b/glib/poppler-page.cc
@@ -71,10 +71,15 @@ poppler_page_finalize (GObject *object)
if (page->annots != NULL)
delete page->annots;
+#if defined (HAVE_CAIRO)
+ if (page->text != NULL)
+ page->text->decRefCnt();
+#else
if (page->gfx != NULL)
- delete page->gfx;
+ delete page->gfx;
if (page->text_dev != NULL)
delete page->text_dev;
+#endif
/* page->page is owned by the document */
}
@@ -230,6 +235,7 @@ poppler_page_get_transition (PopplerPage *page)
return transition;
}
+#if !defined (HAVE_CAIRO)
static TextOutputDev *
poppler_page_get_text_output_dev (PopplerPage *page)
{
@@ -254,9 +260,28 @@ poppler_page_get_text_output_dev (PopplerPage *page)
return page->text_dev;
}
+#endif /* !defined (HAVE_CAIRO) */
#if defined (HAVE_CAIRO)
+static TextPage *
+poppler_page_get_text_page (PopplerPage *page)
+{
+ if (page->text == NULL) {
+ cairo_t *cr;
+ cairo_surface_t *surface;
+
+ surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 1, 1);
+ cr = cairo_create (surface);
+ poppler_page_render (page, cr);
+ cairo_destroy (cr);
+ cairo_surface_destroy (surface);
+
+ }
+
+ return page->text;
+}
+
#ifdef POPPLER_WITH_GDK
typedef struct {
unsigned char *cairo_data;
@@ -515,6 +540,9 @@ _poppler_page_render (PopplerPage *page,
output_dev->setCairo (cairo);
output_dev->setPrinting (printing);
+ if (!printing)
+ output_dev->setTextPage (page->text);
+
/* NOTE: instead of passing -1 we should/could use cairo_clip_extents()
* to get a bounding box */
cairo_save (cairo);
@@ -530,7 +558,8 @@ _poppler_page_render (PopplerPage *page,
printing ? poppler_print_annot_cb : NULL, NULL);
cairo_restore (cairo);
- output_dev->setCairo (NULL);
+ output_dev->setCairo (NULL);
+ output_dev->setTextPage (NULL);
}
/**
@@ -549,6 +578,9 @@ poppler_page_render (PopplerPage *page,
{
g_return_if_fail (POPPLER_IS_PAGE (page));
+ if (!page->text)
+ page->text = new TextPage(gFalse);
+
_poppler_page_render (page, cairo, gFalse);
}
@@ -670,8 +702,8 @@ poppler_page_render_selection (PopplerPage *page,
PopplerColor *glyph_color,
PopplerColor *background_color)
{
- TextOutputDev *text_dev;
CairoOutputDev *output_dev;
+ TextPage *text;
SelectionStyle selection_style = selectionStyleGlyph;
PDFRectangle pdf_selection(selection->x1, selection->y1,
selection->x2, selection->y2);
@@ -704,24 +736,15 @@ poppler_page_render_selection (PopplerPage *page,
break;
}
- text_dev = poppler_page_get_text_output_dev (page);
output_dev = page->document->output_dev;
output_dev->setCairo (cairo);
- text_dev->drawSelection (output_dev, 1.0, 0,
- &pdf_selection, selection_style,
- &gfx_glyph_color, &gfx_background_color);
+ text = poppler_page_get_text_page (page);
+ text->drawSelection (output_dev, 1.0, 0,
+ &pdf_selection, selection_style,
+ &gfx_glyph_color, &gfx_background_color);
output_dev->setCairo (NULL);
-
- /* We'll need a function to destroy page->text_dev and page->gfx
- * when the application wants to get rid of them.
- *
- * Two improvements: 1) make GfxFont refcounted and let TextPage and
- * friends hold a reference to the GfxFonts they need so we can free
- * up Gfx early. 2) use a TextPage directly when rendering the page
- * so we don't have to use TextOutputDev and render a second
- * time. */
}
#endif /* HAVE_CAIRO */
@@ -886,7 +909,6 @@ poppler_page_render_selection_to_pixbuf (PopplerPage *page,
GdkColor *glyph_color,
GdkColor *background_color)
{
- TextOutputDev *text_dev;
OutputDev *output_dev;
OutputDevData data;
SelectionStyle selection_style = selectionStyleGlyph;
@@ -921,19 +943,24 @@ poppler_page_render_selection_to_pixbuf (PopplerPage *page,
break;
}
- text_dev = poppler_page_get_text_output_dev (page);
output_dev = page->document->output_dev;
poppler_page_prepare_output_dev (page, scale, rotation, TRUE, &data);
- text_dev->drawSelection (output_dev, scale, rotation,
+#if defined (HAVE_CAIRO)
+ TextPage *text;
+
+ text = poppler_page_get_text_page (page);
+ text->drawSelection (output_dev, scale, rotation,
&pdf_selection, selection_style,
&gfx_glyph_color, &gfx_background_color);
+#else
+ TextOutputDev *text_dev;
- poppler_page_copy_to_pixbuf (page, pixbuf, &data);
-
- poppler_page_set_selection_alpha (page, scale, pixbuf, style, selection);
-
+ text_dev = poppler_page_get_text_output_dev (page);
+ text_dev->drawSelection (output_dev, scale, rotation,
+ &pdf_selection, selection_style,
+ &gfx_glyph_color, &gfx_background_color);
/* We'll need a function to destroy page->text_dev and page->gfx
* when the application wants to get rid of them.
*
@@ -942,6 +969,11 @@ poppler_page_render_selection_to_pixbuf (PopplerPage *page,
* up Gfx early. 2) use a TextPage directly when rendering the page
* so we don't have to use TextOutputDev and render a second
* time. */
+#endif
+
+ poppler_page_copy_to_pixbuf (page, pixbuf, &data);
+
+ poppler_page_set_selection_alpha (page, scale, pixbuf, style, selection);
}
#endif /* POPPLER_WITH_GDK */
@@ -1013,7 +1045,6 @@ poppler_page_get_selection_region (PopplerPage *page,
PopplerSelectionStyle style,
PopplerRectangle *selection)
{
- TextOutputDev *text_dev;
PDFRectangle poppler_selection;
SelectionStyle selection_style = selectionStyleGlyph;
GooList *list;
@@ -1037,11 +1068,21 @@ poppler_page_get_selection_region (PopplerPage *page,
selection_style = selectionStyleLine;
break;
}
-
+
+#if defined (HAVE_CAIRO)
+ TextPage *text;
+
+ text = poppler_page_get_text_page (page);
+ list = text->getSelectionRegion(&poppler_selection,
+ selection_style, scale);
+#else
+ TextOutputDev *text_dev;
+
text_dev = poppler_page_get_text_output_dev (page);
- list = text_dev->getSelectionRegion(&poppler_selection,
+ list = text_dev->getSelectionRegion(&poppler_selection,
selection_style, scale);
-
+#endif
+
for (i = 0; i < list->getLength(); i++) {
PDFRectangle *selection_rect = (PDFRectangle *) list->get(i);
PopplerRectangle *rect;
@@ -1089,7 +1130,6 @@ poppler_page_get_text (PopplerPage *page,
PopplerSelectionStyle style,
PopplerRectangle *selection)
{
- TextOutputDev *text_dev;
GooString *sel_text;
double height;
char *result;
@@ -1099,9 +1139,7 @@ poppler_page_get_text (PopplerPage *page,
g_return_val_if_fail (POPPLER_IS_PAGE (page), FALSE);
g_return_val_if_fail (selection != NULL, NULL);
- text_dev = poppler_page_get_text_output_dev (page);
poppler_page_get_size (page, NULL, &height);
-
pdf_selection.x1 = selection->x1;
pdf_selection.y1 = height - selection->y2;
pdf_selection.x2 = selection->x2;
@@ -1120,7 +1158,18 @@ poppler_page_get_text (PopplerPage *page,
break;
}
+#if defined (HAVE_CAIRO)
+ TextPage *text;
+
+ text = poppler_page_get_text_page (page);
+ sel_text = text->getSelectionText (&pdf_selection, selection_style);
+#else
+ TextOutputDev *text_dev;
+
+ text_dev = poppler_page_get_text_output_dev (page);
sel_text = text_dev->getSelectionText (&pdf_selection, selection_style);
+#endif
+
result = g_strdup (sel_text->getCString ());
delete sel_text;
@@ -1142,35 +1191,41 @@ poppler_page_find_text (PopplerPage *page,
const char *text)
{
PopplerRectangle *match;
- TextOutputDev *output_dev;
- PDFDoc *doc;
GList *matches;
double xMin, yMin, xMax, yMax;
gunichar *ucs4;
glong ucs4_len;
double height;
-
+#if defined (HAVE_CAIRO)
+ TextPage *text_dev;
+#else
+ TextOutputDev *text_dev;
+#endif
+
g_return_val_if_fail (POPPLER_IS_PAGE (page), FALSE);
g_return_val_if_fail (text != NULL, FALSE);
- ucs4 = g_utf8_to_ucs4_fast (text, -1, &ucs4_len);
-
- output_dev = new TextOutputDev (NULL, gTrue, gFalse, gFalse);
- doc = page->document->doc;
+#if defined (HAVE_CAIRO)
+ text_dev = poppler_page_get_text_page (page);
+#else
+ text_dev = new TextOutputDev (NULL, gTrue, gFalse, gFalse);
+ page->page->display (text_dev, 72, 72, 0,
+ gFalse, gTrue, gFalse,
+ page->document->doc->getCatalog());
+#endif
+ ucs4 = g_utf8_to_ucs4_fast (text, -1, &ucs4_len);
poppler_page_get_size (page, NULL, &height);
- page->page->display (output_dev, 72, 72, 0, gFalse,
- gTrue, gFalse, doc->getCatalog());
matches = NULL;
xMin = 0;
yMin = 0;
- while (output_dev->findText (ucs4, ucs4_len,
- gFalse, gTrue, // startAtTop, stopAtBottom
- gTrue, gFalse, // startAtLast, stopAtLast
- gFalse, gFalse, // caseSensitive, backwards
- &xMin, &yMin, &xMax, &yMax))
+ while (text_dev->findText (ucs4, ucs4_len,
+ gFalse, gTrue, // startAtTop, stopAtBottom
+ gTrue, gFalse, // startAtLast, stopAtLast
+ gFalse, gFalse, // caseSensitive, backwards
+ &xMin, &yMin, &xMax, &yMax))
{
match = g_new (PopplerRectangle, 1);
match->x1 = xMin;
@@ -1180,7 +1235,10 @@ poppler_page_find_text (PopplerPage *page,
matches = g_list_prepend (matches, match);
}
- delete output_dev;
+#if !defined (HAVE_CAIRO)
+ delete text_dev;
+#endif
+
g_free (ucs4);
return g_list_reverse (matches);
diff --git a/glib/poppler-private.h b/glib/poppler-private.h
index 663b8e8..c4380ea 100644
--- a/glib/poppler-private.h
+++ b/glib/poppler-private.h
@@ -59,8 +59,12 @@ struct _PopplerPage
PopplerDocument *document;
Page *page;
int index;
+#if defined (HAVE_CAIRO)
+ TextPage *text;
+#else
TextOutputDev *text_dev;
Gfx *gfx;
+#endif
Annots *annots;
};
commit 3ced71fb68d62308db7b9535367eafefb55d1cde
Author: Carlos Garcia Campos <carlosgc at gnome.org>
Date: Sun Dec 14 11:18:00 2008 +0100
Add optionally text support to CairoOutputDev
If a TextPage is set, it'll be used when rendering so that we don't need
to use TextOutputDev and render again.
diff --git a/poppler/CairoOutputDev.cc b/poppler/CairoOutputDev.cc
index 8ac2201..42bcaac 100644
--- a/poppler/CairoOutputDev.cc
+++ b/poppler/CairoOutputDev.cc
@@ -49,6 +49,7 @@
#include "Link.h"
#include "CharCodeToUnicode.h"
#include "FontEncodingTables.h"
+#include "PDFDocEncoding.h"
#include <fofi/FoFiTrueType.h>
#include <splash/SplashBitmap.h>
#include "CairoOutputDev.h"
@@ -135,6 +136,9 @@ CairoOutputDev::CairoOutputDev() {
shape = NULL;
cairo_shape = NULL;
knockoutCount = 0;
+
+ text = NULL;
+ actualTextBMCLevel = 0;
}
CairoOutputDev::~CairoOutputDev() {
@@ -152,6 +156,8 @@ CairoOutputDev::~CairoOutputDev() {
cairo_pattern_destroy (mask);
if (shape)
cairo_pattern_destroy (shape);
+ if (text)
+ text->decRefCnt();
}
void CairoOutputDev::setCairo(cairo_t *cairo)
@@ -175,6 +181,18 @@ void CairoOutputDev::setCairo(cairo_t *cairo)
}
}
+void CairoOutputDev::setTextPage(TextPage *text)
+{
+ if (this->text)
+ this->text->decRefCnt();
+ if (text) {
+ this->text = text;
+ this->text->incRefCnt();
+ } else {
+ this->text = NULL;
+ }
+}
+
void CairoOutputDev::startDoc(XRef *xrefA, Catalog *catalogA,
CairoFontEngine *parentFontEngine) {
xref = xrefA;
@@ -197,6 +215,16 @@ void CairoOutputDev::startPage(int pageNum, GfxState *state) {
cairo_pattern_destroy(stroke_pattern);
stroke_pattern = cairo_pattern_create_rgb(0., 0., 0.);
+
+ if (text)
+ text->startPage(state);
+}
+
+void CairoOutputDev::endPage() {
+ if (text) {
+ text->endPage();
+ text->coalesce(gTrue, gFalse);
+ }
}
void CairoOutputDev::drawLink(Link *link, Catalog *catalog) {
@@ -416,6 +444,10 @@ void CairoOutputDev::updateFont(GfxState *state) {
needFontUpdate = gFalse;
+ //FIXME: use cairo font engine?
+ if (text)
+ text->updateFont(state);
+
currentFont = fontEngine->getFont (state->getFont(), xref, catalog, printing);
if (!currentFont)
@@ -567,13 +599,37 @@ void CairoOutputDev::drawChar(GfxState *state, double x, double y,
double originX, double originY,
CharCode code, int nBytes, Unicode *u, int uLen)
{
- if (!currentFont)
+ if (currentFont) {
+ glyphs[glyphCount].index = currentFont->getGlyph (code, u, uLen);
+ glyphs[glyphCount].x = x - originX;
+ glyphs[glyphCount].y = y - originY;
+ glyphCount++;
+ }
+
+ if (!text)
return;
- glyphs[glyphCount].index = currentFont->getGlyph (code, u, uLen);
- glyphs[glyphCount].x = x - originX;
- glyphs[glyphCount].y = y - originY;
- glyphCount++;
+ if (actualTextBMCLevel == 0) {
+ text->addChar(state, x, y, dx, dy, code, nBytes, u, uLen);
+ } else {
+ // Inside ActualText span.
+ if (newActualTextSpan) {
+ actualText_x = x;
+ actualText_y = y;
+ actualText_dx = dx;
+ actualText_dy = dy;
+ newActualTextSpan = gFalse;
+ } else {
+ if (x < actualText_x)
+ actualText_x = x;
+ if (y < actualText_y)
+ actualText_y = y;
+ if (x + dx > actualText_x + actualText_dx)
+ actualText_dx = x + dx - actualText_x;
+ if (y + dy > actualText_y + actualText_dy)
+ actualText_dy = y + dy - actualText_y;
+ }
+ }
}
void CairoOutputDev::endString(GfxState *state)
@@ -714,7 +770,85 @@ void CairoOutputDev::endTextObject(GfxState *state) {
cairo_path_destroy (textClipPath);
textClipPath = NULL;
}
+}
+
+void CairoOutputDev::beginMarkedContent(char *name, Dict *properties)
+{
+ Object obj;
+
+ if (!text)
+ return;
+
+ if (actualTextBMCLevel > 0) {
+ // Already inside a ActualText span.
+ actualTextBMCLevel++;
+ return;
+ }
+
+ if (properties->lookup("ActualText", &obj)) {
+ if (obj.isString()) {
+ actualText = obj.getString();
+ actualTextBMCLevel = 1;
+ newActualTextSpan = gTrue;
+ }
+ }
+}
+
+void CairoOutputDev::endMarkedContent(GfxState *state)
+{
+ char *uniString = NULL;
+ Unicode *uni;
+ int length, i;
+
+ if (!text)
+ return;
+
+ if (actualTextBMCLevel > 0) {
+ actualTextBMCLevel--;
+ if (actualTextBMCLevel == 0) {
+ // ActualText span closed. Output the span text and the
+ // extents of all the glyphs inside the span
+
+ if (newActualTextSpan) {
+ // No content inside span.
+ actualText_x = state->getCurX();
+ actualText_y = state->getCurY();
+ actualText_dx = 0;
+ actualText_dy = 0;
+ }
+ 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]<<8) + uniString[2 + i*2+1];
+
+ text->addChar(state,
+ actualText_x, actualText_y,
+ actualText_dx, actualText_dy,
+ 0, 1, uni, length);
+
+ delete [] uni;
+ if (!actualText->hasUnicodeMarker())
+ delete [] uniString;
+ delete actualText;
+ }
+ }
}
static inline int splashRound(SplashCoord x) {
diff --git a/poppler/CairoOutputDev.h b/poppler/CairoOutputDev.h
index 46be9dc..3273d74 100644
--- a/poppler/CairoOutputDev.h
+++ b/poppler/CairoOutputDev.h
@@ -36,6 +36,7 @@
#include "goo/gtypes.h"
#include <cairo-ft.h>
#include "OutputDev.h"
+#include "TextOutputDev.h"
#include "GfxState.h"
class GfxState;
@@ -107,7 +108,7 @@ public:
virtual void startPage(int pageNum, GfxState *state);
// End a page.
- virtual void endPage() { }
+ virtual void endPage();
//----- link borders
virtual void drawLink(Link *link, Catalog *catalog);
@@ -158,6 +159,10 @@ public:
virtual void endType3Char(GfxState *state);
virtual void endTextObject(GfxState *state);
+ //----- grouping operators
+ virtual void beginMarkedContent(char *name, Dict *properties);
+ virtual void endMarkedContent(GfxState *state);
+
//----- image drawing
virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
int width, int height, GBool invert,
@@ -186,7 +191,6 @@ public:
int maskWidth, int maskHeight,
GBool maskInvert);
-
//----- transparency groups and soft masks
virtual void beginTransparencyGroup(GfxState * /*state*/, double * /*bbox*/,
GfxColorSpace * /*blendingColorSpace*/,
@@ -205,13 +209,14 @@ public:
double llx, double lly, double urx, double ury);
//----- special access
-
+
// Called to indicate that a new PDF document has been loaded.
void startDoc(XRef *xrefA, Catalog *catalogA, CairoFontEngine *fontEngine = NULL);
GBool isReverseVideo() { return gFalse; }
void setCairo (cairo_t *cr);
+ void setTextPage (TextPage *text);
void setPrinting (GBool printing) { this->printing = printing; needFontUpdate = gTrue; }
void setInType3Char(GBool inType3Char) { this->inType3Char = inType3Char; }
@@ -252,6 +257,14 @@ protected:
GBool prescaleImages;
+ TextPage *text; // text for the current page
+ int actualTextBMCLevel; // > 0 when inside ActualText span. Incremented
+ // for each nested BMC inside the span.
+ GooString *actualText; // replacement text for the span
+ GBool newActualTextSpan; // true at start of span. used to init the extent
+ double actualText_x, actualText_y; // extent of the text inside the span
+ double actualText_dx, actualText_dy;
+
cairo_pattern_t *group;
cairo_pattern_t *shape;
cairo_pattern_t *mask;
commit 0bdad35cc4cfdb8da5acaf44678920b7a0025f99
Author: Carlos Garcia Campos <carlosgc at gnome.org>
Date: Sun Dec 14 11:14:12 2008 +0100
Add refcount support to TextPage
diff --git a/poppler/TextOutputDev.cc b/poppler/TextOutputDev.cc
index 9b49ad9..1cf3319 100644
--- a/poppler/TextOutputDev.cc
+++ b/poppler/TextOutputDev.cc
@@ -1772,6 +1772,7 @@ TextWord *TextWordList::get(int idx) {
TextPage::TextPage(GBool rawOrderA) {
int rot;
+ refCnt = 1;
rawOrder = rawOrderA;
curWord = NULL;
charPos = 0;
@@ -1810,6 +1811,15 @@ TextPage::~TextPage() {
deleteGooList(links, TextLink);
}
+void TextPage::incRefCnt() {
+ refCnt++;
+}
+
+void TextPage::decRefCnt() {
+ if (--refCnt == 0)
+ delete this;
+}
+
void TextPage::startPage(GfxState *state) {
clear();
if (state) {
@@ -4546,7 +4556,7 @@ TextOutputDev::~TextOutputDev() {
fclose((FILE *)outputStream);
}
if (text) {
- delete text;
+ text->decRefCnt();
}
}
diff --git a/poppler/TextOutputDev.h b/poppler/TextOutputDev.h
index 3dc5f6f..2b019ff 100644
--- a/poppler/TextOutputDev.h
+++ b/poppler/TextOutputDev.h
@@ -469,6 +469,9 @@ public:
// Destructor.
~TextPage();
+ void incRefCnt();
+ void decRefCnt();
+
// Start a new page.
void startPage(GfxState *state);
@@ -599,6 +602,8 @@ private:
GooList *underlines; // [TextUnderline]
GooList *links; // [TextLink]
+ int refCnt;
+
friend class TextLine;
friend class TextLineFrag;
friend class TextBlock;
diff --git a/qt4/src/poppler-page.cc b/qt4/src/poppler-page.cc
index e6d5ed9..50c733e 100644
--- a/qt4/src/poppler-page.cc
+++ b/qt4/src/poppler-page.cc
@@ -335,7 +335,7 @@ bool Page::search(const QString &text, QRectF &rect, SearchDirection direction,
found = textPage->findText( u.data(), len,
gTrue, gFalse, gFalse, gTrue, sCase, gFalse, &sLeft, &sTop, &sRight, &sBottom );
- delete textPage;
+ textPage->decRefCnt();
rect.setLeft( sLeft );
rect.setTop( sTop );
More information about the poppler
mailing list