[evince/333-handle-spaces-and-hyphenation-when-search-pdf: 8/8] Add support for multi-line text search
- From: Germán Poo-Caamaño <gpoo src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evince/333-handle-spaces-and-hyphenation-when-search-pdf: 8/8] Add support for multi-line text search
- Date: Sun, 22 May 2022 21:14:47 +0000 (UTC)
commit 495dd97e46eefa9eb523aa40c9c1e8bdeff23549
Author: Nelson Benítez León <nbenitezl gmail com>
Date: Sun Apr 4 15:47:37 2021 -0400
Add support for multi-line text search
which is available in Poppler since version 21.03.0
For that we create a new EvFindRectangle type to hold more match
information apart from coordinates, and use it all across Evince
including pdf backend (ev-poppler.cc) and djvu backend (djvu-document.c)
which are the only backends implementing the EvDocumentFindInterface.
To not break API compatibility, we added a new EvDocumentFindInterface
function which returns GList of this new EvFindRectangle type:
GList *(* find_text_extended) (EvDocumentFind *document_find,
EvPage *page,
const gchar *text,
EvFindOptions options);
and changed Evince to use this new function instead of find_text_with_options().
Some info about how this new search feature works:
- Ignores hyphen character while matching when:
1) it's the last character of the line.
2) its corresponding matching character in the search term
is not an hyphen too.
- Any whitespace characters in the search term will be allowed
to match on the logic position where the lines split (i.e. what
would normally be the newline character in a text file, but
PDF text does not include newline characters between lines).
- It won't match on text spanning more than two lines, i.e. it
only matches text spanning from end of one line to start of
next line.
Part of issue #333
backend/djvu/djvu-document.c | 66 +++++++++++++++++++++++++++++++++++
backend/pdf/ev-poppler.c | 79 +++++++++++++++++++++++++++++++++++++-----
libdocument/ev-document-find.c | 46 ++++++++++++++++++++++++
libdocument/ev-document-find.h | 32 +++++++++++++++++
libview/ev-jobs.c | 34 +++++++++++++++---
libview/ev-jobs.h | 3 ++
libview/ev-view-private.h | 8 +++--
libview/ev-view.c | 78 ++++++++++++++++++++++++++++++++++-------
shell/ev-find-sidebar.c | 27 +++++++++++----
9 files changed, 337 insertions(+), 36 deletions(-)
---
diff --git a/backend/djvu/djvu-document.c b/backend/djvu/djvu-document.c
index 078aaa692..8dd932afb 100644
--- a/backend/djvu/djvu-document.c
+++ b/backend/djvu/djvu-document.c
@@ -925,6 +925,71 @@ djvu_document_find_find_text (EvDocumentFind *document,
r->y1 = height - r->y2 * 72.0 / dpi;
r->y2 = height - tmp * 72.0 / dpi;
}
+
+
+ return matches;
+}
+
+static GList *
+djvu_document_find_find_text_extended (EvDocumentFind *document,
+ EvPage *page,
+ const char *text,
+ EvFindOptions options)
+{
+ DjvuDocument *djvu_document = DJVU_DOCUMENT (document);
+ miniexp_t page_text;
+ gdouble width, height, dpi;
+ GList *matches = NULL, *l;
+ char *search_text = NULL;
+ gboolean case_sensitive = (options & EV_FIND_CASE_SENSITIVE);
+
+ g_return_val_if_fail (text != NULL, NULL);
+
+ while ((page_text = ddjvu_document_get_pagetext (djvu_document->d_document,
+ page->index,
+ "char")) == miniexp_dummy)
+ djvu_handle_events (djvu_document, TRUE, NULL);
+
+ if (page_text != miniexp_nil) {
+ DjvuTextPage *tpage = djvu_text_page_new (page_text);
+
+ djvu_text_page_index_text (tpage, case_sensitive);
+ if (tpage->links->len > 0) {
+ if (!case_sensitive) {
+ search_text = g_utf8_casefold (text, -1);
+ djvu_text_page_search (tpage, search_text);
+ g_free (search_text);
+ } else {
+ djvu_text_page_search (tpage, text);
+ }
+ matches = tpage->results;
+ }
+ djvu_text_page_free (tpage);
+ ddjvu_miniexp_release (djvu_document->d_document, page_text);
+ }
+ if (!matches)
+ return NULL;
+
+ document_get_page_size (djvu_document, page->index, &width, &height, &dpi);
+ for (l = matches; l && l->data; l = g_list_next (l)) {
+ EvRectangle *r = (EvRectangle *)l->data;
+ gdouble tmp = r->y1;
+
+ r->x1 *= 72.0 / dpi;
+ r->x2 *= 72.0 / dpi;
+
+ r->y1 = height - r->y2 * 72.0 / dpi;
+ r->y2 = height - tmp * 72.0 / dpi;
+
+ EvFindRectangle *ev_rect = ev_find_rectangle_new ();
+ ev_rect->x1 = r->x1;
+ ev_rect->x2 = r->x2;
+ ev_rect->y1 = r->y1;
+ ev_rect->y2 = r->y2;
+
+ ev_rectangle_free (r);
+ l->data = ev_rect;
+ }
return matches;
@@ -940,6 +1005,7 @@ static void
djvu_document_find_iface_init (EvDocumentFindInterface *iface)
{
iface->find_text = djvu_document_find_find_text;
+ iface->find_text_extended = djvu_document_find_find_text_extended;
iface->get_supported_options = djvu_document_find_get_supported_options;
}
diff --git a/backend/pdf/ev-poppler.c b/backend/pdf/ev-poppler.c
index 8738f0052..4d77658a2 100644
--- a/backend/pdf/ev-poppler.c
+++ b/backend/pdf/ev-poppler.c
@@ -1523,9 +1523,60 @@ pdf_document_document_images_iface_init (EvDocumentImagesInterface *iface)
static GList *
pdf_document_find_find_text_with_options (EvDocumentFind *document_find,
- EvPage *page,
- const gchar *text,
- EvFindOptions options)
+ EvPage *page,
+ const gchar *text,
+ EvFindOptions options)
+{
+ GList *matches, *l;
+ PopplerPage *poppler_page;
+ gdouble height;
+ GList *retval = NULL;
+ guint find_flags = 0;
+
+ g_return_val_if_fail (POPPLER_IS_PAGE (page->backend_page), NULL);
+ g_return_val_if_fail (text != NULL, NULL);
+
+ poppler_page = POPPLER_PAGE (page->backend_page);
+
+ if (options & EV_FIND_CASE_SENSITIVE)
+ find_flags |= POPPLER_FIND_CASE_SENSITIVE;
+#if POPPLER_CHECK_VERSION(0, 76, 0)
+ else /* When search is not case sensitive, do also ignore diacritics
+ to broaden our search in order to match on more expected results */
+ find_flags |= POPPLER_FIND_IGNORE_DIACRITICS;
+#endif
+ if (options & EV_FIND_WHOLE_WORDS_ONLY)
+ find_flags |= POPPLER_FIND_WHOLE_WORDS_ONLY;
+ matches = poppler_page_find_text_with_options (poppler_page, text, (PopplerFindFlags)find_flags);
+ if (!matches)
+ return NULL;
+
+ poppler_page_get_size (poppler_page, NULL, &height);
+ for (l = matches; l && l->data; l = g_list_next (l)) {
+ PopplerRectangle *rect = (PopplerRectangle *)l->data;
+ EvRectangle *ev_rect;
+
+ ev_rect = ev_rectangle_new ();
+ ev_rect->x1 = rect->x1;
+ ev_rect->x2 = rect->x2;
+ /* Invert this for X-style coordinates */
+ ev_rect->y1 = height - rect->y2;
+ ev_rect->y2 = height - rect->y1;
+
+ retval = g_list_prepend (retval, ev_rect);
+ }
+
+ g_list_foreach (matches, (GFunc)poppler_rectangle_free, NULL);
+ g_list_free (matches);
+
+ return g_list_reverse (retval);
+}
+
+static GList *
+pdf_document_find_find_text_extended (EvDocumentFind *document_find,
+ EvPage *page,
+ const gchar *text,
+ EvFindOptions options)
{
GList *matches, *l;
PopplerPage *poppler_page;
@@ -1547,27 +1598,36 @@ pdf_document_find_find_text_with_options (EvDocumentFind *document_find,
#endif
if (options & EV_FIND_WHOLE_WORDS_ONLY)
find_flags |= POPPLER_FIND_WHOLE_WORDS_ONLY;
+
+#if POPPLER_CHECK_VERSION(22, 05, 0)
+ /* Allow to match on text spanning from one line to the next */
+ find_flags |= POPPLER_FIND_MULTILINE;
+#endif
matches = poppler_page_find_text_with_options (poppler_page, text, (PopplerFindFlags)find_flags);
if (!matches)
return NULL;
poppler_page_get_size (poppler_page, NULL, &height);
for (l = matches; l && l->data; l = g_list_next (l)) {
- PopplerRectangle *rect = (PopplerRectangle *)l->data;
- EvRectangle *ev_rect;
+ EvFindRectangle *ev_rect = ev_find_rectangle_new ();
- ev_rect = ev_rectangle_new ();
+ PopplerRectangle *rect = (PopplerRectangle *)l->data;
ev_rect->x1 = rect->x1;
ev_rect->x2 = rect->x2;
/* Invert this for X-style coordinates */
ev_rect->y1 = height - rect->y2;
ev_rect->y2 = height - rect->y1;
-
+#if POPPLER_CHECK_VERSION(22, 05, 0)
+ ev_rect->next_line = poppler_rectangle_find_get_match_continued (rect);
+ ev_rect->after_hyphen = ev_rect->next_line && poppler_rectangle_find_get_ignored_hyphen
(rect);
+#else
+ ev_rect->next_line = FALSE;
+ ev_rect->after_hyphen = FALSE;
+#endif
retval = g_list_prepend (retval, ev_rect);
}
- g_list_foreach (matches, (GFunc)poppler_rectangle_free, NULL);
- g_list_free (matches);
+ g_list_free_full (matches, (GDestroyNotify) poppler_rectangle_free);
return g_list_reverse (retval);
}
@@ -1597,6 +1657,7 @@ pdf_document_find_iface_init (EvDocumentFindInterface *iface)
{
iface->find_text = pdf_document_find_find_text;
iface->find_text_with_options = pdf_document_find_find_text_with_options;
+ iface->find_text_extended = pdf_document_find_find_text_extended;
iface->get_supported_options = pdf_document_find_get_supported_options;
}
diff --git a/libdocument/ev-document-find.c b/libdocument/ev-document-find.c
index 607a4957a..3599b07db 100644
--- a/libdocument/ev-document-find.c
+++ b/libdocument/ev-document-find.c
@@ -72,6 +72,52 @@ ev_document_find_find_text_with_options (EvDocumentFind *document_find,
return ev_document_find_find_text (document_find, page, text, options & EV_FIND_CASE_SENSITIVE);
}
+/**
+ * ev_document_find_find_text_extended:
+ * @document_find: an #EvDocumentFind
+ * @page: an #EvPage
+ * @text: text to find
+ * @options: a set of #EvFindOptions
+ *
+ * Returns: (transfer full) (element-type EvFindRectangle): a list of results
+ */
+GList *
+ev_document_find_find_text_extended (EvDocumentFind *document_find,
+ EvPage *page,
+ const gchar *text,
+ EvFindOptions options)
+{
+ EvDocumentFindInterface *iface = EV_DOCUMENT_FIND_GET_IFACE (document_find);
+
+ if (iface->find_text_extended)
+ return iface->find_text_extended (document_find, page, text, options);
+
+ g_warning ("Unimplemented find_text_extended() interface");
+ return NULL;
+}
+
+/* EvFindRectangle */
+G_DEFINE_BOXED_TYPE (EvFindRectangle, ev_find_rectangle, ev_find_rectangle_copy, ev_find_rectangle_free)
+
+EvFindRectangle *
+ev_find_rectangle_new (void)
+{
+ return g_slice_new0 (EvFindRectangle);
+}
+
+EvFindRectangle *
+ev_find_rectangle_copy (EvFindRectangle *rectangle)
+{
+ g_return_val_if_fail (rectangle != NULL, NULL);
+ return g_slice_dup (EvFindRectangle, rectangle);
+}
+
+void
+ev_find_rectangle_free (EvFindRectangle *rectangle)
+{
+ g_slice_free (EvFindRectangle, rectangle);
+}
+
EvFindOptions
ev_document_find_get_supported_options (EvDocumentFind *document_find)
{
diff --git a/libdocument/ev-document-find.h b/libdocument/ev-document-find.h
index 0b929f52a..c4109438e 100644
--- a/libdocument/ev-document-find.h
+++ b/libdocument/ev-document-find.h
@@ -40,6 +40,29 @@ G_BEGIN_DECLS
typedef struct _EvDocumentFind EvDocumentFind;
typedef struct _EvDocumentFindInterface EvDocumentFindInterface;
+typedef struct _EvFindRectangle EvFindRectangle;
+
+#define EV_TYPE_FIND_RECTANGLE (ev_find_rectangle_get_type ())
+struct _EvFindRectangle
+{
+ gdouble x1;
+ gdouble y1;
+ gdouble x2;
+ gdouble y2;
+ gboolean next_line; /* the boolean from poppler_rectangle_find_get_match_continued() */
+ gboolean after_hyphen; /* the boolean from poppler_rectangle_find_get_ignored_hyphen() */
+ void (*_ev_reserved1) (void);
+ void (*_ev_reserved2) (void);
+};
+
+EV_PUBLIC
+GType ev_find_rectangle_get_type (void) G_GNUC_CONST;
+EV_PUBLIC
+EvFindRectangle *ev_find_rectangle_new (void);
+EV_PUBLIC
+EvFindRectangle *ev_find_rectangle_copy (EvFindRectangle *ev_find_rect);
+EV_PUBLIC
+void ev_find_rectangle_free (EvFindRectangle *ev_find_rect);
typedef enum {
EV_FIND_DEFAULT = 0,
@@ -61,6 +84,10 @@ struct _EvDocumentFindInterface
const gchar *text,
EvFindOptions options);
EvFindOptions (*get_supported_options) (EvDocumentFind *document_find);
+ GList *(* find_text_extended) (EvDocumentFind *document_find,
+ EvPage *page,
+ const gchar *text,
+ EvFindOptions options);
};
EV_PUBLIC
@@ -77,5 +104,10 @@ GList *ev_document_find_find_text_with_options (EvDocumentFind *document_
EvFindOptions options);
EV_PUBLIC
EvFindOptions ev_document_find_get_supported_options (EvDocumentFind *document_find);
+EV_PUBLIC
+GList *ev_document_find_find_text_extended (EvDocumentFind *document_find,
+ EvPage *page,
+ const gchar *text,
+ EvFindOptions options);
G_END_DECLS
diff --git a/libview/ev-jobs.c b/libview/ev-jobs.c
index 8b54c8a83..ca63aedf6 100644
--- a/libview/ev-jobs.c
+++ b/libview/ev-jobs.c
@@ -1950,8 +1950,7 @@ ev_job_find_dispose (GObject *object)
gint i;
for (i = 0; i < job->n_pages; i++) {
- g_list_foreach (job->pages[i], (GFunc)ev_rectangle_free, NULL);
- g_list_free (job->pages[i]);
+ g_list_free_full (job->pages[i], (GDestroyNotify)ev_find_rectangle_free);
}
g_free (job->pages);
@@ -1982,8 +1981,8 @@ ev_job_find_run (EvJob *job)
#endif
ev_page = ev_document_get_page (job->document, job_find->current_page);
- matches = ev_document_find_find_text_with_options (find, ev_page, job_find->text,
- job_find->options);
+ matches = ev_document_find_find_text_extended (find, ev_page, job_find->text,
+ job_find->options);
g_object_unref (ev_page);
ev_document_doc_mutex_unlock ();
@@ -2089,6 +2088,31 @@ ev_job_find_get_n_results (EvJobFind *job,
return g_list_length (job->pages[page]);
}
+/**
+ * ev_job_find_get_n_main_results:
+ * @job: an #EvJobFind job
+ * @page: number of the page we want to count its match results.
+ *
+ * This is similar to ev_job_find_get_n_results() but it takes
+ * care to treat any multi-line matches as being only one result.
+ *
+ * Returns: total number of match results in @page
+ */
+gint
+ev_job_find_get_n_main_results (EvJobFind *job,
+ gint page)
+{
+ GList *l;
+ int n = 0;
+
+ for (l = job->pages[page]; l; l = l->next) {
+ if ( !((EvFindRectangle *) l->data)->next_line )
+ n++;
+ }
+
+ return n;
+}
+
gdouble
ev_job_find_get_progress (EvJobFind *job)
{
@@ -2118,7 +2142,7 @@ ev_job_find_has_results (EvJobFind *job)
* ev_job_find_get_results: (skip)
* @job: an #EvJobFind
*
- * Returns: a #GList of #GList<!-- -->s containing #EvRectangle<!-- -->s
+ * Returns: a #GList of #GList<!-- -->s containing #EvFindRectangle<!-- -->s
*/
GList **
ev_job_find_get_results (EvJobFind *job)
diff --git a/libview/ev-jobs.h b/libview/ev-jobs.h
index ae5bca2ef..579f29688 100644
--- a/libview/ev-jobs.h
+++ b/libview/ev-jobs.h
@@ -714,6 +714,9 @@ EV_PUBLIC
gint ev_job_find_get_n_results (EvJobFind *job,
gint pages);
EV_PUBLIC
+gint ev_job_find_get_n_main_results (EvJobFind *job,
+ gint page);
+EV_PUBLIC
gdouble ev_job_find_get_progress (EvJobFind *job);
EV_PUBLIC
gboolean ev_job_find_has_results (EvJobFind *job);
diff --git a/libview/ev-view-private.h b/libview/ev-view-private.h
index 5e60b1af7..660514340 100644
--- a/libview/ev-view-private.h
+++ b/libview/ev-view-private.h
@@ -150,9 +150,11 @@ struct _EvView {
/* Find */
EvJobFind *find_job;
- GList **find_pages; /* Backwards compatibility */
- gint find_page;
- gint find_result;
+ GList **find_pages; /* Backwards compatibility. Contains EvFindRectangles's elements per page */
+ gint find_page; /* Page of active find result */
+ gint find_result; /* Index of active find result on find_pages[find_page]. For matches across
+ * two lines (which comprise two EvFindRectangle's), this will always point
+ * to the first one, i.e. the one where rect->next_line is TRUE */
gboolean jump_to_find_result;
gboolean highlight_find_results;
diff --git a/libview/ev-view.c b/libview/ev-view.c
index 06aeb4ad4..7c6605a75 100644
--- a/libview/ev-view.c
+++ b/libview/ev-view.c
@@ -314,7 +314,7 @@ static void ev_view_handle_cursor_over_xy (EvView *view,
/*** Find ***/
static gint ev_view_find_get_n_results (EvView *view,
gint page);
-static EvRectangle *ev_view_find_get_result (EvView *view,
+static EvFindRectangle *ev_view_find_get_result (EvView *view,
gint page,
gint result);
static void jump_to_find_result (EvView *view);
@@ -7395,21 +7395,41 @@ highlight_find_results (EvView *view,
cairo_t *cr,
int page)
{
+ EvRectangle *ev_rect;
gint i, n_results = 0;
n_results = ev_view_find_get_n_results (view, page);
+ ev_rect = ev_rectangle_new ();
for (i = 0; i < n_results; i++) {
- EvRectangle *rectangle;
+ EvFindRectangle *find_rect;
GdkRectangle view_rectangle;
- gboolean active;
+ gboolean active;
- active = i == view->find_result && page == view->find_page;
+ find_rect = ev_view_find_get_result (view, page, i);
+ ev_rect->x1 = find_rect->x1;
+ ev_rect->x2 = find_rect->x2;
+ ev_rect->y1 = find_rect->y1;
+ ev_rect->y2 = find_rect->y2;
- rectangle = ev_view_find_get_result (view, page, i);
- _ev_view_transform_doc_rect_to_view_rect (view, page, rectangle, &view_rectangle);
+ active = page == view->find_page && i == view->find_result;
+ _ev_view_transform_doc_rect_to_view_rect (view, page, ev_rect, &view_rectangle);
draw_rubberband (view, cr, &view_rectangle, active);
+
+ if (active && find_rect->next_line) {
+ /* Draw now next result (which is second part of multi-line match) */
+ i++;
+ find_rect = ev_view_find_get_result (view, page, i);
+ ev_rect->x1 = find_rect->x1;
+ ev_rect->x2 = find_rect->x2;
+ ev_rect->y1 = find_rect->y1;
+ ev_rect->y2 = find_rect->y2;
+ _ev_view_transform_doc_rect_to_view_rect (view, page, ev_rect, &view_rectangle);
+ draw_rubberband (view, cr, &view_rectangle, TRUE);
+ }
}
+
+ ev_rectangle_free (ev_rect);
}
static void
@@ -9561,32 +9581,60 @@ ev_view_find_get_n_results (EvView *view, gint page)
return view->find_pages ? g_list_length (view->find_pages[page]) : 0;
}
-static EvRectangle *
+static EvFindRectangle *
ev_view_find_get_result (EvView *view, gint page, gint result)
{
- return view->find_pages ? (EvRectangle *) g_list_nth_data (view->find_pages[page], result) : NULL;
+ return view->find_pages ? (EvFindRectangle *) g_list_nth_data (view->find_pages[page], result) : NULL;
+}
+
+static gboolean
+ev_view_find_is_next_line (EvView *view, gint page, gint result)
+{
+ if (!view->find_pages)
+ return FALSE;
+
+ GList *elem = g_list_nth (view->find_pages[page], result);
+ return elem && ((EvFindRectangle *) elem->data)->next_line;
}
static void
jump_to_find_result (EvView *view)
{
+ EvRectangle *rect;
gint n_results;
gint page = view->find_page;
n_results = ev_view_find_get_n_results (view, page);
+ rect = ev_rectangle_new ();
if (n_results > 0 && view->find_result < n_results) {
- EvRectangle *rect;
+ EvFindRectangle *find_rect, *rect_next;
GdkRectangle view_rect;
- rect = ev_view_find_get_result (view, page, view->find_result);
+ rect_next = NULL;
+ find_rect = ev_view_find_get_result (view, page, view->find_result);
+ if (find_rect->next_line) {
+ /* For an across-lines match, make sure both rectangles are visible */
+ rect_next = ev_view_find_get_result (view, page, view->find_result + 1);
+ rect->x1 = MIN (find_rect->x1, rect_next->x1);
+ rect->y1 = MIN (find_rect->y1, rect_next->y1);
+ rect->x2 = MAX (find_rect->x2, rect_next->x2);
+ rect->y2 = MAX (find_rect->y2, rect_next->y2);
+ } else {
+ rect->x1 = find_rect->x1;
+ rect->y1 = find_rect->y1;
+ rect->x2 = find_rect->x2;
+ rect->y2 = find_rect->y2;
+ }
_ev_view_transform_doc_rect_to_view_rect (view, page, rect, &view_rect);
_ev_view_ensure_rectangle_is_visible (view, &view_rect);
if (view->caret_enabled && view->rotation == 0)
- position_caret_cursor_at_doc_point (view, page, rect->x1, rect->y1);
+ position_caret_cursor_at_doc_point (view, page, find_rect->x1, find_rect->y1);
view->jump_to_find_result = FALSE;
}
+
+ ev_rectangle_free (rect);
}
/**
@@ -9712,7 +9760,8 @@ ev_view_find_next (EvView *view)
gint n_results;
n_results = ev_view_find_get_n_results (view, view->find_page);
- view->find_result++;
+ view->find_result += ev_view_find_is_next_line (view, view->find_page, view->find_result)
+ ? 2 : 1;
if (view->find_result >= n_results) {
view->find_result = 0;
@@ -9728,11 +9777,14 @@ ev_view_find_next (EvView *view)
void
ev_view_find_previous (EvView *view)
{
- view->find_result--;
+ view->find_result -= ev_view_find_is_next_line (view, view->find_page, view->find_result - 2)
+ ? 2 : 1;
if (view->find_result < 0) {
jump_to_find_page (view, EV_VIEW_FIND_PREV, -1);
view->find_result = MAX (0, ev_view_find_get_n_results (view, view->find_page) - 1);
+ if (view->find_result && ev_view_find_is_next_line (view, view->find_page, view->find_result))
+ view->find_result--; /* set to last "non-nextline" result */
} else if (view->find_page != view->current_page) {
jump_to_find_page (view, EV_VIEW_FIND_PREV, 0);
}
diff --git a/shell/ev-find-sidebar.c b/shell/ev-find-sidebar.c
index a8a0ef43a..9229233ea 100644
--- a/shell/ev-find-sidebar.c
+++ b/shell/ev-find-sidebar.c
@@ -268,7 +268,7 @@ ev_find_sidebar_highlight_first_match_of_page (EvFindSidebar *sidebar,
return;
for (i = 0; i < page; i++)
- index += ev_job_find_get_n_results (priv->job, i);
+ index += ev_job_find_get_n_main_results (priv->job, i);
if (priv->highlighted_result)
gtk_tree_path_free (priv->highlighted_result);
@@ -339,7 +339,9 @@ get_surrounding_text_markup (const gchar *text,
gboolean case_sensitive,
PangoLogAttr *log_attrs,
gint log_attrs_length,
- gint offset)
+ gint offset,
+ gboolean has_nextline,
+ gboolean hyphen_was_ignored)
{
gint iter;
gchar *prec = NULL;
@@ -356,7 +358,15 @@ get_surrounding_text_markup (const gchar *text,
iter = offset;
offset += g_utf8_strlen (find_text, -1);
- if (!case_sensitive)
+
+ if (has_nextline || g_utf8_offset_to_pointer (text, offset-1)[0] == '\n') {
+ if (has_nextline) {
+ offset += 1; /* for newline */
+ if (hyphen_was_ignored)
+ offset += 1; /* for hyphen */
+ }
+ match = sanitized_substring (text, iter, offset);
+ } else if (!case_sensitive)
match = g_utf8_substring (text, iter, offset);
iter = MIN (log_attrs_length, offset + 1);
@@ -409,7 +419,7 @@ get_page_text (EvDocument *document,
static gint
get_match_offset (EvRectangle *areas,
guint n_areas,
- EvRectangle *match,
+ EvFindRectangle *match,
gint offset)
{
gdouble x, y;
@@ -493,11 +503,14 @@ process_matches_idle (EvFindSidebar *sidebar)
offset = 0;
for (l = matches, result = 0; l; l = g_list_next (l), result++) {
- EvRectangle *match = (EvRectangle *)l->data;
+ EvFindRectangle *match = (EvFindRectangle *)l->data;
gchar *markup;
GtkTreeIter iter;
gint new_offset;
+ if (l->prev && ((EvFindRectangle *)l->prev->data)->next_line)
+ continue; /* Skip as this is second part of a multi-line match */
+
new_offset = get_match_offset (areas, n_areas, match, offset);
if (new_offset == -1) {
g_warning ("No offset found for match \"%s\" at page %d after processing %d
results\n",
@@ -521,7 +534,9 @@ process_matches_idle (EvFindSidebar *sidebar)
priv->job->case_sensitive,
text_log_attrs,
text_log_attrs_length,
- offset);
+ offset,
+ match->next_line,
+ match->after_hyphen);
gtk_list_store_set (GTK_LIST_STORE (model), &iter,
TEXT_COLUMN, markup,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]