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.
This commit is contained in:
Michael Drake 2013-02-06 22:39:45 +00:00
parent 008cdb42d7
commit 762e1aad73
15 changed files with 461 additions and 290 deletions

View File

@ -11,7 +11,7 @@ S_FETCHERS := curl.c data.c file.c about.c resource.c
S_CSS := css.c dump.c internal.c select.c utils.c
S_RENDER := box.c box_construct.c box_normalise.c \
S_RENDER := box.c box_construct.c box_normalise.c box_textarea.c \
font.c form.c \
html.c html_script.c html_interaction.c html_redraw.c \
html_forms.c imagemap.c layout.c list.c search.c table.c \

View File

@ -57,6 +57,8 @@ typedef enum {
DRAGGING_SCR_X,
DRAGGING_SCR_Y,
DRAGGING_CONTENT_SCROLLBAR,
DRAGGING_CONTENT_TEXTAREA_SCROLLBAR,
DRAGGING_CONTENT_TEXTAREA_SELECTION,
DRAGGING_OTHER
} browser_drag_type;

View File

@ -127,7 +127,13 @@ bool browser_window_key_press(struct browser_window *bw, uint32_t key)
assert(bw->window != NULL);
/* safe keys that can be handled whether input claimed or not */
if (focus->caret_callback) {
/* Pass keypress onto anything that has claimed input focus */
return focus->caret_callback(focus, key,
focus->caret_p1, focus->caret_p2);
}
/* TODO: pass these to content to deal with */
switch (key) {
case KEY_COPY_SELECTION:
selection_copy_to_clipboard(bw->cur_sel);
@ -137,6 +143,10 @@ bool browser_window_key_press(struct browser_window *bw, uint32_t key)
selection_clear(bw->cur_sel, true);
return true;
case KEY_SELECT_ALL:
selection_select_all(bw->cur_sel);
return true;
case KEY_ESCAPE:
if (bw->cur_sel && selection_defined(bw->cur_sel)) {
selection_clear(bw->cur_sel, true);
@ -147,19 +157,6 @@ bool browser_window_key_press(struct browser_window *bw, uint32_t key)
return false;
}
if (focus->caret_callback) {
/* Pass keypress onto anything that has claimed input focus */
return focus->caret_callback(focus, key,
focus->caret_p1, focus->caret_p2);
}
/* keys we can't handle here if cursor is in form */
switch (key) {
case KEY_SELECT_ALL:
selection_select_all(bw->cur_sel);
return true;
}
return false;
}

View File

@ -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,89 +2910,15 @@ 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)
if (!box_input_text(content, box, n))
return false;
inline_container->type = BOX_INLINE_CONTAINER;
box_add_child(box, inline_container);
err = dom_node_get_text_content(n, &area_data);
if (err != DOM_NO_ERR)
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;

275
render/box_textarea.c Normal file
View File

@ -0,0 +1,275 @@
/*
* Copyright 2013 Michael Drake <tlsa@netsurf-browser.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
/** \file
* Box tree treeview box replacement (implementation).
*/
#include <dom/dom.h>
#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;
}

44
render/box_textarea.h Normal file
View File

@ -0,0 +1,44 @@
/*
* Copyright 2013 Michael Drake <tlsa@netsurf-browser.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
/** \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

View File

@ -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.
*

View File

@ -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 */

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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");
case GADGET_TEXTAREA:
if (gadget->type == GADGET_TEXTAREA)
status = messages_get("FormTextarea");
else
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);
selection_click(&html->sel, mouse,
text_box->byte_offset + idx);
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 */

View File

@ -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;

View File

@ -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))

View File

@ -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;
}