[poppler] 4 commits - glib/demo glib/poppler.h glib/poppler-page.cc glib/poppler-page.h glib/reference poppler/TextOutputDev.cc

Carlos Garcia Campos carlosgc at kemper.freedesktop.org
Sat Jun 2 08:42:57 PDT 2012


 glib/demo/find.c                    |  314 +++++++++++++++++++++++++++++++-----
 glib/poppler-page.cc                |   52 ++++-
 glib/poppler-page.h                 |    3 
 glib/poppler.h                      |   18 ++
 glib/reference/poppler-sections.txt |    2 
 poppler/TextOutputDev.cc            |  144 ++++++++--------
 6 files changed, 414 insertions(+), 119 deletions(-)

New commits:
commit 0df0aa439eed1d9838a80942e00af08e9acabb8d
Author: Carlos Garcia Campos <carlosgc at gnome.org>
Date:   Sat Jun 2 17:33:23 2012 +0200

    glib-demo: Add find options to find demo

diff --git a/glib/demo/find.c b/glib/demo/find.c
index 0ba3454..664c597 100644
--- a/glib/demo/find.c
+++ b/glib/demo/find.c
@@ -39,6 +39,7 @@ typedef struct {
 	GtkWidget       *entry;
 	GtkWidget       *progress;
 
+        PopplerFindFlags options;
 	gint             n_pages;
 	gint             page_index;
 
@@ -103,7 +104,7 @@ pgd_find_find_text (PgdFindDemo *demo)
 
         model = gtk_tree_view_get_model (GTK_TREE_VIEW (demo->treeview));
 	timer = g_timer_new ();
-	matches = poppler_page_find_text (page, gtk_entry_get_text (GTK_ENTRY (demo->entry)));
+	matches = poppler_page_find_text_with_options (page, gtk_entry_get_text (GTK_ENTRY (demo->entry)), demo->options);
 	g_timer_stop (timer);
 	if (matches) {
 		GtkTreeIter iter;
@@ -335,6 +336,36 @@ pgd_find_selection_changed (GtkTreeSelection *treeselection,
         }
 }
 
+static void
+pgd_find_case_sensitive_toggled (GtkToggleButton *togglebutton,
+                                 PgdFindDemo     *demo)
+{
+        if (gtk_toggle_button_get_active (togglebutton))
+                demo->options |= POPPLER_FIND_CASE_SENSITIVE;
+        else
+                demo->options &= ~POPPLER_FIND_CASE_SENSITIVE;
+}
+
+static void
+pgd_find_backwards_toggled (GtkToggleButton *togglebutton,
+                            PgdFindDemo     *demo)
+{
+        if (gtk_toggle_button_get_active (togglebutton))
+                demo->options |= POPPLER_FIND_BACKWARDS;
+        else
+                demo->options &= ~POPPLER_FIND_BACKWARDS;
+}
+
+static void
+pgd_find_whole_words_toggled (GtkToggleButton *togglebutton,
+                              PgdFindDemo     *demo)
+{
+        if (gtk_toggle_button_get_active (togglebutton))
+                demo->options |= POPPLER_FIND_WHOLE_WORDS_ONLY;
+        else
+                demo->options &= ~POPPLER_FIND_WHOLE_WORDS_ONLY;
+}
+
 GtkWidget *
 pgd_find_create_widget (PopplerDocument *document)
 {
@@ -342,6 +373,7 @@ pgd_find_create_widget (PopplerDocument *document)
 	GtkWidget        *vbox, *hbox;
 	GtkWidget        *button;
 	GtkWidget        *swindow;
+        GtkWidget        *checkbutton;
         GtkTreeModel     *model;
 	GtkWidget        *treeview;
 	GtkCellRenderer  *renderer;
@@ -354,6 +386,7 @@ pgd_find_create_widget (PopplerDocument *document)
 
 	demo->n_pages = poppler_document_get_n_pages (document);
         demo->selected_page = -1;
+        demo->options = POPPLER_FIND_DEFAULT;
 
         hpaned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
         gtk_paned_set_position (GTK_PANED (hpaned), 300);
@@ -386,6 +419,32 @@ pgd_find_create_widget (PopplerDocument *document)
 	gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 6);
 	gtk_widget_show (hbox);
 
+        hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+
+        checkbutton = gtk_check_button_new_with_label ("Case sensitive");
+        g_signal_connect (checkbutton, "toggled",
+                          G_CALLBACK (pgd_find_case_sensitive_toggled),
+                          demo);
+        gtk_box_pack_start (GTK_BOX (hbox), checkbutton, FALSE, FALSE, 0);
+        gtk_widget_show (checkbutton);
+
+        checkbutton = gtk_check_button_new_with_label ("Backwards");
+        g_signal_connect (checkbutton, "toggled",
+                          G_CALLBACK (pgd_find_backwards_toggled),
+                          demo);
+        gtk_box_pack_start (GTK_BOX (hbox), checkbutton, FALSE, FALSE, 0);
+        gtk_widget_show (checkbutton);
+
+        checkbutton = gtk_check_button_new_with_label ("Whole words only");
+        g_signal_connect (checkbutton, "toggled",
+                          G_CALLBACK (pgd_find_whole_words_toggled),
+                          demo);
+        gtk_box_pack_start (GTK_BOX (hbox), checkbutton, FALSE, FALSE, 0);
+        gtk_widget_show (checkbutton);
+
+        gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+        gtk_widget_show (hbox);
+
 	swindow = gtk_scrolled_window_new (NULL, NULL);
 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow),
 					GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
