From 452a27e74c159096f588e6d27dfabb3b6915ccaa Mon Sep 17 00:00:00 2001 From: Adrian Lees Date: Sun, 17 Apr 2005 03:30:35 +0000 Subject: [project @ 2005-04-17 03:30:35 by adrianl] Search text highlighting in browser windows svn path=/import/netsurf/; revision=1657 --- desktop/gui.h | 6 +++ desktop/selection.c | 5 +- desktop/selection.h | 2 + gtk/gtk_gui.c | 10 ++++ render/html_redraw.c | 139 ++++++++++++++++++++++++++++----------------------- riscos/search.c | 131 +++++++++++++++++++++++++++++++++++++++++------- 6 files changed, 209 insertions(+), 84 deletions(-) diff --git a/desktop/gui.h b/desktop/gui.h index df87c16ca..df4fe24f0 100644 --- a/desktop/gui.h +++ b/desktop/gui.h @@ -41,6 +41,8 @@ typedef enum { GUI_POINTER_DEFAULT, GUI_POINTER_POINT, GUI_POINTER_CARET, #include "netsurf/content/content.h" #include "netsurf/desktop/browser.h" +extern struct gui_window *search_current_window; + void gui_init(int argc, char** argv); void gui_init2(int argc, char** argv); void gui_multitask(void); @@ -89,4 +91,8 @@ void gui_create_form_select_menu(struct browser_window *bw, void gui_launch_url(const char *url); +bool gui_search_term_highlighted(struct gui_window *g, struct box *box, + unsigned *start_idx, unsigned *end_idx); + + #endif diff --git a/desktop/selection.c b/desktop/selection.c index afec4180a..fc906f692 100644 --- a/desktop/selection.c +++ b/desktop/selection.c @@ -40,8 +40,6 @@ static inline bool before(const struct box *a, unsigned a_idx, unsigned b); static bool redraw_handler(struct box *box, int offset, size_t length, void *handle); static void selection_redraw(struct selection *s, unsigned start_idx, unsigned end_idx); static unsigned selection_label_subtree(struct selection *s, struct box *node, unsigned idx); -static void selection_set_start(struct selection *s, struct box *box, int idx); -static void selection_set_end(struct selection *s, struct box *box, int idx); static bool save_handler(struct box *box, int offset, size_t length, void *handle); static bool traverse_tree(struct box *box, unsigned start_idx, unsigned end_idx, seln_traverse_handler handler, void *handle); @@ -656,7 +654,8 @@ void selection_set_end(struct selection *s, struct box *box, int idx) bool selection_highlighted(struct selection *s, struct box *box, unsigned *start_idx, unsigned *end_idx) { - assert(selection_defined(s)); /* caller should have checked for efficiency */ + /* caller should have checked first for efficiency */ + assert(selection_defined(s)); assert(s && box); if (box->length > 0) { diff --git a/desktop/selection.h b/desktop/selection.h index 4a5d74980..59af2da9a 100644 --- a/desktop/selection.h +++ b/desktop/selection.h @@ -59,6 +59,8 @@ void selection_reinit(struct selection *s, struct box *root); void selection_clear(struct selection *s, bool redraw); void selection_select_all(struct selection *s); +void selection_set_start(struct selection *s, struct box *box, int idx); +void selection_set_end(struct selection *s, struct box *box, int idx); bool selection_click(struct selection *s, struct box *box, browser_mouse_state mouse, int dx, int dy); void selection_track(struct selection *s, struct box *box, browser_mouse_state mouse, int dx, int dy); diff --git a/gtk/gtk_gui.c b/gtk/gtk_gui.c index dc4c35adb..95ba473d6 100644 --- a/gtk/gtk_gui.c +++ b/gtk/gtk_gui.c @@ -29,6 +29,8 @@ bool gui_in_multitask = false; char *default_stylesheet_url; char *adblock_stylesheet_url; +struct gui_window *search_current_window = 0; + void gui_init(int argc, char** argv) { @@ -121,6 +123,13 @@ void gui_launch_url(const char *url) } +bool gui_search_term_highlighted(struct gui_window *g, struct box *box, + unsigned *start_idx, unsigned *end_idx) +{ + return false; +} + + void warn_user(const char *warning, const char *detail) { } @@ -153,3 +162,4 @@ void schedule_remove(void (*callback)(void *p), void *p) {} void schedule_run(void) {} void global_history_add(struct gui_window *g) {} + diff --git a/render/html_redraw.c b/render/html_redraw.c index c2eef9d3e..38a87b5c2 100644 --- a/render/html_redraw.c +++ b/render/html_redraw.c @@ -15,6 +15,7 @@ #include "netsurf/utils/config.h" #include "netsurf/content/content.h" #include "netsurf/css/css.h" +#include "netsurf/desktop/gui.h" #include "netsurf/desktop/plotters.h" #include "netsurf/desktop/selection.h" #include "netsurf/render/box.h" @@ -314,9 +315,7 @@ bool html_redraw_box(struct box *box, return false; } else if (box->text) { - - unsigned start_idx; - unsigned end_idx; + bool highlighted = false; /* antialias colour for under/overline */ colour = html_redraw_aa(current_background_color, @@ -352,74 +351,90 @@ bool html_redraw_box(struct box *box, return false; } + /* is this box part of a selection? */ + if (box->text && !box->object && current_redraw_browser) { + unsigned start_idx; + unsigned end_idx; - /* is this box part of the current selection? */ - if (box->text && !box->object && current_redraw_browser && - selection_defined(current_redraw_browser->sel) && - selection_highlighted(current_redraw_browser->sel, box, - &start_idx, &end_idx)) { - - unsigned endtxt_idx = end_idx; - int startx, endx; - - if (end_idx > box->length) { - /* adjust for trailing space, not present in box->text */ - assert(end_idx == box->length + 1); - endtxt_idx = box->length; - } - - if (!nsfont_width(box->style, box->text, start_idx, &startx)) - startx = 0; - - if (!nsfont_width(box->style, box->text + start_idx, - endtxt_idx - start_idx, &endx)) - endx = 0; - endx += startx; - - /* is there a trailing space that should be highlighted as well? */ - if (end_idx > box->length) { - int spc_width; - /* \todo is there a more elegant/efficient solution? */ - if (nsfont_width(box->style, " ", 1, &spc_width)) - endx += spc_width; + /* first try the browser window's current selection */ + if (selection_defined(current_redraw_browser->sel) && + selection_highlighted(current_redraw_browser->sel, + box, &start_idx, &end_idx)) { + highlighted = true; } - if (scale != 1.0) { - startx *= scale; - endx *= scale; + /* what about the current search operation, if any */ + if (!highlighted && + search_current_window == current_redraw_browser->window && + gui_search_term_highlighted(current_redraw_browser->window, + box, &start_idx, &end_idx)) { + highlighted = true; } - if (start_idx > 0) { - - if (!plot.text(x, y + (int) (box->height * 0.75 * scale), - box->style, box->text, start_idx, - current_background_color, - /*print_text_black ? 0 :*/ box->style->color)) + /* \todo make search terms visible within selected text */ + if (highlighted) { + unsigned endtxt_idx = end_idx; + int startx, endx; + + if (end_idx > box->length) { + /* adjust for trailing space, not present in box->text */ + assert(end_idx == box->length + 1); + endtxt_idx = box->length; + } + + if (!nsfont_width(box->style, box->text, start_idx, &startx)) + startx = 0; + + if (!nsfont_width(box->style, box->text + start_idx, + endtxt_idx - start_idx, &endx)) + endx = 0; + endx += startx; + + /* is there a trailing space that should be highlighted as well? */ + if (end_idx > box->length) { + int spc_width; + /* \todo is there a more elegant/efficient solution? */ + if (nsfont_width(box->style, " ", 1, &spc_width)) + endx += spc_width; + } + + if (scale != 1.0) { + startx *= scale; + endx *= scale; + } + + if (start_idx > 0) { + + if (!plot.text(x, y + (int) (box->height * 0.75 * scale), + box->style, box->text, start_idx, + current_background_color, + /*print_text_black ? 0 :*/ box->style->color)) + return false; + + } + + if (!plot.fill(x + startx, y, x + endx, y + box->height * scale, + current_background_color ^ 0xffffff)) return false; - - } - - if (!plot.fill(x + startx, y, x + endx, y + box->height * scale, - current_background_color ^ 0xffffff)) - return false; - - if (!plot.text(x + startx, y + (int) (box->height * 0.75 * scale), - box->style, box->text + start_idx, endtxt_idx - start_idx, - current_background_color ^ 0xffffff, - current_background_color)) - return false; - - if (endtxt_idx < box->length) { - - if (!plot.text(x + endx, y + (int) (box->height * 0.75 * scale), - box->style, box->text + endtxt_idx, box->length - endtxt_idx, - current_background_color, - /*print_text_black ? 0 :*/ box->style->color)) + + if (!plot.text(x + startx, y + (int) (box->height * 0.75 * scale), + box->style, box->text + start_idx, endtxt_idx - start_idx, + current_background_color ^ 0xffffff, + current_background_color)) return false; - + + if (endtxt_idx < box->length) { + + if (!plot.text(x + endx, y + (int) (box->height * 0.75 * scale), + box->style, box->text + endtxt_idx, box->length - endtxt_idx, + current_background_color, + /*print_text_black ? 0 :*/ box->style->color)) + return false; + } } } - else { + + if (!highlighted) { if (!plot.text(x, y + (int) (box->height * 0.75 * scale), box->style, box->text, box->length, current_background_color, diff --git a/riscos/search.c b/riscos/search.c index 6ece879c7..34005d690 100644 --- a/riscos/search.c +++ b/riscos/search.c @@ -3,6 +3,7 @@ * Licensed under the GNU General Public License, * http://www.opensource.org/licenses/gpl-license * Copyright 2004 John M Bell + * Copyright 2005 Adrian Lees */ /** \file @@ -18,6 +19,7 @@ #include "netsurf/content/content.h" #include "netsurf/desktop/browser.h" #include "netsurf/desktop/gui.h" +#include "netsurf/desktop/selection.h" #include "netsurf/render/box.h" #include "netsurf/render/html.h" #include "netsurf/riscos/gui.h" @@ -34,15 +36,22 @@ #endif struct list_entry { - struct box *box; + /* start position of match */ + struct box *start_box; + unsigned start_idx; + /* end of match */ + struct box *end_box; + unsigned end_idx; + struct list_entry *prev; struct list_entry *next; }; -static struct gui_window *search_current_window = 0; +struct gui_window *search_current_window = 0; +static struct selection *search_selection = 0; static char *search_string = 0; -static struct list_entry search_head = { 0, 0, 0 }; +static struct list_entry search_head = { 0, 0, 0, 0, 0, 0 }; static struct list_entry *search_found = &search_head; static struct list_entry *search_current = 0; static struct content *search_content = 0; @@ -52,8 +61,10 @@ static bool search_prev_case_sens = false; static void start_search(void); static void end_search(void); static void do_search(char *string, bool from_top, bool case_sens, bool forwards); -static const char *find_pattern(const char *string, int s_len, const char *pattern, int p_len, bool case_sens); -static bool find_occurrences(const char *pattern, int p_len, struct box *cur, bool case_sens); +static const char *find_pattern(const char *string, int s_len, + const char *pattern, int p_len, bool case_sens, int *m_len); +static bool find_occurrences(const char *pattern, int p_len, struct box *cur, + bool case_sens); /** @@ -63,6 +74,8 @@ static bool find_occurrences(const char *pattern, int p_len, struct box *cur, bo */ void ro_gui_search_prepare(struct gui_window *g) { + struct content *c; + assert(g != NULL); search_current_window = g; @@ -76,6 +89,22 @@ void ro_gui_search_prepare(struct gui_window *g) false); ro_gui_set_icon_selected_state(dialog_search, ICON_SEARCH_CASE_SENSITIVE, false); + + c = search_current_window->bw->current_content; + + if (!c) + return; + + /* only handle html contents */ + if (c->type != CONTENT_HTML) + return; + +/* \todo build me properly please! */ + search_selection = selection_create(g->bw); + if (!search_selection) + warn_user("NoMemory", 0); + + selection_init(search_selection, c->data.html.layout); } /** @@ -172,6 +201,10 @@ void end_search(void) { struct list_entry *a, *b; + selection_clear(search_selection, true); + selection_destroy(search_selection); + search_selection = 0; + search_current_window = 0; if (search_string) @@ -289,7 +322,7 @@ void do_search(char *string, bool from_top, bool case_sens, bool forwards) } for (a = search_found->next; a; a = a->next) { - box_coords(a->box, &x, &y); + box_coords(a->start_box, &x, &y); LOG(("%d, %d", y, state.yscroll / 2)); if (forwards && -y <= state.yscroll / 2) break; @@ -315,8 +348,16 @@ void do_search(char *string, bool from_top, bool case_sens, bool forwards) if (!search_current) return; + box = search_current->start_box; + + selection_clear(search_selection, true); + selection_set_start(search_selection, search_current->start_box, + search_current->start_idx); + selection_set_end(search_selection, search_current->end_box, + search_current->end_idx); + /* get box position and jump to it */ - box_coords(search_current->box, &x, &y); + box_coords(search_current->start_box, &x, &y); // LOG(("%p (%d, %d)", search_current, x, y)); gui_window_set_scroll(search_current_window, x, y); @@ -326,21 +367,25 @@ void do_search(char *string, bool from_top, bool case_sens, bool forwards) /** * Find the first occurrence of 'match' in 'string' and return its index * - * /param string the string to be searched (unterminated) - * /param s_len length of the string to be searched - * /param match the pattern for which we are searching (unterminated) - * /param m_len length of pattern - * /return pointer to first match, NULL if none + * /param string the string to be searched (unterminated) + * /param s_len length of the string to be searched + * /param pattern the pattern for which we are searching (unterminated) + * /param p_len length of pattern + * /param case_sens true iff case sensitive match required + * /param m_len accepts length of match in bytes + * /return pointer to first match, NULL if none */ -const char *find_pattern(const char *string, int s_len, const char *pattern, int p_len, bool case_sens) +const char *find_pattern(const char *string, int s_len, const char *pattern, + int p_len, bool case_sens, int *m_len) { - struct { const char *ss, *s, *p; } context[16]; + struct { const char *ss, *s, *p; bool first; } context[16]; const char *ep = pattern + p_len; const char *es = string + s_len; const char *p = pattern - 1; /* a virtual '*' before the pattern */ const char *ss = string; const char *s = string; + bool first = true; int top = 0; while (p < ep) { @@ -352,7 +397,7 @@ const char *find_pattern(const char *string, int s_len, const char *pattern, int do p++; while (p < ep && *p == '*'); /* if we're at the end of the pattern, yes, it matches */ - if (p >= ep) return ss; + if (p >= ep) break; /* anything matches a # so continue matching from here, and stack a context that will try to match @@ -372,13 +417,21 @@ const char *find_pattern(const char *string, int s_len, const char *pattern, int } if (s < es) { - /* remember where we are in case the match fails; we can then resume */ + /* remember where we are in case the match fails; + we can then resume */ if (top < (int)NOF_ELEMENTS(context)) { context[top].ss = ss; context[top].s = s + 1; context[top].p = p - 1; /* ptr to last asterisk */ + context[top].first = first; top++; } + + if (first) { + ss = s; /* remember first non-'*' char */ + first = false; + } + matches = true; } else @@ -394,6 +447,10 @@ const char *find_pattern(const char *string, int s_len, const char *pattern, int else matches = (toupper(*s) == toupper(ch)); } + if (matches && first) { + ss = s; /* remember first non-'*' char */ + first = false; + } } else matches = false; @@ -408,10 +465,12 @@ const char *find_pattern(const char *string, int s_len, const char *pattern, int ss = context[top].ss; s = context[top].s; p = context[top].p; + first = context[top].first; } } /* end of pattern reached */ + *m_len = s - ss; return ss; } @@ -425,21 +484,31 @@ const char *find_pattern(const char *string, int s_len, const char *pattern, int * \param case_sens whether to perform a case sensitive search * \return true on success, false on memory allocation failure */ -bool find_occurrences(const char *pattern, int p_len, struct box *cur, bool case_sens) +bool find_occurrences(const char *pattern, int p_len, struct box *cur, + bool case_sens) { struct box *a; /* ignore this box, if there's no visible text */ if (!cur->object && cur->text) { - const char *pos = find_pattern(cur->text, cur->length, pattern, p_len, case_sens); + unsigned match_length; + const char *pos = find_pattern(cur->text, cur->length, + pattern, p_len, case_sens, &match_length); if (pos) { /* found string in box => add to list */ + unsigned match_offset; struct list_entry *entry = calloc(1, sizeof(*entry)); if (!entry) { warn_user("NoMemory", 0); return false; } - entry->box = cur; + + match_offset = pos - cur->text; + + entry->start_box = cur; + entry->start_idx = match_offset; + entry->end_box = cur; + entry->end_idx = match_offset + match_length; entry->next = 0; entry->prev = search_found->prev; if (!search_found->prev) @@ -459,4 +528,28 @@ bool find_occurrences(const char *pattern, int p_len, struct box *cur, bool case return true; } + + +/** + * Determines whether any portion of the given text box should be + * selected because it matches the current search string. + * + * \param g gui window + * \param box box being tested + * \param start_idx byte offset within text box of highlight start + * \param end_idx byte offset of highlight end + * \return true iff part of the box should be highlighted + */ + +bool gui_search_term_highlighted(struct gui_window *g, struct box *box, + unsigned *start_idx, unsigned *end_idx) +{ + if (g == search_current_window && search_selection) { + if (selection_defined(search_selection)) + return selection_highlighted(search_selection, box, start_idx, end_idx); + } + return false; +} + + #endif -- cgit v1.2.3