mirror of
https://github.com/netsurf-browser/netsurf
synced 2025-01-08 20:12:01 +03:00
[project @ 2005-04-15 18:00:19 by jmb]
Split out generic text input code. Support internationalised text input. Fix textarea-related bugs. svn path=/import/netsurf/; revision=1642
This commit is contained in:
parent
34b92e905f
commit
ee9a4712cd
@ -32,8 +32,8 @@
|
||||
#include "netsurf/desktop/imagemap.h"
|
||||
#include "netsurf/desktop/options.h"
|
||||
#include "netsurf/desktop/selection.h"
|
||||
#include "netsurf/desktop/textinput.h"
|
||||
#include "netsurf/render/box.h"
|
||||
#include "netsurf/render/font.h"
|
||||
#include "netsurf/render/form.h"
|
||||
#include "netsurf/render/layout.h"
|
||||
#include "netsurf/utils/log.h"
|
||||
@ -66,29 +66,8 @@ static const char *browser_window_scrollbar_click(struct browser_window *bw,
|
||||
int box_x, int box_y, int x, int y);
|
||||
static void browser_radio_set(struct content *content,
|
||||
struct form_control *radio);
|
||||
static void browser_redraw_box(struct content *c, struct box *box);
|
||||
static void browser_window_textarea_click(struct browser_window *bw,
|
||||
browser_mouse_state mouse,
|
||||
struct box *textarea,
|
||||
int box_x, int box_y,
|
||||
int x, int y);
|
||||
static void browser_window_textarea_callback(struct browser_window *bw,
|
||||
wchar_t key, void *p);
|
||||
static void browser_window_input_click(struct browser_window* bw,
|
||||
struct box *input,
|
||||
int box_x, int box_y,
|
||||
int x, int y);
|
||||
static void browser_window_input_callback(struct browser_window *bw,
|
||||
wchar_t key, void *p);
|
||||
static void browser_window_place_caret(struct browser_window *bw,
|
||||
int x, int y, int height,
|
||||
void (*callback)(struct browser_window *bw,
|
||||
wchar_t key, void *p),
|
||||
void *p);
|
||||
static void browser_window_remove_caret(struct browser_window *bw);
|
||||
static gui_pointer_shape get_pointer_shape(css_cursor cursor);
|
||||
static void browser_form_submit(struct browser_window *bw, struct form *form,
|
||||
struct form_control *submit_button);
|
||||
|
||||
static struct box *browser_window_pick_text_box(struct browser_window *bw,
|
||||
browser_mouse_state mouse, int x, int y, int *dx, int *dy);
|
||||
static void browser_window_page_drag_start(struct browser_window *bw, int x, int y);
|
||||
@ -195,6 +174,7 @@ void browser_window_go_post(struct browser_window *bw, const char *url,
|
||||
return;
|
||||
}
|
||||
|
||||
/* find any fragment identifier on end of URL */
|
||||
hash = strchr(url2, '#');
|
||||
if (bw->frag_id) {
|
||||
free(bw->frag_id);
|
||||
@ -205,7 +185,7 @@ void browser_window_go_post(struct browser_window *bw, const char *url,
|
||||
/* if we're simply moving to another ID on the same page,
|
||||
* don't bother to fetch, just update the window
|
||||
*/
|
||||
if (bw->current_content &&
|
||||
if (bw->current_content && bw->current_content->url &&
|
||||
strncasecmp(bw->current_content->url,
|
||||
url2, hash - url2) == 0 &&
|
||||
strlen(bw->current_content->url) ==
|
||||
@ -1333,20 +1313,20 @@ void browser_window_redraw_rect(struct browser_window *bw, int x, int y, int wid
|
||||
|
||||
if (c && c->type == CONTENT_HTML) {
|
||||
union content_msg_data data;
|
||||
|
||||
|
||||
data.redraw.x = x;
|
||||
data.redraw.y = y;
|
||||
data.redraw.width = width;
|
||||
data.redraw.height = height;
|
||||
|
||||
|
||||
data.redraw.full_redraw = true;
|
||||
|
||||
|
||||
data.redraw.object = c;
|
||||
data.redraw.object_x = 0;
|
||||
data.redraw.object_y = 0;
|
||||
data.redraw.object_width = c->width;
|
||||
data.redraw.object_height = c->height;
|
||||
|
||||
|
||||
content_broadcast(c, CONTENT_MSG_REDRAW, data);
|
||||
}
|
||||
}
|
||||
@ -1385,788 +1365,6 @@ void browser_redraw_box(struct content *c, struct box *box)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle clicks in a text area by placing the caret.
|
||||
*
|
||||
* \param bw browser window where click occurred
|
||||
* \param mouse state of mouse buttons and modifier keys
|
||||
* \param textarea textarea box
|
||||
* \param box_x position of textarea in global document coordinates
|
||||
* \param box_y position of textarea in global document coordinates
|
||||
* \param x coordinate of click relative to textarea
|
||||
* \param y coordinate of click relative to textarea
|
||||
*/
|
||||
|
||||
void browser_window_textarea_click(struct browser_window *bw,
|
||||
browser_mouse_state mouse,
|
||||
struct box *textarea,
|
||||
int box_x, int box_y,
|
||||
int x, int y)
|
||||
{
|
||||
/* A textarea is an INLINE_BLOCK containing a single INLINE_CONTAINER,
|
||||
* which contains the text as runs of INLINE separated by BR. There is
|
||||
* at least one INLINE. The first and last boxes are INLINE.
|
||||
* Consecutive BR may not be present. These constraints are satisfied
|
||||
* by using a 0-length INLINE for blank lines. */
|
||||
|
||||
int char_offset = 0, pixel_offset = 0, new_scroll_y;
|
||||
struct box *inline_container, *text_box;
|
||||
|
||||
inline_container = textarea->children;
|
||||
|
||||
if (inline_container->y + inline_container->height < y) {
|
||||
/* below the bottom of the textarea: place caret at end */
|
||||
text_box = inline_container->last;
|
||||
assert(text_box->type == BOX_INLINE);
|
||||
assert(text_box->text);
|
||||
/** \todo handle errors */
|
||||
nsfont_position_in_string(text_box->style, text_box->text,
|
||||
text_box->length,
|
||||
textarea->width,
|
||||
&char_offset, &pixel_offset);
|
||||
} else {
|
||||
/* find the relevant text box */
|
||||
y -= inline_container->y;
|
||||
for (text_box = inline_container->children;
|
||||
text_box && text_box->y + text_box->height < y;
|
||||
text_box = text_box->next)
|
||||
;
|
||||
for (; text_box && text_box->type != BOX_BR &&
|
||||
text_box->y <= y &&
|
||||
text_box->x + text_box->width < x;
|
||||
text_box = text_box->next)
|
||||
;
|
||||
if (!text_box) {
|
||||
/* past last text box */
|
||||
text_box = inline_container->last;
|
||||
assert(text_box->type == BOX_INLINE);
|
||||
assert(text_box->text);
|
||||
nsfont_position_in_string(text_box->style,
|
||||
text_box->text,
|
||||
text_box->length,
|
||||
textarea->width,
|
||||
&char_offset, &pixel_offset);
|
||||
} else {
|
||||
/* in a text box */
|
||||
if (text_box->type == BOX_BR)
|
||||
text_box = text_box->prev;
|
||||
else if (y < text_box->y && text_box->prev)
|
||||
text_box = text_box->prev;
|
||||
assert(text_box->type == BOX_INLINE);
|
||||
assert(text_box->text);
|
||||
nsfont_position_in_string(text_box->style,
|
||||
text_box->text,
|
||||
text_box->length,
|
||||
(unsigned int)(x - text_box->x),
|
||||
&char_offset, &pixel_offset);
|
||||
}
|
||||
}
|
||||
|
||||
/* scroll to place the caret in the centre of the visible region */
|
||||
new_scroll_y = inline_container->y + text_box->y +
|
||||
text_box->height / 2 -
|
||||
textarea->height / 2;
|
||||
if (textarea->descendant_y1 - textarea->height < new_scroll_y)
|
||||
new_scroll_y = textarea->descendant_y1 - textarea->height;
|
||||
if (new_scroll_y < 0)
|
||||
new_scroll_y = 0;
|
||||
box_y += textarea->scroll_y - new_scroll_y;
|
||||
|
||||
textarea->gadget->caret_inline_container = inline_container;
|
||||
textarea->gadget->caret_text_box = text_box;
|
||||
textarea->gadget->caret_box_offset = char_offset;
|
||||
textarea->gadget->caret_pixel_offset = pixel_offset;
|
||||
browser_window_place_caret(bw,
|
||||
box_x + inline_container->x + text_box->x +
|
||||
pixel_offset,
|
||||
box_y + inline_container->y + text_box->y,
|
||||
text_box->height,
|
||||
browser_window_textarea_callback, textarea);
|
||||
|
||||
if (new_scroll_y != textarea->scroll_y) {
|
||||
textarea->scroll_y = new_scroll_y;
|
||||
browser_redraw_box(bw->current_content, textarea);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Key press callback for text areas.
|
||||
*/
|
||||
|
||||
void browser_window_textarea_callback(struct browser_window *bw,
|
||||
wchar_t key, void *p)
|
||||
{
|
||||
struct box *textarea = p;
|
||||
struct box *inline_container = textarea->gadget->caret_inline_container;
|
||||
struct box *text_box = textarea->gadget->caret_text_box;
|
||||
struct box *new_br, *new_text, *t;
|
||||
struct box *prev;
|
||||
size_t char_offset = textarea->gadget->caret_box_offset;
|
||||
int pixel_offset = textarea->gadget->caret_pixel_offset;
|
||||
int new_scroll_y;
|
||||
int box_x, box_y;
|
||||
char utf8[5];
|
||||
unsigned int utf8_len, i;
|
||||
char *text;
|
||||
int width = 0, height = 0;
|
||||
bool reflow = false;
|
||||
|
||||
/* box_dump(textarea, 0); */
|
||||
LOG(("key %i at %i in '%.*s'", key, char_offset,
|
||||
(int) text_box->length, text_box->text));
|
||||
|
||||
box_coords(textarea, &box_x, &box_y);
|
||||
box_x -= textarea->scroll_x;
|
||||
box_y -= textarea->scroll_y;
|
||||
|
||||
if (!(key <= 0x001F || (0x007F <= key && key <= 0x009F))) {
|
||||
/* normal character insertion */
|
||||
/** \todo convert key to UTF-8 properly */
|
||||
utf8[0] = key;
|
||||
utf8_len = 1;
|
||||
|
||||
text = talloc_realloc(bw->current_content, text_box->text,
|
||||
char, text_box->length + 8);
|
||||
if (!text) {
|
||||
warn_user("NoMemory", 0);
|
||||
return;
|
||||
}
|
||||
text_box->text = text;
|
||||
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;
|
||||
text_box->text[text_box->length] = 0;
|
||||
text_box->width = UNKNOWN_WIDTH;
|
||||
char_offset += utf8_len;
|
||||
|
||||
reflow = true;
|
||||
}
|
||||
else switch (key) {
|
||||
|
||||
case 8:
|
||||
case 127: /* delete to left */
|
||||
if (char_offset == 0) {
|
||||
/* at the start of a text box */
|
||||
if (!text_box->prev)
|
||||
/* at very beginning of text area: ignore */
|
||||
return;
|
||||
|
||||
if (text_box->prev->type == BOX_BR) {
|
||||
/* previous box is BR: remove it */
|
||||
t = text_box->prev;
|
||||
t->prev->next = t->next;
|
||||
t->next->prev = t->prev;
|
||||
box_free(t);
|
||||
}
|
||||
|
||||
/* delete space by merging with previous text box */
|
||||
prev = text_box->prev;
|
||||
assert(prev->text);
|
||||
text = talloc_realloc(bw->current_content, prev->text,
|
||||
char,
|
||||
prev->length + text_box->length + 1);
|
||||
if (!text) {
|
||||
warn_user("NoMemory", 0);
|
||||
return;
|
||||
}
|
||||
prev->text = text;
|
||||
memcpy(prev->text + prev->length, text_box->text,
|
||||
text_box->length);
|
||||
char_offset = prev->length; /* caret at join */
|
||||
prev->length += text_box->length;
|
||||
prev->text[prev->length] = 0;
|
||||
prev->width = UNKNOWN_WIDTH;
|
||||
prev->next = text_box->next;
|
||||
if (prev->next)
|
||||
prev->next->prev = prev;
|
||||
else
|
||||
prev->parent->last = prev;
|
||||
box_free(text_box);
|
||||
|
||||
/* place caret at join (see above) */
|
||||
text_box = prev;
|
||||
|
||||
} else {
|
||||
/* delete a character */
|
||||
/** \todo delete entire UTF-8 character */
|
||||
utf8_len = 1;
|
||||
memmove(text_box->text + char_offset - utf8_len,
|
||||
text_box->text + char_offset,
|
||||
text_box->length - char_offset);
|
||||
text_box->length -= utf8_len;
|
||||
text_box->width = UNKNOWN_WIDTH;
|
||||
char_offset -= utf8_len;
|
||||
}
|
||||
|
||||
reflow = true;
|
||||
break;
|
||||
|
||||
case 10:
|
||||
case 13: /* paragraph break */
|
||||
text = talloc_array(bw->current_content, char,
|
||||
text_box->length + 1);
|
||||
if (!text) {
|
||||
warn_user("NoMemory", 0);
|
||||
return;
|
||||
}
|
||||
|
||||
new_br = box_create(text_box->style, 0, text_box->title, 0,
|
||||
bw->current_content);
|
||||
new_text = talloc(bw->current_content, struct box);
|
||||
if (!new_text) {
|
||||
warn_user("NoMemory", 0);
|
||||
return;
|
||||
}
|
||||
|
||||
new_br->type = BOX_BR;
|
||||
box_insert_sibling(text_box, new_br);
|
||||
|
||||
memcpy(new_text, text_box, sizeof (struct box));
|
||||
new_text->clone = 1;
|
||||
new_text->text = text;
|
||||
memcpy(new_text->text, text_box->text + char_offset,
|
||||
text_box->length - char_offset);
|
||||
new_text->length = text_box->length - char_offset;
|
||||
text_box->length = char_offset;
|
||||
text_box->width = new_text->width = UNKNOWN_WIDTH;
|
||||
box_insert_sibling(new_br, new_text);
|
||||
|
||||
/* place caret at start of new text box */
|
||||
text_box = new_text;
|
||||
char_offset = 0;
|
||||
|
||||
reflow = true;
|
||||
break;
|
||||
|
||||
case 22: /* Ctrl+V */
|
||||
// gui_paste_from_clipboard();
|
||||
break;
|
||||
|
||||
case 24: /* Ctrl+X */
|
||||
if (gui_copy_to_clipboard(bw->sel)) {
|
||||
/* \todo block delete */
|
||||
}
|
||||
break;
|
||||
|
||||
case 28: /* Right cursor -> */
|
||||
if ((unsigned int) char_offset != text_box->length) {
|
||||
/** \todo move by a UTF-8 character */
|
||||
utf8_len = 1;
|
||||
char_offset += utf8_len;
|
||||
} else {
|
||||
if (!text_box->next)
|
||||
/* at end of text area: ignore */
|
||||
return;
|
||||
|
||||
text_box = text_box->next;
|
||||
if (text_box->type == BOX_BR)
|
||||
text_box = text_box->next;
|
||||
char_offset = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 29: /* Left cursor <- */
|
||||
if (char_offset != 0) {
|
||||
/** \todo move by a UTF-8 character */
|
||||
utf8_len = 1;
|
||||
char_offset -= utf8_len;
|
||||
} else {
|
||||
if (!text_box->prev)
|
||||
/* at start of text area: ignore */
|
||||
return;
|
||||
|
||||
text_box = text_box->prev;
|
||||
if (text_box->type == BOX_BR)
|
||||
text_box = text_box->prev;
|
||||
char_offset = text_box->length;
|
||||
}
|
||||
break;
|
||||
|
||||
case 30: /* Up Cursor */
|
||||
browser_window_textarea_click(bw,
|
||||
BROWSER_MOUSE_CLICK_1, textarea,
|
||||
box_x, box_y,
|
||||
text_box->x + pixel_offset,
|
||||
inline_container->y + text_box->y - 1);
|
||||
return;
|
||||
|
||||
case 31: /* Down cursor */
|
||||
browser_window_textarea_click(bw,
|
||||
BROWSER_MOUSE_CLICK_1, textarea,
|
||||
box_x, box_y,
|
||||
text_box->x + pixel_offset,
|
||||
inline_container->y + text_box->y +
|
||||
text_box->height + 1);
|
||||
return;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
/* box_dump(textarea, 0); */
|
||||
/* for (struct box *t = inline_container->children; t; t = t->next) {
|
||||
assert(t->type == BOX_INLINE);
|
||||
assert(t->text);
|
||||
assert(t->font);
|
||||
assert(t->parent == inline_container);
|
||||
if (t->next) assert(t->next->prev == t);
|
||||
if (t->prev) assert(t->prev->next == t);
|
||||
if (!t->next) {
|
||||
assert(inline_container->last == t);
|
||||
break;
|
||||
}
|
||||
if (t->next->type == BOX_BR) {
|
||||
assert(t->next->next);
|
||||
t = t->next;
|
||||
}
|
||||
} */
|
||||
|
||||
if (reflow) {
|
||||
/* reflow textarea preserving width and height */
|
||||
width = textarea->width;
|
||||
height = textarea->height;
|
||||
if (!layout_inline_container(inline_container, width,
|
||||
textarea, 0, 0,
|
||||
bw->current_content))
|
||||
warn_user("NoMemory", 0);
|
||||
textarea->width = width;
|
||||
textarea->height = height;
|
||||
layout_calculate_descendant_bboxes(textarea);
|
||||
}
|
||||
|
||||
if (text_box->length < char_offset) {
|
||||
/* the text box has been split and the caret is in the
|
||||
* second part */
|
||||
char_offset -= (text_box->length + 1); /* +1 for the space */
|
||||
text_box = text_box->next;
|
||||
assert(text_box);
|
||||
assert(char_offset <= text_box->length);
|
||||
}
|
||||
|
||||
/* scroll to place the caret in the centre of the visible region */
|
||||
new_scroll_y = inline_container->y + text_box->y +
|
||||
text_box->height / 2 -
|
||||
textarea->height / 2;
|
||||
if (textarea->descendant_y1 - textarea->height < new_scroll_y)
|
||||
new_scroll_y = textarea->descendant_y1 - textarea->height;
|
||||
if (new_scroll_y < 0)
|
||||
new_scroll_y = 0;
|
||||
box_y += textarea->scroll_y - new_scroll_y;
|
||||
|
||||
nsfont_width(text_box->style, text_box->text,
|
||||
char_offset, &pixel_offset);
|
||||
|
||||
textarea->gadget->caret_inline_container = inline_container;
|
||||
textarea->gadget->caret_text_box = text_box;
|
||||
textarea->gadget->caret_box_offset = char_offset;
|
||||
textarea->gadget->caret_pixel_offset = pixel_offset;
|
||||
browser_window_place_caret(bw,
|
||||
box_x + inline_container->x + text_box->x +
|
||||
pixel_offset,
|
||||
box_y + inline_container->y + text_box->y,
|
||||
text_box->height,
|
||||
browser_window_textarea_callback, textarea);
|
||||
|
||||
if (new_scroll_y != textarea->scroll_y || reflow) {
|
||||
textarea->scroll_y = new_scroll_y;
|
||||
browser_redraw_box(bw->current_content, textarea);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle clicks in a text or password input box by placing the caret.
|
||||
*
|
||||
* \param bw browser window where click occurred
|
||||
* \param input input box
|
||||
* \param box_x position of input in global document coordinates
|
||||
* \param box_y position of input in global document coordinates
|
||||
* \param x coordinate of click relative to input
|
||||
* \param y coordinate of click relative to input
|
||||
*/
|
||||
|
||||
void browser_window_input_click(struct browser_window* bw,
|
||||
struct box *input,
|
||||
int box_x, int box_y,
|
||||
int x, int y)
|
||||
{
|
||||
size_t char_offset = 0;
|
||||
int pixel_offset = 0, dx = 0;
|
||||
struct box *text_box = input->children->children;
|
||||
int uchars;
|
||||
unsigned int offset;
|
||||
|
||||
nsfont_position_in_string(text_box->style, 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) &&
|
||||
(input->width / 2 < pixel_offset)) {
|
||||
dx = text_box->x;
|
||||
text_box->x = input->width / 2 - pixel_offset;
|
||||
if (text_box->x < input->width - text_box->width)
|
||||
text_box->x = input->width - text_box->width;
|
||||
dx -= text_box->x;
|
||||
}
|
||||
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 + input->children->x + text_box->x + pixel_offset,
|
||||
box_y + input->children->y + text_box->y,
|
||||
text_box->height,
|
||||
browser_window_input_callback, input);
|
||||
|
||||
if (dx)
|
||||
browser_redraw_box(bw->current_content, input);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Key press callback for text or password input boxes.
|
||||
*/
|
||||
|
||||
void browser_window_input_callback(struct browser_window *bw,
|
||||
wchar_t key, void *p)
|
||||
{
|
||||
struct box *input = (struct box *)p;
|
||||
struct box *text_box = input->children->children;
|
||||
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;
|
||||
bool changed = false;
|
||||
|
||||
box_coords(input, &box_x, &box_y);
|
||||
|
||||
if (!(key <= 0x001F || (0x007F <= key && key <= 0x009F))) {
|
||||
char key_to_insert;
|
||||
char *utf8key;
|
||||
size_t utf8keySize;
|
||||
char *value;
|
||||
|
||||
/** \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 */
|
||||
|
||||
/* Insert key in gadget */
|
||||
key_to_insert = (char)key;
|
||||
if ((utf8key = cnv_local_enc_str(&key_to_insert, 1)) == NULL)
|
||||
return;
|
||||
utf8keySize = strlen(utf8key);
|
||||
|
||||
value = realloc(input->gadget->value,
|
||||
input->gadget->length + utf8keySize + 1);
|
||||
if (!value) {
|
||||
free(utf8key);
|
||||
warn_user("NoMemory", 0);
|
||||
return;
|
||||
}
|
||||
input->gadget->value = value;
|
||||
|
||||
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(utf8key);
|
||||
|
||||
/* 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;
|
||||
utf8keySize = strlen(utf8key);
|
||||
|
||||
value = talloc_realloc(bw->current_content, text_box->text,
|
||||
char, text_box->length + utf8keySize + 1);
|
||||
if (!value) {
|
||||
free(utf8key);
|
||||
warn_user("NoMemory", 0);
|
||||
return;
|
||||
}
|
||||
text_box->text = value;
|
||||
|
||||
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;
|
||||
box_offset += utf8keySize;
|
||||
free(utf8key);
|
||||
|
||||
nsfont_width(text_box->style, text_box->text, text_box->length,
|
||||
&text_box->width);
|
||||
changed = true;
|
||||
|
||||
} else switch (key) {
|
||||
|
||||
case 8:
|
||||
case 127: { /* delete to left */
|
||||
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;
|
||||
|
||||
nsfont_width(text_box->style, text_box->text, text_box->length,
|
||||
&text_box->width);
|
||||
|
||||
changed = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 9: { /* Tab */
|
||||
struct form_control *next_input;
|
||||
for (next_input = input->gadget->next;
|
||||
next_input &&
|
||||
next_input->type != GADGET_TEXTBOX &&
|
||||
next_input->type != GADGET_TEXTAREA &&
|
||||
next_input->type != GADGET_PASSWORD;
|
||||
next_input = next_input->next)
|
||||
;
|
||||
if (!next_input)
|
||||
return;
|
||||
|
||||
input = next_input->box;
|
||||
text_box = input->children->children;
|
||||
box_coords(input, &box_x, &box_y);
|
||||
form_offset = box_offset = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 10:
|
||||
case 13: /* Return/Enter hit */
|
||||
/* Return/Enter hit */
|
||||
if (form)
|
||||
browser_form_submit(bw, form, 0);
|
||||
return;
|
||||
|
||||
case 11: { /* Shift+Tab */
|
||||
struct form_control *prev_input;
|
||||
for (prev_input = input->gadget->prev;
|
||||
prev_input &&
|
||||
prev_input->type != GADGET_TEXTBOX &&
|
||||
prev_input->type != GADGET_TEXTAREA &&
|
||||
prev_input->type != GADGET_PASSWORD;
|
||||
prev_input = prev_input->prev)
|
||||
;
|
||||
if (!prev_input)
|
||||
return;
|
||||
|
||||
input = prev_input->box;
|
||||
text_box = input->children->children;
|
||||
box_coords(input, &box_x, &box_y);
|
||||
form_offset = box_offset = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 128: /* Ctrl+Left */
|
||||
box_offset = form_offset = 0;
|
||||
break;
|
||||
|
||||
case 129: /* Ctrl+Right */
|
||||
box_offset = text_box->length;
|
||||
form_offset = input->gadget->length;
|
||||
break;
|
||||
|
||||
case 21: /* Ctrl+U */
|
||||
text_box->text[0] = 0;
|
||||
text_box->length = 0;
|
||||
box_offset = 0;
|
||||
|
||||
input->gadget->value[0] = 0;
|
||||
input->gadget->length = 0;
|
||||
form_offset = 0;
|
||||
|
||||
text_box->width = 0;
|
||||
changed = true;
|
||||
break;
|
||||
|
||||
case 22: /* Ctrl+V */
|
||||
// gui_paste_from_clipboard();
|
||||
break;
|
||||
|
||||
case 28: /* Right cursor -> */
|
||||
/* 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))
|
||||
;
|
||||
break;
|
||||
|
||||
case 29: /* Left cursor <- */
|
||||
/* 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))
|
||||
;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
nsfont_width(text_box->style, text_box->text, box_offset,
|
||||
&pixel_offset);
|
||||
dx = text_box->x;
|
||||
text_box->x = 0;
|
||||
if (input->width < text_box->width && input->width / 2 < pixel_offset) {
|
||||
text_box->x = input->width / 2 - pixel_offset;
|
||||
if (text_box->x < input->width - text_box->width)
|
||||
text_box->x = input->width - text_box->width;
|
||||
}
|
||||
dx -= text_box->x;
|
||||
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 + input->children->x + text_box->x + pixel_offset,
|
||||
box_y + input->children->y + text_box->y,
|
||||
text_box->height,
|
||||
browser_window_input_callback, input);
|
||||
|
||||
if (dx || changed)
|
||||
browser_redraw_box(bw->current_content, input);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Position the caret and assign a callback for key presses.
|
||||
*/
|
||||
|
||||
void browser_window_place_caret(struct browser_window *bw,
|
||||
int x, int y, int height,
|
||||
void (*callback)(struct browser_window *bw,
|
||||
wchar_t key, void *p),
|
||||
void *p)
|
||||
{
|
||||
gui_window_place_caret(bw->window, x, y, height);
|
||||
bw->caret_callback = callback;
|
||||
bw->caret_p = p;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes the caret and callback for key process.
|
||||
*/
|
||||
|
||||
void browser_window_remove_caret(struct browser_window *bw)
|
||||
{
|
||||
gui_window_remove_caret(bw->window);
|
||||
bw->caret_callback = NULL;
|
||||
bw->caret_p = NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle key presses in a browser window.
|
||||
*/
|
||||
|
||||
bool browser_window_key_press(struct browser_window *bw, wchar_t key)
|
||||
{
|
||||
/* keys that take effect wherever the caret is positioned */
|
||||
switch (key) {
|
||||
case 1: /* Ctrl+A */
|
||||
selection_select_all(bw->sel);
|
||||
return true;
|
||||
|
||||
case 3: /* Ctrl+C */
|
||||
gui_copy_to_clipboard(bw->sel);
|
||||
return true;
|
||||
|
||||
case 26: /* Ctrl+Z */
|
||||
selection_clear(bw->sel, true);
|
||||
return true;
|
||||
|
||||
case 27:
|
||||
if (selection_defined(bw->sel)) {
|
||||
selection_clear(bw->sel, true);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* pass on to the appropriate field */
|
||||
if (!bw->caret_callback)
|
||||
return false;
|
||||
bw->caret_callback(bw, key, bw->caret_p);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process a selection from a form select menu.
|
||||
*
|
||||
@ -2378,7 +1576,7 @@ struct box *browser_window_pick_text_box(struct browser_window *bw,
|
||||
|
||||
while ((box = box_at_point(box, x, y, &box_x, &box_y, &content)) !=
|
||||
NULL) {
|
||||
|
||||
|
||||
if (box->text && !box->object)
|
||||
text_box = box;
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
struct box;
|
||||
struct content;
|
||||
struct form;
|
||||
struct form_control;
|
||||
struct form_successful_control;
|
||||
struct gui_window;
|
||||
@ -126,6 +127,9 @@ void browser_window_mouse_drag_end(struct browser_window *bw,
|
||||
bool browser_window_key_press(struct browser_window *bw, wchar_t key);
|
||||
void browser_window_form_select(struct browser_window *bw,
|
||||
struct form_control *control, int item);
|
||||
void browser_redraw_box(struct content *c, struct box *box);
|
||||
void browser_form_submit(struct browser_window *bw, struct form *form,
|
||||
struct form_control *submit_button);
|
||||
|
||||
void browser_window_redraw_rect(struct browser_window *bw, int x, int y,
|
||||
int width, int height);
|
||||
|
949
desktop/textinput.c
Normal file
949
desktop/textinput.c
Normal file
@ -0,0 +1,949 @@
|
||||
/*
|
||||
* This file is part of NetSurf, http://netsurf.sourceforge.net/
|
||||
* Licensed under the GNU General Public License,
|
||||
* http://www.opensource.org/licenses/gpl-license
|
||||
* Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
|
||||
* Copyright 2004 James Bursa <bursa@users.sourceforge.net>
|
||||
* Copyright 2004 Andrew Timmins <atimmins@blueyonder.co.uk>
|
||||
* Copyright 2004 John Tytgat <John.Tytgat@aaug.net>
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* Textual input handling (implementation)
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "netsurf/desktop/browser.h"
|
||||
#include "netsurf/desktop/gui.h"
|
||||
#include "netsurf/desktop/selection.h"
|
||||
#include "netsurf/desktop/textinput.h"
|
||||
#include "netsurf/render/box.h"
|
||||
#include "netsurf/render/font.h"
|
||||
#include "netsurf/render/form.h"
|
||||
#include "netsurf/render/layout.h"
|
||||
#define NDEBUG
|
||||
#include "netsurf/utils/log.h"
|
||||
#include "netsurf/utils/talloc.h"
|
||||
#include "netsurf/utils/utils.h"
|
||||
|
||||
static void browser_window_textarea_callback(struct browser_window *bw,
|
||||
wchar_t key, void *p);
|
||||
static void browser_window_input_callback(struct browser_window *bw,
|
||||
wchar_t key, void *p);
|
||||
static void browser_window_place_caret(struct browser_window *bw,
|
||||
int x, int y, int height,
|
||||
void (*callback)(struct browser_window *bw,
|
||||
wchar_t key, void *p),
|
||||
void *p);
|
||||
|
||||
/**
|
||||
* Convert a single UCS4 character into a UTF8 multibyte sequence
|
||||
*
|
||||
* Encoding of UCS values outside the UTF16 plane has been removed from
|
||||
* RFC3629. This macro conforms to RFC2279, however, as it is possible
|
||||
* that the platform specific keyboard input handler will generate a UCS4
|
||||
* value outside the UTF16 plane.
|
||||
*
|
||||
* \param c The character to process (0 <= c <= 0x7FFFFFFF)
|
||||
* \param s Pointer to 6 byte long output buffer
|
||||
* \param l Integer in which to store length of multibyte sequence
|
||||
*/
|
||||
#define ucs4_to_utf8(c, s, l) \
|
||||
do { \
|
||||
if ((c) < 0) \
|
||||
assert(0); \
|
||||
else if ((c) < 0x80) { \
|
||||
*(s) = (char)(c); \
|
||||
(l) = 1; \
|
||||
} \
|
||||
else if ((c) < 0x800) { \
|
||||
*(s) = 0xC0 | (((c) >> 6) & 0x1F); \
|
||||
*((s)+1) = 0x80 | ((c) & 0x3F); \
|
||||
(l) = 2; \
|
||||
} \
|
||||
else if ((c) < 0x10000) { \
|
||||
*(s) = 0xE0 | (((c) >> 12) & 0xF); \
|
||||
*((s)+1) = 0x80 | (((c) >> 6) & 0x3F); \
|
||||
*((s)+2) = 0x80 | ((c) & 0x3F); \
|
||||
(l) = 3; \
|
||||
} \
|
||||
else if ((c) < 0x200000) { \
|
||||
*(s) = 0xF0 | (((c) >> 18) & 0x7); \
|
||||
*((s)+1) = 0x80 | (((c) >> 12) & 0x3F); \
|
||||
*((s)+2) = 0x80 | (((c) >> 6) & 0x3F); \
|
||||
*((s)+3) = 0x80 | ((c) & 0x3F); \
|
||||
(l) = 4; \
|
||||
} \
|
||||
else if ((c) < 0x4000000) { \
|
||||
*(s) = 0xF8 | (((c) >> 24) & 0x3); \
|
||||
*((s)+1) = 0x80 | (((c) >> 18) & 0x3F); \
|
||||
*((s)+2) = 0x80 | (((c) >> 12) & 0x3F); \
|
||||
*((s)+3) = 0x80 | (((c) >> 6) & 0x3F); \
|
||||
*((s)+4) = 0x80 | ((c) & 0x3F); \
|
||||
(l) = 5; \
|
||||
} \
|
||||
else if ((c) <= 0x7FFFFFFF) { \
|
||||
*(s) = 0xFC | (((c) >> 30) & 0x1); \
|
||||
*((s)+1) = 0x80 | (((c) >> 24) & 0x3F); \
|
||||
*((s)+2) = 0x80 | (((c) >> 18) & 0x3F); \
|
||||
*((s)+3) = 0x80 | (((c) >> 12) & 0x3F); \
|
||||
*((s)+4) = 0x80 | (((c) >> 6) & 0x3F); \
|
||||
*((s)+5) = 0x80 | ((c) & 0x3F); \
|
||||
(l) = 6; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/**
|
||||
* Calculate the length (in characters) of a NULL-terminated UTF8 string
|
||||
*
|
||||
* \param s The string
|
||||
* \param l Integer in which to store length
|
||||
*/
|
||||
#define utf8_length(s, l) \
|
||||
do { \
|
||||
char *__s = (s); \
|
||||
(l) = 0; \
|
||||
while (*__s != '\0') { \
|
||||
if ((*__s & 0x80) == 0x00) \
|
||||
__s += 1; \
|
||||
else if ((*__s & 0xE0) == 0xC0) \
|
||||
__s += 2; \
|
||||
else if ((*__s & 0xF0) == 0xE0) \
|
||||
__s += 3; \
|
||||
else if ((*__s & 0xF8) == 0xF0) \
|
||||
__s += 4; \
|
||||
else if ((*__s & 0xFC) == 0xF8) \
|
||||
__s += 5; \
|
||||
else if ((*__s & 0xFE) == 0xFC) \
|
||||
__s += 6; \
|
||||
else \
|
||||
assert(0); \
|
||||
(l)++; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* Find previous legal UTF8 char in string
|
||||
*
|
||||
* \param s The string
|
||||
* \param o Offset in the string to start at (updated on exit)
|
||||
*/
|
||||
#define utf8_prev(s, o) \
|
||||
do { \
|
||||
while ((o) != 0 && \
|
||||
!((((s)[--(o)] & 0x80) == 0x00) || \
|
||||
(((s)[(o)] & 0xC0) == 0xC0))) \
|
||||
/* do nothing */; \
|
||||
} while(0)
|
||||
|
||||
/**
|
||||
* Find next legal UTF8 char in string
|
||||
*
|
||||
* \param s The string
|
||||
* \param l Maximum offset in string
|
||||
* \param o Offset in the string to start at (updated on exit)
|
||||
*/
|
||||
#define utf8_next(s, l, o) \
|
||||
do { \
|
||||
while ((o) != (l) && \
|
||||
!((((s)[++(o)] & 0x80) == 0x00) || \
|
||||
(((s)[(o)] & 0xC0) == 0xC0))) \
|
||||
/* do nothing */; \
|
||||
} while(0)
|
||||
|
||||
/**
|
||||
* Handle clicks in a text area by placing the caret.
|
||||
*
|
||||
* \param bw browser window where click occurred
|
||||
* \param mouse state of mouse buttons and modifier keys
|
||||
* \param textarea textarea box
|
||||
* \param box_x position of textarea in global document coordinates
|
||||
* \param box_y position of textarea in global document coordinates
|
||||
* \param x coordinate of click relative to textarea
|
||||
* \param y coordinate of click relative to textarea
|
||||
*/
|
||||
void browser_window_textarea_click(struct browser_window *bw,
|
||||
browser_mouse_state mouse,
|
||||
struct box *textarea,
|
||||
int box_x, int box_y,
|
||||
int x, int y)
|
||||
{
|
||||
/* A textarea is an INLINE_BLOCK containing a single
|
||||
* INLINE_CONTAINER, which contains the text as runs of INLINE
|
||||
* separated by BR. There is at least one INLINE. The first and
|
||||
* last boxes are INLINE. Consecutive BR may not be present. These
|
||||
* constraints are satisfied by using a 0-length INLINE for blank
|
||||
* lines. */
|
||||
|
||||
int char_offset = 0, pixel_offset = 0, new_scroll_y;
|
||||
struct box *inline_container, *text_box;
|
||||
|
||||
inline_container = textarea->children;
|
||||
|
||||
if (inline_container->y + inline_container->height < y) {
|
||||
/* below the bottom of the textarea: place caret at end */
|
||||
text_box = inline_container->last;
|
||||
assert(text_box->type == BOX_INLINE);
|
||||
assert(text_box->text);
|
||||
/** \todo handle errors */
|
||||
nsfont_position_in_string(text_box->style, text_box->text,
|
||||
text_box->length,
|
||||
textarea->width,
|
||||
&char_offset, &pixel_offset);
|
||||
} else {
|
||||
/* find the relevant text box */
|
||||
y -= inline_container->y;
|
||||
for (text_box = inline_container->children;
|
||||
text_box &&
|
||||
text_box->y + text_box->height < y;
|
||||
text_box = text_box->next)
|
||||
;
|
||||
for (; text_box && text_box->type != BOX_BR &&
|
||||
text_box->y <= y &&
|
||||
text_box->x + text_box->width < x;
|
||||
text_box = text_box->next)
|
||||
;
|
||||
if (!text_box) {
|
||||
/* past last text box */
|
||||
text_box = inline_container->last;
|
||||
assert(text_box->type == BOX_INLINE);
|
||||
assert(text_box->text);
|
||||
nsfont_position_in_string(text_box->style,
|
||||
text_box->text,
|
||||
text_box->length,
|
||||
textarea->width,
|
||||
&char_offset, &pixel_offset);
|
||||
} else {
|
||||
/* in a text box */
|
||||
if (text_box->type == BOX_BR)
|
||||
text_box = text_box->prev;
|
||||
else if (y < text_box->y && text_box->prev) {
|
||||
if (text_box->prev->type == BOX_BR) {
|
||||
assert(text_box->prev->prev);
|
||||
text_box = text_box->prev->prev;
|
||||
}
|
||||
else
|
||||
text_box = text_box->prev;
|
||||
}
|
||||
assert(text_box->type == BOX_INLINE);
|
||||
assert(text_box->text);
|
||||
nsfont_position_in_string(text_box->style,
|
||||
text_box->text,
|
||||
text_box->length,
|
||||
(unsigned int)(x - text_box->x),
|
||||
&char_offset, &pixel_offset);
|
||||
}
|
||||
}
|
||||
|
||||
/* scroll to place the caret in the centre of the visible region */
|
||||
new_scroll_y = inline_container->y + text_box->y +
|
||||
text_box->height / 2 -
|
||||
textarea->height / 2;
|
||||
if (textarea->descendant_y1 - textarea->height < new_scroll_y)
|
||||
new_scroll_y = textarea->descendant_y1 - textarea->height;
|
||||
if (new_scroll_y < 0)
|
||||
new_scroll_y = 0;
|
||||
box_y += textarea->scroll_y - new_scroll_y;
|
||||
|
||||
textarea->gadget->caret_inline_container = inline_container;
|
||||
textarea->gadget->caret_text_box = text_box;
|
||||
textarea->gadget->caret_box_offset = char_offset;
|
||||
textarea->gadget->caret_pixel_offset = pixel_offset;
|
||||
browser_window_place_caret(bw,
|
||||
box_x + inline_container->x + text_box->x +
|
||||
pixel_offset,
|
||||
box_y + inline_container->y + text_box->y,
|
||||
text_box->height,
|
||||
browser_window_textarea_callback, textarea);
|
||||
|
||||
if (new_scroll_y != textarea->scroll_y) {
|
||||
textarea->scroll_y = new_scroll_y;
|
||||
browser_redraw_box(bw->current_content, textarea);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Key press callback for text areas.
|
||||
*
|
||||
* \param bw The browser window containing the text area
|
||||
* \param key The ucs4 character codepoint
|
||||
* \param p The text area box
|
||||
*/
|
||||
void browser_window_textarea_callback(struct browser_window *bw,
|
||||
wchar_t key, void *p)
|
||||
{
|
||||
struct box *textarea = p;
|
||||
struct box *inline_container =
|
||||
textarea->gadget->caret_inline_container;
|
||||
struct box *text_box = textarea->gadget->caret_text_box;
|
||||
struct box *new_br, *new_text, *t;
|
||||
struct box *prev;
|
||||
size_t char_offset = textarea->gadget->caret_box_offset;
|
||||
int pixel_offset = textarea->gadget->caret_pixel_offset;
|
||||
int new_scroll_y;
|
||||
int box_x, box_y;
|
||||
char utf8[6];
|
||||
unsigned int utf8_len, i;
|
||||
char *text;
|
||||
int width = 0, height = 0;
|
||||
bool reflow = false;
|
||||
|
||||
/* box_dump(textarea, 0); */
|
||||
LOG(("key %i at %i in '%.*s'", key, char_offset,
|
||||
(int) text_box->length, text_box->text));
|
||||
|
||||
box_coords(textarea, &box_x, &box_y);
|
||||
box_x -= textarea->scroll_x;
|
||||
box_y -= textarea->scroll_y;
|
||||
|
||||
if (!(key <= 0x001F || (0x007F <= key && key <= 0x009F))) {
|
||||
/* normal character insertion */
|
||||
ucs4_to_utf8(key, utf8, utf8_len);
|
||||
|
||||
text = talloc_realloc(bw->current_content, text_box->text,
|
||||
char, text_box->length + 8);
|
||||
if (!text) {
|
||||
warn_user("NoMemory", 0);
|
||||
return;
|
||||
}
|
||||
text_box->text = text;
|
||||
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;
|
||||
text_box->text[text_box->length] = 0;
|
||||
text_box->width = UNKNOWN_WIDTH;
|
||||
char_offset += utf8_len;
|
||||
|
||||
reflow = true;
|
||||
|
||||
} else switch (key) {
|
||||
case 8:
|
||||
case 127: /* delete to left */
|
||||
if (char_offset == 0) {
|
||||
/* at the start of a text box */
|
||||
if (!text_box->prev)
|
||||
/* at very beginning of text area: ignore */
|
||||
return;
|
||||
|
||||
if (text_box->prev->type == BOX_BR) {
|
||||
/* previous box is BR: remove it */
|
||||
t = text_box->prev;
|
||||
t->prev->next = t->next;
|
||||
t->next->prev = t->prev;
|
||||
box_free(t);
|
||||
}
|
||||
|
||||
/* delete space by merging with previous text box */
|
||||
prev = text_box->prev;
|
||||
assert(prev->text);
|
||||
text = talloc_realloc(bw->current_content,
|
||||
prev->text, char,
|
||||
prev->length + text_box->length + 1);
|
||||
if (!text) {
|
||||
warn_user("NoMemory", 0);
|
||||
return;
|
||||
}
|
||||
prev->text = text;
|
||||
memcpy(prev->text + prev->length, text_box->text,
|
||||
text_box->length);
|
||||
char_offset = prev->length; /* caret at join */
|
||||
prev->length += text_box->length;
|
||||
prev->text[prev->length] = 0;
|
||||
prev->width = UNKNOWN_WIDTH;
|
||||
prev->next = text_box->next;
|
||||
if (prev->next)
|
||||
prev->next->prev = prev;
|
||||
else
|
||||
prev->parent->last = prev;
|
||||
box_free(text_box);
|
||||
|
||||
/* place caret at join (see above) */
|
||||
text_box = prev;
|
||||
|
||||
} else {
|
||||
/* delete a character */
|
||||
int prev_offset = char_offset;
|
||||
utf8_prev(text_box->text, char_offset);
|
||||
|
||||
memmove(text_box->text + char_offset,
|
||||
text_box->text + prev_offset,
|
||||
text_box->length - prev_offset);
|
||||
text_box->length -= (prev_offset - char_offset);
|
||||
text_box->width = UNKNOWN_WIDTH;
|
||||
}
|
||||
|
||||
reflow = true;
|
||||
break;
|
||||
|
||||
case 10:
|
||||
case 13: /* paragraph break */
|
||||
text = talloc_array(bw->current_content, char,
|
||||
text_box->length + 1);
|
||||
if (!text) {
|
||||
warn_user("NoMemory", 0);
|
||||
return;
|
||||
}
|
||||
|
||||
new_br = box_create(text_box->style, 0, text_box->title, 0,
|
||||
bw->current_content);
|
||||
new_text = talloc(bw->current_content, struct box);
|
||||
if (!new_text) {
|
||||
warn_user("NoMemory", 0);
|
||||
return;
|
||||
}
|
||||
|
||||
new_br->type = BOX_BR;
|
||||
box_insert_sibling(text_box, new_br);
|
||||
|
||||
memcpy(new_text, text_box, sizeof (struct box));
|
||||
new_text->clone = 1;
|
||||
new_text->text = text;
|
||||
memcpy(new_text->text, text_box->text + char_offset,
|
||||
text_box->length - char_offset);
|
||||
new_text->length = text_box->length - char_offset;
|
||||
text_box->length = char_offset;
|
||||
text_box->width = new_text->width = UNKNOWN_WIDTH;
|
||||
box_insert_sibling(new_br, new_text);
|
||||
|
||||
/* place caret at start of new text box */
|
||||
text_box = new_text;
|
||||
char_offset = 0;
|
||||
|
||||
reflow = true;
|
||||
break;
|
||||
|
||||
case 22: /* Ctrl + V */
|
||||
// gui_paste_from_clipboard();
|
||||
break;
|
||||
|
||||
case 24: /* Ctrl + X */
|
||||
if (gui_copy_to_clipboard(bw->sel)) {
|
||||
/** \todo block delete */
|
||||
}
|
||||
break;
|
||||
|
||||
case 28: /* Right cursor -> */
|
||||
if ((unsigned int) char_offset != text_box->length) {
|
||||
utf8_next(text_box->text, text_box->length,
|
||||
char_offset);
|
||||
} else {
|
||||
if (!text_box->next)
|
||||
/* at end of text area: ignore */
|
||||
return;
|
||||
|
||||
text_box = text_box->next;
|
||||
if (text_box->type == BOX_BR)
|
||||
text_box = text_box->next;
|
||||
char_offset = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 29: /* Left cursor <- */
|
||||
if (char_offset != 0) {
|
||||
utf8_prev(text_box->text, char_offset);
|
||||
} else {
|
||||
if (!text_box->prev)
|
||||
/* at start of text area: ignore */
|
||||
return;
|
||||
|
||||
text_box = text_box->prev;
|
||||
if (text_box->type == BOX_BR)
|
||||
text_box = text_box->prev;
|
||||
char_offset = text_box->length;
|
||||
}
|
||||
break;
|
||||
|
||||
case 30: /* Up cursor */
|
||||
browser_window_textarea_click(bw, BROWSER_MOUSE_CLICK_1,
|
||||
textarea,
|
||||
box_x, box_y,
|
||||
text_box->x + pixel_offset,
|
||||
inline_container->y + text_box->y - 1);
|
||||
return;
|
||||
|
||||
case 31: /* Down cursor */
|
||||
browser_window_textarea_click(bw, BROWSER_MOUSE_CLICK_1,
|
||||
textarea,
|
||||
box_x, box_y,
|
||||
text_box->x + pixel_offset,
|
||||
inline_container->y + text_box->y +
|
||||
text_box->height + 1);
|
||||
return;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
/* box_dump(textarea, 0); */
|
||||
/* for (struct box *t = inline_container->children; t; t = t->next) {
|
||||
assert(t->type == BOX_INLINE);
|
||||
assert(t->text);
|
||||
assert(t->font);
|
||||
assert(t->parent == inline_container);
|
||||
if (t->next) assert(t->next->prev == t);
|
||||
if (t->prev) assert(t->prev->next == t);
|
||||
if (!t->next) {
|
||||
assert(inline_container->last == t);
|
||||
break;
|
||||
}
|
||||
if (t->next->type == BOX_BR) {
|
||||
assert(t->next->next);
|
||||
t = t->next;
|
||||
}
|
||||
} */
|
||||
|
||||
if (reflow) {
|
||||
/* reflow textarea preserving width and height */
|
||||
width = textarea->width;
|
||||
height = textarea->height;
|
||||
if (!layout_inline_container(inline_container, width,
|
||||
textarea, 0, 0,
|
||||
bw->current_content))
|
||||
warn_user("NoMemory", 0);
|
||||
textarea->width = width;
|
||||
textarea->height = height;
|
||||
layout_calculate_descendant_bboxes(textarea);
|
||||
}
|
||||
|
||||
if (text_box->length < char_offset) {
|
||||
/* the text box has been split and the caret is in the
|
||||
* second part */
|
||||
char_offset -= (text_box->length + 1); /* +1 for the space */
|
||||
text_box = text_box->next;
|
||||
assert(text_box);
|
||||
assert(char_offset <= text_box->length);
|
||||
}
|
||||
|
||||
/* scroll to place the caret in the centre of the visible region */
|
||||
new_scroll_y = inline_container->y + text_box->y +
|
||||
text_box->height / 2 -
|
||||
textarea->height / 2;
|
||||
if (textarea->descendant_y1 - textarea->height < new_scroll_y)
|
||||
new_scroll_y = textarea->descendant_y1 - textarea->height;
|
||||
if (new_scroll_y < 0)
|
||||
new_scroll_y = 0;
|
||||
box_y += textarea->scroll_y - new_scroll_y;
|
||||
|
||||
nsfont_width(text_box->style, text_box->text,
|
||||
char_offset, &pixel_offset);
|
||||
|
||||
textarea->gadget->caret_inline_container = inline_container;
|
||||
textarea->gadget->caret_text_box = text_box;
|
||||
textarea->gadget->caret_box_offset = char_offset;
|
||||
textarea->gadget->caret_pixel_offset = pixel_offset;
|
||||
browser_window_place_caret(bw,
|
||||
box_x + inline_container->x + text_box->x +
|
||||
pixel_offset,
|
||||
box_y + inline_container->y + text_box->y,
|
||||
text_box->height,
|
||||
browser_window_textarea_callback, textarea);
|
||||
|
||||
if (new_scroll_y != textarea->scroll_y || reflow) {
|
||||
textarea->scroll_y = new_scroll_y;
|
||||
browser_redraw_box(bw->current_content, textarea);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle clicks in a text or password input box by placing the caret.
|
||||
*
|
||||
* \param bw browser window where click occurred
|
||||
* \param input input box
|
||||
* \param box_x position of input in global document coordinates
|
||||
* \param box_y position of input in global document coordinates
|
||||
* \param x coordinate of click relative to input
|
||||
* \param y coordinate of click relative to input
|
||||
*/
|
||||
void browser_window_input_click(struct browser_window* bw,
|
||||
struct box *input,
|
||||
int box_x, int box_y,
|
||||
int x, int y)
|
||||
{
|
||||
size_t char_offset = 0;
|
||||
int pixel_offset = 0, dx = 0;
|
||||
struct box *text_box = input->children->children;
|
||||
int uchars;
|
||||
unsigned int offset;
|
||||
|
||||
nsfont_position_in_string(text_box->style, 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) &&
|
||||
(input->width / 2 < pixel_offset)) {
|
||||
dx = text_box->x;
|
||||
text_box->x = input->width / 2 - pixel_offset;
|
||||
if (text_box->x < input->width - text_box->width)
|
||||
text_box->x = input->width - text_box->width;
|
||||
dx -= text_box->x;
|
||||
}
|
||||
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++)
|
||||
/* do nothing */;
|
||||
}
|
||||
/* 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++)
|
||||
/* do nothing */;
|
||||
}
|
||||
assert(uchars == 0);
|
||||
input->gadget->caret_form_offset = offset;
|
||||
input->gadget->caret_pixel_offset = pixel_offset;
|
||||
browser_window_place_caret(bw,
|
||||
box_x + input->children->x +
|
||||
text_box->x + pixel_offset,
|
||||
box_y + input->children->y + text_box->y,
|
||||
text_box->height,
|
||||
browser_window_input_callback, input);
|
||||
|
||||
if (dx)
|
||||
browser_redraw_box(bw->current_content, input);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Key press callback for text or password input boxes.
|
||||
*
|
||||
* \param bw The browser window containing the input box
|
||||
* \param key The UCS4 character codepoint
|
||||
* \param p The input box
|
||||
*/
|
||||
void browser_window_input_callback(struct browser_window *bw,
|
||||
wchar_t key, void *p)
|
||||
{
|
||||
struct box *input = (struct box *)p;
|
||||
struct box *text_box = input->children->children;
|
||||
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;
|
||||
bool changed = false;
|
||||
char utf8[6];
|
||||
unsigned int utf8_len;
|
||||
bool to_textarea = false;
|
||||
|
||||
box_coords(input, &box_x, &box_y);
|
||||
|
||||
if (!(key <= 0x001F || (0x007F <= key && key <= 0x009F))) {
|
||||
char *value;
|
||||
|
||||
/* have we exceeded max length of input? */
|
||||
utf8_length(input->gadget->value, utf8_len);
|
||||
if (utf8_len >= input->gadget->maxlength)
|
||||
return;
|
||||
|
||||
/* normal character insertion */
|
||||
|
||||
/* Insert key in gadget */
|
||||
ucs4_to_utf8(key, utf8, utf8_len);
|
||||
|
||||
value = realloc(input->gadget->value,
|
||||
input->gadget->length + utf8_len + 1);
|
||||
if (!value) {
|
||||
warn_user("NoMemory", 0);
|
||||
return;
|
||||
}
|
||||
input->gadget->value = value;
|
||||
|
||||
memmove(input->gadget->value + form_offset + utf8_len,
|
||||
input->gadget->value + form_offset,
|
||||
input->gadget->length - form_offset);
|
||||
memcpy(input->gadget->value + form_offset, utf8, utf8_len);
|
||||
input->gadget->length += utf8_len;
|
||||
input->gadget->value[input->gadget->length] = 0;
|
||||
form_offset += utf8_len;
|
||||
|
||||
/* Insert key in text box */
|
||||
/* Convert space into NBSP */
|
||||
ucs4_to_utf8((input->gadget->type == GADGET_PASSWORD) ?
|
||||
'*' : (key == ' ') ? 160 : key,
|
||||
utf8, utf8_len);
|
||||
|
||||
value = talloc_realloc(bw->current_content, text_box->text,
|
||||
char, text_box->length + utf8_len + 1);
|
||||
if (!value) {
|
||||
warn_user("NoMemory", 0);
|
||||
return;
|
||||
}
|
||||
text_box->text = value;
|
||||
|
||||
memmove(text_box->text + box_offset + utf8_len,
|
||||
text_box->text + box_offset,
|
||||
text_box->length - box_offset);
|
||||
memcpy(text_box->text + box_offset, utf8, utf8_len);
|
||||
text_box->length += utf8_len;
|
||||
text_box->text[text_box->length] = 0;
|
||||
box_offset += utf8_len;
|
||||
|
||||
nsfont_width(text_box->style, text_box->text,
|
||||
text_box->length, &text_box->width);
|
||||
changed = true;
|
||||
|
||||
} else switch (key) {
|
||||
case 8:
|
||||
case 127: { /* Delete to left */
|
||||
int prev_offset;
|
||||
|
||||
if (box_offset == 0)
|
||||
return;
|
||||
|
||||
/* Gadget */
|
||||
prev_offset = form_offset;
|
||||
/* Go to the previous valid UTF-8 character */
|
||||
utf8_prev(input->gadget->value, form_offset);
|
||||
|
||||
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 */
|
||||
utf8_prev(text_box->text, box_offset);
|
||||
|
||||
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;
|
||||
|
||||
nsfont_width(text_box->style, text_box->text,
|
||||
text_box->length, &text_box->width);
|
||||
|
||||
changed = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 9: { /* Tab */
|
||||
struct form_control *next_input;
|
||||
for (next_input = input->gadget->next;
|
||||
next_input &&
|
||||
next_input->type != GADGET_TEXTBOX &&
|
||||
next_input->type != GADGET_TEXTAREA &&
|
||||
next_input->type != GADGET_PASSWORD;
|
||||
next_input = next_input->next)
|
||||
;
|
||||
if (!next_input)
|
||||
return;
|
||||
|
||||
input = next_input->box;
|
||||
text_box = input->children->children;
|
||||
box_coords(input, &box_x, &box_y);
|
||||
form_offset = box_offset = 0;
|
||||
to_textarea = next_input->type == GADGET_TEXTAREA;
|
||||
}
|
||||
break;
|
||||
|
||||
case 10:
|
||||
case 13: /* Return/Enter hit */
|
||||
if (form)
|
||||
browser_form_submit(bw, form, 0);
|
||||
return;
|
||||
|
||||
case 11: { /* Shift + Tab */
|
||||
struct form_control *prev_input;
|
||||
for (prev_input = input->gadget->prev;
|
||||
prev_input &&
|
||||
prev_input->type != GADGET_TEXTBOX &&
|
||||
prev_input->type != GADGET_TEXTAREA &&
|
||||
prev_input->type != GADGET_PASSWORD;
|
||||
prev_input = prev_input->prev)
|
||||
;
|
||||
if (!prev_input)
|
||||
return;
|
||||
|
||||
input = prev_input->box;
|
||||
text_box = input->children->children;
|
||||
box_coords(input, &box_x, &box_y);
|
||||
form_offset = box_offset = 0;
|
||||
to_textarea = prev_input->type == GADGET_TEXTAREA;
|
||||
}
|
||||
break;
|
||||
|
||||
case 21: /* Ctrl + U */
|
||||
text_box->text[0] = 0;
|
||||
text_box->length = 0;
|
||||
box_offset = 0;
|
||||
|
||||
input->gadget->value[0] = 0;
|
||||
input->gadget->length = 0;
|
||||
form_offset = 0;
|
||||
|
||||
text_box->width = 0;
|
||||
changed = true;
|
||||
break;
|
||||
|
||||
case 22: /* Ctrl + V */
|
||||
// gui_paste_from_clipboard();
|
||||
break;
|
||||
|
||||
case 28: /* Right cursor -> */
|
||||
/* Text box */
|
||||
/* Go to the next valid UTF-8 character */
|
||||
utf8_next(text_box->text, text_box->length, box_offset);
|
||||
/* Gadget */
|
||||
/* Go to the next valid UTF-8 character */
|
||||
utf8_next(input->gadget->value, input->gadget->length,
|
||||
form_offset);
|
||||
break;
|
||||
|
||||
case 29: /* Left cursor -> */
|
||||
/* Text box */
|
||||
/* Go to the previous valid UTF-8 character */
|
||||
utf8_prev(text_box->text, box_offset);
|
||||
/* Gadget */
|
||||
/* Go to the previous valid UTF-8 character */
|
||||
utf8_prev(input->gadget->value, form_offset);
|
||||
break;
|
||||
|
||||
case 128: /* Ctrl + Left */
|
||||
box_offset = form_offset = 0;
|
||||
break;
|
||||
|
||||
case 129: /* Ctrl + Right */
|
||||
box_offset = text_box->length;
|
||||
form_offset = input->gadget->length;
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
nsfont_width(text_box->style, text_box->text, box_offset,
|
||||
&pixel_offset);
|
||||
dx = text_box->x;
|
||||
text_box->x = 0;
|
||||
if (input->width < text_box->width &&
|
||||
input->width / 2 < pixel_offset) {
|
||||
text_box->x = input->width / 2 - pixel_offset;
|
||||
if (text_box->x < input->width - text_box->width)
|
||||
text_box->x = input->width - text_box->width;
|
||||
}
|
||||
dx -= text_box->x;
|
||||
input->gadget->caret_pixel_offset = pixel_offset;
|
||||
|
||||
if (to_textarea) {
|
||||
/* moving to textarea so need to set these up */
|
||||
input->gadget->caret_inline_container = input->children;
|
||||
input->gadget->caret_text_box = text_box;
|
||||
}
|
||||
|
||||
input->gadget->caret_box_offset = box_offset;
|
||||
input->gadget->caret_form_offset = form_offset;
|
||||
|
||||
browser_window_place_caret(bw,
|
||||
box_x + input->children->x +
|
||||
text_box->x + pixel_offset,
|
||||
box_y + input->children->y + text_box->y,
|
||||
text_box->height,
|
||||
/* use the appropriate callback */
|
||||
to_textarea ? browser_window_textarea_callback
|
||||
: browser_window_input_callback, input);
|
||||
|
||||
if (dx || changed)
|
||||
browser_redraw_box(bw->current_content, input);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Position the caret and assign a callback for key presses.
|
||||
*
|
||||
* \param bw The browser window in which to place the caret
|
||||
* \param x X coordinate of the caret
|
||||
* \param y Y coordinate
|
||||
* \param height Height of caret
|
||||
* \param callback Callback function for keypresses
|
||||
* \param p Callback private data pointer, passed to callback function
|
||||
*/
|
||||
void browser_window_place_caret(struct browser_window *bw,
|
||||
int x, int y, int height,
|
||||
void (*callback)(struct browser_window *bw,
|
||||
wchar_t key, void *p),
|
||||
void *p)
|
||||
{
|
||||
gui_window_place_caret(bw->window, x, y, height);
|
||||
bw->caret_callback = callback;
|
||||
bw->caret_p = p;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes the caret and callback for key process.
|
||||
*
|
||||
* \param bw The browser window from which to remove caret
|
||||
*/
|
||||
void browser_window_remove_caret(struct browser_window *bw)
|
||||
{
|
||||
gui_window_remove_caret(bw->window);
|
||||
bw->caret_callback = NULL;
|
||||
bw->caret_p = NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle key presses in a browser window.
|
||||
*
|
||||
* \param bw The browser window with input focus
|
||||
* \param key The UCS4 character codepoint
|
||||
* \return true if key handled, false otherwise
|
||||
*/
|
||||
bool browser_window_key_press(struct browser_window *bw, wchar_t key)
|
||||
{
|
||||
/* keys that take effect wherever the caret is positioned */
|
||||
switch (key) {
|
||||
case 1: /* Ctrl + A */
|
||||
selection_select_all(bw->sel);
|
||||
return true;
|
||||
|
||||
case 3: /* Ctrl + C */
|
||||
gui_copy_to_clipboard(bw->sel);
|
||||
return true;
|
||||
|
||||
case 26: /* Ctrl + Z */
|
||||
selection_clear(bw->sel, true);
|
||||
return true;
|
||||
|
||||
case 27: /** Escape */
|
||||
if (selection_defined(bw->sel)) {
|
||||
selection_clear(bw->sel, true);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* pass on to the appropriate field */
|
||||
if (!bw->caret_callback)
|
||||
return false;
|
||||
bw->caret_callback(bw, key, bw->caret_p);
|
||||
return true;
|
||||
}
|
27
desktop/textinput.h
Normal file
27
desktop/textinput.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* This file is part of NetSurf, http://netsurf.sourceforge.net/
|
||||
* Licensed under the GNU General Public License,
|
||||
* http://www.opensource.org/licenses/gpl-license
|
||||
* Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
|
||||
* Copyright 2004 James Bursa <bursa@users.sourceforge.net>
|
||||
* Copyright 2004 Andrew Timmins <atimmins@blueyonder.co.uk>
|
||||
* Copyright 2004 John Tytgat <John.Tytgat@aaug.net>
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* Textual input handling (interface)
|
||||
*/
|
||||
|
||||
struct browser_window;
|
||||
struct box;
|
||||
|
||||
void browser_window_textarea_click(struct browser_window *bw,
|
||||
browser_mouse_state mouse,
|
||||
struct box *textarea,
|
||||
int box_x, int box_y,
|
||||
int x, int y);
|
||||
void browser_window_input_click(struct browser_window* bw,
|
||||
struct box *input,
|
||||
int box_x, int box_y,
|
||||
int x, int y);
|
||||
void browser_window_remove_caret(struct browser_window *bw);
|
4
makefile
4
makefile
@ -22,8 +22,8 @@ OBJECTS_COMMON += css.o css_enum.o parser.o ruleset.o scanner.o # css/
|
||||
OBJECTS_COMMON += box.o box_construct.o box_normalise.o form.o html.o \
|
||||
html_redraw.o layout.o list.o textplain.o # render/
|
||||
OBJECTS_COMMON += messages.o pool.o talloc.o url.o utils.o # utils/
|
||||
OBJECTS_COMMON += imagemap.o loginlist.o options.o \
|
||||
selection.o tree.o # desktop/
|
||||
OBJECTS_COMMON += imagemap.o loginlist.o options.o selection.o \
|
||||
textinput.o tree.o # desktop/
|
||||
|
||||
OBJECTS_IMAGE = jpeg.o mng.o gif.o gifread.o # image/
|
||||
|
||||
|
333
riscos/ucstables.c
Normal file
333
riscos/ucstables.c
Normal file
@ -0,0 +1,333 @@
|
||||
/*
|
||||
* This file is part of NetSurf, http://netsurf.sourceforge.net/
|
||||
* Licensed under the GNU General Public License,
|
||||
* http://www.opensource.org/licenses/gpl-license
|
||||
* Copyright 2005 John M Bell <jmb202@ecs.soton.ac.uk>
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* UCS conversion tables
|
||||
*/
|
||||
|
||||
#include "oslib/territory.h"
|
||||
#include "netsurf/riscos/ucstables.h"
|
||||
|
||||
/* Common values (ASCII) */
|
||||
#define common \
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, \
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, \
|
||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, \
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, \
|
||||
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, \
|
||||
80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, \
|
||||
96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111, \
|
||||
112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127 \
|
||||
|
||||
/* 0x8c->0x9F, used by many of the encodings */
|
||||
#define common2 \
|
||||
0x2026, 0x2122, 0x2030, 0x2022, 0x2018, 0x2019, 0x2039, 0x203a, \
|
||||
0x201c, 0x201d, 0x201e, 0x2013, 0x2014, 0x2212, 0x0152, 0x0153, \
|
||||
0x2020, 0x2021, 0xfb01, 0xfb02
|
||||
|
||||
static int latin1_table[256] =
|
||||
{
|
||||
common,
|
||||
0x20ac, 0x0174, 0x0175, -1, -1, 0x0176, 0x0177, -1, -1, -1, -1, -1,
|
||||
common2,
|
||||
160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
|
||||
176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
|
||||
192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
|
||||
208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
|
||||
224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
|
||||
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
|
||||
};
|
||||
|
||||
static int latin2_table[256] =
|
||||
{
|
||||
common,
|
||||
0x20ac, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
common2,
|
||||
0x00A0, 0x0104, 0x02D8, 0x0141, 0x00A4, 0x013D, 0x015A, 0x00A7,
|
||||
0x00A8, 0x0160, 0x015E, 0x0164, 0x0179, 0x00AD, 0x017D, 0x017B,
|
||||
0x00B0, 0x0105, 0x02DB, 0x0142, 0x00B4, 0x013E, 0x015B, 0x02C7,
|
||||
0x00B8, 0x0161, 0x015F, 0x0165, 0x017A, 0x02DD, 0x017E, 0x017C,
|
||||
0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7,
|
||||
0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E,
|
||||
0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7,
|
||||
0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF,
|
||||
0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7,
|
||||
0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F,
|
||||
0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7,
|
||||
0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9
|
||||
};
|
||||
|
||||
static int latin3_table[256] =
|
||||
{
|
||||
common,
|
||||
0x20ac, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
common2,
|
||||
0x00A0, 0x0126, 0x02D8, 0x00A3, 0x00A4, -1, 0x0124, 0x00A7,
|
||||
0x00A8, 0x0130, 0x015E, 0x011E, 0x0134, 0x00AD, -1, 0x017B,
|
||||
0x00B0, 0x0127, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x0125, 0x00B7,
|
||||
0x00B8, 0x0131, 0x015F, 0x011F, 0x0135, 0x00BD, -1, 0x017C,
|
||||
0x00C0, 0x00C1, 0x00C2, -1, 0x00C4, 0x010A, 0x0108, 0x00C7,
|
||||
0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
|
||||
-1, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x0120, 0x00D6, 0x00D7,
|
||||
0x011C, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x016C, 0x015C, 0x00DF,
|
||||
0x00E0, 0x00E1, 0x00E2, -1, 0x00E4, 0x010B, 0x0109, 0x00E7,
|
||||
0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
|
||||
-1, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x0121, 0x00F6, 0x00F7,
|
||||
0x011D, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x016D, 0x015D, 0x02D9
|
||||
};
|
||||
|
||||
static int latin4_table[256] =
|
||||
{
|
||||
common,
|
||||
0x20ac, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
common2,
|
||||
0x00A0, 0x0104, 0x0138, 0x0156, 0x00A4, 0x0128, 0x013B, 0x00A7,
|
||||
0x00A8, 0x0160, 0x0112, 0x0122, 0x0166, 0x00AD, 0x017D, 0x00AF,
|
||||
0x00B0, 0x0105, 0x02DB, 0x0157, 0x00B4, 0x0129, 0x013C, 0x02C7,
|
||||
0x00B8, 0x0161, 0x0113, 0x0123, 0x0167, 0x014A, 0x017E, 0x014B,
|
||||
0x0100, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x012E,
|
||||
0x010C, 0x00C9, 0x0118, 0x00CB, 0x0116, 0x00CD, 0x00CE, 0x012A,
|
||||
0x0110, 0x0145, 0x014C, 0x0136, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
|
||||
0x00D8, 0x0172, 0x00DA, 0x00DB, 0x00DC, 0x0168, 0x016A, 0x00DF,
|
||||
0x0101, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x012F,
|
||||
0x010D, 0x00E9, 0x0119, 0x00EB, 0x0117, 0x00ED, 0x00EE, 0x012B,
|
||||
0x0111, 0x0146, 0x014D, 0x0137, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
|
||||
0x00F8, 0x0173, 0x00FA, 0x00FB, 0x00FC, 0x0169, 0x016B, 0x02D9
|
||||
};
|
||||
|
||||
static int latin5_table[256] =
|
||||
{
|
||||
common,
|
||||
0x20ac, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
common2,
|
||||
0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
|
||||
0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
|
||||
0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
|
||||
0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
|
||||
0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
|
||||
0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
|
||||
0x011E, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
|
||||
0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0130, 0x015E, 0x00DF,
|
||||
0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
|
||||
0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
|
||||
0x011F, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
|
||||
0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015F, 0x00FF
|
||||
};
|
||||
|
||||
static int latin6_table[256] =
|
||||
{
|
||||
common,
|
||||
0x20ac, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
common2,
|
||||
0x00A0, 0x0104, 0x0112, 0x0122, 0x012A, 0x0128, 0x0136, 0x00A7,
|
||||
0x013B, 0x0110, 0x0160, 0x0166, 0x017D, 0x00AD, 0x016A, 0x014A,
|
||||
0x00B0, 0x0105, 0x0113, 0x0123, 0x012B, 0x0129, 0x0137, 0x00B7,
|
||||
0x013C, 0x0111, 0x0161, 0x0167, 0x017E, 0x2015, 0x016B, 0x014B,
|
||||
0x0100, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x012E,
|
||||
0x010C, 0x00C9, 0x0118, 0x00CB, 0x0116, 0x00CD, 0x00CE, 0x00CF,
|
||||
0x00D0, 0x0145, 0x014C, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x0168,
|
||||
0x00D8, 0x0172, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF,
|
||||
0x0101, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x012F,
|
||||
0x010D, 0x00E9, 0x0119, 0x00EB, 0x0117, 0x00ED, 0x00EE, 0x00EF,
|
||||
0x00F0, 0x0146, 0x014D, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x0169,
|
||||
0x00F8, 0x0173, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x0138
|
||||
};
|
||||
|
||||
static int latin7_table[256] =
|
||||
{
|
||||
common,
|
||||
0x20ac, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
0x2026, 0x2122, 0x2030, 0x2022, 0x2018, -1, 0x2039, 0x203a,
|
||||
-1, -1, -1, 0x2013, 0x2014, 0x2212, 0x0152, 0x0153,
|
||||
0x2020, 0x2021, 0xfb01, 0xfb02,
|
||||
0x00A0, 0x201D, 0x00A2, 0x00A3, 0x00A4, 0x201E, 0x00A6, 0x00A7,
|
||||
0x00D8, 0x00A9, 0x0156, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00C6,
|
||||
0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x201C, 0x00B5, 0x00B6, 0x00B7,
|
||||
0x00F8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00E6,
|
||||
0x0104, 0x012E, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112,
|
||||
0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012A, 0x013B,
|
||||
0x0160, 0x0143, 0x0145, 0x00D3, 0x014C, 0x00D5, 0x00D6, 0x00D7,
|
||||
0x0172, 0x0141, 0x015A, 0x016A, 0x00DC, 0x017B, 0x017D, 0x00DF,
|
||||
0x0105, 0x012F, 0x0101, 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113,
|
||||
0x010D, 0x00E9, 0x017A, 0x0117, 0x0123, 0x0137, 0x012B, 0x013C,
|
||||
0x0161, 0x0144, 0x0146, 0x00F3, 0x014D, 0x00F5, 0x00F6, 0x00F7,
|
||||
0x0173, 0x0142, 0x015B, 0x016B, 0x00FC, 0x017C, 0x017E, 0x2019
|
||||
};
|
||||
|
||||
static int latin8_table[256] =
|
||||
{
|
||||
common,
|
||||
0x20ac, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
common2,
|
||||
0x00A0, 0x1E02, 0x1E03, 0x00A3, 0x010A, 0x010B, 0x1E0A, 0x00A7,
|
||||
0x1E80, 0x00A9, 0x1E82, 0x1E0B, 0x1EF2, 0x00AD, 0x00AE, 0x0178,
|
||||
0x1E1E, 0x1E1F, 0x0120, 0x0121, 0x1E40, 0x1E41, 0x00B6, 0x1E56,
|
||||
0x1E81, 0x1E57, 0x1E83, 0x1E60, 0x1EF3, 0x1E84, 0x1E85, 0x1E61,
|
||||
0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
|
||||
0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
|
||||
0x0174, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x1E6A,
|
||||
0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x0176, 0x00DF,
|
||||
0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
|
||||
0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
|
||||
0x0175, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x1E6B,
|
||||
0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x0177, 0x00FF
|
||||
};
|
||||
|
||||
static int latin9_table[256] =
|
||||
{
|
||||
common,
|
||||
-1, 0x0174, 0x0175, -1, -1, 0x0176, 0x0177, -1, -1, -1, -1, -1,
|
||||
0x2026, 0x2122, 0x2030, 0x2022, 0x2018, 0x2019, 0x2039, 0x203a,
|
||||
0x201c, 0x201d, 0x201e, 0x2013, 0x2014, 0x2212, -1, -1,
|
||||
0x2020, 0x2021, 0xfb01, 0xfb02,
|
||||
0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x20AC, 0x00A5, 0x0160, 0x00A7,
|
||||
0x0161, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
|
||||
0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x017D, 0x00B5, 0x00B6, 0x00B7,
|
||||
0x017E, 0x00B9, 0x00BA, 0x00BB, 0x0152, 0x0153, 0x0178, 0x00BF,
|
||||
0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
|
||||
0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
|
||||
0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
|
||||
0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF,
|
||||
0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
|
||||
0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
|
||||
0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
|
||||
0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF
|
||||
};
|
||||
|
||||
static int welsh_table[256] =
|
||||
{
|
||||
common,
|
||||
0x20ac, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
common2,
|
||||
0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
|
||||
0x1E80, 0x00A9, 0x1E82, 0x00AB, 0x1EF2, 0x00AD, 0x00AE, 0x0178,
|
||||
0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
|
||||
0x1E81, 0x00B9, 0x1E83, 0x00BB, 0x1EF3, 0x1E84, 0x1E85, 0x00BF,
|
||||
0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7,
|
||||
0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
|
||||
0x0174, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
|
||||
0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x0176, 0x00DF,
|
||||
0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
|
||||
0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
|
||||
0x0175, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
|
||||
0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x0177, 0x00FF
|
||||
};
|
||||
|
||||
static int greek_table[256] =
|
||||
{
|
||||
common,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
0x00A0, 0x2018, 0x2019, 0x00A3, 0x20AC, 0x20AF, 0x00A6, 0x00A7,
|
||||
0x00A8, 0x00A9, 0x037A, 0x00AB, 0x00AC, 0x00AD, 0x037E, 0x2015,
|
||||
0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0384, 0x0385, 0x0386, 0x0387,
|
||||
0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, 0x038F,
|
||||
0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397,
|
||||
0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F,
|
||||
0x03A0, 0x03A1, -1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7,
|
||||
0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF,
|
||||
0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7,
|
||||
0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
|
||||
0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7,
|
||||
0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, -1
|
||||
};
|
||||
|
||||
static int cyrillic_table[256] =
|
||||
{
|
||||
common,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
0x00A0, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407,
|
||||
0x0408, 0x0409, 0x040A, 0x040B, 0x040C, 0x00AD, 0x040E, 0x040F,
|
||||
0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
|
||||
0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
|
||||
0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
|
||||
0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
|
||||
0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
|
||||
0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
|
||||
0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
|
||||
0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
|
||||
0x2116, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457,
|
||||
0x0458, 0x0459, 0x045A, 0x045B, 0x045C, 0x00A7, 0x045E, 0x045F
|
||||
};
|
||||
|
||||
static int hebrew_table[256] =
|
||||
{
|
||||
common,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
0x00A0, -1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
|
||||
0x00A8, 0x00A9, 0x00D7, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x203E,
|
||||
0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
|
||||
0x00B8, 0x00B9, 0x00F7, 0x00BB, 0x00BC, 0x00BD, 0x00BE, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, 0x2017,
|
||||
0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7,
|
||||
0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
|
||||
0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7,
|
||||
0x05E8, 0x05E9, 0x05EA, -1, -1, 0x200E, 0x200F, -1
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve UCS table (above), given alphabet number
|
||||
*
|
||||
* \param alphabet The RISC OS alphabet number
|
||||
* \return pointer to table, or NULL if not found
|
||||
*/
|
||||
int *ucstable_from_alphabet(int alphabet)
|
||||
{
|
||||
int *ucstable = NULL;
|
||||
|
||||
switch (alphabet) {
|
||||
case territory_ALPHABET_LATIN1:
|
||||
ucstable = latin1_table;
|
||||
break;
|
||||
case territory_ALPHABET_LATIN2:
|
||||
ucstable = latin2_table;
|
||||
break;
|
||||
case territory_ALPHABET_LATIN3:
|
||||
ucstable = latin3_table;
|
||||
break;
|
||||
case territory_ALPHABET_LATIN4:
|
||||
ucstable = latin4_table;
|
||||
break;
|
||||
case territory_ALPHABET_LATIN5:
|
||||
ucstable = latin5_table;
|
||||
break;
|
||||
case territory_ALPHABET_LATIN6:
|
||||
ucstable = latin6_table;
|
||||
break;
|
||||
case 114: /* Latin7 */
|
||||
ucstable = latin7_table;
|
||||
break;
|
||||
case 115: /* Latin8 */
|
||||
ucstable = latin8_table;
|
||||
break;
|
||||
case territory_ALPHABET_LATIN9:
|
||||
ucstable = latin9_table;
|
||||
break;
|
||||
case territory_ALPHABET_WELSH:
|
||||
ucstable = welsh_table;
|
||||
break;
|
||||
case territory_ALPHABET_GREEK:
|
||||
ucstable = greek_table;
|
||||
break;
|
||||
case territory_ALPHABET_CYRILLIC:
|
||||
ucstable = cyrillic_table;
|
||||
break;
|
||||
case territory_ALPHABET_HEBREW:
|
||||
ucstable = hebrew_table;
|
||||
break;
|
||||
default:
|
||||
ucstable = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ucstable;
|
||||
}
|
13
riscos/ucstables.h
Normal file
13
riscos/ucstables.h
Normal file
@ -0,0 +1,13 @@
|
||||
/*
|
||||
* This file is part of NetSurf, http://netsurf.sourceforge.net/
|
||||
* Licensed under the GNU General Public License,
|
||||
* http://www.opensource.org/licenses/gpl-license
|
||||
* Copyright 2005 John M Bell <jmb202@ecs.soton.ac.uk>
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* UCS conversion tables (interface)
|
||||
* This is only used if nothing claims Service_International,8
|
||||
*/
|
||||
|
||||
int *ucstable_from_alphabet(int alphabet);
|
150
riscos/window.c
150
riscos/window.c
@ -21,6 +21,7 @@
|
||||
#include "oslib/colourtrans.h"
|
||||
#include "oslib/osbyte.h"
|
||||
#include "oslib/osspriteop.h"
|
||||
#include "oslib/serviceinternational.h"
|
||||
#include "oslib/wimp.h"
|
||||
#include "oslib/wimpspriteop.h"
|
||||
#include "netsurf/utils/config.h"
|
||||
@ -38,9 +39,11 @@
|
||||
#include "netsurf/riscos/theme.h"
|
||||
#include "netsurf/riscos/thumbnail.h"
|
||||
#include "netsurf/riscos/treeview.h"
|
||||
#include "netsurf/riscos/ucstables.h"
|
||||
#include "netsurf/riscos/url_complete.h"
|
||||
#include "netsurf/riscos/wimp.h"
|
||||
#include "netsurf/utils/log.h"
|
||||
#include "netsurf/utils/talloc.h"
|
||||
#include "netsurf/utils/url.h"
|
||||
#include "netsurf/utils/utils.h"
|
||||
#include "netsurf/utils/messages.h"
|
||||
@ -341,7 +344,7 @@ void gui_window_set_title(struct gui_window *g, const char *title)
|
||||
|
||||
assert(g);
|
||||
assert(title);
|
||||
|
||||
|
||||
if (g->option.scale != 1.0) {
|
||||
scale_disp = g->option.scale * 100;
|
||||
if ((float)scale_disp != g->option.scale * 100)
|
||||
@ -473,7 +476,7 @@ void ro_gui_window_redraw(struct gui_window *g, wimp_draw *redraw)
|
||||
clear_background = true;
|
||||
scale = g->option.scale;
|
||||
break;
|
||||
|
||||
|
||||
|
||||
#ifdef WITH_SPRITE
|
||||
case CONTENT_SPRITE:
|
||||
@ -1084,7 +1087,7 @@ void ro_gui_window_open(struct gui_window *g, wimp_open *open)
|
||||
|
||||
/* first resize stops any flickering by making the URL window on top */
|
||||
ro_gui_url_complete_resize(g, open);
|
||||
|
||||
|
||||
error = xwimp_open_window(open);
|
||||
if (error) {
|
||||
LOG(("xwimp_open_window: 0x%x: %s",
|
||||
@ -1253,12 +1256,12 @@ void ro_gui_toolbar_click(struct gui_window *g, wimp_pointer *pointer)
|
||||
pointer->pos.y, g->window);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Handle toolbar edits
|
||||
*/
|
||||
if ((g->toolbar->editor) && (pointer->i < ICON_TOOLBAR_URL)) {
|
||||
ro_gui_theme_toolbar_editor_click(g->toolbar, pointer);
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Handle the buttons appropriately
|
||||
@ -1535,13 +1538,15 @@ bool ro_gui_window_keypress(struct gui_window *g, int key, bool toolbar)
|
||||
{
|
||||
struct content *content = g->bw->current_content;
|
||||
wimp_window_state state;
|
||||
int y;
|
||||
int y, t_alphabet;
|
||||
char *url;
|
||||
char *toolbar_url;
|
||||
os_error *error;
|
||||
wimp_pointer pointer;
|
||||
url_func_result res;
|
||||
float old_scale;
|
||||
static int *ucstable = NULL;
|
||||
static int alphabet = 0;
|
||||
|
||||
error = xwimp_get_pointer_info(&pointer);
|
||||
if (error) {
|
||||
@ -1551,24 +1556,147 @@ bool ro_gui_window_keypress(struct gui_window *g, int key, bool toolbar)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* In order to make sensible use of the 0x80->0xFF ranges specified
|
||||
* in the RISC OS 8bit alphabets, we must do the following:
|
||||
*
|
||||
* + Read the currently selected alphabet
|
||||
* + Acquire a pointer to the UCS conversion table for this alphabet:
|
||||
* + Try using ServiceInternational 8 to get the table
|
||||
* + If that fails, use our internal table (see ucstables.c)
|
||||
* + If the alphabet is not UTF8 and the conversion table exists:
|
||||
* + Lookup UCS code in the conversion table
|
||||
* + If code is -1 (i.e. undefined):
|
||||
* + Use codepoint 0xFFFD instead
|
||||
* + If the alphabet is UTF8, we must buffer input, thus:
|
||||
* + If the keycode is < 0x80:
|
||||
* + Handle it directly
|
||||
* + If the keycode is a UTF8 sequence start:
|
||||
* + Initialise the buffer appropriately
|
||||
* + Otherwise:
|
||||
* + OR in relevant bits from keycode to buffer
|
||||
* + If we've received an entire UTF8 character:
|
||||
* + Handle UCS code
|
||||
* + Otherwise:
|
||||
* + Simply handle the keycode directly, as there's no easy way
|
||||
* of performing the mapping from keycode -> UCS4 codepoint.
|
||||
*/
|
||||
error = xosbyte1(osbyte_ALPHABET_NUMBER, 127, 0, &t_alphabet);
|
||||
if (error) {
|
||||
LOG(("failed reading alphabet: 0x%x: %s",
|
||||
error->errnum, error->errmess));
|
||||
/* prevent any corruption of ucstable */
|
||||
t_alphabet = alphabet;
|
||||
}
|
||||
|
||||
if (t_alphabet != alphabet) {
|
||||
osbool unclaimed;
|
||||
/* Alphabet has changed, so read UCS table location */
|
||||
alphabet = t_alphabet;
|
||||
error = xserviceinternational_get_ucs_conversion_table(
|
||||
alphabet, &unclaimed,
|
||||
(void**)&ucstable);
|
||||
if (error) {
|
||||
LOG(("failed reading UCS conversion table: 0x%x: %s",
|
||||
error->errnum, error->errmess));
|
||||
/* try using our own table instead */
|
||||
ucstable = ucstable_from_alphabet(alphabet);
|
||||
}
|
||||
if (unclaimed)
|
||||
/* Service wasn't claimed so use our own ucstable */
|
||||
ucstable = ucstable_from_alphabet(alphabet);
|
||||
}
|
||||
|
||||
/* First send the key to the browser window, eg. form fields. */
|
||||
if (!toolbar) {
|
||||
wchar_t c = (wchar_t)key;
|
||||
static wchar_t wc = 0; /* buffer for UTF8 alphabet */
|
||||
static int shift = 0;
|
||||
/* Munge cursor keys into unused control chars */
|
||||
/* We can't map onto 1->26 (reserved for ctrl+<qwerty>
|
||||
That leaves 27->31 and 128->159 */
|
||||
|
||||
if (c == 394) c = 9; /* Tab */
|
||||
else if (c == 410) c = 11; /* Shift+Tab */
|
||||
else if (c == 428) c = 128; /* Ctrl+Left */
|
||||
else if (c == 429) c = 129; /* Ctrl+Right*/
|
||||
else if (c == 428) c = 128; /* Ctrl+Left */
|
||||
else if (c == 429) c = 129; /* Ctrl+Right*/
|
||||
else if (c == 396) c = 29; /* Left */
|
||||
else if (c == 397) c = 28; /* Right */
|
||||
else if (c == 398) c = 31; /* Down */
|
||||
else if (c == 399) c = 30; /* Up */
|
||||
if (c < 256)
|
||||
if (c < 256) {
|
||||
if (alphabet != 111 /* UTF8 */ && ucstable != NULL)
|
||||
/* read UCS4 value out of table */
|
||||
c = ucstable[c] == -1 ? 0xFFFD : ucstable[c];
|
||||
else if (alphabet == 111 /* UTF8 */) {
|
||||
if ((c & 0x80) == 0x00 ||
|
||||
(c & 0xC0) == 0xC0) {
|
||||
/* UTF8 start sequence */
|
||||
if ((c & 0xE0) == 0xC0) {
|
||||
wc = ((c & 0x1F) << 6);
|
||||
shift = 1;
|
||||
return true;
|
||||
}
|
||||
else if ((c & 0xF0) == 0xE0) {
|
||||
wc = ((c & 0x0F) << 12);
|
||||
shift = 2;
|
||||
return true;
|
||||
}
|
||||
else if ((c & 0xF8) == 0xF0) {
|
||||
wc = ((c & 0x07) << 18);
|
||||
shift = 3;
|
||||
return true;
|
||||
}
|
||||
/* These next two have been removed
|
||||
* from RFC3629, but there's no
|
||||
* guarantee that RISC OS won't
|
||||
* generate a UCS4 value outside the
|
||||
* UTF16 plane, so we handle them
|
||||
* anyway. */
|
||||
else if ((c & 0xFC) == 0xF8) {
|
||||
wc = ((c & 0x03) << 24);
|
||||
shift = 4;
|
||||
}
|
||||
else if ((c & 0xFE) == 0xFC) {
|
||||
wc = ((c & 0x01) << 30);
|
||||
shift = 5;
|
||||
}
|
||||
else if (c >= 0x80) {
|
||||
/* If this ever happens,
|
||||
* RISC OS' UTF8 keyboard
|
||||
* drivers are broken */
|
||||
LOG(("unexpected UTF8 start"
|
||||
" byte %x (ignoring)",
|
||||
c));
|
||||
return true;
|
||||
}
|
||||
/* Anything else is ASCII, so just
|
||||
* handle it directly. */
|
||||
}
|
||||
else {
|
||||
if ((c & 0xC0) != 0x80) {
|
||||
/* If this ever happens,
|
||||
* RISC OS' UTF8 keyboard
|
||||
* drivers are broken */
|
||||
LOG(("unexpected keycode: "
|
||||
"%x (ignoring)", c));
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Continuation of UTF8 character */
|
||||
wc |= ((c & 0x3F) << (6 * --shift));
|
||||
if (shift > 0)
|
||||
/* partial character */
|
||||
return true;
|
||||
else
|
||||
/* got entire character, so
|
||||
* fetch from buffer and
|
||||
* handle it */
|
||||
c = wc;
|
||||
}
|
||||
}
|
||||
if (browser_window_key_press(g->bw, c))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
switch (key) {
|
||||
@ -1706,13 +1834,13 @@ bool ro_gui_window_keypress(struct gui_window *g, int key, bool toolbar)
|
||||
if (scale_snap_to[i] < old_scale) {
|
||||
g->option.scale = scale_snap_to[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (unsigned int i = 0; i < SCALE_SNAP_TO_SIZE; i++)
|
||||
if (scale_snap_to[i] > old_scale) {
|
||||
g->option.scale = scale_snap_to[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (g->option.scale < scale_snap_to[0])
|
||||
g->option.scale = scale_snap_to[0];
|
||||
|
Loading…
Reference in New Issue
Block a user