summaryrefslogtreecommitdiff
path: root/content/handlers/html
diff options
context:
space:
mode:
authorVincent Sanders <vince@kyllikki.org>2020-05-23 20:38:41 +0100
committerVincent Sanders <vince@kyllikki.org>2020-05-23 23:00:08 +0100
commite65e41e2d6efccba983cd63aadfb10b5b4a935b2 (patch)
tree3833ea9b7bb989fd5c96d5d230b66b6d29a59794 /content/handlers/html
parent36b9262e1481fc24d302b58f03006e733b2e6d16 (diff)
downloadnetsurf-e65e41e2d6efccba983cd63aadfb10b5b4a935b2.tar.gz
netsurf-e65e41e2d6efccba983cd63aadfb10b5b4a935b2.tar.bz2
move content handler specific selection copying into handlers
Diffstat (limited to 'content/handlers/html')
-rw-r--r--content/handlers/html/html.c1
-rw-r--r--content/handlers/html/textselection.c227
-rw-r--r--content/handlers/html/textselection.h2
3 files changed, 230 insertions, 0 deletions
diff --git a/content/handlers/html/html.c b/content/handlers/html/html.c
index 2a3cb1774..a8ae9e452 100644
--- a/content/handlers/html/html.c
+++ b/content/handlers/html/html.c
@@ -2336,6 +2336,7 @@ static const content_handler html_content_handler = {
.textsearch_find = html_textsearch_find,
.textsearch_bounds = html_textsearch_bounds,
.textselection_redraw = html_textselection_redraw,
+ .textselection_copy = html_textselection_copy,
.create_selection = html_create_selection,
.no_share = true,
};
diff --git a/content/handlers/html/textselection.c b/content/handlers/html/textselection.c
index bbd55732e..11e9deeb4 100644
--- a/content/handlers/html/textselection.c
+++ b/content/handlers/html/textselection.c
@@ -277,6 +277,7 @@ html_create_selection(struct content *c, struct selection **sel_out)
return NSERROR_OK;
}
+/* exported interface documented in html/textselection.h */
nserror
html_textselection_redraw(struct content *c,
unsigned start_idx,
@@ -301,3 +302,229 @@ html_textselection_redraw(struct content *c,
return NSERROR_OK;
}
+
+/**
+ * Selection traversal routine for appending text to a string
+ *
+ * \param text pointer to text being added, or NULL for newline
+ * \param length length of text to be appended (bytes)
+ * \param box pointer to text box, or NULL if from textplain
+ * \param len_ctx Length conversion context
+ * \param handle selection string to append to
+ * \param whitespace_text whitespace to place before text for formatting
+ * may be NULL
+ * \param whitespace_length length of whitespace_text
+ * \return true iff successful and traversal should continue
+ */
+static bool
+selection_copy(const char *text,
+ size_t length,
+ struct box *box,
+ const nscss_len_ctx *len_ctx,
+ struct selection_string *handle,
+ const char *whitespace_text,
+ size_t whitespace_length)
+{
+ bool add_space = false;
+ plot_font_style_t style;
+ plot_font_style_t *pstyle = NULL;
+
+ /* add any whitespace which precedes the text from this box */
+ if (whitespace_text != NULL &&
+ whitespace_length > 0) {
+ if (!selection_string_append(whitespace_text,
+ whitespace_length,
+ false,
+ pstyle,
+ handle)) {
+ return false;
+ }
+ }
+
+ if (box != NULL) {
+ /* HTML */
+ add_space = (box->space != 0);
+
+ if (box->style != NULL) {
+ /* Override default font style */
+ font_plot_style_from_css(len_ctx, box->style, &style);
+ pstyle = &style;
+ } else {
+ /* If there's no style, there must be no text */
+ assert(box->text == NULL);
+ }
+ }
+
+ /* add the text from this box */
+ if (!selection_string_append(text, length, add_space, pstyle, handle)) {
+ return false;
+ }
+
+ return true;
+}
+
+
+/**
+ * Traverse the given box subtree, calling selection copy for all
+ * boxes that lie (partially) within the given range
+ *
+ * \param box box subtree
+ * \param len_ctx Length conversion context.
+ * \param start_idx start of range within textual representation (bytes)
+ * \param end_idx end of range
+ * \param handler handler function to call
+ * \param handle handle to pass
+ * \param before type of whitespace to place before next encountered text
+ * \param first whether this is the first box with text
+ * \param do_marker whether deal enter any marker box
+ * \return false iff traversal abandoned part-way through
+ */
+static bool
+traverse_tree(struct box *box,
+ const nscss_len_ctx *len_ctx,
+ unsigned start_idx,
+ unsigned end_idx,
+ struct selection_string *selstr,
+ save_text_whitespace *before,
+ bool *first,
+ bool do_marker)
+{
+ struct box *child;
+ const char *whitespace_text = "";
+ size_t whitespace_length = 0;
+
+ 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 (!traverse_tree(box->list_marker,
+ len_ctx,
+ start_idx,
+ end_idx,
+ selstr,
+ before,
+ first,
+ 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 nicely formatted output of the selected text is required, work
+ * out what whitespace should be placed before the next bit of text */
+ if (before) {
+ save_text_solve_whitespace(box,
+ first,
+ before,
+ &whitespace_text,
+ &whitespace_length);
+ } else {
+ whitespace_text = NULL;
+ }
+
+ 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)) {
+ if (!selection_copy(box->text + start_offset,
+ min(box->length, end_offset) - start_offset,
+ box,
+ len_ctx,
+ selstr,
+ whitespace_text,
+ whitespace_length)) {
+ return false;
+ }
+ if (before) {
+ *first = false;
+ *before = WHITESPACE_NONE;
+ }
+ }
+ }
+
+ /* 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 (!traverse_tree(child,
+ len_ctx,
+ start_idx,
+ end_idx,
+ selstr,
+ before,
+ first,
+ false)) {
+ return false;
+ }
+
+ child = next;
+ }
+ }
+
+ return true;
+}
+
+/* exported interface documented in html/textselection.h */
+nserror
+html_textselection_copy(struct content *c,
+ unsigned start_idx,
+ unsigned end_idx,
+ struct selection_string *selstr)
+{
+ html_content *html = (html_content *)c;
+ save_text_whitespace before = WHITESPACE_NONE;
+ bool first = true;
+ bool res;
+
+ res = traverse_tree(html->layout,
+ &html->len_ctx,
+ start_idx,
+ end_idx,
+ selstr,
+ &before,
+ &first,
+ false);
+
+ if (res == false) {
+ return NSERROR_NOMEM;
+ }
+ return NSERROR_OK;
+}
diff --git a/content/handlers/html/textselection.h b/content/handlers/html/textselection.h
index 0287f3c58..4a866b0b2 100644
--- a/content/handlers/html/textselection.h
+++ b/content/handlers/html/textselection.h
@@ -34,4 +34,6 @@ nserror html_create_selection(struct content *c, struct selection **sel_out);
nserror html_textselection_redraw(struct content *c, unsigned start_idx, unsigned end_idx);
+nserror html_textselection_copy(struct content *c, unsigned start_idx, unsigned end_idx, struct selection_string *selstr);
+
#endif