commit 52b3ede4bfd1e2288a0efca34da5d6239d3563e9
Author: Carlos Garcia Campos <carlosgc at gnome.org>
Date:   Sat Jun 2 16:25:06 2012 +0200

    glib-demo: Show search matches in a document view

diff --git a/glib/demo/find.c b/glib/demo/find.c
index 0fdce85..0ba3454 100644
--- a/glib/demo/find.c
+++ b/glib/demo/find.c
@@ -26,20 +26,27 @@ enum {
 	Y2_COLUMN,
 
 	VISIBLE_COLUMN,
+        PAGE_COLUMN,
+        PAGE_RECT,
 	N_COLUMNS
 };
 
 typedef struct {
 	PopplerDocument *doc;
 
-	GtkTreeModel    *model;
+	GtkWidget       *treeview;
+        GtkWidget       *darea;
 	GtkWidget       *entry;
 	GtkWidget       *progress;
 
 	gint             n_pages;
 	gint             page_index;
-	
+
 	guint            idle_id;
+
+        cairo_surface_t *surface;
+        gint             selected_page;
+        GdkRectangle     selected_match;
 } PgdFindDemo;
 
 static void
@@ -58,10 +65,10 @@ pgd_find_free (PgdFindDemo *demo)
 		demo->doc = NULL;
 	}
 
-	if (demo->model) {
-		g_object_unref (demo->model);
-		demo->model = NULL;
-	}
+        if (demo->surface) {
+                cairo_surface_destroy (demo->surface);
+                demo->surface = NULL;
+        }
 
 	g_free (demo);
 }
