summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--content/content_protected.h11
-rw-r--r--content/handlers/html/html.c1
-rw-r--r--content/handlers/html/textselection.c227
-rw-r--r--content/handlers/html/textselection.h2
-rw-r--r--content/handlers/text/textplain.c79
-rw-r--r--content/handlers/text/textplain.h14
-rw-r--r--desktop/selection.c314
-rw-r--r--desktop/selection.h9
8 files changed, 317 insertions, 340 deletions
diff --git a/content/content_protected.h b/content/content_protected.h
index 9a3654beb..02bc8614d 100644
--- a/content/content_protected.h
+++ b/content/content_protected.h
@@ -47,6 +47,7 @@ struct browser_window_features;
struct textsearch_context;
struct box;
struct selection;
+struct selection_string;
typedef struct content_handler content_handler;
@@ -112,7 +113,10 @@ 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
+ * redraw an area of selected text
+ *
+ * The defined text selection will cause an area of the
+ * content to be marked as invalid and hence redrawn.
*
* \param c The content being redrawn
* \param start_idx The start index of the text region to be redrawn
@@ -122,6 +126,11 @@ struct content_handler {
nserror (*textselection_redraw)(struct content *c, unsigned start_idx, unsigned end_idx);
/**
+ * copy selected text into selection string possibly with formatting
+ */
+ nserror (*textselection_copy)(struct content *c, unsigned start_idx, unsigned end_idx, struct selection_string *selstr);
+
+ /**
* create a selection object
*/
nserror (*create_selection)(struct content *c, struct selection **sel_out);
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
diff --git a/content/handlers/text/textplain.c b/content/handlers/text/textplain.c
index d8f61be89..275efda83 100644
--- a/content/handlers/text/textplain.c
+++ b/content/handlers/text/textplain.c
@@ -1514,6 +1514,43 @@ textplain_coords_from_range(struct content *c,
/**
+ * 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.
+ *
+ * \param[in] c content of type CONTENT_TEXTPLAIN
+ * \param[in] start starting byte offset within UTF-8 text
+ * \param[in] end ending byte offset
+ * \param[out] plen receives validated length
+ * \return pointer to text, or NULL if no text
+ */
+static char *
+textplain_get_raw_data(struct content *c,
+ unsigned start,
+ unsigned end,
+ size_t *plen)
+{
+ textplain_content *text = (textplain_content *) c;
+ size_t utf8_size;
+
+ assert(c != NULL);
+
+ utf8_size = text->utf8_data_size;
+
+ /* any text at all? */
+ if (!utf8_size) return NULL;
+
+ /* clamp to valid offset range */
+ if (start >= utf8_size) start = utf8_size;
+ if (end >= utf8_size) end = utf8_size;
+
+ *plen = end - start;
+
+ return text->utf8_data + start;
+}
+
+
+/**
* get bounds of a free text search match
*/
static nserror
@@ -1570,6 +1607,23 @@ textplain_textselection_redraw(struct content *c,
return NSERROR_OK;
}
+static nserror
+textplain_textselection_copy(struct content *c,
+ unsigned start_idx,
+ unsigned end_idx,
+ struct selection_string *selstr)
+{
+ const char *text;
+ size_t length;
+ bool res;
+
+ text = textplain_get_raw_data(c, start_idx, end_idx, &length);
+ res = selection_string_append(text, length, false, NULL, selstr);
+ if (res == false) {
+ return NSERROR_NOMEM;
+ }
+ return NSERROR_OK;
+}
/**
* plain text content handler table
@@ -1593,6 +1647,7 @@ static const content_handler textplain_content_handler = {
.textsearch_find = textplain_textsearch_find,
.textsearch_bounds = textplain_textsearch_bounds,
.textselection_redraw = textplain_textselection_redraw,
+ .textselection_copy = textplain_textselection_copy,
.create_selection = textplain_create_selection,
.no_share = true,
};
@@ -1643,28 +1698,4 @@ size_t textplain_size(struct content *c)
-/* exported interface documented in html/textplain.h */
-char *
-textplain_get_raw_data(struct content *c,
- unsigned start,
- unsigned end,
- size_t *plen)
-{
- textplain_content *text = (textplain_content *) c;
- size_t utf8_size;
- assert(c != NULL);
-
- utf8_size = text->utf8_data_size;
-
- /* any text at all? */
- if (!utf8_size) return NULL;
-
- /* clamp to valid offset range */
- if (start >= utf8_size) start = utf8_size;
- if (end >= utf8_size) end = utf8_size;
-
- *plen = end - start;
-
- return text->utf8_data + start;
-}
diff --git a/content/handlers/text/textplain.h b/content/handlers/text/textplain.h
index 206c5831e..b94ee33d3 100644
--- a/content/handlers/text/textplain.h
+++ b/content/handlers/text/textplain.h
@@ -46,18 +46,4 @@ nserror textplain_init(void);
size_t textplain_size(struct content *c);
-/**
- * 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.
- *
- * \param[in] c content of type CONTENT_TEXTPLAIN
- * \param[in] start starting byte offset within UTF-8 text
- * \param[in] end ending byte offset
- * \param[out] plen receives validated length
- * \return pointer to text, or NULL if no text
- */
-char *textplain_get_raw_data(struct content *c, unsigned start, unsigned end, size_t *plen);
-
-
#endif
diff --git a/desktop/selection.c b/desktop/selection.c
index 11cd1fb06..d4fa7ca7d 100644
--- a/desktop/selection.c
+++ b/desktop/selection.c
@@ -57,11 +57,6 @@
#define SPACE_LEN(b) ((b->space == 0) ? 0 : 1)
-struct rdw_info {
- bool inited;
- struct rect r;
-};
-
struct selection_string {
char *buffer;
size_t buffer_len;
@@ -72,15 +67,6 @@ struct selection_string {
};
-typedef bool (*seln_traverse_handler)(const char *text,
- size_t length,
- struct box *box,
- const nscss_len_ctx *len_ctx,
- void *handle,
- const char *whitespace_text,
- size_t whitespace_length);
-
-
/**
* Label each text box in the given box subtree with its position
* in a textual representation of the content.
@@ -113,206 +99,6 @@ static unsigned selection_label_subtree(struct box *box, unsigned idx)
/**
- * 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 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,
- seln_traverse_handler handler,
- void *handle,
- 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,
- handler,
- handle,
- 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 (!handler(box->text + start_offset,
- min(box->length, end_offset) - start_offset,
- box,
- len_ctx,
- handle,
- 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,
- handler,
- handle,
- before,
- first,
- false)) {
- return false;
- }
-
- child = next;
- }
- }
-
- return true;
-}
-
-
-
-
-/**
* Redraws the given range of text.
*
* \param s selection object
@@ -404,35 +190,22 @@ static void selection_set_end(struct selection *s, unsigned offset)
* \return false iff traversal abandoned part-way through
*/
static bool
-selection_traverse(struct selection *s,
- seln_traverse_handler handler,
- void *handle)
+selection_copy(struct selection *s, struct selection_string *selstr)
{
- save_text_whitespace before = WHITESPACE_NONE;
- bool first = true;
- const char *text;
- size_t length;
-
- if (!s->defined) {
- return true; /* easy case, nothing to do */
- }
+ nserror res;
- if (s->root) {
- /* HTML */
- return traverse_tree(s->root, &s->len_ctx,
- s->start_idx, s->end_idx,
- handler, handle,
- &before, &first, false);
+ if (s->c->handler->textselection_copy != NULL) {
+ res = s->c->handler->textselection_copy(s->c,
+ s->start_idx,
+ s->end_idx,
+ selstr);
+ } else {
+ res = NSERROR_NOT_IMPLEMENTED;
}
- /* Text */
- text = textplain_get_raw_data(s->c, s->start_idx, s->end_idx, &length);
-
- if (text &&
- !handler(text, length, NULL, NULL, handle, NULL, 0)) {
+ if (res != NSERROR_OK) {
return false;
}
-
return true;
}
@@ -447,7 +220,7 @@ selection_traverse(struct selection *s,
* \param sel_string string to append to, may be resized
* \return true iff successful
*/
-static bool
+bool
selection_string_append(const char *text,
size_t length,
bool space,
@@ -509,67 +282,6 @@ selection_string_append(const char *text,
}
-/**
- * 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_handler(const char *text,
- size_t length,
- struct box *box,
- const nscss_len_ctx *len_ctx,
- void *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;
-}
-
-
/* exported interface documented in desktop/selection.h */
struct selection *selection_create(struct content *c, bool is_html)
{
@@ -821,7 +533,7 @@ char *selection_get_copy(struct selection *s)
if (s == NULL || !s->defined)
return NULL;
- if (!selection_traverse(s, selection_copy_handler, &sel_string)) {
+ if (!selection_copy(s, &sel_string)) {
free(sel_string.buffer);
free(sel_string.styles);
return NULL;
@@ -849,7 +561,7 @@ bool selection_copy_to_clipboard(struct selection *s)
return false;
}
- if (!selection_traverse(s, selection_copy_handler, &sel_string)) {
+ if (!selection_copy(s, &sel_string)) {
free(sel_string.buffer);
free(sel_string.styles);
return false;
diff --git a/desktop/selection.h b/desktop/selection.h
index cfaf59baf..cc8d8da4e 100644
--- a/desktop/selection.h
+++ b/desktop/selection.h
@@ -29,6 +29,8 @@
struct box;
struct browser_window;
+struct plot_font_style;
+struct selection_string;
typedef enum {
DRAG_NONE,
@@ -218,4 +220,11 @@ char *selection_get_copy(struct selection *s);
*/
bool selection_highlighted(const struct selection *s, unsigned start, unsigned end, unsigned *start_idx, unsigned *end_idx);
+bool
+selection_string_append(const char *text,
+ size_t length,
+ bool space,
+ struct plot_font_style *style,
+ struct selection_string *sel_string);
+
#endif