From 9c918930289b18dbfd4bb44081891d5780105bfd Mon Sep 17 00:00:00 2001 From: Michael Drake Date: Wed, 13 Jul 2011 13:20:26 +0000 Subject: Fix selection for non-gui browser windows (iframes). Selection no longer uses current_redraw_browser. Fix long-standing selection bugs on platforms that use action on release behaviour. svn path=/trunk/netsurf/; revision=12598 --- content/content.c | 16 ++++++++ content/content.h | 1 + content/content_protected.h | 1 + desktop/browser.c | 91 +++++++++++++++++++++------------------------ desktop/browser.h | 23 ++++++++++-- desktop/frames.c | 7 ++-- desktop/selection.c | 37 +++++++++++++++--- desktop/selection.h | 4 +- desktop/textinput.c | 20 ++++------ gtk/scaffolding.c | 6 +-- render/html.c | 25 +++++++++++-- render/html.h | 1 + render/html_interaction.c | 67 +++++++++++++++++++-------------- render/html_internal.h | 4 ++ render/html_redraw.c | 30 +++++++-------- render/textinput.c | 54 +++++++++++++-------------- render/textplain.c | 68 ++++++++++++++++++++++++--------- riscos/window.c | 8 ++-- 18 files changed, 294 insertions(+), 169 deletions(-) diff --git a/content/content.c b/content/content.c index 1f7003404..c3f8d7855 100644 --- a/content/content.c +++ b/content/content.c @@ -676,6 +676,22 @@ void content_close(hlcache_handle *h) } +/** + * Find this content's selection context, if it has one. + */ + +struct selection *content_get_selection(hlcache_handle *h) +{ + struct content *c = hlcache_handle_get_content(h); + assert(c != 0); + + if (c->handler->get_selection != NULL) + return c->handler->get_selection(c); + else + return NULL; +} + + void content_add_error(struct content *c, const char *token, unsigned int line) { diff --git a/content/content.h b/content/content.h index ca267060c..40e7f2089 100644 --- a/content/content.h +++ b/content/content.h @@ -157,6 +157,7 @@ void content_open(struct hlcache_handle *h, struct browser_window *bw, struct content *page, struct box *box, struct object_params *params); void content_close(struct hlcache_handle *h); +struct selection *content_get_selection(struct hlcache_handle *h); /* Member accessors */ content_type content_get_type(struct hlcache_handle *c); diff --git a/content/content_protected.h b/content/content_protected.h index bc2079017..4fe9b942a 100644 --- a/content/content_protected.h +++ b/content/content_protected.h @@ -64,6 +64,7 @@ struct content_handler { struct box *box, struct object_params *params); void (*close)(struct content *c); + struct selection * (*get_selection)(struct content *c); nserror (*clone)(const struct content *old, struct content **newc); bool (*matches_quirks)(const struct content *c, bool quirks); content_type (*type)(lwc_string *mime_type); diff --git a/desktop/browser.c b/desktop/browser.c index 0fca4a2dd..54c89fe64 100644 --- a/desktop/browser.c +++ b/desktop/browser.c @@ -344,16 +344,40 @@ bool browser_window_has_selection(struct browser_window *bw) { assert(bw->window); - /* TODO: handle selections in (i)frames */ - - if (bw->current_content != NULL && bw->sel != NULL && - selection_defined(bw->sel)) { + if (bw->cur_sel != NULL && selection_defined(bw->cur_sel)) { return true; } else { return false; } } +/* exported interface, documented in browser.h */ +void browser_window_set_selection(struct browser_window *bw, + struct selection *s) +{ + assert(bw->window); + + if (bw->cur_sel != s && bw->cur_sel != NULL) { + /* Clear any existing selection */ + selection_clear(bw->cur_sel, true); + } + + /* Replace current selection pointer */ + if (s == NULL && bw->current_content != NULL) { + bw->cur_sel = content_get_selection(bw->current_content); + } else { + bw->cur_sel = s; + } +} + +/* exported interface, documented in browser.h */ +struct selection *browser_window_get_selection(struct browser_window *bw) +{ + assert(bw->window); + + return bw->cur_sel; +} + /** * Set scroll offsets for a browser window. * @@ -407,8 +431,6 @@ struct browser_window *browser_window_create(const char *url, bw->last_action = wallclock(); bw->focus = bw; - bw->sel = selection_create(); - /* gui window */ /* from the front end's pov, it clones the top level browser window, * so find that. */ @@ -446,7 +468,7 @@ void browser_window_initialise_common(struct browser_window *bw, bw->history = history_clone(clone->history); /* window characteristics */ - bw->sel = NULL; + bw->cur_sel = NULL; bw->refresh_interval = -1; bw->reformat_pending = false; @@ -799,13 +821,11 @@ nserror browser_window_callback(hlcache_handle *c, global_history_add(urldb_get_url(url)); } } - - /* text selection */ - if (content_get_type(c) == CONTENT_HTML) - selection_init(bw->sel, - html_get_box_tree(bw->current_content)); - if (content_get_type(c) == CONTENT_TEXTPLAIN) - selection_init(bw->sel, NULL); + + if (bw->window != NULL) { + browser_window_set_selection(bw, + content_get_selection(c)); + } /* frames */ if (content_get_type(c) == CONTENT_HTML && @@ -854,7 +874,6 @@ nserror browser_window_callback(hlcache_handle *c, else if (c == bw->current_content) { bw->current_content = NULL; browser_window_remove_caret(bw); - selection_init(bw->sel, NULL); } hlcache_handle_release(c); @@ -875,8 +894,6 @@ nserror browser_window_callback(hlcache_handle *c, /* reflow iframe positions */ if (html_get_iframe(c) != NULL) browser_window_recalculate_iframes(bw); - /* box tree may have changed, need to relabel */ - selection_reinit(bw->sel, html_get_box_tree(c)); } if (bw->move_callback) @@ -1439,6 +1456,12 @@ void browser_window_destroy_internal(struct browser_window *bw) if (top->focus == bw) top->focus = top; + + if (bw->current_content != NULL && + top->cur_sel == content_get_selection( + bw->current_content)) { + browser_window_set_selection(top, NULL); + } } /* Destruction order is important: we must ensure that the frontend @@ -1471,12 +1494,6 @@ void browser_window_destroy_internal(struct browser_window *bw) bw->box = NULL; } - /* TODO: After core FRAMES are done, should be - * if (bw->browser_window_type == BROWSER_WINDOW_NORMAL) */ - if (bw->browser_window_type != BROWSER_WINDOW_IFRAME) { - selection_destroy(bw->sel); - } - /* These simply free memory, so are safe here */ history_destroy(bw->history); @@ -1831,6 +1848,7 @@ void browser_window_mouse_track(struct browser_window *bw, browser_window_mouse_drag_end(bw, mouse, x, y); } + /* Browser window's horizontal scrollbar */ if (bw->scroll_x != NULL) { int scr_x, scr_y; browser_window_get_scrollbar_pos(bw, true, &scr_x, &scr_y); @@ -1853,6 +1871,7 @@ void browser_window_mouse_track(struct browser_window *bw, } } + /* Browser window's vertical scrollbar */ if (bw->scroll_y != NULL) { int scr_x, scr_y; browser_window_get_scrollbar_pos(bw, false, &scr_x, &scr_y); @@ -2002,31 +2021,7 @@ void browser_window_mouse_drag_end(struct browser_window *bw, switch (bw->drag_type) { case DRAGGING_SELECTION: - { - hlcache_handle *h = bw->current_content; - if (h) { - int dir = -1; - size_t idx; - - if (selection_dragging_start(bw->sel)) - dir = 1; - - if (content_get_type(h) == CONTENT_HTML) { - idx = html_selection_drag_end(h, mouse, x, y, - dir); - if (idx != 0) - selection_track(bw->sel, mouse, idx); - } else { - assert(content_get_type(h) == - CONTENT_TEXTPLAIN); - idx = textplain_offset_from_coords(h, x, y, - dir); - selection_track(bw->sel, mouse, idx); - } - } - selection_drag_end(bw->sel); - } - bw->drag_type = DRAGGING_NONE; + /* Drag handled by content handler */ break; case DRAGGING_OTHER: diff --git a/desktop/browser.h b/desktop/browser.h index d0695f295..f008cfc00 100644 --- a/desktop/browser.h +++ b/desktop/browser.h @@ -78,9 +78,6 @@ struct browser_window { /** Window history structure. */ struct history *history; - /** Selection state */ - struct selection *sel; - /** Handler for keyboard input, or 0. */ browser_caret_callback caret_callback; /** Handler for pasting text, or 0. */ @@ -193,6 +190,9 @@ struct browser_window { /** search context for free text search */ struct search_context *search_context; + /** Content with current selection, or NULL if none */ + struct selection *cur_sel; + /** cache of the currently displayed status text. */ char *status_text; /**< Current status bar text. */ int status_text_len; /**< Length of the ::status_text buffer. */ @@ -365,6 +365,23 @@ struct browser_window * browser_window_get_root(struct browser_window *bw); */ bool browser_window_has_selection(struct browser_window *bw); +/** + * Set pointer to current selection. Clears any existing selection. + * + * \param bw The browser window + * \param s The new selection + */ +void browser_window_set_selection(struct browser_window *bw, + struct selection *s); + +/** + * Get the current selection context from a root browser window + * + * \param bw The browser window + * \return the selection context, or NULL + */ +struct selection *browser_window_get_selection(struct browser_window *bw); + /* In platform specific hotlist.c. */ void hotlist_visited(struct hlcache_handle *c); diff --git a/desktop/frames.c b/desktop/frames.c index afcd84e01..f1710437f 100644 --- a/desktop/frames.c +++ b/desktop/frames.c @@ -201,7 +201,7 @@ void browser_window_create_iframes(struct browser_window *bw, window->no_resize = true; window->margin_width = cur->margin_width; window->margin_height = cur->margin_height; - window->sel = bw->sel; + window->cur_sel = bw->cur_sel; window->scale = bw->scale; if (cur->name) { window->name = strdup(cur->name); @@ -315,9 +315,8 @@ void browser_window_create_frameset(struct browser_window *bw, warn_user("NoMemory", 0); } - /* TODO: when framesets are handled in the core, remove - * the following line. */ - window->sel = selection_create(); + /* TODO: When frames are handled in core: + * window->cur_sel = bw->cur_sel; */ /* linking */ window->parent = bw; diff --git a/desktop/selection.c b/desktop/selection.c index 24502ac47..7c775f4c2 100644 --- a/desktop/selection.c +++ b/desktop/selection.c @@ -90,20 +90,34 @@ static struct box *get_box(struct box *b, unsigned offset, size_t *pidx); /** * Creates a new selection object associated with a browser window. * - * \param s selection object - * \param bw browser window + * \return new selection context */ struct selection *selection_create(void) { struct selection *s = calloc(1, sizeof(struct selection)); + if (s) { + selection_prepare(s); + } + return s; +} + +/** + * Prepare a newly created selection object for use. + * + * \param s selection object + * \param bw browser window + */ + +void selection_prepare(struct selection *s) +{ if (s) { s->bw = NULL; s->root = NULL; s->drag_state = DRAG_NONE; + s->max_idx = 0; selection_clear(s, false); } - return s; } /** @@ -304,12 +318,16 @@ bool selection_click(struct selection *s, browser_mouse_state mouse, gui_drag_save_selection(s, top->window); } else if (!modkeys) { - if (pos && (mouse & BROWSER_MOUSE_PRESS_1)) + if (pos && (mouse & BROWSER_MOUSE_PRESS_1)) { /* Clear the selection if mouse is pressed outside the selection, * Otherwise clear on release (to allow for drags) */ + browser_window_set_selection(top, s); + selection_clear(s, true); - else if (mouse & BROWSER_MOUSE_DRAG_1) { + } else if (mouse & BROWSER_MOUSE_DRAG_1) { /* start new selection drag */ + browser_window_set_selection(top, s); + selection_clear(s, true); selection_set_start(s, idx); @@ -325,6 +343,8 @@ bool selection_click(struct selection *s, browser_mouse_state mouse, if (!selection_defined(s)) return false; /* ignore Adjust drags */ + browser_window_set_selection(top, s); + if (pos >= 0) { selection_set_end(s, idx); @@ -385,6 +405,10 @@ void selection_track(struct selection *s, browser_mouse_state mouse, if (!SAME_SPACE(s, idx)) return; + if (!mouse) { + s->drag_state = DRAG_NONE; + } + switch (s->drag_state) { case DRAG_START: @@ -902,7 +926,8 @@ struct box *selection_get_end(struct selection *s, size_t *pidx) * \return true iff part of the given box lies within the selection */ -bool selection_highlighted(struct selection *s, unsigned start, unsigned end, +bool selection_highlighted(const struct selection *s, + unsigned start, unsigned end, unsigned *start_idx, unsigned *end_idx) { /* caller should have checked first for efficiency */ diff --git a/desktop/selection.h b/desktop/selection.h index 8dc3ce103..4b8bd8ec8 100644 --- a/desktop/selection.h +++ b/desktop/selection.h @@ -60,6 +60,7 @@ typedef bool (*seln_traverse_handler)(const char *text, size_t length, struct selection *selection_create(void); +void selection_prepare(struct selection *s); void selection_destroy(struct selection *s); void selection_init(struct selection *s, struct box *root); @@ -103,7 +104,8 @@ void selection_track(struct selection *s, browser_mouse_state mouse, bool selection_traverse(struct selection *s, seln_traverse_handler handler, void *handle); -bool selection_highlighted(struct selection *s, unsigned start, unsigned end, +bool selection_highlighted(const struct selection *s, + unsigned start, unsigned end, unsigned *start_idx, unsigned *end_idx); bool selection_save_text(struct selection *s, const char *path); diff --git a/desktop/textinput.c b/desktop/textinput.c index 32d8f5167..1879f414c 100644 --- a/desktop/textinput.c +++ b/desktop/textinput.c @@ -100,11 +100,7 @@ void browser_window_remove_caret(struct browser_window *bw) { struct browser_window *root_bw; - /* Find top level browser window */ - root_bw = bw; - while (root_bw && !root_bw->window && root_bw->parent) { - root_bw = root_bw->parent; - } + root_bw = browser_window_get_root(bw); gui_window_remove_caret(root_bw->window); @@ -113,8 +109,6 @@ void browser_window_remove_caret(struct browser_window *bw) bw->move_callback = NULL; bw->caret_p1 = NULL; bw->caret_p2 = NULL; - - selection_clear(bw->sel, true); } @@ -129,23 +123,25 @@ bool browser_window_key_press(struct browser_window *bw, uint32_t key) { struct browser_window *focus = bw->focus; + assert(bw->window != NULL); + /* keys that take effect wherever the caret is positioned */ switch (key) { case KEY_SELECT_ALL: - selection_select_all(focus->sel); + selection_select_all(bw->cur_sel); return true; case KEY_COPY_SELECTION: - gui_copy_to_clipboard(focus->sel); + gui_copy_to_clipboard(bw->cur_sel); return true; case KEY_CLEAR_SELECTION: - selection_clear(focus->sel, true); + selection_clear(bw->cur_sel, true); return true; case KEY_ESCAPE: - if (selection_defined(focus->sel)) { - selection_clear(focus->sel, true); + if (selection_defined(bw->cur_sel)) { + selection_clear(bw->cur_sel, true); return true; } /* if there's no selection, diff --git a/gtk/scaffolding.c b/gtk/scaffolding.c index 269aa27ac..81a96a70a 100644 --- a/gtk/scaffolding.c +++ b/gtk/scaffolding.c @@ -381,7 +381,7 @@ static guint nsgtk_scaffolding_update_edit_actions_sensitivity( } else { struct browser_window *bw = gui_window_get_browser_window(g->top_level); - has_selection = bw->sel->defined; + has_selection = browser_window_has_selection(bw); g->buttons[COPY_BUTTON]->sensitivity = has_selection; g->buttons[CUT_BUTTON]->sensitivity = (has_selection && @@ -959,7 +959,7 @@ MULTIHANDLER(copy) if (GTK_IS_EDITABLE (focused)) gtk_editable_copy_clipboard(GTK_EDITABLE(g->url_bar)); else - gui_copy_to_clipboard(bw->sel); + gui_copy_to_clipboard(browser_window_get_selection(bw)); return TRUE; } @@ -999,7 +999,7 @@ MULTIHANDLER(selectall) gtk_editable_select_region(GTK_EDITABLE(g->url_bar), 0, -1); } else { LOG(("Selecting all document text")); - selection_select_all(bw->sel); + selection_select_all(browser_window_get_selection(bw)); } return TRUE; diff --git a/render/html.c b/render/html.c index 6f76bf6ac..c377b72a5 100644 --- a/render/html.c +++ b/render/html.c @@ -74,6 +74,7 @@ static void html_open(struct content *c, struct browser_window *bw, struct content *page, struct box *box, struct object_params *params); static void html_close(struct content *c); +struct selection *html_get_selection(struct content *c); static nserror html_clone(const struct content *old, struct content **newc); static content_type html_content_type(lwc_string *mime_type); @@ -114,6 +115,7 @@ static const content_handler html_content_handler = { .redraw = html_redraw, .open = html_open, .close = html_close, + .get_selection = html_get_selection, .clone = html_clone, .type = html_content_type, .no_share = true, @@ -255,6 +257,8 @@ nserror html_create_html_data(html_content *c, const http_parameter *params) c->font_func = &nsfont; c->scrollbar = NULL; + selection_prepare(&c->sel); + nerror = http_parameter_list_find_item(params, html_charset, &charset); if (nerror == NSERROR_OK) { c->encoding = talloc_strdup(c, lwc_string_data(charset)); @@ -1754,6 +1758,8 @@ void html_reformat(struct content *c, int width, int height) if (c->height < layout->y + layout->descendant_y1) c->height = layout->y + layout->descendant_y1; + selection_reinit(&htmlc->sel, htmlc->layout); + time_taken = wallclock() - time_before; c->reformat_time = wallclock() + ((time_taken * 3 < option_min_reflow_period ? @@ -1962,7 +1968,9 @@ void html_open(struct content *c, struct browser_window *bw, html->page = (html_content *) page; html->box = box; - selection_set_browser_window(bw->sel, bw); + /* text selection */ + selection_init(&html->sel, html->layout); + selection_set_browser_window(&html->sel, bw); for (object = html->object_list; object != NULL; object = next) { next = object->next; @@ -1990,8 +1998,7 @@ void html_close(struct content *c) html_content *html = (html_content *) c; struct content_html_object *object, *next; - if (html->bw && html->bw->sel) - selection_set_browser_window(html->bw->sel, NULL); + selection_set_browser_window(&html->sel, NULL); html->bw = NULL; @@ -2011,6 +2018,18 @@ void html_close(struct content *c) } } + +/** + * Return an HTML content's selection context + */ + +struct selection *html_get_selection(struct content *c) +{ + html_content *html = (html_content *) c; + + return &html->sel; +} + #if ALWAYS_DUMP_FRAMESET /** * Print a frameset tree to stderr. diff --git a/render/html.h b/render/html.h index ba55a6cdd..f137a83f1 100644 --- a/render/html.h +++ b/render/html.h @@ -159,6 +159,7 @@ bool text_redraw(const char *utf8_text, size_t utf8_len, int height, float scale, bool excluded, + const struct selection *sel, const struct redraw_context *ctx); xmlDoc *html_get_document(struct hlcache_handle *h); diff --git a/render/html_interaction.c b/render/html_interaction.c index db68f4629..8f60877e2 100644 --- a/render/html_interaction.c +++ b/render/html_interaction.c @@ -61,18 +61,35 @@ static void html_box_drag_start(struct box *box, int x, int y); void html_mouse_track(struct content *c, struct browser_window *bw, browser_mouse_state mouse, int x, int y) { + html_content *html = (html_content*) c; hlcache_handle *h = bw->current_content; + if (bw->drag_type == DRAGGING_SELECTION && !mouse) { + int dir = -1; + size_t idx; + + if (selection_dragging_start(&html->sel)) + dir = 1; + + idx = html_selection_drag_end(h, mouse, x, y, dir); + + if (idx != 0) + selection_track(&html->sel, mouse, idx); + + browser_window_set_drag_type(bw, DRAGGING_NONE); + } + switch (bw->drag_type) { case DRAGGING_SELECTION: { struct box *box; int dir = -1; int dx, dy; - if (selection_dragging_start(bw->sel)) dir = 1; + if (selection_dragging_start(&html->sel)) + dir = 1; + + box = box_pick_text_box(h, x, y, dir, &dx, &dy); - box = box_pick_text_box(h, x, y, dir, - &dx, &dy); if (box) { int pixel_offset; size_t idx; @@ -84,7 +101,7 @@ void html_mouse_track(struct content *c, struct browser_window *bw, box->text, box->length, dx, &idx, &pixel_offset); - selection_track(bw->sel, mouse, + selection_track(&html->sel, mouse, box->byte_offset + idx); } } @@ -116,6 +133,7 @@ void html_mouse_track(struct content *c, struct browser_window *bw, void html_mouse_action(struct content *c, struct browser_window *bw, browser_mouse_state mouse, int x, int y) { + html_content *html = (html_content *) c; enum { ACTION_NONE, ACTION_SUBMIT, ACTION_GO } action = ACTION_NONE; char *title = 0; const char *url = 0; @@ -143,8 +161,6 @@ void html_mouse_action(struct content *c, struct browser_window *bw, plot_font_style_t fstyle; int scroll_mouse_x = 0, scroll_mouse_y = 0; int padding_left, padding_right, padding_top, padding_bottom; - html_content *html = (html_content *) c; - if (bw->drag_type != DRAGGING_NONE && !mouse && html->visible_select_menu != NULL) { @@ -376,12 +392,11 @@ void html_mouse_action(struct content *c, struct browser_window *bw, if (mouse & (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_PRESS_2)) { - if (text_box && selection_root(bw->sel) != + if (text_box && selection_root(&html->sel) != gadget_box) - selection_init(bw->sel, gadget_box); + selection_init(&html->sel, gadget_box); - textinput_textarea_click(c, - mouse, + textinput_textarea_click(c, mouse, gadget_box, gadget_box_x, gadget_box_y, @@ -403,17 +418,17 @@ void html_mouse_action(struct content *c, struct browser_window *bw, &idx, &pixel_offset); - selection_click(bw->sel, mouse, + selection_click(&html->sel, mouse, text_box->byte_offset + idx); - if (selection_dragging(bw->sel)) { + if (selection_dragging(&html->sel)) { bw->drag_type = DRAGGING_SELECTION; status = messages_get("Selecting"); } else status = content_get_status_message(h); } else if (mouse & BROWSER_MOUSE_PRESS_1) - selection_clear(bw->sel, true); + selection_clear(&html->sel, true); break; case GADGET_TEXTBOX: case GADGET_PASSWORD: @@ -436,7 +451,7 @@ void html_mouse_action(struct content *c, struct browser_window *bw, if (mouse & (BROWSER_MOUSE_DRAG_1 | BROWSER_MOUSE_DRAG_2)) - selection_init(bw->sel, gadget_box); + selection_init(&html->sel, gadget_box); font_plot_style_from_css(text_box->style, &fstyle); @@ -448,14 +463,14 @@ void html_mouse_action(struct content *c, struct browser_window *bw, &idx, &pixel_offset); - selection_click(bw->sel, mouse, + selection_click(&html->sel, mouse, text_box->byte_offset + idx); - if (selection_dragging(bw->sel)) + if (selection_dragging(&html->sel)) bw->drag_type = DRAGGING_SELECTION; } else if (mouse & BROWSER_MOUSE_PRESS_1) - selection_clear(bw->sel, true); + selection_clear(&html->sel, true); break; case GADGET_HIDDEN: /* not possible: no box generated */ @@ -538,11 +553,10 @@ void html_mouse_action(struct content *c, struct browser_window *bw, if (!done) { struct box *layout = html_get_box_tree(h); - if (text_box && - (mouse & (BROWSER_MOUSE_CLICK_1 | - BROWSER_MOUSE_CLICK_2)) && - selection_root(bw->sel) != layout) - selection_init(bw->sel, layout); + if (mouse && (mouse < BROWSER_MOUSE_MOD_1) && + selection_root(&html->sel) != layout) { + selection_init(&html->sel, layout); + } if (text_box) { int pixel_offset; @@ -558,13 +572,13 @@ void html_mouse_action(struct content *c, struct browser_window *bw, &idx, &pixel_offset); - if (selection_click(bw->sel, mouse, + if (selection_click(&html->sel, mouse, text_box->byte_offset + idx)) { /* key presses must be directed at the * main browser window, paste text * operations ignored */ - if (selection_dragging(bw->sel)) { + if (selection_dragging(&html->sel)) { bw->drag_type = DRAGGING_SELECTION; status = @@ -576,7 +590,7 @@ void html_mouse_action(struct content *c, struct browser_window *bw, } } else if (mouse & BROWSER_MOUSE_PRESS_1) - selection_clear(bw->sel, true); + selection_clear(&html->sel, true); } if (!done) { @@ -621,8 +635,7 @@ void html_mouse_action(struct content *c, struct browser_window *bw, } } } - if ((mouse & BROWSER_MOUSE_CLICK_1) && - !selection_defined(bw->sel)) { + if (mouse && mouse < BROWSER_MOUSE_MOD_1) { /* ensure key presses still act on the browser window */ browser_window_remove_caret(bw); } diff --git a/render/html_internal.h b/render/html_internal.h index c736be58a..dc852878a 100644 --- a/render/html_internal.h +++ b/render/html_internal.h @@ -24,6 +24,7 @@ #define NETSURF_RENDER_HTML_INTERNAL_H_ #include "content/content_protected.h" +#include "desktop/selection.h" #include "render/html.h" /** Data specific to CONTENT_HTML. */ @@ -92,6 +93,9 @@ typedef struct html_content { /** Open core-handled form SELECT menu, * or NULL if none currently open. */ struct form_control *visible_select_menu; + + /** Selection state */ + struct selection sel; } html_content; diff --git a/render/html_redraw.c b/render/html_redraw.c index 1b762614c..41b78314a 100644 --- a/render/html_redraw.c +++ b/render/html_redraw.c @@ -52,16 +52,16 @@ #include "utils/utils.h" -static bool html_redraw_box(html_content *html, struct box *box, int x, int y, - const struct rect *clip, float scale, +static bool html_redraw_box(const html_content *html, struct box *box, + int x, int y, const struct rect *clip, float scale, colour current_background_color, const struct redraw_context *ctx); -static bool html_redraw_box_children(html_content *html, struct box *box, +static bool html_redraw_box_children(const html_content *html, struct box *box, int x_parent, int y_parent, const struct rect *clip, float scale, colour current_background_color, const struct redraw_context *ctx); -static bool html_redraw_text_box(struct box *box, int x, int y, - const struct rect *clip, float scale, +static bool html_redraw_text_box(const html_content *html, struct box *box, + int x, int y, const struct rect *clip, float scale, colour current_background_color, const struct redraw_context *ctx); static bool html_redraw_borders(struct box *box, int x_parent, int y_parent, @@ -253,7 +253,7 @@ static struct box *html_redraw_find_bg_box(struct box *box) * x, y, clip_[xy][01] are in target coordinates. */ -bool html_redraw_box(html_content *html, struct box *box, +bool html_redraw_box(const html_content *html, struct box *box, int x_parent, int y_parent, const struct rect *clip, float scale, colour current_background_color, @@ -692,7 +692,7 @@ bool html_redraw_box(html_content *html, struct box *box, return false; } else if (box->text) { - if (!html_redraw_text_box(box, x, y, &r, scale, + if (!html_redraw_text_box(html, box, x, y, &r, scale, current_background_color, ctx)) return false; @@ -770,7 +770,7 @@ bool html_redraw_box(html_content *html, struct box *box, * \return true if successful, false otherwise */ -bool html_redraw_box_children(html_content *html, struct box *box, +bool html_redraw_box_children(const html_content *html, struct box *box, int x_parent, int y_parent, const struct rect *clip, float scale, colour current_background_color, @@ -818,8 +818,8 @@ bool html_redraw_box_children(html_content *html, struct box *box, * \return true iff successful and redraw should proceed */ -bool html_redraw_text_box(struct box *box, int x, int y, - const struct rect *clip, float scale, +bool html_redraw_text_box(const html_content *html, struct box *box, + int x, int y, const struct rect *clip, float scale, colour current_background_color, const struct redraw_context *ctx) { @@ -831,7 +831,7 @@ bool html_redraw_text_box(struct box *box, int x, int y, if (!text_redraw(box->text, box->length, box->byte_offset, box->space, &fstyle, x, y, - clip, box->height, scale, excluded, ctx)) + clip, box->height, scale, excluded, &html->sel, ctx)) return false; return true; @@ -859,7 +859,7 @@ bool html_redraw_text_box(struct box *box, int x, int y, bool text_redraw(const char *utf8_text, size_t utf8_len, size_t offset, int space, const plot_font_style_t *fstyle, int x, int y, const struct rect *clip, int height, - float scale, bool excluded, + float scale, bool excluded, const struct selection *sel, const struct redraw_context *ctx) { const struct plotter_table *plot = ctx->plot; @@ -876,9 +876,9 @@ bool text_redraw(const char *utf8_text, size_t utf8_len, unsigned end_idx; /* first try the browser window's current selection */ - if (selection_defined(current_redraw_browser->sel) && - selection_highlighted(current_redraw_browser->sel, - offset, offset + len, &start_idx, &end_idx)) { + if (selection_defined(sel) && selection_highlighted(sel, + offset, offset + len, + &start_idx, &end_idx)) { highlighted = true; } diff --git a/render/textinput.c b/render/textinput.c index 114c1c818..1a205f748 100644 --- a/render/textinput.c +++ b/render/textinput.c @@ -258,8 +258,8 @@ static bool textinput_textbox_insert(struct content *c, struct box *input = text_box->parent->parent; bool hide; - if (html->bw && html->bw->sel->defined) - textinput_delete_selection(c, html->bw->sel); + if (html->bw && html->sel.defined) + textinput_delete_selection(c, &html->sel); /* insert into form gadget (text and password inputs only) */ if (input->gadget && (input->gadget->type == GADGET_TEXTBOX || @@ -402,8 +402,8 @@ bool textinput_textbox_delete(struct content *c, struct box *text_box, unsigned next_offset = char_offset + utf8_len; struct box *form = text_box->parent->parent; - if (html->bw && html->bw->sel->defined) { - textinput_delete_selection(c, html->bw->sel); + if (html->bw && html->sel.defined) { + textinput_delete_selection(c, &html->sel); return true; } @@ -1113,7 +1113,7 @@ bool textinput_textarea_callback(struct browser_window *bw, uint32_t key, char utf8[6]; unsigned int utf8_len; bool scrolled, reflow = false; - bool selection_exists = html->bw->sel->defined; + bool selection_exists = html->sel.defined; plot_font_style_t fstyle; /* box_dump(textarea, 0); */ @@ -1192,7 +1192,7 @@ bool textinput_textarea_callback(struct browser_window *bw, uint32_t key, /* Clear the selection, if one exists */ if (selection_exists) - selection_clear(html->bw->sel, false); + selection_clear(&html->sel, false); textinput_textarea_cut(c, start_box, 0, text_box, char_offset, false); @@ -1208,7 +1208,7 @@ bool textinput_textarea_callback(struct browser_window *bw, uint32_t key, /* Clear the selection, if one exists */ if (selection_exists) - selection_clear(html->bw->sel, false); + selection_clear(&html->sel, false); if (end_box != text_box || char_offset < text_box->length + SPACE_LEN(text_box)) { @@ -1293,7 +1293,7 @@ bool textinput_textarea_callback(struct browser_window *bw, uint32_t key, /* Clear the selection, if one exists */ if (selection_exists) - selection_clear(html->bw->sel, false); + selection_clear(&html->sel, false); textinput_textarea_cut(c, start_box, 0, end_box, end_box->length, false); @@ -1317,11 +1317,11 @@ bool textinput_textarea_callback(struct browser_window *bw, uint32_t key, { size_t start_idx, end_idx; struct box *start_box = - selection_get_start(html->bw->sel, &start_idx); - struct box *end_box = selection_get_end(html->bw->sel, &end_idx); + selection_get_start(&html->sel, &start_idx); + struct box *end_box = selection_get_end(&html->sel, &end_idx); if (start_box && end_box) { - selection_clear(html->bw->sel, false); + selection_clear(&html->sel, false); textinput_textarea_cut(c, start_box, start_idx, end_box, end_idx, true); text_box = start_box; @@ -1334,7 +1334,7 @@ bool textinput_textarea_callback(struct browser_window *bw, uint32_t key, case KEY_RIGHT: if (selection_exists) { /* In selection, move caret to end */ - text_box = selection_get_end(html->bw->sel, &char_offset); + text_box = selection_get_end(&html->sel, &char_offset); } else if (char_offset < text_box->length) { /* Within-box movement */ char_offset = utf8_next(text_box->text, @@ -1355,7 +1355,7 @@ bool textinput_textarea_callback(struct browser_window *bw, uint32_t key, case KEY_LEFT: if (selection_exists) { /* In selection, move caret to start */ - text_box = selection_get_start(html->bw->sel, &char_offset); + text_box = selection_get_start(&html->sel, &char_offset); } else if (char_offset > 0) { /* Within-box movement */ char_offset = utf8_prev(text_box->text, char_offset); @@ -1373,7 +1373,7 @@ bool textinput_textarea_callback(struct browser_window *bw, uint32_t key, break; case KEY_UP: - selection_clear(html->bw->sel, true); + selection_clear(&html->sel, true); textinput_textarea_click(c, BROWSER_MOUSE_CLICK_1, textarea, box_x, box_y, @@ -1382,7 +1382,7 @@ bool textinput_textarea_callback(struct browser_window *bw, uint32_t key, return true; case KEY_DOWN: - selection_clear(html->bw->sel, true); + selection_clear(&html->sel, true); textinput_textarea_click(c, BROWSER_MOUSE_CLICK_1, textarea, box_x, box_y, @@ -1458,7 +1458,7 @@ bool textinput_textarea_callback(struct browser_window *bw, uint32_t key, bool in_word; /* if there is a selection, caret should move to the end */ if (selection_exists) { - text_box = selection_get_end(html->bw->sel, &char_offset); + text_box = selection_get_end(&html->sel, &char_offset); break; } @@ -1572,7 +1572,7 @@ bool textinput_textarea_callback(struct browser_window *bw, uint32_t key, nsfont.font_width(&fstyle, text_box->text, char_offset, &pixel_offset); - selection_clear(html->bw->sel, true); + selection_clear(&html->sel, true); textarea->gadget->caret_inline_container = inline_container; textarea->gadget->caret_text_box = text_box; @@ -1804,7 +1804,7 @@ bool textinput_input_callback(struct browser_window *bw, uint32_t key, char utf8[6]; unsigned int utf8_len; bool to_textarea = false; - bool selection_exists = html->bw->sel->defined; + bool selection_exists = html->sel.defined; input->gadget->caret_form_offset = textinput_get_form_offset(input, text_box, box_offset); @@ -1813,7 +1813,7 @@ bool textinput_input_callback(struct browser_window *bw, uint32_t key, input->gadget->caret_form_offset = textinput_get_form_offset(input, text_box, box_offset); - selection_get_end(html->bw->sel, &end_offset); + selection_get_end(&html->sel, &end_offset); box_coords(input, &box_x, &box_y); @@ -1905,7 +1905,7 @@ bool textinput_input_callback(struct browser_window *bw, uint32_t key, case KEY_NL: case KEY_CR: /* Return/Enter hit */ - selection_clear(html->bw->sel, true); + selection_clear(&html->sel, true); if (form) form_submit(bw->current_content, bw, form, 0); @@ -1936,7 +1936,7 @@ bool textinput_input_callback(struct browser_window *bw, uint32_t key, case KEY_CUT_LINE: /* Clear the selection, if one exists */ if (selection_exists) - selection_clear(html->bw->sel, false); + selection_clear(&html->sel, false); textinput_textarea_cut(c, text_box, 0, text_box, text_box->length, false); @@ -1957,11 +1957,11 @@ bool textinput_input_callback(struct browser_window *bw, uint32_t key, { size_t start_idx, end_idx; struct box *start_box = - selection_get_start(html->bw->sel, &start_idx); - struct box *end_box = selection_get_end(html->bw->sel, &end_idx); + selection_get_start(&html->sel, &start_idx); + struct box *end_box = selection_get_end(&html->sel, &end_idx); if (start_box && end_box) { - selection_clear(html->bw->sel, false); + selection_clear(&html->sel, false); textinput_textarea_cut(c, start_box, start_idx, end_box, end_idx, true); @@ -2026,7 +2026,7 @@ bool textinput_input_callback(struct browser_window *bw, uint32_t key, case KEY_DELETE_LINE_START: if (selection_exists) - selection_clear(html->bw->sel, true); + selection_clear(&html->sel, true); if (box_offset == 0) return true; @@ -2040,7 +2040,7 @@ bool textinput_input_callback(struct browser_window *bw, uint32_t key, case KEY_DELETE_LINE_END: if (selection_exists) - selection_clear(html->bw->sel, true); + selection_clear(&html->sel, true); if (box_offset >= text_box->length) return true; @@ -2055,7 +2055,7 @@ bool textinput_input_callback(struct browser_window *bw, uint32_t key, return false; } - selection_clear(html->bw->sel, true); + selection_clear(&html->sel, true); textinput_input_update_display(c, input, box_offset, to_textarea, changed); diff --git a/render/textplain.c b/render/textplain.c index 247afc90d..58a94c41d 100644 --- a/render/textplain.c +++ b/render/textplain.c @@ -67,6 +67,8 @@ typedef struct textplain_content { struct textplain_line *physical_line; int formatted_width; struct browser_window *bw; + + struct selection sel; /** Selection state */ } textplain_content; @@ -109,6 +111,7 @@ static void textplain_open(struct content *c, struct browser_window *bw, struct content *page, struct box *box, struct object_params *params); void textplain_close(struct content *c); +struct selection *textplain_get_selection(struct content *c); static nserror textplain_clone(const struct content *old, struct content **newc); static content_type textplain_content_type(lwc_string *mime_type); @@ -134,6 +137,7 @@ static const content_handler textplain_content_handler = { .redraw = textplain_redraw, .open = textplain_open, .close = textplain_close, + .get_selection = textplain_get_selection, .clone = textplain_clone, .type = textplain_content_type, .no_share = true, @@ -288,6 +292,8 @@ nserror textplain_create_internal(textplain_content *c, lwc_string *encoding) c->formatted_width = 0; c->bw = NULL; + selection_prepare(&c->sel); + return NSERROR_OK; no_memory: @@ -616,6 +622,22 @@ content_type textplain_content_type(lwc_string *mime_type) void textplain_mouse_track(struct content *c, struct browser_window *bw, browser_mouse_state mouse, int x, int y) { + textplain_content *text = (textplain_content *) c; + hlcache_handle *h = bw->current_content; + + if (bw->drag_type == DRAGGING_SELECTION && !mouse) { + int dir = -1; + size_t idx; + + if (selection_dragging_start(&text->sel)) + dir = 1; + + idx = textplain_offset_from_coords(h, x, y, dir); + selection_track(&text->sel, mouse, idx); + + browser_window_set_drag_type(bw, DRAGGING_NONE); + } + switch (bw->drag_type) { case DRAGGING_SELECTION: { @@ -623,10 +645,10 @@ void textplain_mouse_track(struct content *c, struct browser_window *bw, int dir = -1; size_t idx; - if (selection_dragging_start(bw->sel)) dir = 1; + if (selection_dragging_start(&text->sel)) dir = 1; idx = textplain_offset_from_coords(h, x, y, dir); - selection_track(bw->sel, mouse, idx); + selection_track(&text->sel, mouse, idx); } break; @@ -650,20 +672,19 @@ void textplain_mouse_track(struct content *c, struct browser_window *bw, void textplain_mouse_action(struct content *c, struct browser_window *bw, browser_mouse_state mouse, int x, int y) { + textplain_content *text = (textplain_content *) c; hlcache_handle *h = bw->current_content; gui_pointer_shape pointer = GUI_POINTER_DEFAULT; const char *status = 0; size_t idx; int dir = 0; - bw->drag_type = DRAGGING_NONE; - - if (!bw->sel) return; + browser_window_set_drag_type(bw, DRAGGING_NONE); idx = textplain_offset_from_coords(h, x, y, dir); - if (selection_click(bw->sel, mouse, idx)) { + if (selection_click(&text->sel, mouse, idx)) { - if (selection_dragging(bw->sel)) { + if (selection_dragging(&text->sel)) { bw->drag_type = DRAGGING_SELECTION; status = messages_get("Selecting"); } @@ -751,7 +772,7 @@ bool textplain_redraw(struct content *c, struct content_redraw_data *data, x = (x + MARGIN) * data->scale; y = (y + MARGIN) * data->scale; for (lineno = line0; lineno != line1; lineno++) { - const char *text = utf8_data + line[lineno].start; + const char *text_d = utf8_data + line[lineno].start; int tab_width = textplain_tab_width * data->scale; size_t offset = 0; int tx = x; @@ -767,22 +788,22 @@ bool textplain_redraw(struct content *c, struct content_redraw_data *data, int width; int ntx; - while (next_offset < length && text[next_offset] != '\t') - next_offset = utf8_next(text, length, next_offset); + while (next_offset < length && text_d[next_offset] != '\t') + next_offset = utf8_next(text_d, length, next_offset); - if (!text_redraw(text + offset, next_offset - offset, + if (!text_redraw(text_d + offset, next_offset - offset, line[lineno].start + offset, 0, &textplain_style, tx, y + (lineno * scaled_line_height), clip, line_height, data->scale, false, - ctx)) + &text->sel, ctx)) return false; if (next_offset >= length) break; /* locate end of string and align to next tab position */ - if (nsfont.font_width(&textplain_style, &text[offset], + if (nsfont.font_width(&textplain_style, &text_d[offset], next_offset - offset, &width)) tx += (int)(width * data->scale); @@ -794,7 +815,7 @@ bool textplain_redraw(struct content *c, struct content_redraw_data *data, if (bw) { unsigned tab_ofst = line[lineno].start + next_offset; - struct selection *sel = bw->sel; + struct selection *sel = &text->sel; bool highlighted = false; if (selection_defined(sel)) { @@ -845,7 +866,9 @@ void textplain_open(struct content *c, struct browser_window *bw, text->bw = bw; - selection_set_browser_window(bw->sel, bw); + /* text selection */ + selection_set_browser_window(&text->sel, bw); + selection_init(&text->sel, NULL); } @@ -857,12 +880,23 @@ void textplain_close(struct content *c) { textplain_content *text = (textplain_content *) c; - if (text->bw && text->bw->sel) - selection_set_browser_window(text->bw->sel, NULL); + selection_set_browser_window(&text->sel, NULL); text->bw = NULL; } + +/** + * Return an textplain content's selection context + */ + +struct selection *textplain_get_selection(struct content *c) +{ + textplain_content *text = (textplain_content *) c; + + return &text->sel; +} + /** * Retrieve number of lines in content * diff --git a/riscos/window.c b/riscos/window.c index dbbfb81be..37a68432e 100644 --- a/riscos/window.c +++ b/riscos/window.c @@ -2580,7 +2580,7 @@ bool ro_gui_window_menu_prepare(wimp_w w, wimp_i i, wimp_menu *menu, ro_gui_menu_set_entry_shaded(menu, BROWSER_SELECTION_CUT, !browser_window_has_selection(bw) || - selection_read_only(bw->sel)); + selection_read_only(browser_window_get_selection(bw))); ro_gui_menu_set_entry_shaded(menu, BROWSER_SELECTION_PASTE, h == NULL || bw->paste_callback == NULL); @@ -2726,7 +2726,8 @@ void ro_gui_window_menu_warning(wimp_w w, wimp_i i, wimp_menu *menu, case BROWSER_SELECTION_SAVE: if (browser_window_has_selection(bw)) ro_gui_save_prepare(GUI_SAVE_TEXT_SELECTION, NULL, - bw->sel, NULL, NULL); + browser_window_get_selection(bw), + NULL, NULL); break; case BROWSER_SAVE_URL_URI: @@ -3069,7 +3070,8 @@ bool ro_gui_window_menu_select(wimp_w w, wimp_i i, wimp_menu *menu, case BROWSER_SELECTION_SAVE: if (h != NULL) { ro_gui_save_prepare(GUI_SAVE_TEXT_SELECTION, NULL, - bw->sel, NULL, NULL); + browser_window_get_selection(bw), + NULL, NULL); ro_gui_dialog_open_persistent(g->window, dialog_saveas, false); } -- cgit v1.2.3