@@ -83,9 +90,10 @@ pgd_find_update_progress (PgdFindDemo *demo,
 static gboolean
 pgd_find_find_text (PgdFindDemo *demo)
 {
-	PopplerPage *page;
-	GList       *matches;
-	GTimer      *timer;
+	PopplerPage  *page;
+	GList        *matches;
+	GTimer       *timer;
+        GtkTreeModel *model;
 
 	page = poppler_document_get_page (demo->doc, demo->page_index);
 	if (!page) {
@@ -93,6 +101,7 @@ pgd_find_find_text (PgdFindDemo *demo)
 		return demo->page_index < demo->n_pages;
 	}
 
+        model = gtk_tree_view_get_model (GTK_TREE_VIEW (demo->treeview));
 	timer = g_timer_new ();
 	matches = poppler_page_find_text (page, gtk_entry_get_text (GTK_ENTRY (demo->entry)));
 	g_timer_stop (timer);
@@ -100,45 +109,58 @@ pgd_find_find_text (PgdFindDemo *demo)
 		GtkTreeIter iter;
 		gchar      *str;
 		GList      *l;
+                gdouble     height;
 		gint        n_match = 0;
 
 		str = g_strdup_printf ("%d matches found on page %d in %.4f seconds",
 				       g_list_length (matches), demo->page_index + 1,
 				       g_timer_elapsed (timer, NULL));
 		
-		gtk_tree_store_append (GTK_TREE_STORE (demo->model), &iter, NULL);
-		gtk_tree_store_set (GTK_TREE_STORE (demo->model), &iter,
+		gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
+		gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
 				    TITLE_COLUMN, str,
 				    VISIBLE_COLUMN, FALSE,
+                                    PAGE_COLUMN, demo->page_index,
 				    -1);
 		g_free (str);
-		
+
+                poppler_page_get_size (page, NULL, &height);
+
 		for (l = matches; l && l->data; l = g_list_next (l)) {
 			PopplerRectangle *rect = (PopplerRectangle *)l->data;
 			GtkTreeIter       iter_child;
 			gchar            *x1, *y1, *x2, *y2;
+                        gdouble           tmp;
 
 			str = g_strdup_printf ("Match %d", ++n_match);
 			x1 = g_strdup_printf ("%.2f", rect->x1);
 			y1 = g_strdup_printf ("%.2f", rect->y1);
 			x2 = g_strdup_printf ("%.2f", rect->x2);
 			y2 = g_strdup_printf ("%.2f", rect->y2);
-			
-			gtk_tree_store_append (GTK_TREE_STORE (demo->model), &iter_child, &iter);
-			gtk_tree_store_set (GTK_TREE_STORE (demo->model), &iter_child,
+
+                        tmp = rect->y1;
+                        rect->y1 = height - rect->y2;
+                        rect->y2 = height - tmp;
+
+			gtk_tree_store_append (GTK_TREE_STORE (model), &iter_child, &iter);
+			gtk_tree_store_set (GTK_TREE_STORE (model), &iter_child,
 					    TITLE_COLUMN, str,
 					    X1_COLUMN, x1,
 					    Y1_COLUMN, y1,
 					    X2_COLUMN, x2,
 					    Y2_COLUMN, y2,
 					    VISIBLE_COLUMN, TRUE,
+                                            PAGE_COLUMN, demo->page_index,
+                                            PAGE_RECT, rect,
 					    -1);
 			g_free (str);
 			g_free (x1);
 			g_free (y1);
 			g_free (x2);
 			g_free (y2);
-			poppler_rectangle_free (rect);
+                        g_object_weak_ref (G_OBJECT (model),
+                                           (GWeakNotify)poppler_rectangle_free,
+                                           rect);
 		}
 		g_list_free (matches);
 	}
@@ -152,11 +174,115 @@ pgd_find_find_text (PgdFindDemo *demo)
 	return demo->page_index < demo->n_pages;
 }
 
+static cairo_surface_t *
+pgd_find_render_page (PgdFindDemo *demo)
+{
+        cairo_t *cr;
+        PopplerPage *page;
+        gdouble width, height;
+        cairo_surface_t *surface = NULL;
+
+        page = poppler_document_get_page (demo->doc, demo->selected_page);
+        if (!page)
+                return NULL;
+
+        poppler_page_get_size (page, &width, &height);
+        gtk_widget_set_size_request (demo->darea, width, height);
+
+        surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
+                                              width, height);
+        cr = cairo_create (surface);
+
+        cairo_save (cr);
+        cairo_set_source_rgb (cr, 1, 1, 1);
+        cairo_rectangle (cr, 0, 0, width, height);
+        cairo_fill (cr);
+        cairo_restore (cr);
+
+        cairo_save (cr);
+        poppler_page_render (page, cr);
+        cairo_restore (cr);
+
+        cairo_destroy (cr);
+        g_object_unref (page);
+
+        return surface;
+}
+
+static gboolean
+pgd_find_viewer_drawing_area_draw (GtkWidget   *area,
+                                   cairo_t     *cr,
+                                   PgdFindDemo *demo)
+{
+        if (demo->selected_page == -1)
+                return FALSE;
+
+        if (!demo->surface) {
+                demo->surface = pgd_find_render_page (demo);
+                if (!demo->surface)
+                        return FALSE;
+        }
+
+        cairo_set_source_surface (cr, demo->surface, 0, 0);
+        cairo_paint (cr);
+
+        if (demo->selected_match.width > 0 && demo->selected_match.height > 0) {
+                cairo_set_source_rgb (cr, 1., 1., 0.);
+                cairo_set_operator (cr, CAIRO_OPERATOR_MULTIPLY);
+                gdk_cairo_rectangle (cr, &demo->selected_match);
+                cairo_fill (cr);
+        }
+
+        return TRUE;
+}
+
+static gboolean
+pgd_find_viewer_redraw (PgdFindDemo *demo)
+{
+        cairo_surface_destroy (demo->surface);
+        demo->surface = NULL;
+
+        gtk_widget_queue_draw (demo->darea);
+
+        return FALSE;
+}
+
+static void
+pgd_find_viewer_queue_redraw (PgdFindDemo *demo)
+{
+        g_idle_add ((GSourceFunc)pgd_find_viewer_redraw, demo);
+}
+
+static GtkTreeModel *
+pgd_find_create_model ()
+{
+        return GTK_TREE_MODEL (gtk_tree_store_new (N_COLUMNS,
+                                                   G_TYPE_STRING,
+                                                   G_TYPE_STRING, G_TYPE_STRING,
+                                                   G_TYPE_STRING, G_TYPE_STRING,
+                                                   G_TYPE_BOOLEAN, G_TYPE_UINT,
+                                                   G_TYPE_POINTER));
+}
+
 static void
 pgd_find_button_clicked (GtkButton   *button,
 			 PgdFindDemo *demo)
 {
-	gtk_tree_store_clear (GTK_TREE_STORE (demo->model));
+        GtkTreeModel *model;
+
+        /* Delete the model and create a new one instead of
+         * just clearing it to make sure rectangle are free.
+         * This is a workaround because GtkTreeModel doesn't
+         * support boxed types and we have to store rectangles
+         * as pointers that are freed when the model is deleted.
+         */
+        model = pgd_find_create_model ();
+        gtk_tree_view_set_model (GTK_TREE_VIEW (demo->treeview), model);
+        g_object_unref (model);
+
+        demo->selected_page = -1;
+        pgd_find_viewer_queue_redraw (demo);
+
 	demo->page_index = 0;
 	pgd_find_update_progress (demo, demo->page_index);
 	if (demo->idle_id > 0)
@@ -174,21 +300,63 @@ pgd_find_button_sensitivity_cb (GtkWidget *button,
 	gtk_widget_set_sensitive (button, text != NULL && text[0] != '\0');
 }
 
+static void
+pgd_find_selection_changed (GtkTreeSelection *treeselection,
+                            PgdFindDemo      *demo)
+{
+        GtkTreeModel *model;
+        GtkTreeIter   iter;
+
+        if (gtk_tree_selection_get_selected (treeselection, &model, &iter)) {
+                guint page_index;
+                PopplerRectangle *rect;
+
+                gtk_tree_model_get (model, &iter,
+                                    PAGE_COLUMN, &page_index,
+                                    PAGE_RECT, &rect,
+                                    -1);
+
+                if (rect) {
+                        demo->selected_match.x = rect->x1;
+                        demo->selected_match.y = rect->y1;
+                        demo->selected_match.width = rect->x2 - rect->x1;
+                        demo->selected_match.height = rect->y2 - rect->y1;
+                } else {
+                        demo->selected_match.width = 0;
+                        demo->selected_match.height = 0;
+                }
+
+                if (page_index != demo->selected_page) {
+                        demo->selected_page = page_index;
+                        pgd_find_viewer_queue_redraw (demo);
+                } else {
+                        gtk_widget_queue_draw (demo->darea);
+                }
+        }
+}
+
 GtkWidget *
 pgd_find_create_widget (PopplerDocument *document)
 {
-	PgdFindDemo     *demo;
-	GtkWidget       *vbox, *hbox;
-	GtkWidget       *button;
-	GtkWidget       *swindow;
-	GtkWidget       *treeview;
-	GtkCellRenderer *renderer;
+	PgdFindDemo      *demo;
+	GtkWidget        *vbox, *hbox;
+	GtkWidget        *button;
+	GtkWidget        *swindow;
+        GtkTreeModel     *model;
+	GtkWidget        *treeview;
+	GtkCellRenderer  *renderer;
+        GtkWidget        *hpaned;
+        GtkTreeSelection *selection;
 
 	demo = g_new0 (PgdFindDemo, 1);
 
 	demo->doc = g_object_ref (document);
 
 	demo->n_pages = poppler_document_get_n_pages (document);
+        demo->selected_page = -1;
+
+        hpaned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
+        gtk_paned_set_position (GTK_PANED (hpaned), 300);
 
 	vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
 
@@ -222,17 +390,17 @@ pgd_find_create_widget (PopplerDocument *document)
 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow),
 					GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
 
-	demo->model = GTK_TREE_MODEL (
-		gtk_tree_store_new (N_COLUMNS,
-				    G_TYPE_STRING,
-				    G_TYPE_STRING, G_TYPE_STRING,
-				    G_TYPE_STRING, G_TYPE_STRING,
-				    G_TYPE_BOOLEAN));
-	treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (demo->model));
+	model = pgd_find_create_model ();
+	treeview = gtk_tree_view_new_with_model (model);
+        g_object_unref (model);
+        demo->treeview = treeview;
 	gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (treeview), TRUE);
