summaryrefslogtreecommitdiff
path: root/content
diff options
context:
space:
mode:
authorVincent Sanders <vince@kyllikki.org>2020-05-23 18:39:25 +0100
committerVincent Sanders <vince@kyllikki.org>2020-05-23 23:00:08 +0100
commit36b9262e1481fc24d302b58f03006e733b2e6d16 (patch)
treea2189e438023c837d8b8949b7c38e54fa143cab1 /content
parent0432d9556187d00fd7f78963afcefc4b7dd71f2a (diff)
downloadnetsurf-36b9262e1481fc24d302b58f03006e733b2e6d16.tar.gz
netsurf-36b9262e1481fc24d302b58f03006e733b2e6d16.tar.bz2
split selection redraw into content handler specific implementations
Diffstat (limited to 'content')
-rw-r--r--content/content_protected.h10
-rw-r--r--content/handlers/html/Makefile3
-rw-r--r--content/handlers/html/html.c22
-rw-r--r--content/handlers/html/textselection.c303
-rw-r--r--content/handlers/html/textselection.h37
-rw-r--r--content/handlers/text/textplain.c136
-rw-r--r--content/handlers/text/textplain.h13
7 files changed, 439 insertions, 85 deletions
diff --git a/content/content_protected.h b/content/content_protected.h
index 881a43268..9a3654beb 100644
--- a/content/content_protected.h
+++ b/content/content_protected.h
@@ -112,6 +112,16 @@ struct content_handler {
nserror (*textsearch_bounds)(struct content *c, unsigned start_idx, unsigned end_idx, struct box *start_ptr, struct box *end_ptr, struct rect *bounds_out);
/**
+ * cause a region of the content to be marked invalid and hence redraw
+ *
+ * \param c The content being redrawn
+ * \param start_idx The start index of the text region to be redrawn
+ * \param end_idx The end index of teh text region to be redrawn
+ * \return NSERROR_OK on success else error code
+ */
+ nserror (*textselection_redraw)(struct content *c, unsigned start_idx, unsigned end_idx);
+
+ /**
* create a selection object
*/
nserror (*create_selection)(struct content *c, struct selection **sel_out);
diff --git a/content/handlers/html/Makefile b/content/handlers/html/Makefile
index 233fb1327..8bb329b76 100644
--- a/content/handlers/html/Makefile
+++ b/content/handlers/html/Makefile
@@ -20,4 +20,5 @@ S_HTML := box_construct.c \
redraw.c \
redraw_border.c \
script.c \
- table.c
+ table.c \
+ textselection.c
diff --git a/content/handlers/html/html.c b/content/handlers/html/html.c
index 33320aa7b..2a3cb1774 100644
--- a/content/handlers/html/html.c
+++ b/content/handlers/html/html.c
@@ -70,6 +70,7 @@
#include "html/form_internal.h"
#include "html/imagemap.h"
#include "html/layout.h"
+#include "html/textselection.h"
#define CHUNK 4096
@@ -2304,26 +2305,6 @@ html_textsearch_bounds(struct content *c,
/**
- * create a selection object suitable for this content
- */
-static nserror
-html_create_selection(struct content *c, struct selection **sel_out)
-{
- html_content *html = (html_content *)c;
- struct selection *sel;
- sel = selection_create(c, true);
- if (sel == NULL) {
- return NSERROR_NOMEM;
- }
-
- selection_init(sel, html->layout, &html->len_ctx);
-
- *sel_out = sel;
- return NSERROR_OK;
-}
-
-
-/**
* HTML content handler function table
*/
static const content_handler html_content_handler = {
@@ -2354,6 +2335,7 @@ static const content_handler html_content_handler = {
.saw_insecure_objects = html_saw_insecure_objects,
.textsearch_find = html_textsearch_find,
.textsearch_bounds = html_textsearch_bounds,
+ .textselection_redraw = html_textselection_redraw,
.create_selection = html_create_selection,
.no_share = true,
};
diff --git a/content/handlers/html/textselection.c b/content/handlers/html/textselection.c
new file mode 100644
index 000000000..bbd55732e
--- /dev/null
+++ b/content/handlers/html/textselection.c
@@ -0,0 +1,303 @@
+/*
+ * Copyright 2006 James Bursa <bursa@users.sourceforge.net>
+ * Copyright 2006 Richard Wilson <info@tinct.net>
+ * Copyright 2008 Michael Drake <tlsa@netsurf-browser.org>
+ * Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * implementation of user interaction with a CONTENT_HTML.
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+
+#include <dom/dom.h>
+
+#include "utils/corestrings.h"
+#include "utils/messages.h"
+#include "utils/utils.h"
+#include "utils/log.h"
+#include "utils/nsoption.h"
+#include "netsurf/content.h"
+#include "netsurf/browser_window.h"
+#include "netsurf/mouse.h"
+#include "netsurf/misc.h"
+#include "netsurf/layout.h"
+#include "netsurf/keypress.h"
+#include "content/hlcache.h"
+#include "content/textsearch.h"
+#include "desktop/frames.h"
+#include "desktop/scrollbar.h"
+#include "desktop/selection.h"
+#include "desktop/textarea.h"
+#include "javascript/js.h"
+#include "desktop/gui_internal.h"
+#include "desktop/save_text.h"
+
+#include "html/box.h"
+#include "html/box_textarea.h"
+#include "html/box_inspect.h"
+#include "html/font.h"
+#include "html/form_internal.h"
+#include "html/private.h"
+#include "html/imagemap.h"
+#include "html/textselection.h"
+
+#define SPACE_LEN(b) ((b->space == 0) ? 0 : 1)
+
+
+
+struct rdw_info {
+ bool inited;
+ struct rect r;
+};
+
+
+
+/**
+ * Tests whether a text box lies partially within the given range of
+ * byte offsets, returning the start and end indexes of the bytes
+ * that are enclosed.
+ *
+ * \param box box to be tested
+ * \param start_idx byte offset of start of range
+ * \param end_idx byte offset of end of range
+ * \param start_offset receives the start offset of the selected part
+ * \param end_offset receives the end offset of the selected part
+ * \return true iff the range encloses at least part of the box
+ */
+static bool
+selected_part(struct box *box,
+ unsigned start_idx,
+ unsigned end_idx,
+ unsigned *start_offset,
+ unsigned *end_offset)
+{
+ size_t box_length = box->length + SPACE_LEN(box);
+
+ if (box_length > 0) {
+ if ((box->byte_offset >= start_idx) &&
+ (box->byte_offset + box_length <= end_idx)) {
+
+ /* fully enclosed */
+ *start_offset = 0;
+ *end_offset = box_length;
+ return true;
+ } else if ((box->byte_offset + box_length > start_idx) &&
+ (box->byte_offset < end_idx)) {
+ /* partly enclosed */
+ int offset = 0;
+ int len;
+
+ if (box->byte_offset < start_idx) {
+ offset = start_idx - box->byte_offset;
+ }
+
+ len = box_length - offset;
+
+ if (box->byte_offset + box_length > end_idx) {
+ len = end_idx - (box->byte_offset + offset);
+ }
+
+ *start_offset = offset;
+ *end_offset = offset + len;
+
+ return true;
+ }
+ }
+ return false;
+}
+
+
+/**
+ * Traverse the given box subtree, calling the handler function (with
+ * its handle) for all boxes that lie (partially) within the given
+ * range
+ *
+ * \param box box subtree
+ * \param start_idx start of range within textual representation (bytes)
+ * \param end_idx end of range
+ * \param rdwi redraw range to fill in
+ * \param do_marker whether deal enter any marker box
+ * \return false iff traversal abandoned part-way through
+ */
+static bool
+coords_from_range(struct box *box,
+ unsigned start_idx,
+ unsigned end_idx,
+ struct rdw_info *rdwi,
+ bool do_marker)
+{
+ struct box *child;
+
+ assert(box);
+
+ /* If selection starts inside marker */
+ if (box->parent &&
+ box->parent->list_marker == box &&
+ !do_marker) {
+ /* set box to main list element */
+ box = box->parent;
+ }
+
+ /* If box has a list marker */
+ if (box->list_marker) {
+ /* do the marker box before continuing with the rest of the
+ * list element */
+ if (!coords_from_range(box->list_marker,
+ start_idx,
+ end_idx,
+ rdwi,
+ true)) {
+ return false;
+ }
+ }
+
+ /* we can prune this subtree, it's after the selection */
+ if (box->byte_offset >= end_idx) {
+ return true;
+ }
+
+ /* read before calling the handler in case it modifies the tree */
+ child = box->children;
+
+ if ((box->type != BOX_BR) &&
+ !((box->type == BOX_FLOAT_LEFT ||
+ box->type == BOX_FLOAT_RIGHT) &&
+ !box->text)) {
+ unsigned start_offset;
+ unsigned end_offset;
+
+ if (selected_part(box, start_idx, end_idx, &start_offset, &end_offset)) {
+ int width, height;
+ int x, y;
+
+ /**
+ * \todo it should be possible to reduce the redrawn
+ * area using the offsets
+ */
+ box_coords(box, &x, &y);
+
+ width = box->padding[LEFT] + box->width + box->padding[RIGHT];
+ height = box->padding[TOP] + box->height + box->padding[BOTTOM];
+
+ if ((box->type == BOX_TEXT) &&
+ (box->space != 0)) {
+ width += box->space;
+ }
+
+ if (rdwi->inited) {
+ if (x < rdwi->r.x0) {
+ rdwi->r.x0 = x;
+ }
+ if (y < rdwi->r.y0) {
+ rdwi->r.y0 = y;
+ }
+ if (x + width > rdwi->r.x1) {
+ rdwi->r.x1 = x + width;
+ }
+ if (y + height > rdwi->r.y1) {
+ rdwi->r.y1 = y + height;
+ }
+ } else {
+ rdwi->inited = true;
+ rdwi->r.x0 = x;
+ rdwi->r.y0 = y;
+ rdwi->r.x1 = x + width;
+ rdwi->r.y1 = y + height;
+ }
+ }
+ }
+
+ /* find the first child that could lie partially within the selection;
+ * this is important at the top-levels of the tree for pruning subtrees
+ * that lie entirely before the selection */
+
+ if (child) {
+ struct box *next = child->next;
+
+ while (next && next->byte_offset < start_idx) {
+ child = next;
+ next = child->next;
+ }
+
+ while (child) {
+ /* read before calling the handler in case it modifies
+ * the tree */
+ struct box *next = child->next;
+
+ if (!coords_from_range(child,
+ start_idx,
+ end_idx,
+ rdwi,
+ false)) {
+ return false;
+ }
+
+ child = next;
+ }
+ }
+
+ return true;
+}
+
+
+/**
+ * create a selection object suitable for this content
+ */
+nserror
+html_create_selection(struct content *c, struct selection **sel_out)
+{
+ html_content *html = (html_content *)c;
+ struct selection *sel;
+ sel = selection_create(c, true);
+ if (sel == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ selection_init(sel, html->layout, &html->len_ctx);
+
+ *sel_out = sel;
+ return NSERROR_OK;
+}
+
+nserror
+html_textselection_redraw(struct content *c,
+ unsigned start_idx,
+ unsigned end_idx)
+{
+ html_content *html = (html_content *)c;
+ struct rdw_info rdw;
+
+ rdw.inited = false;
+
+ if (!coords_from_range(html->layout, start_idx, end_idx, &rdw, false)) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ if (rdw.inited) {
+ content__request_redraw(c,
+ rdw.r.x0,
+ rdw.r.y0,
+ rdw.r.x1 - rdw.r.x0,
+ rdw.r.y1 - rdw.r.y0);
+ }
+
+ return NSERROR_OK;
+}
diff --git a/content/handlers/html/textselection.h b/content/handlers/html/textselection.h
new file mode 100644
index 000000000..0287f3c58
--- /dev/null
+++ b/content/handlers/html/textselection.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * HTML text selection handling
+ */
+
+#ifndef NETSURF_HTML_TEXTSELECTION_H
+#define NETSURF_HTML_TEXTSELECTION_H
+
+struct content;
+struct selection;
+
+/**
+ * create a selection object suitable for this content
+ */
+nserror html_create_selection(struct content *c, struct selection **sel_out);
+
+nserror html_textselection_redraw(struct content *c, unsigned start_idx, unsigned end_idx);
+
+#endif
diff --git a/content/handlers/text/textplain.c b/content/handlers/text/textplain.c
index 534b91d93..d8f61be89 100644
--- a/content/handlers/text/textplain.c
+++ b/content/handlers/text/textplain.c
@@ -1452,6 +1452,68 @@ textplain_textsearch_find(struct content *c,
/**
+ * Given a range of byte offsets within a UTF8 textplain content,
+ * return a box that fully encloses the text
+ *
+ * \param[in] c content of type CONTENT_TEXTPLAIN
+ * \param[in] start byte offset of start of text range
+ * \param[in] end byte offset of end
+ * \param[out] r rectangle to be completed
+ */
+static void
+textplain_coords_from_range(struct content *c,
+ unsigned start,
+ unsigned end,
+ struct rect *r)
+{
+ textplain_content *text = (textplain_content *) c;
+ float line_height = textplain_line_height();
+ char *utf8_data;
+ struct textplain_line *line;
+ unsigned lineno = 0;
+ unsigned nlines;
+
+ assert(c != NULL);
+ assert(start <= end);
+ assert(end <= text->utf8_data_size);
+
+ utf8_data = text->utf8_data;
+ nlines = text->physical_line_count;
+ line = text->physical_line;
+
+ /* find start */
+ lineno = textplain_find_line(c, start);
+
+ r->y0 = (int)(MARGIN + lineno * line_height);
+
+ if (lineno + 1 <= nlines || line[lineno + 1].start >= end) {
+ /* \todo - it may actually be more efficient just to
+ * run forwards most of the time
+ */
+
+ /* find end */
+ lineno = textplain_find_line(c, end);
+
+ r->x0 = 0;
+ r->x1 = text->formatted_width;
+ } else {
+ /* single line */
+ const char *text = utf8_data + line[lineno].start;
+
+ r->x0 = textplain_coord_from_offset(text,
+ start - line[lineno].start,
+ line[lineno].length);
+
+ r->x1 = textplain_coord_from_offset(text,
+ end - line[lineno].start,
+ line[lineno].length);
+ }
+
+ r->y1 = (int)(MARGIN + (lineno + 1) * line_height);
+}
+
+
+/**
* get bounds of a free text search match
*/
static nserror
@@ -1488,6 +1550,28 @@ textplain_create_selection(struct content *c, struct selection **sel_out)
/**
+ * invalidate a region based on offsets into the text cauing a redraw
+ */
+static nserror
+textplain_textselection_redraw(struct content *c,
+ unsigned start_idx,
+ unsigned end_idx)
+{
+ struct rect r;
+
+ if (end_idx <= start_idx) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ textplain_coords_from_range(c, start_idx, end_idx, &r);
+
+ content__request_redraw(c, r.x0, r.y0, r.x1 - r.x0, r.y1 - r.y0);
+
+ return NSERROR_OK;
+}
+
+
+/**
* plain text content handler table
*/
static const content_handler textplain_content_handler = {
@@ -1508,6 +1592,7 @@ static const content_handler textplain_content_handler = {
.type = textplain_content_type,
.textsearch_find = textplain_textsearch_find,
.textsearch_bounds = textplain_textsearch_bounds,
+ .textselection_redraw = textplain_textselection_redraw,
.create_selection = textplain_create_selection,
.no_share = true,
};
@@ -1555,58 +1640,7 @@ size_t textplain_size(struct content *c)
}
-/* exported interface documented in html/textplain.h */
-void
-textplain_coords_from_range(struct content *c,
- unsigned start,
- unsigned end,
- struct rect *r)
-{
- textplain_content *text = (textplain_content *) c;
- float line_height = textplain_line_height();
- char *utf8_data;
- struct textplain_line *line;
- unsigned lineno = 0;
- unsigned nlines;
-
- assert(c != NULL);
- assert(start <= end);
- assert(end <= text->utf8_data_size);
-
- utf8_data = text->utf8_data;
- nlines = text->physical_line_count;
- line = text->physical_line;
- /* find start */
- lineno = textplain_find_line(c, start);
-
- r->y0 = (int)(MARGIN + lineno * line_height);
-
- if (lineno + 1 <= nlines || line[lineno + 1].start >= end) {
- /* \todo - it may actually be more efficient just to
- * run forwards most of the time
- */
-
- /* find end */
- lineno = textplain_find_line(c, end);
-
- r->x0 = 0;
- r->x1 = text->formatted_width;
- } else {
- /* single line */
- const char *text = utf8_data + line[lineno].start;
-
- r->x0 = textplain_coord_from_offset(text,
- start - line[lineno].start,
- line[lineno].length);
-
- r->x1 = textplain_coord_from_offset(text,
- end - line[lineno].start,
- line[lineno].length);
- }
-
- r->y1 = (int)(MARGIN + (lineno + 1) * line_height);
-}
/* exported interface documented in html/textplain.h */
diff --git a/content/handlers/text/textplain.h b/content/handlers/text/textplain.h
index 716397acc..206c5831e 100644
--- a/content/handlers/text/textplain.h
+++ b/content/handlers/text/textplain.h
@@ -47,19 +47,6 @@ size_t textplain_size(struct content *c);
/**
- * Given a range of byte offsets within a UTF8 textplain content,
- * return a box that fully encloses the text
- *
- * \param[in] c content of type CONTENT_TEXTPLAIN
- * \param[in] start byte offset of start of text range
- * \param[in] end byte offset of end
- * \param[out] r rectangle to be completed
- */
-void textplain_coords_from_range(struct content *c,
- unsigned start, unsigned end, struct rect *r);
-
-
-/**
* Return a pointer to the raw UTF-8 data, as opposed to the reformatted
* text to fit the window width. Thus only hard newlines are preserved
* in the saved/copied text of a selection.