summaryrefslogtreecommitdiff
path: root/content
diff options
context:
space:
mode:
authorVincent Sanders <vince@kyllikki.org>2020-05-13 18:03:22 +0100
committerVincent Sanders <vince@kyllikki.org>2020-05-13 14:31:39 +0100
commit95e0a24fac2abc4cddaa91bf44304ebc3d776b17 (patch)
tree74fbe23b4f5f48c263453d4598888c6d0a5de784 /content
parentf4e50b45c834b644caa6a82bd044faa82f6f4860 (diff)
downloadnetsurf-95e0a24fac2abc4cddaa91bf44304ebc3d776b17.tar.gz
netsurf-95e0a24fac2abc4cddaa91bf44304ebc3d776b17.tar.bz2
use content messages to inform frontend of text search changes
Diffstat (limited to 'content')
-rw-r--r--content/content.h44
-rw-r--r--content/textsearch.c572
2 files changed, 386 insertions, 230 deletions
diff --git a/content/content.h b/content/content.h
index f68af538b..edf9ed2cc 100644
--- a/content/content.h
+++ b/content/content.h
@@ -242,6 +242,50 @@ union content_msg_data {
struct {
struct form_control *gadget;
} gadget_click;
+
+ /**
+ * CONTENT_MSG_TEXTSEARCH - Free text search action
+ */
+ struct {
+ /**
+ * The type of text search operation
+ */
+ enum {
+ /**
+ * Free text search find operation has started or finished
+ */
+ CONTENT_TEXTSEARCH_FIND,
+ /**
+ * Free text search match state has changed
+ */
+ CONTENT_TEXTSEARCH_MATCH,
+ /**
+ * Free text search back available state changed
+ */
+ CONTENT_TEXTSEARCH_BACK,
+ /**
+ * Free text search forward available state changed
+ */
+ CONTENT_TEXTSEARCH_FORWARD,
+ /**
+ * add a search query string to the recent searches
+ */
+ CONTENT_TEXTSEARCH_RECENT
+ } type;
+ /**
+ * context passed to browser_window_search()
+ */
+ void *ctx;
+ /**
+ * state for operation
+ */
+ bool state;
+ /**
+ * search string
+ */
+ const char *string;
+ } textsearch;
+
};
diff --git a/content/textsearch.c b/content/textsearch.c
index 145c8c41b..899739435 100644
--- a/content/textsearch.c
+++ b/content/textsearch.c
@@ -1,7 +1,6 @@
/*
* Copyright 2004 John M Bell <jmb202@ecs.soton.ac.uk>
- * Copyright 2005 Adrian Lees <adrianl@users.sourceforge.net>
- * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
+ * Copyright 2020 Vincent Sanders <vince@netsurf-browser.org>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -28,37 +27,81 @@
#include "utils/errors.h"
#include "utils/utils.h"
#include "netsurf/types.h"
-#include "netsurf/search.h"
#include "desktop/selection.h"
-#include "desktop/gui_internal.h"
#include "content/content.h"
#include "content/content_protected.h"
#include "content/hlcache.h"
#include "content/textsearch.h"
-
+/**
+ * search match
+ */
struct list_entry {
- unsigned start_idx; /* start position of match */
- unsigned end_idx; /* end of match */
+ /**
+ * previous match
+ */
+ struct list_entry *prev;
+
+ /**
+ * next match
+ */
+ struct list_entry *next;
+
+ /**
+ * start position of match
+ */
+ unsigned start_idx;
+
+ /**
+ * end of match
+ */
+ unsigned end_idx;
+
+ /**
+ * content opaque start pointer
+ */
+ struct box *start_box;
- struct box *start_box; /* used only for html contents */
+ /**
+ * content opaque end pointer
+ */
struct box *end_box;
+ /**
+ * content specific selection object
+ */
struct selection *sel;
-
- struct list_entry *prev;
- struct list_entry *next;
};
/**
* The context for a free text search
*/
struct textsearch_context {
- void *gui_p;
+
+ /**
+ * content search was performed upon
+ */
struct content *c;
+
+ /**
+ * opaque pointer passed to constructor.
+ */
+ void *gui_p;
+
+ /**
+ * List of matches
+ */
struct list_entry *found;
+
+ /**
+ * current selected match
+ */
struct list_entry *current; /* first for select all */
+
+ /**
+ * query string search results are for
+ */
char *string;
bool prev_case_sens;
bool newsearch;
@@ -66,6 +109,24 @@ struct textsearch_context {
/**
+ * broadcast textsearch message
+ */
+static inline void
+textsearch_broadcast(struct textsearch_context *textsearch,
+ int type,
+ bool state,
+ const char *string)
+{
+ union content_msg_data msg_data;
+ msg_data.textsearch.type = type;
+ msg_data.textsearch.ctx = textsearch->gui_p;
+ msg_data.textsearch.state = state;
+ msg_data.textsearch.string = string;
+ content_broadcast(textsearch->c, CONTENT_MSG_TEXTSEARCH, &msg_data);
+}
+
+
+/**
* Release the memory used by the list of matches,
* deleting selection objects too
*/
@@ -96,154 +157,6 @@ static void free_matches(struct textsearch_context *textsearch)
}
-/* Exported function documented in content/textsearch.h */
-const char *
-content_textsearch_find_pattern(const char *string,
- int s_len,
- const char *pattern,
- int p_len,
- bool case_sens,
- unsigned int *m_len)
-{
- 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) {
- bool matches;
- if (p < pattern || *p == '*') {
- char ch;
-
- /* skip any further asterisks; one is the same as many
- */
- do p++; while (p < ep && *p == '*');
-
- /* if we're at the end of the pattern, yes, it matches
- */
- if (p >= ep) break;
-
- /* anything matches a # so continue matching from
- here, and stack a context that will try to match
- the wildcard against the next character */
-
- ch = *p;
- if (ch != '#') {
- /* scan forwards until we find a match for
- this char */
- if (!case_sens) ch = toupper(ch);
- while (s < es) {
- if (case_sens) {
- if (*s == ch) break;
- } else if (toupper(*s) == ch)
- break;
- s++;
- }
- }
-
- if (s < es) {
- /* remember where we are in case the match
- fails; we may 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 {
- matches = false;
- }
-
- } else if (s < es) {
- char ch = *p;
- if (ch == '#')
- matches = true;
- else {
- if (case_sens)
- matches = (*s == ch);
- else
- matches = (toupper(*s) == toupper(ch));
- }
- if (matches && first) {
- ss = s; /* remember first non-'*' char */
- first = false;
- }
- } else {
- matches = false;
- }
-
- if (matches) {
- p++; s++;
- } else {
- /* doesn't match,
- * resume with stacked context if we have one */
- if (--top < 0)
- return NULL; /* no match, give up */
-
- ss = context[top].ss;
- s = context[top].s;
- p = context[top].p;
- first = context[top].first;
- }
- }
-
- /* end of pattern reached */
- *m_len = max(s - ss, 1);
- return ss;
-}
-
-
-/* Exported function documented in content/textsearch.h */
-nserror
-content_textsearch_add_match(struct textsearch_context *context,
- unsigned start_idx,
- unsigned end_idx,
- struct box *start_box,
- struct box *end_box)
-{
- struct list_entry *entry;
-
- /* found string in box => add to list */
- entry = calloc(1, sizeof(*entry));
- if (entry == NULL) {
- return NSERROR_NOMEM;
- }
-
- entry->start_idx = start_idx;
- entry->end_idx = end_idx;
- entry->start_box = start_box;
- entry->end_box = end_box;
- entry->sel = NULL;
-
- entry->next = NULL;
- entry->prev = context->found->prev;
-
- if (context->found->prev == NULL) {
- context->found->next = entry;
- } else {
- context->found->prev->next = entry;
- }
-
- context->found->prev = entry;
-
- return NSERROR_OK;
-}
-
-
/**
* Specifies whether all matches or just the current match should
* be highlighted in the search text.
@@ -278,17 +191,17 @@ static void search_show_all(bool all, struct textsearch_context *context)
/**
- * Search for a string in the box tree
+ * Search for a string in a content.
*
+ * \param context The search context.
* \param string the string to search for
* \param string_len length of search string
- * \param context The search context to add the entry to.
* \param flags flags to control the search.
*/
static nserror
-search_text(const char *string,
+search_text(struct textsearch_context *context,
+ const char *string,
int string_len,
- struct textsearch_context *context,
search_flags_t flags)
{
struct rect bounds;
@@ -322,7 +235,9 @@ search_text(const char *string,
context->string[string_len] = '\0';
}
- guit->search->hourglass(true, context->gui_p);
+ /* indicate find operation starting */
+ textsearch_broadcast(context, CONTENT_TEXTSEARCH_FIND, true, NULL);
+
/* call content find handler */
res = context->c->handler->textsearch_find(context->c,
@@ -331,7 +246,8 @@ search_text(const char *string,
string_len,
case_sensitive);
- guit->search->hourglass(false, context->gui_p);
+ /* indicate find operation finished */
+ textsearch_broadcast(context, CONTENT_TEXTSEARCH_FIND, false, NULL);
if (res != NSERROR_OK) {
free_matches(context);
@@ -355,29 +271,41 @@ search_text(const char *string,
}
}
- guit->search->status((context->current != NULL), context->gui_p);
+ /* update match state */
+ textsearch_broadcast(context,
+ CONTENT_TEXTSEARCH_MATCH,
+ (context->current != NULL),
+ NULL);
search_show_all(showall, context);
- guit->search->back_state((context->current != NULL) &&
- (context->current->prev != NULL),
- context->gui_p);
- guit->search->forward_state((context->current != NULL) &&
- (context->current->next != NULL),
- context->gui_p);
+ /* update back state */
+ textsearch_broadcast(context,
+ CONTENT_TEXTSEARCH_BACK,
+ ((context->current != NULL) &&
+ (context->current->prev != NULL)),
+ NULL);
+
+ /* update forward state */
+ textsearch_broadcast(context,
+ CONTENT_TEXTSEARCH_FORWARD,
+ ((context->current != NULL) &&
+ (context->current->next != NULL)),
+ NULL);
+
if (context->current == NULL) {
+ /* no current match */
return res;
}
/* call content match bounds handler */
res = context->c->handler->textsearch_bounds(context->c,
- context->current->start_idx,
- context->current->end_idx,
-
- context->current->start_box,
- context->current->end_box,
- &bounds);
+ context->current->start_idx,
+ context->current->end_idx,
+ context->current->start_box,
+ context->current->end_box,
+ &bounds);
if (res == NSERROR_OK) {
msg_data.scroll.area = true;
msg_data.scroll.x0 = bounds.x0;
@@ -411,7 +339,11 @@ content_textsearch_step(struct textsearch_context *textsearch,
assert(textsearch != NULL);
- guit->search->add_recent(string, textsearch->gui_p);
+ /* broadcast recent query string */
+ textsearch_broadcast(textsearch,
+ CONTENT_TEXTSEARCH_RECENT,
+ false,
+ string);
string_len = strlen(string);
for (i = 0; i < string_len; i++) {
@@ -420,52 +352,61 @@ content_textsearch_step(struct textsearch_context *textsearch,
}
if (i < string_len) {
- res = search_text(string, string_len, textsearch, flags);
+ res = search_text(textsearch, string, string_len, flags);
} else {
union content_msg_data msg_data;
- free_matches(textsearch);
- guit->search->status(true, textsearch->gui_p);
- guit->search->back_state(false, textsearch->gui_p);
- guit->search->forward_state(false, textsearch->gui_p);
+ free_matches(textsearch);
+ /* update match state */
+ textsearch_broadcast(textsearch,
+ CONTENT_TEXTSEARCH_MATCH,
+ true,
+ NULL);
+
+ /* update back state */
+ textsearch_broadcast(textsearch,
+ CONTENT_TEXTSEARCH_BACK,
+ false,
+ NULL);
+
+ /* update forward state */
+ textsearch_broadcast(textsearch,
+ CONTENT_TEXTSEARCH_FORWARD,
+ false,
+ NULL);
+
+ /* clear scroll */
msg_data.scroll.area = false;
msg_data.scroll.x0 = 0;
msg_data.scroll.y0 = 0;
- content_broadcast(textsearch->c, CONTENT_MSG_SCROLL, &msg_data);
+ content_broadcast(textsearch->c,
+ CONTENT_MSG_SCROLL,
+ &msg_data);
}
return res;
}
-/* Exported function documented in content/textsearch.h */
-bool
-content_textsearch_ishighlighted(struct textsearch_context *textsearch,
- unsigned start_offset,
- unsigned end_offset,
- unsigned *start_idx,
- unsigned *end_idx)
+/**
+ * Terminate a search.
+ *
+ * \param c content to clear
+ */
+static nserror content_textsearch__clear(struct content *c)
{
- struct list_entry *cur;
+ free(c->textsearch.string);
+ c->textsearch.string = NULL;
- for (cur = textsearch->found->next; cur != NULL; cur = cur->next) {
- if (cur->sel &&
- selection_defined(cur->sel) &&
- selection_highlighted(cur->sel,
- start_offset,
- end_offset,
- start_idx,
- end_idx)) {
- return true;
- }
+ if (c->textsearch.context != NULL) {
+ content_textsearch_destroy(c->textsearch.context);
+ c->textsearch.context = NULL;
}
-
- return false;
+ return NSERROR_OK;
}
-/* Exported function documented in content/textsearch.h */
/**
* create a search_context
*
@@ -528,44 +469,215 @@ content_textsearch_create(struct content *c,
}
-/* Exported function documented in search.h */
-nserror content_textsearch_destroy(struct textsearch_context *textsearch)
+/* exported interface, documented in content/textsearch.h */
+const char *
+content_textsearch_find_pattern(const char *string,
+ int s_len,
+ const char *pattern,
+ int p_len,
+ bool case_sens,
+ unsigned int *m_len)
{
- assert(textsearch != NULL);
+ 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;
- if (textsearch->string != NULL) {
- guit->search->add_recent(textsearch->string, textsearch->gui_p);
- free(textsearch->string);
+ while (p < ep) {
+ bool matches;
+ if (p < pattern || *p == '*') {
+ char ch;
+
+ /* skip any further asterisks; one is the same as many
+ */
+ do p++; while (p < ep && *p == '*');
+
+ /* if we're at the end of the pattern, yes, it matches
+ */
+ if (p >= ep) break;
+
+ /* anything matches a # so continue matching from
+ here, and stack a context that will try to match
+ the wildcard against the next character */
+
+ ch = *p;
+ if (ch != '#') {
+ /* scan forwards until we find a match for
+ this char */
+ if (!case_sens) ch = toupper(ch);
+ while (s < es) {
+ if (case_sens) {
+ if (*s == ch) break;
+ } else if (toupper(*s) == ch)
+ break;
+ s++;
+ }
+ }
+
+ if (s < es) {
+ /* remember where we are in case the match
+ fails; we may 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 {
+ matches = false;
+ }
+
+ } else if (s < es) {
+ char ch = *p;
+ if (ch == '#')
+ matches = true;
+ else {
+ if (case_sens)
+ matches = (*s == ch);
+ else
+ matches = (toupper(*s) == toupper(ch));
+ }
+ if (matches && first) {
+ ss = s; /* remember first non-'*' char */
+ first = false;
+ }
+ } else {
+ matches = false;
+ }
+
+ if (matches) {
+ p++; s++;
+ } else {
+ /* doesn't match,
+ * resume with stacked context if we have one */
+ if (--top < 0)
+ return NULL; /* no match, give up */
+
+ ss = context[top].ss;
+ s = context[top].s;
+ p = context[top].p;
+ first = context[top].first;
+ }
}
- guit->search->forward_state(true, textsearch->gui_p);
- guit->search->back_state(true, textsearch->gui_p);
+ /* end of pattern reached */
+ *m_len = max(s - ss, 1);
+ return ss;
+}
- free_matches(textsearch);
- free(textsearch);
+
+/* exported interface, documented in content/textsearch.h */
+nserror
+content_textsearch_add_match(struct textsearch_context *context,
+ unsigned start_idx,
+ unsigned end_idx,
+ struct box *start_box,
+ struct box *end_box)
+{
+ struct list_entry *entry;
+
+ /* found string in box => add to list */
+ entry = calloc(1, sizeof(*entry));
+ if (entry == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ entry->start_idx = start_idx;
+ entry->end_idx = end_idx;
+ entry->start_box = start_box;
+ entry->end_box = end_box;
+ entry->sel = NULL;
+
+ entry->next = NULL;
+ entry->prev = context->found->prev;
+
+ if (context->found->prev == NULL) {
+ context->found->next = entry;
+ } else {
+ context->found->prev->next = entry;
+ }
+
+ context->found->prev = entry;
return NSERROR_OK;
}
-/**
- * Terminate a search.
- *
- * \param c content to clear
- */
-static nserror content_textsearch__clear(struct content *c)
+
+/* exported interface, documented in content/textsearch.h */
+bool
+content_textsearch_ishighlighted(struct textsearch_context *textsearch,
+ unsigned start_offset,
+ unsigned end_offset,
+ unsigned *start_idx,
+ unsigned *end_idx)
{
- free(c->textsearch.string);
- c->textsearch.string = NULL;
+ struct list_entry *cur;
- if (c->textsearch.context != NULL) {
- content_textsearch_destroy(c->textsearch.context);
- c->textsearch.context = NULL;
+ for (cur = textsearch->found->next; cur != NULL; cur = cur->next) {
+ if (cur->sel &&
+ selection_defined(cur->sel) &&
+ selection_highlighted(cur->sel,
+ start_offset,
+ end_offset,
+ start_idx,
+ end_idx)) {
+ return true;
+ }
}
- return NSERROR_OK;
+
+ return false;
}
/* exported interface, documented in content/textsearch.h */
+nserror content_textsearch_destroy(struct textsearch_context *textsearch)
+{
+ assert(textsearch != NULL);
+
+ if (textsearch->string != NULL) {
+ /* broadcast recent query string */
+ textsearch_broadcast(textsearch,
+ CONTENT_TEXTSEARCH_RECENT,
+ false,
+ textsearch->string);
+
+ free(textsearch->string);
+ }
+
+ /* update back state */
+ textsearch_broadcast(textsearch,
+ CONTENT_TEXTSEARCH_BACK,
+ true,
+ NULL);
+
+ /* update forward state */
+ textsearch_broadcast(textsearch,
+ CONTENT_TEXTSEARCH_FORWARD,
+ true,
+ NULL);
+
+ free_matches(textsearch);
+ free(textsearch);
+
+ return NSERROR_OK;
+}
+
+
+/* exported interface, documented in content/content.h */
nserror
content_textsearch(struct hlcache_handle *h,
void *context,
@@ -618,7 +730,7 @@ content_textsearch(struct hlcache_handle *h,
}
-/* exported interface, documented in content/textsearch.h */
+/* exported interface, documented in content/content.h */
nserror content_textsearch_clear(struct hlcache_handle *h)
{
struct content *c = hlcache_handle_get_content(h);