-	gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)),
-				     GTK_SELECTION_NONE);
-	
+        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
+	gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
+        g_signal_connect (selection, "changed",
+                          G_CALLBACK (pgd_find_selection_changed),
+                          demo);
+
 	renderer = gtk_cell_renderer_text_new ();
 	gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
 						     TITLE_COLUMN, "Matches",
@@ -271,8 +439,23 @@ pgd_find_create_widget (PopplerDocument *document)
 	gtk_container_add (GTK_CONTAINER (swindow), treeview);
 	gtk_widget_show (treeview);
 
-	gtk_box_pack_start (GTK_BOX (vbox), swindow, TRUE, TRUE, 0);
-	gtk_widget_show (swindow);
+        gtk_paned_add1 (GTK_PANED (hpaned), swindow);
+        gtk_widget_show (swindow);
+
+        demo->darea = gtk_drawing_area_new ();
+        g_signal_connect (demo->darea, "draw",
+                          G_CALLBACK (pgd_find_viewer_drawing_area_draw),
+                          demo);
+
+        swindow = gtk_scrolled_window_new (NULL, NULL);
+        gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (swindow), demo->darea);
+        gtk_widget_show (demo->darea);
+
+        gtk_paned_add2 (GTK_PANED (hpaned), swindow);
+        gtk_widget_show (swindow);
+
+        gtk_box_pack_start (GTK_BOX (vbox), hpaned, TRUE, TRUE, 0);
+        gtk_widget_show (hpaned);
 
 	g_object_weak_ref (G_OBJECT (vbox),
 			   (GWeakNotify)pgd_find_free,
commit ed0c761c2190a3c1959a60ae9b7961f58a43c939
Author: Thomas Schenker <mail.thomas.schenker at googlemail.com>
Date:   Sat Jun 2 11:54:21 2012 +0200

    glib: Add poppler_page_find_text_with_options
    
    To be able to search text with options like case sensitive, search
    backwards and whole words only.
    
    https://bugs.freedesktop.org/show_bug.cgi?id=2951

diff --git a/glib/poppler-page.cc b/glib/poppler-page.cc
index 90f9a62..8113e9c 100644
--- a/glib/poppler-page.cc
+++ b/glib/poppler-page.cc
@@ -850,18 +850,23 @@ poppler_page_get_text (PopplerPage *page)
 }
 
 /**
- * poppler_page_find_text:
+ * poppler_page_find_text_with_options:
  * @page: a #PopplerPage
  * @text: the text to search for (UTF-8 encoded)
- * 
- * A #GList of rectangles for each occurance of the text on the page.
+ * @options: find options
+ *
+ * Finds @text in @page with the given #PopplerFindFlags options and
+ * returns a #GList of rectangles for each occurance of the text on the page.
  * The coordinates are in PDF points.
- * 
+ *
  * Return value: (element-type PopplerRectangle) (transfer full): a #GList of #PopplerRectangle,
+ *
+ * Since: 0.22
  **/
 GList *
