[project @ 2004-07-19 20:40:11 by joty]

form.h (struct form_control): renamed caret_char_offset to caret_box_offset; Added caret_form_offset & length.
form.c: initialise new entries in struct form_control; form_successful_controls() : code reshuffling to improve readibility.
box.h: TABing.
box.c (box_input): init struct form_control::length.
browser.c (browser_window_input_callback): UTF-8 support. Text area code needs similar changes.

svn path=/import/netsurf/; revision=1117
This commit is contained in:
John Tytgat 2004-07-19 20:40:11 +00:00
parent f94da48139
commit c93b54b07c
5 changed files with 341 additions and 247 deletions

View File

@ -881,7 +881,7 @@ void browser_window_textarea_click(struct browser_window *bw,
textarea->gadget->caret_inline_container = inline_container;
textarea->gadget->caret_text_box = text_box;
textarea->gadget->caret_char_offset = char_offset;
textarea->gadget->caret_box_offset = textarea->gadget->caret_form_offset = char_offset;
textarea->gadget->caret_pixel_offset = pixel_offset;
browser_window_place_caret(bw,
box_x + text_box->x + pixel_offset,
@ -906,7 +906,7 @@ void browser_window_textarea_callback(struct browser_window *bw,
struct box *text_box = textarea->gadget->caret_text_box;
struct box *new_br, *new_text, *t;
struct box *prev;
int char_offset = textarea->gadget->caret_char_offset;
int char_offset = textarea->gadget->caret_box_offset;
int pixel_offset = textarea->gadget->caret_pixel_offset;
int dy;
int box_x, box_y;
@ -1148,7 +1148,7 @@ void browser_window_textarea_callback(struct browser_window *bw,
textarea->gadget->caret_inline_container = inline_container;
textarea->gadget->caret_text_box = text_box;
textarea->gadget->caret_char_offset = char_offset;
textarea->gadget->caret_box_offset = textarea->gadget->caret_form_offset = char_offset;
textarea->gadget->caret_pixel_offset = pixel_offset;
browser_window_place_caret(bw,
box_x + text_box->x + pixel_offset,
@ -1179,10 +1179,13 @@ void browser_window_input_click(struct browser_window* bw,
{
int char_offset, pixel_offset, dx = 0;
struct box *text_box = input->children->children;
int uchars;
unsigned int offset;
nsfont_position_in_string(text_box->font, text_box->text,
text_box->length, x - text_box->x,
&char_offset, &pixel_offset);
assert(char_offset <= text_box->length);
text_box->x = 0;
if ((input->width < text_box->width) &&
@ -1193,7 +1196,31 @@ void browser_window_input_click(struct browser_window* bw,
text_box->x = input->width - text_box->width;
dx -= text_box->x;
}
input->gadget->caret_char_offset = char_offset;
input->gadget->caret_box_offset = char_offset;
/* Update caret_form_offset */
for (uchars = 0, offset = 0; offset < char_offset; ++uchars) {
if ((text_box->text[offset] & 0x80) == 0x00) {
++offset;
continue;
}
assert((text_box->text[offset] & 0xC0) == 0xC0);
for (++offset; offset < char_offset && (text_box->text[offset] & 0xC0) == 0x80; ++offset)
;
}
/* uchars is the number of real Unicode characters at the left
* side of the caret.
*/
for (offset = 0; uchars > 0 && offset < input->gadget->length; --uchars) {
if ((input->gadget->value[offset] & 0x80) == 0x00) {
++offset;
continue;
}
assert((input->gadget->value[offset] & 0xC0) == 0xC0);
for (++offset; offset < input->gadget->length && (input->gadget->value[offset] & 0xC0) == 0x80; ++offset)
;
}
assert(uchars == 0);
input->gadget->caret_form_offset = offset;
input->gadget->caret_pixel_offset = pixel_offset;
browser_window_place_caret(bw,
box_x + text_box->x + pixel_offset,
@ -1213,83 +1240,96 @@ void browser_window_input_click(struct browser_window* bw,
void browser_window_input_callback(struct browser_window *bw,
unsigned int key, void *p)
{
struct box *input = p;
struct box *input = (struct box *)p;
struct box *text_box = input->children->children;
int char_offset = input->gadget->caret_char_offset;
unsigned int box_offset = input->gadget->caret_box_offset;
unsigned int form_offset = input->gadget->caret_form_offset;
int pixel_offset, dx;
int box_x, box_y;
struct form *form = input->gadget->form;
char utf8[5];
unsigned int utf8_len, i;
char *text, *value;
struct form* form = input->gadget->form;
bool changed = false;
box_coords(input, &box_x, &box_y);
if (!(key <= 0x001F || (0x007F <= key && key <= 0x009F))) {
char key_to_insert;
const char *utf8key;
size_t utf8keySize;
/** \todo: text_box has data in UTF-8 and its length in
* bytes is not necessarily equal to number of characters.
*/
if (input->gadget->length >= input->gadget->maxlength)
return;
/* normal character insertion */
/** \todo convert key to UTF-8 properly */
utf8[0] = key;
utf8_len = 1;
/** \todo this is wrong for passwords, because multi-byte
* UTF-8 sequences in the value get only one character in
* the password, so we can't just use char_offset in
* input->gadget->value */
text = realloc(text_box->text, text_box->length + 8);
if (!text) {
warn_user("NoMemory", 0);
/* Insert key in gadget */
key_to_insert = (char)key;
if ((utf8key = cnv_local_enc_str(&key_to_insert, 1)) == NULL)
return;
}
text_box->text = text;
utf8keySize = strlen(utf8key);
input->gadget->value = xrealloc(input->gadget->value, input->gadget->length + utf8keySize + 1);
memmove(input->gadget->value + form_offset + utf8keySize,
input->gadget->value + form_offset,
input->gadget->length - form_offset);
memcpy(input->gadget->value + form_offset, utf8key, utf8keySize);
input->gadget->length += utf8keySize;
input->gadget->value[input->gadget->length] = 0;
form_offset += utf8keySize;
free((void *)utf8key);
value = realloc(input->gadget->value, text_box->length + 8);
if (!value) {
warn_user("NoMemory", 0);
/* Insert key in text box */
/* Convert space into NBSP */
key_to_insert = (input->gadget->type == GADGET_PASSWORD) ? '*' : (key == ' ') ? 160 : key;
if ((utf8key = cnv_local_enc_str(&key_to_insert, 1)) == NULL)
return;
}
input->gadget->value = value;
memmove(input->gadget->value + char_offset + utf8_len,
input->gadget->value + char_offset,
text_box->length - char_offset);
for (i = 0; i != utf8_len; i++)
input->gadget->value[char_offset + i] = key;
if (input->gadget->type == GADGET_PASSWORD) {
text_box->text[text_box->length] = '*';
text_box->length++;
char_offset++;
} else {
memmove(text_box->text + char_offset + utf8_len,
text_box->text + char_offset,
text_box->length - char_offset);
for (i = 0; i != utf8_len; i++)
text_box->text[char_offset + i] = utf8[i];
text_box->length += utf8_len;
char_offset += utf8_len;
}
utf8keySize = strlen(utf8key);
text_box->text = xrealloc(text_box->text, text_box->length + utf8keySize + 1);
memmove(text_box->text + box_offset + utf8keySize,
text_box->text + box_offset,
text_box->length - box_offset);
memcpy(text_box->text + box_offset, utf8key, utf8keySize);
text_box->length += utf8keySize;
text_box->text[text_box->length] = 0;
input->gadget->value[text_box->length] = 0;
box_offset += utf8keySize;
free((void *)utf8key);
text_box->width = nsfont_width(text_box->font, text_box->text,
(unsigned int)text_box->length);
changed = true;
} else if ((key == 8 || key == 127) && char_offset != 0) {
} else if (key == 8 || key == 127) {
/* delete to left */
/** \todo delete entire UTF-8 character, handling passwords */
utf8_len = 1;
memmove(text_box->text + char_offset - utf8_len,
text_box->text + char_offset,
text_box->length - char_offset);
memmove(input->gadget->value + char_offset - utf8_len,
input->gadget->value + char_offset,
text_box->length - char_offset);
text_box->length--;
input->gadget->value[text_box->length] = 0;
char_offset--;
int prev_offset;
if (box_offset == 0)
return;
/* Gadget */
prev_offset = form_offset;
/* Go to the previous valid UTF-8 character */
while (form_offset != 0
&& !((input->gadget->value[--form_offset] & 0x80) == 0x00 || (input->gadget->value[form_offset] & 0xC0) == 0xC0))
;
memmove(input->gadget->value + form_offset,
input->gadget->value + prev_offset,
input->gadget->length - prev_offset);
input->gadget->length -= prev_offset - form_offset;
input->gadget->value[input->gadget->length] = 0;
/* Text box */
prev_offset = box_offset;
/* Go to the previous valid UTF-8 character */
while (box_offset != 0
&& !((text_box->text[--box_offset] & 0x80) == 0x00 || (text_box->text[box_offset] & 0xC0) == 0xC0))
;
memmove(text_box->text + box_offset,
text_box->text + prev_offset,
text_box->length - prev_offset);
text_box->length -= prev_offset - box_offset;
text_box->text[text_box->length] = 0;
text_box->width = nsfont_width(text_box->font, text_box->text,
(unsigned int)text_box->length);
@ -1299,12 +1339,18 @@ void browser_window_input_callback(struct browser_window *bw,
/* Ctrl+U */
text_box->text[0] = 0;
text_box->length = 0;
box_offset = 0;
input->gadget->value[0] = 0;
char_offset = 0;
input->gadget->length = 0;
form_offset = 0;
text_box->width = 0;
changed = true;
} else if (key == 10 || key == 13) {
/* Return/Enter hit */
LOG(("Submit, text <%s>, gadget <%s>\n", text_box->text, input->gadget->value));
if (form)
browser_form_submit(bw, form, 0);
@ -1324,7 +1370,7 @@ void browser_window_input_callback(struct browser_window *bw,
input = next_input->box;
text_box = input->children->children;
box_coords(input, &box_x, &box_y);
char_offset = 0;
form_offset = box_offset = 0;
} else if (key == 11) {
/* Shift+Tab */
@ -1342,34 +1388,49 @@ void browser_window_input_callback(struct browser_window *bw,
input = prev_input->box;
text_box = input->children->children;
box_coords(input, &box_x, &box_y);
char_offset = 0;
form_offset = box_offset = 0;
} else if (key == 26) {
/* Ctrl+Left */
char_offset = 0;
box_offset = form_offset = 0;
} else if (key == 27) {
/* Ctrl+Right */
char_offset = text_box->length;
box_offset = text_box->length;
form_offset = input->gadget->length;
} else if (key == 28 && (unsigned int)char_offset != text_box->length) {
} else if (key == 28) {
/* Right cursor -> */
/** \todo UTF-8 */
utf8_len = 1;
char_offset += utf8_len;
/* Text box */
/* Go to the next valid UTF-8 character */
while (box_offset != text_box->length
&& !((text_box->text[++box_offset] & 0x80) == 0x00 || (text_box->text[box_offset] & 0xC0) == 0xC0))
;
/* Gadget */
/* Go to the next valid UTF-8 character */
while (form_offset != input->gadget->length
&& !((input->gadget->value[++form_offset] & 0x80) == 0x00 || (input->gadget->value[form_offset] & 0xC0) == 0xC0))
;
} else if (key == 29 && char_offset != 0) {
} else if (key == 29) {
/* Left cursor <- */
/** \todo UTF-8 */
utf8_len = 1;
char_offset -= utf8_len;
/* Text box */
/* Go to the previous valid UTF-8 character */
while (box_offset != 0
&& !((text_box->text[--box_offset] & 0x80) == 0x00 || (text_box->text[box_offset] & 0xC0) == 0xC0))
;
/* Gadget */
/* Go to the previous valid UTF-8 character */
while (form_offset != 0
&& !((input->gadget->value[--form_offset] & 0x80) == 0x00 || (input->gadget->value[form_offset] & 0xC0) == 0xC0))
;
} else {
return;
}
pixel_offset = nsfont_width(text_box->font, text_box->text,
(unsigned int)char_offset);
(unsigned int)box_offset);
dx = text_box->x;
text_box->x = 0;
if (input->width < text_box->width && input->width / 2 < pixel_offset) {
@ -1378,9 +1439,11 @@ void browser_window_input_callback(struct browser_window *bw,
text_box->x = input->width - text_box->width;
}
dx -= text_box->x;
input->gadget->caret_char_offset = char_offset;
input->gadget->caret_pixel_offset = pixel_offset;
input->gadget->caret_box_offset = box_offset;
input->gadget->caret_form_offset = form_offset;
browser_window_place_caret(bw,
box_x + text_box->x + pixel_offset,
box_y + text_box->y,
@ -1477,8 +1540,8 @@ void browser_window_form_select(struct browser_window *bw,
}
gui_pointer_shape get_pointer_shape(css_cursor cursor) {
gui_pointer_shape get_pointer_shape(css_cursor cursor)
{
gui_pointer_shape pointer;
switch (cursor) {

View File

@ -1179,8 +1179,8 @@ void add_option(xmlNode* n, struct form_control* current_select, const char *tex
struct box_result box_input(xmlNode *n, struct box_status *status,
struct css_style *style)
{
struct box* box = 0;
struct form_control *gadget = 0;
struct box* box = NULL;
struct form_control *gadget = NULL;
char *s, *type, *url;
type = (char *) xmlGetProp(n, (const xmlChar *) "type");
@ -1219,21 +1219,20 @@ struct box_result box_input(xmlNode *n, struct box_status *status,
xmlFree(type);
return (struct box_result) {0, false, true};
}
gadget->length = strlen(gadget->value);
}
} else if (type && (strcasecmp(type, "checkbox") == 0 ||
strcasecmp(type, "radio") == 0)) {
box = box_create(style, NULL, 0,
status->content->data.html.box_pool);
box->gadget = gadget = form_new_control(GADGET_RADIO);
box->gadget = gadget = form_new_control((type[0] == 'c' || type[0] == 'C') ? GADGET_CHECKBOX : GADGET_RADIO);
if (!gadget) {
box_free_box(box);
xmlFree(type);
return (struct box_result) {0, false, true};
}
gadget->box = box;
if (type[0] == 'c' || type[0] == 'C')
gadget->type = GADGET_CHECKBOX;
if ((s = (char *) xmlGetProp(n, (const xmlChar *) "checked"))) {
gadget->selected = true;
@ -1248,6 +1247,7 @@ struct box_result box_input(xmlNode *n, struct box_status *status,
xmlFree(type);
return (struct box_result) {0, false, true};
}
gadget->length = strlen(gadget->value);
}
} else if (type && (strcasecmp(type, "submit") == 0 ||
@ -1365,7 +1365,7 @@ struct box *box_input_text(xmlNode *n, struct box_status *status,
struct box *inline_container, *inline_box;
box->type = BOX_INLINE_BLOCK;
box->gadget = form_new_control(GADGET_TEXTBOX);
box->gadget = form_new_control((password) ? GADGET_PASSWORD : GADGET_TEXTBOX);
box->gadget->box = box;
box->gadget->maxlength = 100;
@ -1376,13 +1376,14 @@ struct box *box_input_text(xmlNode *n, struct box_status *status,
s = (char *) xmlGetProp(n, (const xmlChar *) "value");
box->gadget->value = strdup((s != NULL) ? s : "");
box->gadget->initial_value = strdup(box->gadget->value);
box->gadget->initial_value = strdup((box->gadget->value != NULL) ? box->gadget->value : "");
if (s)
xmlFree(s);
if (box->gadget->value == NULL || box->gadget->initial_value == NULL) {
box_free(box);
return NULL;
}
box->gadget->length = strlen(box->gadget->value);
inline_container = box_create(0, 0, 0,
status->content->data.html.box_pool);
@ -1392,13 +1393,11 @@ struct box *box_input_text(xmlNode *n, struct box_status *status,
inline_box->type = BOX_INLINE;
inline_box->style_clone = 1;
if (password) {
box->gadget->type = GADGET_PASSWORD;
inline_box->length = strlen(box->gadget->value);
inline_box->text = malloc(inline_box->length + 1);
memset(inline_box->text, '*', inline_box->length);
inline_box->text[inline_box->length] = '\0';
} else {
box->gadget->type = GADGET_TEXTBOX;
/* replace spaces/TABs with hard spaces to prevent line wrapping */
inline_box->text = cnv_space2nbsp(box->gadget->value);
inline_box->length = strlen(inline_box->text);

View File

@ -115,7 +115,6 @@ struct object_params {
};
struct plugin_params {
char* name;
char* value;
char* type;

View File

@ -33,19 +33,22 @@ struct form_control *form_new_control(form_control_type type)
{
struct form_control *control;
control = malloc(sizeof *control);
if (!control)
return 0;
if ((control = malloc(sizeof *control)) == NULL)
return NULL;
control->type = type;
control->name = 0;
control->value = 0;
control->initial_value = 0;
control->name = NULL;
control->value = NULL;
control->initial_value = NULL;
control->disabled = false;
control->form = 0;
control->box = 0;
control->form = NULL;
control->box = NULL;
control->caret_inline_container = NULL;
control->caret_text_box = NULL;
control->caret_box_offset = control->caret_form_offset = 0;
control->length = control->maxlength = 0;
control->selected = false;
control->prev = 0;
control->next = 0;
control->prev = NULL;
control->next = NULL;
return control;
}
@ -57,11 +60,11 @@ struct form_control *form_new_control(form_control_type type)
void form_add_control(struct form *form, struct form_control *control)
{
control->form = form;
if (form->controls) {
if (form->controls != NULL) {
assert(form->last_control);
form->last_control->next = control;
control->prev = form->last_control;
control->next = 0;
control->next = NULL;
form->last_control = control;
} else {
form->controls = form->last_control = control;
@ -106,11 +109,13 @@ struct form_successful_control *form_successful_controls(struct form *form,
struct form_control *control;
struct form_option *option;
struct form_successful_control sentinel, *last_success;
last_success = &sentinel;
sentinel.next = 0;
for (control = form->controls; control; control = control->next) {
struct form_successful_control *success_new;
bool add_val;
/* ignore disabled controls */
if (control->disabled)
@ -120,48 +125,57 @@ struct form_successful_control *form_successful_controls(struct form *form,
if (!control->name)
continue;
/* only the activated submit button is successful */
if (control->type == GADGET_SUBMIT && control != submit_button)
continue;
switch (control->type) {
case GADGET_HIDDEN:
case GADGET_TEXTBOX:
case GADGET_PASSWORD:
add_val = true;
break;
/* ignore checkboxes and radio buttons which aren't selected */
if (control->type == GADGET_CHECKBOX && !control->selected)
continue;
if (control->type == GADGET_RADIO && !control->selected)
continue;
case GADGET_RADIO:
case GADGET_CHECKBOX:
/* ignore checkboxes and radio buttons which
* aren't selected
*/
add_val = control->selected;
break;
case GADGET_SELECT:
/* select */
if (control->type == GADGET_SELECT) {
for (option = control->data.select.items; option;
for (option = control->data.select.items;
option != NULL;
option = option->next) {
if (option->selected) {
success_new = xcalloc(1, sizeof(*success_new));
success_new->file = false;
success_new->name = xstrdup(control->name);
success_new->value = xstrdup(option->value);
success_new->next = 0;
success_new->name = cnv_str_local_enc(control->name);
success_new->value = cnv_str_local_enc(option->value);
success_new->next = NULL;
last_success->next = success_new;
last_success = success_new;
}
}
continue;
}
add_val = false;
break;
case GADGET_TEXTAREA:
/* textarea */
if (control->type == GADGET_TEXTAREA) {
success_new = xcalloc(1, sizeof(*success_new));
success_new->file = false;
success_new->name = xstrdup(control->name);
success_new->name = cnv_str_local_enc(control->name);
success_new->value = form_textarea_value(control);
success_new->next = 0;
last_success->next = success_new;
last_success = success_new;
continue;
}
add_val = false;
break;
case GADGET_IMAGE: {
/* image */
if (control->type == GADGET_IMAGE) {
unsigned int len = strlen(control->name) + 3;
const size_t len = strlen(control->name) + 3;
/* x */
success_new = xcalloc(1, sizeof(*success_new));
success_new->file = false;
@ -172,6 +186,7 @@ struct form_successful_control *form_successful_controls(struct form *form,
success_new->next = 0;
last_success->next = success_new;
last_success = success_new;
/* y */
success_new = xcalloc(1, sizeof(*success_new));
success_new->file = false;
@ -182,31 +197,48 @@ struct form_successful_control *form_successful_controls(struct form *form,
success_new->next = 0;
last_success->next = success_new;
last_success = success_new;
add_val = false;
break;
}
/* ignore reset */
if (control->type == GADGET_RESET)
continue;
case GADGET_SUBMIT:
/* only the activated submit button is
* successful
*/
add_val = (control != submit_button) ? false : true;
break;
case GADGET_RESET:
/* ignore reset */
add_val = false;
break;
case GADGET_FILE:
/* file */
if (control->type == GADGET_FILE && control->value) {
success_new = xcalloc(1, sizeof(*success_new));
success_new->file = true;
success_new->name = xstrdup(control->name);
success_new->value = xstrdup(control->value);
success_new->name = cnv_str_local_enc(control->name);
success_new->value = cnv_str_local_enc(control->value);
success_new->next = 0;
last_success->next = success_new;
last_success = success_new;
continue;
add_val = false;
break;
default:
assert(0);
break;
}
/* all others added if they have a value */
if (control->value) {
if (add_val && control->value != NULL) {
success_new = xcalloc(1, sizeof(*success_new));
success_new->file = false;
success_new->name = xstrdup(control->name);
success_new->value = xstrdup(control->value);
success_new->next = 0;
success_new->name = cnv_str_local_enc(control->name);
success_new->value = cnv_str_local_enc(control->value);
success_new->next = NULL;
last_success->next = success_new;
last_success = success_new;
}
@ -228,10 +260,10 @@ char *form_textarea_value(struct form_control *textarea)
/* find required length */
for (inline_container = textarea->box->children;
inline_container;
inline_container != NULL;
inline_container = inline_container->next) {
for (text_box = inline_container->children;
text_box;
text_box != NULL;
text_box = text_box->next) {
len += text_box->length + 1;
}
@ -241,10 +273,10 @@ char *form_textarea_value(struct form_control *textarea)
/* construct value */
s = value = xcalloc(1, len);
for (inline_container = textarea->box->children;
inline_container;
inline_container != NULL;
inline_container = inline_container->next) {
for (text_box = inline_container->children;
text_box;
text_box != NULL;
text_box = text_box->next) {
strncpy(s, text_box->text, text_box->length);
s += text_box->length;
@ -269,8 +301,8 @@ char *form_url_encode(struct form_successful_control *control)
unsigned int len = 0, len1;
for (; control; control = control->next) {
char *name = curl_escape(control->name, 0);
char *value = curl_escape(control->value, 0);
const char *name = curl_escape(control->name, 0);
const char *value = curl_escape(control->value, 0);
len1 = len + strlen(name) + strlen(value) + 2;
s = xrealloc(s, len1 + 1);
sprintf(s + len, "%s=%s&", name, value);

View File

@ -58,7 +58,8 @@ struct form_control {
struct box *box;
struct box *caret_inline_container;
struct box *caret_text_box;
int caret_char_offset;
unsigned int caret_box_offset, caret_form_offset;
unsigned int length;
int caret_pixel_offset;
unsigned int maxlength;
bool selected;