From 762e1aad733c4d56edbb85c7b21b0951d8f759f2 Mon Sep 17 00:00:00 2001 From: Michael Drake Date: Wed, 6 Feb 2013 22:39:45 +0000 Subject: First pass at getting html forms to use textarea widget. (Input element types text & password, and textarea element.) Can edit and submit forms, but there are loads of issues. --- render/box_construct.c | 164 +++++++-------------------- render/box_textarea.c | 275 ++++++++++++++++++++++++++++++++++++++++++++++ render/box_textarea.h | 44 ++++++++ render/form.c | 87 +++++---------- render/form.h | 12 ++ render/html.c | 1 + render/html.h | 1 + render/html_forms.c | 3 +- render/html_interaction.c | 93 ++-------------- render/html_internal.h | 7 +- render/html_redraw.c | 20 +++- render/layout.c | 15 +++ 12 files changed, 447 insertions(+), 275 deletions(-) create mode 100644 render/box_textarea.c create mode 100644 render/box_textarea.h (limited to 'render') diff --git a/render/box_construct.c b/render/box_construct.c index 52c8cfee5..e5800edf8 100644 --- a/render/box_construct.c +++ b/render/box_construct.c @@ -38,6 +38,7 @@ #include "css/select.h" #include "desktop/options.h" #include "render/box.h" +#include "render/box_textarea.h" #include "render/form.h" #include "render/html_internal.h" #include "utils/corestrings.h" @@ -111,7 +112,6 @@ static bool box_image(BOX_SPECIAL_PARAMS); static bool box_textarea(BOX_SPECIAL_PARAMS); static bool box_select(BOX_SPECIAL_PARAMS); static bool box_input(BOX_SPECIAL_PARAMS); -static bool box_input_text(BOX_SPECIAL_PARAMS, bool password); static bool box_button(BOX_SPECIAL_PARAMS); static bool box_frameset(BOX_SPECIAL_PARAMS); static bool box_create_frameset(struct content_html_frames *f, dom_node *n, @@ -2496,6 +2496,38 @@ bool box_iframe(BOX_SPECIAL_PARAMS) } +/** + * Helper function for adding textarea widget to box. + * + * This is a load of hacks to ensure boxes replaced with textareas + * can be handled by the layout code. + */ + +static bool box_input_text(html_content *html, struct box *box, + struct dom_node *node) +{ + struct box *inline_container, *inline_box; + + box->type = BOX_INLINE_BLOCK; + + inline_container = box_create(NULL, 0, false, 0, 0, 0, 0, html->bctx); + if (!inline_container) + return false; + inline_container->type = BOX_INLINE_CONTAINER; + inline_box = box_create(NULL, box->style, false, 0, 0, box->title, 0, + html->bctx); + if (!inline_box) + return false; + inline_box->type = BOX_TEXT; + inline_box->text = talloc_strdup(html->bctx, ""); + + box_add_child(inline_container, inline_box); + box_add_child(box, inline_container); + + return box_textarea_create_textarea(html, box, node); +} + + /** * Form control [17.4]. */ @@ -2518,7 +2550,7 @@ bool box_input(BOX_SPECIAL_PARAMS) if (type && dom_string_caseless_lwc_isequal(type, corestring_lwc_password)) { - if (box_input_text(n, content, box, 0, true) == false) + if (box_input_text(content, box, n) == false) goto no_memory; } else if (type && dom_string_caseless_lwc_isequal(type, @@ -2620,7 +2652,7 @@ bool box_input(BOX_SPECIAL_PARAMS) } } else { /* the default type is "text" */ - if (box_input_text(n, content, box, 0, false) == false) + if (box_input_text(content, box, n) == false) goto no_memory; } @@ -2638,52 +2670,6 @@ no_memory: } -/** - * Helper function for box_input(). - */ - -bool box_input_text(BOX_SPECIAL_PARAMS, bool password) -{ - struct box *inline_container, *inline_box; - - box->type = BOX_INLINE_BLOCK; - - inline_container = box_create(NULL, 0, false, 0, 0, 0, 0, content->bctx); - if (!inline_container) - return false; - inline_container->type = BOX_INLINE_CONTAINER; - inline_box = box_create(NULL, box->style, false, 0, 0, box->title, 0, - content->bctx); - if (!inline_box) - return false; - inline_box->type = BOX_TEXT; - if (password) { - inline_box->length = strlen(box->gadget->value); - inline_box->text = talloc_array(content->bctx, char, - inline_box->length + 1); - if (!inline_box->text) - return false; - memset(inline_box->text, '*', inline_box->length); - inline_box->text[inline_box->length] = '\0'; - } else { - /* replace spaces/TABs with hard spaces to prevent line - * wrapping */ - char *text = cnv_space2nbsp(box->gadget->value); - if (!text) - return false; - inline_box->text = talloc_strdup(content->bctx, text); - free(text); - if (!inline_box->text) - return false; - inline_box->length = strlen(inline_box->text); - } - box_add_child(inline_container, inline_box); - box_add_child(box, inline_container); - - return true; -} - - /** * Push button [17.5]. */ @@ -2924,90 +2910,16 @@ no_memory: bool box_textarea(BOX_SPECIAL_PARAMS) { - /* A textarea is an INLINE_BLOCK containing a single INLINE_CONTAINER, - * which contains the text as runs of TEXT separated by BR. There is - * at least one TEXT. The first and last boxes are TEXT. - * Consecutive BR may not be present. These constraints are satisfied - * by using a 0-length TEXT for blank lines. */ - - const char *current; - dom_string *area_data = NULL; - dom_exception err; - struct box *inline_container, *inline_box, *br_box; - char *s; - size_t len; - - box->type = BOX_INLINE_BLOCK; + /* Get the form_control for the DOM node */ box->gadget = html_forms_get_control_for_node(content->forms, n); if (box->gadget == NULL) return false; - box->gadget->box = box; - inline_container = box_create(NULL, 0, false, 0, 0, box->title, 0, - content->bctx); - if (inline_container == NULL) - return false; - inline_container->type = BOX_INLINE_CONTAINER; - box_add_child(box, inline_container); + box->gadget->box = box; - err = dom_node_get_text_content(n, &area_data); - if (err != DOM_NO_ERR) + if (!box_input_text(content, box, n)) return false; - if (area_data != NULL) { - current = dom_string_data(area_data); - } else { - /* No content, or failed reading it: use a blank string */ - current = ""; - } - - while (true) { - /* BOX_TEXT */ - len = strcspn(current, "\r\n"); - s = talloc_strndup(content->bctx, current, len); - if (s == NULL) { - if (area_data != NULL) - dom_string_unref(area_data); - return false; - } - - inline_box = box_create(NULL, box->style, false, 0, 0, - box->title, 0, content->bctx); - if (inline_box == NULL) { - if (area_data != NULL) - dom_string_unref(area_data); - return false; - } - inline_box->type = BOX_TEXT; - inline_box->text = s; - inline_box->length = len; - box_add_child(inline_container, inline_box); - - current += len; - if (current[0] == 0) - /* finished */ - break; - - /* BOX_BR */ - br_box = box_create(NULL, box->style, false, 0, 0, box->title, - 0, content->bctx); - if (br_box == NULL) { - if (area_data != NULL) - dom_string_unref(area_data); - return false; - } - br_box->type = BOX_BR; - box_add_child(inline_container, br_box); - - if (current[0] == '\r' && current[1] == '\n') - current += 2; - else - current++; - } - - if (area_data != NULL) - dom_string_unref(area_data); - *convert_children = false; return true; } diff --git a/render/box_textarea.c b/render/box_textarea.c new file mode 100644 index 000000000..3d2455f7c --- /dev/null +++ b/render/box_textarea.c @@ -0,0 +1,275 @@ +/* + * Copyright 2013 Michael Drake + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** \file + * Box tree treeview box replacement (implementation). + */ + +#include + +#include "desktop/browser.h" +#include "desktop/textarea.h" +#include "desktop/textinput.h" +#include "render/box_textarea.h" +#include "render/font.h" +#include "render/form.h" + + +static bool box_textarea_browser_caret_callback(struct browser_window *bw, + uint32_t key, void *p1, void *p2) +{ + struct box *box = p1; + struct form_control *gadget = box->gadget; + struct textarea *ta = gadget->data.text.ta; + struct form* form = box->gadget->form; + html_content *html = p2; + struct content *c = (struct content *) html; + + assert(ta != NULL); + + if (gadget->type != GADGET_TEXTAREA) { + switch (key) { + case KEY_NL: + case KEY_CR: + if (form) + form_submit(content_get_url(c), html->bw, + form, 0); + return true; + + case KEY_TAB: + { + struct form_control *next_input; + /* Find next text entry field that is actually + * displayed (i.e. has an associated box) */ + for (next_input = gadget->next; + next_input && + ((next_input->type != GADGET_TEXTBOX && + next_input->type != GADGET_TEXTAREA && + next_input->type != GADGET_PASSWORD) || + !next_input->box); + next_input = next_input->next) + ; + if (!next_input) + return true; + + textarea_set_caret(ta, -1); + textarea_set_caret(next_input->data.text.ta, 0); + } + return true; + + case KEY_SHIFT_TAB: + { + struct form_control *prev_input; + /* Find previous text entry field that is actually + * displayed (i.e. has an associated box) */ + for (prev_input = gadget->prev; + prev_input && + ((prev_input->type != GADGET_TEXTBOX && + prev_input->type != GADGET_TEXTAREA && + prev_input->type != GADGET_PASSWORD) || + !prev_input->box); + prev_input = prev_input->prev) + ; + if (!prev_input) + return true; + + textarea_set_caret(ta, -1); + textarea_set_caret(prev_input->data.text.ta, 0); + } + return true; + + default: + /* Pass to textarea widget */ + break; + } + } + + return textarea_keypress(ta, key); +} + + +static void box_textarea_browser_move_callback(struct browser_window *bw, + void *p1, void *p2) +{ +} + + +static bool box_textarea_browser_paste_callback(struct browser_window *bw, + const char *utf8, unsigned utf8_len, bool last, + void *p1, void *p2) +{ + printf("AWWOOOOOGA!\n"); + return true; +} + + +/** + * Callback for html form textareas. + */ +static void box_textarea_callback(void *data, struct textarea_msg *msg) +{ + struct form_textarea_data *d = data; + struct content *c = (struct content *)d->html; + struct html_content *html = d->html; + struct form_control *gadget = d->gadget; + struct box *box = gadget->box; + union content_msg_data msg_data; + + switch (msg->type) { + case TEXTAREA_MSG_DRAG_REPORT: + if (msg->data.drag == TEXTAREA_DRAG_NONE) { + /* Textarea drag finished */ + html->textarea = NULL; + + browser_window_set_drag_type(html->bw, + DRAGGING_NONE, NULL); + + msg_data.pointer = BROWSER_POINTER_AUTO; + content_broadcast(c, CONTENT_MSG_POINTER, msg_data); + } else { + /* Textarea drag started */ + struct rect rect = { + .x0 = INT_MIN, + .y0 = INT_MIN, + .x1 = INT_MAX, + .y1 = INT_MAX + }; + browser_drag_type bdt; + + if (msg->data.drag == TEXTAREA_DRAG_SCROLLBAR) + bdt = DRAGGING_CONTENT_TEXTAREA_SCROLLBAR; + else + bdt = DRAGGING_CONTENT_TEXTAREA_SELECTION; + + browser_window_set_drag_type(html->bw, bdt, &rect); + + html->textarea = msg->ta; + } + break; + + case TEXTAREA_MSG_REDRAW_REQUEST: + /* Redraw the textarea */ + /* TODO: don't redraw whole box, just the part asked for */ + html__redraw_a_box(html, box); + break; + + case TEXTAREA_MSG_MOVED_CARET: + if (html->bw == NULL) + break; + + if (msg->data.caret.hidden) { + browser_window_remove_caret(html->bw); + } else { + browser_window_place_caret(html->bw, + msg->data.caret.x, msg->data.caret.y, + msg->data.caret.height, + box_textarea_browser_caret_callback, + box_textarea_browser_paste_callback, + box_textarea_browser_move_callback, + box, html); + } + break; + } +} + + +/* Exported interface, documented in box_textarea.h */ +bool box_textarea_create_textarea(html_content *html, + struct box *box, struct dom_node *node) +{ + dom_string *dom_text = NULL; + dom_exception err; + textarea_setup ta_setup; + textarea_flags ta_flags; + plot_font_style_t fstyle; + struct form_control *gadget = box->gadget; + const char *text; + + /** TODO: Read only textarea */ + + assert(gadget != NULL); + assert(gadget->type == GADGET_TEXTAREA || + gadget->type == GADGET_TEXTBOX || + gadget->type == GADGET_PASSWORD); + + if (gadget->type == GADGET_TEXTAREA) { + ta_flags = TEXTAREA_MULTILINE; + + /* Get the textarea's initial content */ + err = dom_node_get_text_content(node, &dom_text); + if (err != DOM_NO_ERR) + return false; + + } else { + dom_html_input_element *input = (dom_html_input_element *) node; + + if (gadget->type == GADGET_PASSWORD) + ta_flags = TEXTAREA_PASSWORD; + else + ta_flags = TEXTAREA_DEFAULT; + + /* Get initial text */ + err = dom_html_input_element_get_value(input, &dom_text); + if (err != DOM_NO_ERR) + return false; + } + + if (dom_text != NULL) { + text = dom_string_data(dom_text); + } else { + /* No initial text, or failed reading it; + * use a blank string */ + text = ""; + } + + gadget->data.text.data.html = html; + gadget->data.text.data.gadget = gadget; + + font_plot_style_from_css(gadget->box->style, &fstyle); + + /* Reset to correct values by layout */ + ta_setup.width = 200; + ta_setup.height = 20; + ta_setup.pad_top = 4; + ta_setup.pad_right = 4; + ta_setup.pad_bottom = 4; + ta_setup.pad_left = 4; + ta_setup.border_width = 0; + ta_setup.border_col = 0x000000; + ta_setup.selected_text = 0xffffff; + ta_setup.selected_bg = 0x000000; + ta_setup.text = fstyle; + ta_setup.text.foreground = 0x000000; + ta_setup.text.background = NS_TRANSPARENT; + + /* Hand reference to dom text over to gadget */ + gadget->data.text.initial = dom_text; + + gadget->data.text.ta = textarea_create(ta_flags, &ta_setup, + box_textarea_callback, &gadget->data.text.data); + + if (gadget->data.text.ta == NULL) { + return false; + } + + if (!textarea_set_text(gadget->data.text.ta, text)) + return false; + + return true; +} + diff --git a/render/box_textarea.h b/render/box_textarea.h new file mode 100644 index 000000000..30414e816 --- /dev/null +++ b/render/box_textarea.h @@ -0,0 +1,44 @@ +/* + * Copyright 2013 Michael Drake + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** \file + * Box tree treeview box replacement (interface). + */ + + + +#ifndef _NETSURF_RENDER_BOX_TEXTAREA_H_ +#define _NETSURF_RENDER_BOX_TEXTAREA_H_ + + +#include "render/box.h" +#include "render/html_internal.h" + +struct dom_node; + +/** + * Create textarea widget for a form element + * + * \param html html content object + * \param box box with gadget to be given textarea widget + * \param node DOM node for form element + */ +bool box_textarea_create_textarea(html_content *html, + struct box *box, struct dom_node *node); + +#endif diff --git a/render/form.c b/render/form.c index 42e76e1f2..c2819b479 100644 --- a/render/form.c +++ b/render/form.c @@ -43,6 +43,7 @@ #include "desktop/plot_style.h" #include "desktop/plotters.h" #include "desktop/scrollbar.h" +#include "desktop/textarea.h" #include "render/box.h" #include "render/font.h" #include "render/form.h" @@ -85,7 +86,6 @@ static plot_font_style_t plot_fstyle_entry = { .foreground = 0x000000, }; -static char *form_textarea_value(struct form_control *textarea); static char *form_acceptable_charset(struct form *form); static char *form_encode_item(const char *item, const char *charset, const char *fallback); @@ -252,6 +252,17 @@ void form_free_control(struct form_control *control) form_free_select_menu(control); } + if (control->type == GADGET_TEXTAREA || + control->type == GADGET_TEXTBOX || + control->type == GADGET_PASSWORD) { + + if (control->data.text.initial != NULL) + dom_string_unref(control->data.text.initial); + + if (control->data.text.ta != NULL) + textarea_destroy(control->data.text.ta); + } + free(control); } @@ -350,8 +361,6 @@ bool form_successful_controls(struct form *form, switch (control->type) { case GADGET_HIDDEN: - case GADGET_TEXTBOX: - case GADGET_PASSWORD: if (control->value) value = ENCODE_ITEM(control->value); else @@ -416,17 +425,26 @@ bool form_successful_controls(struct form *form, continue; break; + case GADGET_TEXTBOX: + case GADGET_PASSWORD: case GADGET_TEXTAREA: - { + { char *v2; + int ta_len = textarea_get_text( + control->data.text.ta, + NULL, 0); - /* textarea */ - value = form_textarea_value(control); + value = malloc(ta_len); if (!value) { LOG(("failed handling textarea")); goto no_memory; } - if (value[0] == 0) { + textarea_get_text(control->data.text.ta, + value, ta_len); + + if (control->type == GADGET_TEXTAREA && + value[0] == '\0') { + /* Textarea not submitted if empty */ free(value); continue; } @@ -440,7 +458,7 @@ bool form_successful_controls(struct form *form, free(value); value = v2; - } + } break; case GADGET_IMAGE: { @@ -616,59 +634,6 @@ no_memory: } -/** - * Find the value for a textarea control. - * - * \param textarea control of type GADGET_TEXTAREA - * \return the value as a UTF-8 string on heap, or 0 on memory exhaustion - */ -char *form_textarea_value(struct form_control *textarea) -{ - unsigned int len = 0; - char *value, *s; - struct box *text_box; - - /* Textarea may have no associated box if styled with display: none */ - if (textarea->box == NULL) { - /* Return the empty string: caller treats this as a - * non-successful control. */ - return strdup(""); - } - - /* find required length */ - for (text_box = textarea->box->children->children; text_box; - text_box = text_box->next) { - if (text_box->type == BOX_TEXT) - len += text_box->length + 1; - else /* BOX_BR */ - len += 2; - } - - /* construct value */ - s = value = malloc(len + 1); - if (!s) - return NULL; - - for (text_box = textarea->box->children->children; text_box; - text_box = text_box->next) { - if (text_box->type == BOX_TEXT) { - strncpy(s, text_box->text, text_box->length); - s += text_box->length; - if (text_box->next && text_box->next->type != BOX_BR) - /* only add space if this isn't - * the last box on a line (or in the area) */ - *s++ = ' '; - } else { /* BOX_BR */ - *s++ = '\r'; - *s++ = '\n'; - } - } - *s = 0; - - return value; -} - - /** * Encode controls using application/x-www-form-urlencoded. * diff --git a/render/form.h b/render/form.h index 67372d5d5..b5f6a7e2c 100644 --- a/render/form.h +++ b/render/form.h @@ -34,6 +34,7 @@ struct form_control; struct form_option; struct form_select_menu; struct html_content; +struct dom_string; /** Form submit method. */ typedef enum { @@ -73,6 +74,12 @@ typedef enum { GADGET_BUTTON } form_control_type; +/** Data for textarea */ +struct form_textarea_data { + struct html_content *html; + struct form_control *gadget; +}; + /** Form control. */ struct form_control { void *node; /**< Corresponding DOM node */ @@ -111,6 +118,11 @@ struct form_control { struct form_option *current; struct form_select_menu *menu; } select; + struct { + struct textarea *ta; + struct dom_string *initial; + struct form_textarea_data data; + } text; /**< input type=text or textarea */ } data; struct form_control *prev; /**< Previous control in this form */ diff --git a/render/html.c b/render/html.c index 3e26928fd..85e377095 100644 --- a/render/html.c +++ b/render/html.c @@ -344,6 +344,7 @@ html_create_html_data(html_content *c, const http_parameter *params) c->page = NULL; c->font_func = &nsfont; c->scrollbar = NULL; + c->textarea = NULL; c->scripts_count = 0; c->scripts = NULL; c->jscontext = NULL; diff --git a/render/html.h b/render/html.h index e11fc76ac..a9f7967f6 100644 --- a/render/html.h +++ b/render/html.h @@ -46,6 +46,7 @@ struct http_parameter; struct imagemap; struct object_params; struct plotters; +struct textarea; struct scrollbar; struct scrollbar_msg_data; struct search_context; diff --git a/render/html_forms.c b/render/html_forms.c index d1223819a..c80edc6bb 100644 --- a/render/html_forms.c +++ b/render/html_forms.c @@ -523,7 +523,8 @@ invent_fake_gadget(dom_node *node) } /* documented in html_internal.h */ -struct form_control *html_forms_get_control_for_node(struct form *forms, dom_node *node) +struct form_control *html_forms_get_control_for_node(struct form *forms, + dom_node *node) { struct form *f; struct form_control *ctl = NULL; diff --git a/render/html_interaction.c b/render/html_interaction.c index d22869edc..a685241bc 100644 --- a/render/html_interaction.c +++ b/render/html_interaction.c @@ -35,6 +35,7 @@ #include "desktop/options.h" #include "desktop/scrollbar.h" #include "desktop/selection.h" +#include "desktop/textarea.h" #include "desktop/textinput.h" #include "render/box.h" #include "render/font.h" @@ -592,94 +593,18 @@ void html_mouse_action(struct content *c, struct browser_window *bw, status = messages_get("FormBadSubmit"); } break; - case GADGET_TEXTAREA: - status = messages_get("FormTextarea"); - pointer = get_pointer_shape(gadget_box, false); - - if (mouse & (BROWSER_MOUSE_PRESS_1 | - BROWSER_MOUSE_PRESS_2)) { - if (text_box && selection_root(&html->sel) != - gadget_box) - selection_init(&html->sel, gadget_box); - - textinput_textarea_click(c, mouse, - gadget_box, - gadget_box_x, - gadget_box_y, - x - gadget_box_x, - y - gadget_box_y); - } - - if (text_box) { - int pixel_offset; - size_t idx; - - font_plot_style_from_css(text_box->style, - &fstyle); - - nsfont.font_position_in_string(&fstyle, - text_box->text, - text_box->length, - x - gadget_box_x - text_box->x, - &idx, - &pixel_offset); - - selection_click(&html->sel, mouse, - text_box->byte_offset + idx); - - if (selection_dragging(&html->sel)) { - browser_window_set_drag_type(bw, - DRAGGING_SELECTION, - NULL); - status = messages_get("Selecting"); - } - } - else if (mouse & BROWSER_MOUSE_PRESS_1) - selection_clear(&html->sel, true); - break; case GADGET_TEXTBOX: case GADGET_PASSWORD: - status = messages_get("FormTextbox"); - pointer = get_pointer_shape(gadget_box, false); - - if ((mouse & BROWSER_MOUSE_PRESS_1) && - !(mouse & (BROWSER_MOUSE_MOD_1 | - BROWSER_MOUSE_MOD_2))) { - textinput_input_click(c, - gadget_box, - gadget_box_x, - gadget_box_y, - x - gadget_box_x, - y - gadget_box_y); - } - if (text_box) { - int pixel_offset; - size_t idx; - - if (mouse & (BROWSER_MOUSE_DRAG_1 | - BROWSER_MOUSE_DRAG_2)) - selection_init(&html->sel, gadget_box); - - font_plot_style_from_css(text_box->style, - &fstyle); - - nsfont.font_position_in_string(&fstyle, - text_box->text, - text_box->length, - x - gadget_box_x - text_box->x, - &idx, - &pixel_offset); + case GADGET_TEXTAREA: + if (gadget->type == GADGET_TEXTAREA) + status = messages_get("FormTextarea"); + else + status = messages_get("FormTextbox"); - selection_click(&html->sel, mouse, - text_box->byte_offset + idx); + pointer = get_pointer_shape(gadget_box, false); - if (selection_dragging(&html->sel)) - browser_window_set_drag_type(bw, - DRAGGING_SELECTION, - NULL); - } - else if (mouse & BROWSER_MOUSE_PRESS_1) - selection_clear(&html->sel, true); + textarea_mouse_action(gadget->data.text.ta, mouse, + x - gadget_box_x, y - gadget_box_y); break; case GADGET_HIDDEN: /* not possible: no box generated */ diff --git a/render/html_internal.h b/render/html_internal.h index 53021a15a..d09121675 100644 --- a/render/html_internal.h +++ b/render/html_internal.h @@ -102,6 +102,10 @@ typedef struct html_content { * scrollbar, or NULL when no scrollbar drags active */ struct scrollbar *scrollbar; + /** Textarea capturing all mouse events, updated to any active HTML + * textarea, or NULL when no textarea drags active */ + struct textarea *textarea; + /** Open core-handled form SELECT menu, * or NULL if none currently open. */ struct form_control *visible_select_menu; @@ -162,7 +166,8 @@ bool html_scripts_exec(html_content *c); /* in render/html_forms.c */ struct form *html_forms_get_forms(const char *docenc, dom_html_document *doc); -struct form_control *html_forms_get_control_for_node(struct form *forms, dom_node *node); +struct form_control *html_forms_get_control_for_node(struct form *forms, + dom_node *node); /* Useful dom_string pointers */ struct dom_string; diff --git a/render/html_redraw.c b/render/html_redraw.c index e305b7b08..fed5ffdc4 100644 --- a/render/html_redraw.c +++ b/render/html_redraw.c @@ -41,6 +41,7 @@ #include "desktop/options.h" #include "desktop/print.h" #include "desktop/scrollbar.h" +#include "desktop/textarea.h" #include "image/bitmap.h" #include "render/box.h" #include "render/font.h" @@ -2109,7 +2110,11 @@ bool html_redraw_box(const html_content *html, struct box *box, bg_box->type != BOX_TEXT && bg_box->type != BOX_INLINE_END && (bg_box->type != BOX_INLINE || bg_box->object || - bg_box->flags & IFRAME || box->flags & REPLACE_DIM)) { + bg_box->flags & IFRAME || box->flags & REPLACE_DIM || + (bg_box->gadget != NULL && + (bg_box->gadget->type == GADGET_TEXTAREA || + bg_box->gadget->type == GADGET_TEXTBOX || + bg_box->gadget->type == GADGET_PASSWORD)))) { /* find intersection of clip box and border edge */ struct rect p; p.x0 = x - border_left < r.x0 ? r.x0 : x - border_left; @@ -2154,7 +2159,11 @@ bool html_redraw_box(const html_content *html, struct box *box, if (box->style && box->type != BOX_TEXT && box->type != BOX_INLINE_END && (box->type != BOX_INLINE || box->object || - box->flags & IFRAME || box->flags & REPLACE_DIM) && + box->flags & IFRAME || box->flags & REPLACE_DIM || + (box->gadget != NULL && + (box->gadget->type == GADGET_TEXTAREA || + box->gadget->type == GADGET_TEXTBOX || + box->gadget->type == GADGET_PASSWORD))) && (border_top || border_right || border_bottom || border_left)) { if (!html_redraw_borders(box, x_parent, y_parent, @@ -2398,6 +2407,13 @@ bool html_redraw_box(const html_content *html, struct box *box, current_background_color, ctx)) return false; + } else if (box->gadget && + (box->gadget->type == GADGET_TEXTAREA || + box->gadget->type == GADGET_PASSWORD || + box->gadget->type == GADGET_TEXTBOX)) { + textarea_redraw(box->gadget->data.text.ta, + x, y, current_background_color, &r, ctx); + } else if (box->text) { if (!html_redraw_text_box(html, box, x, y, &r, scale, current_background_color, ctx)) diff --git a/render/layout.c b/render/layout.c index 331e1efdb..95903a2bb 100644 --- a/render/layout.c +++ b/render/layout.c @@ -46,6 +46,7 @@ #include "content/content_protected.h" #include "desktop/options.h" #include "desktop/scrollbar.h" +#include "desktop/textarea.h" #include "render/box.h" #include "render/font.h" #include "render/form.h" @@ -650,6 +651,20 @@ bool layout_block_context(struct box *block, int viewport_height, layout_apply_minmax_height(block, NULL); } + if (block->gadget && + (block->gadget->type == GADGET_TEXTAREA || + block->gadget->type == GADGET_PASSWORD || + block->gadget->type == GADGET_TEXTBOX)) { + int ta_width = block->padding[LEFT] + block->width + + block->padding[RIGHT]; + int ta_height = block->padding[TOP] + block->height + + block->padding[BOTTOM]; + textarea_set_layout(block->gadget->data.text.ta, + ta_width, ta_height, + block->padding[TOP], block->padding[RIGHT], + block->padding[BOTTOM], block->padding[LEFT]); + } + return true; } -- cgit v1.2.3