mirror of
https://github.com/netsurf-browser/netsurf
synced 2024-12-26 22:09:43 +03:00
move content handler specific selection copying into handlers
This commit is contained in:
parent
36b9262e14
commit
e65e41e2d6
@ -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
|
||||
@ -121,6 +125,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
|
||||
*/
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -1513,6 +1513,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
|
||||
*/
|
||||
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
@ -112,206 +98,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.
|
||||
*
|
||||
@ -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;
|
||||
nserror res;
|
||||
|
||||
if (!s->defined) {
|
||||
return true; /* easy case, nothing to do */
|
||||
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;
|
||||
}
|
||||
|
||||
if (s->root) {
|
||||
/* HTML */
|
||||
return traverse_tree(s->root, &s->len_ctx,
|
||||
s->start_idx, s->end_idx,
|
||||
handler, handle,
|
||||
&before, &first, false);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user