diff options
Diffstat (limited to 'render/html_interaction.c')
-rw-r--r-- | render/html_interaction.c | 359 |
1 files changed, 300 insertions, 59 deletions
diff --git a/render/html_interaction.c b/render/html_interaction.c index 3f1bee475..d734c6b9f 100644 --- a/render/html_interaction.c +++ b/render/html_interaction.c @@ -223,54 +223,7 @@ static size_t html_selection_drag_end(struct html_content *html, 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; - union html_drag_owner drag_owner; - - if (html->drag_type == HTML_DRAG_SELECTION && !mouse) { - /* End of selection drag */ - int dir = -1; - size_t idx; - - if (selection_dragging_start(&html->sel)) - dir = 1; - - idx = html_selection_drag_end(html, mouse, x, y, dir); - - if (idx != 0) - selection_track(&html->sel, mouse, idx); - - drag_owner.no_owner = true; - html_set_drag_type(html, HTML_DRAG_NONE, drag_owner, NULL); - } - - if (html->drag_type == HTML_DRAG_SELECTION) { - /* Selection drag */ - struct box *box; - int dir = -1; - int dx, dy; - - if (selection_dragging_start(&html->sel)) - dir = 1; - - box = box_pick_text_box(html, x, y, dir, &dx, &dy); - - if (box != NULL) { - int pixel_offset; - size_t idx; - plot_font_style_t fstyle; - - font_plot_style_from_css(box->style, &fstyle); - - nsfont.font_position_in_string(&fstyle, - box->text, box->length, - dx, &idx, &pixel_offset); - - selection_track(&html->sel, mouse, - box->byte_offset + idx); - } - } else { - html_mouse_action(c, bw, mouse, x, y); - } + html_mouse_action(c, bw, mouse, x, y); } @@ -323,6 +276,11 @@ void html_mouse_action(struct content *c, struct browser_window *bw, browser_drag_type drag_type = browser_window_get_drag_type(bw); union content_msg_data msg_data; struct dom_node *node = NULL; + union html_drag_owner drag_owner; + union html_selection_owner sel_owner; + bool click = mouse & (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_PRESS_2 | + BROWSER_MOUSE_CLICK_1 | BROWSER_MOUSE_CLICK_2 | + BROWSER_MOUSE_DRAG_1 | BROWSER_MOUSE_DRAG_2); if (drag_type != DRAGGING_NONE && !mouse && html->visible_select_menu != NULL) { @@ -349,7 +307,55 @@ void html_mouse_action(struct content *c, struct browser_window *bw, &width, &height); html->visible_select_menu = NULL; browser_window_redraw_rect(bw, box_x, box_y, - width, height); + width, height); + } + return; + } + + if (html->drag_type == HTML_DRAG_SELECTION) { + /* Selection drag */ + + if (!mouse) { + /* End of selection drag */ + int dir = -1; + size_t idx; + + if (selection_dragging_start(&html->sel)) + dir = 1; + + idx = html_selection_drag_end(html, mouse, x, y, dir); + + if (idx != 0) + selection_track(&html->sel, mouse, idx); + + drag_owner.no_owner = true; + html_set_drag_type(html, HTML_DRAG_NONE, + drag_owner, NULL); + return; + } + + struct box *box; + int dir = -1; + int dx, dy; + + if (selection_dragging_start(&html->sel)) + dir = 1; + + box = box_pick_text_box(html, x, y, dir, &dx, &dy); + + if (box != NULL) { + int pixel_offset; + size_t idx; + plot_font_style_t fstyle; + + font_plot_style_from_css(box->style, &fstyle); + + nsfont.font_position_in_string(&fstyle, + box->text, box->length, + dx, &idx, &pixel_offset); + + selection_track(&html->sel, mouse, + box->byte_offset + idx); } return; } @@ -413,6 +419,16 @@ void html_mouse_action(struct content *c, struct browser_window *bw, return; } + if (html->drag_type == HTML_DRAG_CONTENT_SELECTION) { + box = html->drag_owner.content; + assert(box->object != NULL); + + box_coords(box, &box_x, &box_y); + content_mouse_track(box->object, bw, mouse, + x - box_x, y - box_y); + return; + } + /* Content related drags handled by now */ assert(html->drag_type == HTML_DRAG_NONE); @@ -536,7 +552,8 @@ void html_mouse_action(struct content *c, struct browser_window *bw, /* mouse inside padding box */ if ((box->scroll_y != NULL) && - (x > (padding_right - SCROLLBAR_WIDTH))) { + (x > (padding_right - + SCROLLBAR_WIDTH))) { /* mouse above vertical box scroll */ scrollbar = box->scroll_y; @@ -546,7 +563,8 @@ void html_mouse_action(struct content *c, struct browser_window *bw, break; } else if ((box->scroll_x != NULL) && - (y > (padding_bottom - SCROLLBAR_WIDTH))) { + (y > (padding_bottom - + SCROLLBAR_WIDTH))) { /* mouse above horizontal box scroll */ scrollbar = box->scroll_x; @@ -628,6 +646,15 @@ void html_mouse_action(struct content *c, struct browser_window *bw, pointer = get_pointer_shape(gadget_box, false); + if (click && (html->selection_type != + HTML_SELECTION_TEXTAREA || + html->selection_owner.textarea != + gadget_box)) { + sel_owner.none = true; + html_set_selection(html, HTML_SELECTION_NONE, + sel_owner, true); + } + textarea_mouse_action(gadget->data.text.ta, mouse, x - gadget_box_x, y - gadget_box_y); break; @@ -679,6 +706,14 @@ void html_mouse_action(struct content *c, struct browser_window *bw, x - pos_x, y - pos_y); } } else if (html_object_box) { + + if (click && (html->selection_type != HTML_SELECTION_CONTENT || + html->selection_owner.content != + html_object_box)) { + sel_owner.none = true; + html_set_selection(html, HTML_SELECTION_NONE, + sel_owner, true); + } if (mouse & BROWSER_MOUSE_CLICK_1 || mouse & BROWSER_MOUSE_CLICK_2) { content_mouse_action(html_object_box->object, @@ -738,11 +773,18 @@ void html_mouse_action(struct content *c, struct browser_window *bw, /* if clicking in the main page, remove the selection from any * text areas */ if (!done) { - struct box *layout = html->layout; - - if (mouse && (mouse < BROWSER_MOUSE_MOD_1) && - selection_root(&html->sel) != layout) { - selection_init(&html->sel, layout); + + if (click && html->focus_type != HTML_FOCUS_SELF) { + union html_focus_owner fo; + fo.self = true; + html_set_focus(html, HTML_FOCUS_SELF, fo, + true, 0, 0, 0, NULL); + } + if (click && html->selection_type != + HTML_SELECTION_SELF) { + sel_owner.none = true; + html_set_selection(html, HTML_SELECTION_NONE, + sel_owner, true); } if (text_box) { @@ -781,8 +823,24 @@ void html_mouse_action(struct content *c, struct browser_window *bw, done = true; } - } else if (mouse & BROWSER_MOUSE_PRESS_1) + } else if (mouse & BROWSER_MOUSE_PRESS_1) { + union html_selection_owner sel_owner; + sel_owner.none = true; selection_clear(&html->sel, true); + } + + if (selection_defined(&html->sel)) { + sel_owner.none = false; + html_set_selection(html, HTML_SELECTION_SELF, + sel_owner, + selection_read_only( + &html->sel)); + } else if (click && html->selection_type != + HTML_SELECTION_NONE) { + sel_owner.none = true; + html_set_selection(html, HTML_SELECTION_NONE, + sel_owner, true); + } } if (!done) { @@ -832,7 +890,10 @@ void html_mouse_action(struct content *c, struct browser_window *bw, } if (mouse && mouse < BROWSER_MOUSE_MOD_1) { /* ensure key presses still act on the browser window */ - browser_window_remove_caret(bw); + union html_focus_owner fo; + fo.self = true; + html_set_focus(html, HTML_FOCUS_SELF, fo, + true, 0, 0, 0, NULL); } } @@ -876,6 +937,61 @@ void html_mouse_action(struct content *c, struct browser_window *bw, /** + * Handle keypresses. + * + * \param c content of type CONTENT_TEXTPLAIN + * \param key The UCS4 character codepoint + * \return true if key handled, false otherwise + */ + +bool html_keypress(struct content *c, uint32_t key) +{ + html_content *html = (html_content *) c; + struct selection *sel = &html->sel; + struct box *box; + + switch (html->focus_type) { + case HTML_FOCUS_CONTENT: + box = html->focus_owner.content; + return content_keypress(box->object, key); + + case HTML_FOCUS_TEXTAREA: + box = html->focus_owner.textarea; + return textarea_keypress(box->gadget->data.text.ta, key); + + default: + /* Deal with it below */ + break; + } + + switch (key) { + case KEY_COPY_SELECTION: + selection_copy_to_clipboard(sel); + return true; + + case KEY_CLEAR_SELECTION: + selection_clear(sel, true); + return true; + + case KEY_SELECT_ALL: + selection_select_all(sel); + return true; + + case KEY_ESCAPE: + if (selection_defined(sel)) { + selection_clear(sel, true); + return true; + } + + /* if there's no selection, leave Escape for the caller */ + return false; + } + + return false; +} + + +/** * Callback for in-page scrollbars. */ void html_overflow_scroll_callback(void *client_data, @@ -985,6 +1101,131 @@ void html_set_drag_type(html_content *html, html_drag_type drag_type, } msg_data.drag.rect = rect; - /* Inform the content's drag status change */ + /* Inform of the content's drag status change */ content_broadcast((struct content *)html, CONTENT_MSG_DRAG, msg_data); } + +/* Documented in html_internal.h */ +void html_set_focus(html_content *html, html_focus_type focus_type, + union html_focus_owner focus_owner, bool hide_caret, + int x, int y, int height, const struct rect *clip) +{ + union content_msg_data msg_data; + int x_off = 0; + int y_off = 0; + bool textarea_lost_focus = html->focus_type == HTML_FOCUS_TEXTAREA && + focus_type != HTML_FOCUS_TEXTAREA; + + assert(html != NULL); + + switch (focus_type) { + case HTML_FOCUS_SELF: + assert(focus_owner.self == true); + if (html->focus_type == HTML_FOCUS_SELF) + /* Don't need to tell anyone anything */ + return; + break; + + case HTML_FOCUS_CONTENT: + box_coords(focus_owner.content, &x_off, &y_off); + break; + + case HTML_FOCUS_TEXTAREA: + box_coords(focus_owner.textarea, &x_off, &y_off); + break; + } + + html->focus_type = focus_type; + html->focus_owner = focus_owner; + + if (textarea_lost_focus) { + msg_data.caret.type = CONTENT_CARET_REMOVE; + } else if (focus_type != HTML_FOCUS_SELF && hide_caret) { + msg_data.caret.type = CONTENT_CARET_HIDE; + } else { + msg_data.caret.type = CONTENT_CARET_SET_POS; + msg_data.caret.pos.x = x + x_off; + msg_data.caret.pos.y = y + y_off; + msg_data.caret.pos.height = height; + msg_data.caret.pos.clip = clip; + } + + /* Inform of the content's drag status change */ + content_broadcast((struct content *)html, CONTENT_MSG_CARET, msg_data); +} + +/* Documented in html_internal.h */ +void html_set_selection(html_content *html, html_selection_type selection_type, + union html_selection_owner selection_owner, bool read_only) +{ + union content_msg_data msg_data; + struct box *box; + bool changed = false; + bool same_type = html->selection_type == selection_type; + + assert(html != NULL); + + if ((selection_type == HTML_SELECTION_NONE && + html->selection_type != HTML_SELECTION_NONE) || + (selection_type != HTML_SELECTION_NONE && + html->selection_type == HTML_SELECTION_NONE)) + /* Existance of selection has changed, and we'll need to + * inform our owner */ + changed = true; + + /* Clear any existing selection */ + if (html->selection_type != HTML_SELECTION_NONE) { + switch (html->selection_type) { + case HTML_SELECTION_SELF: + if (same_type) + break; + selection_clear(&html->sel, true); + break; + case HTML_SELECTION_TEXTAREA: + if (same_type && html->selection_owner.textarea == + selection_owner.textarea) + break; + box = html->selection_owner.textarea; + textarea_clear_selection(box->gadget->data.text.ta); + break; + case HTML_SELECTION_CONTENT: + if (same_type && html->selection_owner.content == + selection_owner.content) + break; + box = html->selection_owner.content; + content_clear_selection(box->object); + break; + default: + break; + } + } + + html->selection_type = selection_type; + html->selection_owner = selection_owner; + + if (!changed) + /* Don't need to report lack of change to owner */ + return; + + /* Prepare msg */ + switch (selection_type) { + case HTML_SELECTION_NONE: + assert(selection_owner.none == true); + msg_data.selection.selection = false; + break; + case HTML_SELECTION_SELF: + assert(selection_owner.none == false); + /* fall through */ + case HTML_SELECTION_TEXTAREA: + case HTML_SELECTION_CONTENT: + msg_data.selection.selection = true; + break; + default: + break; + } + msg_data.selection.read_only = read_only; + + /* Inform of the content's selection status change */ + content_broadcast((struct content *)html, CONTENT_MSG_SELECTION, + msg_data); +} |