-poppler_page_find_text (PopplerPage *page,
-			const char  *text)
+poppler_page_find_text_with_options (PopplerPage     *page,
+                                     const char      *text,
+                                     PopplerFindFlags options)
 {
   PopplerRectangle *match;
   GList *matches;
@@ -870,6 +875,7 @@ poppler_page_find_text (PopplerPage *page,
   glong ucs4_len;
   double height;
   TextPage *text_dev;
+  gboolean backwards;
 
   g_return_val_if_fail (POPPLER_IS_PAGE (page), NULL);
   g_return_val_if_fail (text != NULL, NULL);
@@ -878,17 +884,19 @@ poppler_page_find_text (PopplerPage *page,
 
   ucs4 = g_utf8_to_ucs4_fast (text, -1, &ucs4_len);
   poppler_page_get_size (page, NULL, &height);
-  
+
+  backwards = options & POPPLER_FIND_BACKWARDS;
   matches = NULL;
   xMin = 0;
-  yMin = 0;
+  yMin = backwards ? height : 0;
 
   while (text_dev->findText (ucs4, ucs4_len,
-			     gFalse, gTrue, // startAtTop, stopAtBottom
-			     gFalse, gFalse, // startAtLast, stopAtLast
-			     gFalse, gFalse, // caseSensitive, backwards
-			     gFalse, // wholeWord
-			     &xMin, &yMin, &xMax, &yMax))
+                             gFalse, gTrue, // startAtTop, stopAtBottom
+                             gTrue, gFalse, // startAtLast, stopAtLast
+                             options & POPPLER_FIND_CASE_SENSITIVE,
+                             backwards,
+                             options & POPPLER_FIND_WHOLE_WORDS_ONLY,
+                             &xMin, &yMin, &xMax, &yMax))
     {
       match = poppler_rectangle_new ();
       match->x1 = xMin;
@@ -903,6 +911,24 @@ poppler_page_find_text (PopplerPage *page,
   return g_list_reverse (matches);
 }
 
+/**
+ * poppler_page_find_text:
+ * @page: a #PopplerPage
+ * @text: the text to search for (UTF-8 encoded)
+ *
+ * Finds @text in @page with the default options (%POPPLER_FIND_DEFAULT) and
+ * returns a #GList of rectangles for each occurance of the text on the page.
+ * The coordinates are in PDF points.
+ *
+ * Return value: (element-type PopplerRectangle) (transfer full): a #GList of #PopplerRectangle,
+ **/
+GList *
+poppler_page_find_text (PopplerPage *page,
+			const char  *text)
+{
+  return poppler_page_find_text_with_options (page, text, POPPLER_FIND_DEFAULT);
+}
+
 static CairoImageOutputDev *
 poppler_page_get_image_output_dev (PopplerPage *page,
 				   GBool (*imgDrawDeviceCbk)(int img_id, void *data),
diff --git a/glib/poppler-page.h b/glib/poppler-page.h
index 6064ac5..c081b8c 100644
--- a/glib/poppler-page.h
+++ b/glib/poppler-page.h
@@ -60,6 +60,9 @@ PopplerPageTransition *poppler_page_get_transition       (PopplerPage        *pa
 gboolean               poppler_page_get_thumbnail_size   (PopplerPage        *page,
 							  int                *width,
 							  int                *height);
+GList             *poppler_page_find_text_with_options   (PopplerPage        *page,
+							  const  char        *text,
+							  PopplerFindFlags    options);
 GList     	      *poppler_page_find_text            (PopplerPage        *page,
 							  const  char        *text);
 void                   poppler_page_render_to_ps         (PopplerPage        *page,
diff --git a/glib/poppler.h b/glib/poppler.h
index 6c2eefd..2d190f3 100644
--- a/glib/poppler.h
+++ b/glib/poppler.h
@@ -153,6 +153,24 @@ typedef enum /*< flags >*/
   POPPLER_PRINT_ALL               = POPPLER_PRINT_MARKUP_ANNOTS
 } PopplerPrintFlags;
 
+/**
+ * PopplerFindFlags:
+ * @POPPLER_FIND_CASE_SENSITIVE: do case sensitive search
+ * @POPPLER_FIND_BACKWARDS: search backwards
+ * @POPPLER_FIND_WHOLE_WORDS_ONLY: search only whole words
+ *
+ * Flags using while searching text in a page
+ *
+ * Since: 0.22
+ */
+typedef enum /*< flags >*/
+{
+  POPPLER_FIND_DEFAULT          = 0,
+  POPPLER_FIND_CASE_SENSITIVE   = 1 << 0,
+  POPPLER_FIND_BACKWARDS        = 1 << 1,
+  POPPLER_FIND_WHOLE_WORDS_ONLY = 1 << 2
+} PopplerFindFlags;
+
 typedef struct _PopplerDocument            PopplerDocument;
 typedef struct _PopplerIndexIter           PopplerIndexIter;
 typedef struct _PopplerFontsIter           PopplerFontsIter;
diff --git a/glib/reference/poppler-sections.txt b/glib/reference/poppler-sections.txt
index 76abf4c..6fb14bc 100644
--- a/glib/reference/poppler-sections.txt
+++ b/glib/reference/poppler-sections.txt
@@ -33,6 +33,7 @@ poppler_page_get_selection_region
 poppler_page_selection_region_free
 poppler_page_get_selected_text
 poppler_page_find_text
+poppler_page_find_text_with_options
 poppler_page_get_text
 poppler_page_get_text_layout
 poppler_page_get_text_attributes
@@ -338,6 +339,7 @@ PopplerOrientation
 PopplerBackend
 PopplerColor
 PopplerPrintFlags
+PopplerFindFlags
 poppler_get_backend
 poppler_get_version
 poppler_date_parse
commit 126b55c9a44ccb0dba55e758843e9ee4aa43ee2b
Author: Carlos Garcia Campos <carlosgc at gnome.org>
Date:   Sat Jun 2 17:19:30 2012 +0200

    Implement whole words only option to search text
    
    It seems we missed it in the xpdf303 merge.

diff --git a/poppler/TextOutputDev.cc b/poppler/TextOutputDev.cc
index e8d993b..9af7532 100644
--- a/poppler/TextOutputDev.cc
+++ b/poppler/TextOutputDev.cc
@@ -3653,76 +3653,80 @@ GBool TextPage::findText(Unicode *s, int len,
       j = backward ? m - len : 0;
       p = txt + j;
       while (backward ? j >= 0 : j <= m - len) {
+        if (!wholeWord ||
+            ((j == 0 || !unicodeTypeAlphaNum(txt[j - 1])) &&
+             (j + len == m || !unicodeTypeAlphaNum(txt[j + len])))) {
+
+          // compare the strings
+          for (k = 0; k < len; ++k) {
+            if (p[k] != s2[k]) {
+              break;
+            }
+          }
 
-	// compare the strings
-	for (k = 0; k < len; ++k) {
-	  if (p[k] != s2[k]) {
-	    break;
-	  }
-	}
-
-	// found it
-	if (k == len) {
-	  // where s2 matches a subsequence of a compatibility equivalence
-	  // decomposition, highlight the entire glyph, since we don't know
-	  // the internal layout of subglyph components
-	  int normStart = line->normalized_idx[j];
-	  int normAfterEnd = line->normalized_idx[j + len - 1] + 1;
-	  switch (line->rot) {
-	  case 0:
-	    xMin1 = line->edge[normStart];
-	    xMax1 = line->edge[normAfterEnd];
-	    yMin1 = line->yMin;
-	    yMax1 = line->yMax;
-	    break;
-	  case 1:
-	    xMin1 = line->xMin;
-	    xMax1 = line->xMax;
-	    yMin1 = line->edge[normStart];
-	    yMax1 = line->edge[normAfterEnd];
-	    break;
-	  case 2:
-	    xMin1 = line->edge[normAfterEnd];
-	    xMax1 = line->edge[normStart];
-	    yMin1 = line->yMin;
-	    yMax1 = line->yMax;
-	    break;
-	  case 3:
-	    xMin1 = line->xMin;
-	    xMax1 = line->xMax;
-	    yMin1 = line->edge[normAfterEnd];
-	    yMax1 = line->edge[normStart];
-	    break;
-	  }
-	  if (backward) {
-	    if ((startAtTop ||
-		 yMin1 < yStart || (yMin1 == yStart && xMin1 < xStart)) &&
-		(stopAtBottom ||
-		 yMin1 > yStop || (yMin1 == yStop && xMin1 > xStop))) {
-	      if (!found ||
-		  yMin1 > yMin0 || (yMin1 == yMin0 && xMin1 > xMin0)) {
-		xMin0 = xMin1;
-		xMax0 = xMax1;
-		yMin0 = yMin1;
-		yMax0 = yMax1;
-		found = gTrue;
-	      }
-	    }
-	  } else {
-	    if ((startAtTop ||
-		 yMin1 > yStart || (yMin1 == yStart && xMin1 > xStart)) &&
-		(stopAtBottom ||
-		 yMin1 < yStop || (yMin1 == yStop && xMin1 < xStop))) {
-	      if (!found ||
-		  yMin1 < yMin0 || (yMin1 == yMin0 && xMin1 < xMin0)) {
-		xMin0 = xMin1;
-		xMax0 = xMax1;
-		yMin0 = yMin1;
-		yMax0 = yMax1;
-		found = gTrue;
-	      }
-	    }
-	  }
+          // found it
+          if (k == len) {
+            // where s2 matches a subsequence of a compatibility equivalence
+            // decomposition, highlight the entire glyph, since we don't know
+            // the internal layout of subglyph components
+            int normStart = line->normalized_idx[j];
+            int normAfterEnd = line->normalized_idx[j + len - 1] + 1;
+            switch (line->rot) {
+            case 0:
+              xMin1 = line->edge[normStart];
+              xMax1 = line->edge[normAfterEnd];
+              yMin1 = line->yMin;
+              yMax1 = line->yMax;
+              break;
+            case 1:
+              xMin1 = line->xMin;
+              xMax1 = line->xMax;
+              yMin1 = line->edge[normStart];
+              yMax1 = line->edge[normAfterEnd];
+              break;
+            case 2:
+              xMin1 = line->edge[normAfterEnd];
+              xMax1 = line->edge[normStart];
+              yMin1 = line->yMin;
+              yMax1 = line->yMax;
+              break;
+            case 3:
+              xMin1 = line->xMin;
+              xMax1 = line->xMax;
+              yMin1 = line->edge[normAfterEnd];
+              yMax1 = line->edge[normStart];
+              break;
+            }
+            if (backward) {
+              if ((startAtTop ||
+                   yMin1 < yStart || (yMin1 == yStart && xMin1 < xStart)) &&
+                  (stopAtBottom ||
+                   yMin1 > yStop || (yMin1 == yStop && xMin1 > xStop))) {
+                if (!found ||
+                    yMin1 > yMin0 || (yMin1 == yMin0 && xMin1 > xMin0)) {
+                  xMin0 = xMin1;
+                  xMax0 = xMax1;
+                  yMin0 = yMin1;
+                  yMax0 = yMax1;
+                  found = gTrue;
+                }
+              }
+            } else {
+              if ((startAtTop ||
+                   yMin1 > yStart || (yMin1 == yStart && xMin1 > xStart)) &&
+                  (stopAtBottom ||
+                   yMin1 < yStop || (yMin1 == yStop && xMin1 < xStop))) {
+                if (!found ||
+                    yMin1 < yMin0 || (yMin1 == yMin0 && xMin1 < xMin0)) {
+                  xMin0 = xMin1;
+                  xMax0 = xMax1;
+                  yMin0 = yMin1;
+                  yMax0 = yMax1;
+                  found = gTrue;
+                }
+              }
+            }
+          }
 	}
 	if (backward) {
 	  --j;
@@ -3733,7 +3737,7 @@ GBool TextPage::findText(Unicode *s, int len,
 	}
       }
     }
-    }
+  }
 
   gfree(s2);
   if (!caseSensitive) {


More information about the poppler mailing list