mirror of
https://github.com/netsurf-browser/netsurf
synced 2025-02-22 17:34:19 +03:00
Add support for password text inputs.
+ Text display obscured. + Cut/Copy put the obscured version on the clipboard.
This commit is contained in:
parent
5ee7c6fd5c
commit
97bc1d0189
@ -23,7 +23,6 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "css/css.h"
|
||||
#include "css/utils.h"
|
||||
#include "desktop/mouse.h"
|
||||
#include "desktop/textarea.h"
|
||||
@ -54,6 +53,14 @@ struct textarea_drag {
|
||||
} data;
|
||||
};
|
||||
|
||||
struct textarea_utf8 {
|
||||
char *data; /**< UTF-8 text */
|
||||
unsigned int alloc; /**< Size of allocated text */
|
||||
unsigned int len; /**< Length of text, in bytes */
|
||||
unsigned int utf8_len; /**< Length of text, in characters without
|
||||
* trailing NULL */
|
||||
};
|
||||
|
||||
struct textarea {
|
||||
|
||||
int scroll_x, scroll_y; /**< scroll offsets for the textarea */
|
||||
@ -76,11 +83,12 @@ struct textarea {
|
||||
plot_font_style_t fstyle; /**< Text style, inc. textarea bg col */
|
||||
plot_font_style_t sel_fstyle; /**< Selected text style */
|
||||
|
||||
char *text; /**< UTF-8 text */
|
||||
unsigned int text_alloc; /**< Size of allocated text */
|
||||
unsigned int text_len; /**< Length of text, in bytes */
|
||||
unsigned int text_utf8_len; /**< Length of text, in characters
|
||||
* without the trailing NULL */
|
||||
struct textarea_utf8 text; /**< Textarea text content */
|
||||
#define PASSWORD_REPLACEMENT "\xe2\x80\xa2"
|
||||
struct textarea_utf8 password; /**< Text for obscured display */
|
||||
|
||||
struct textarea_utf8 *show; /**< Points at .text or .password */
|
||||
|
||||
struct {
|
||||
int line; /**< Line caret is on */
|
||||
int char_off; /**< Character index of caret on line */
|
||||
@ -99,7 +107,7 @@ struct textarea {
|
||||
struct line_info *lines; /**< Line info array */
|
||||
int line_height; /**< Line height obtained from style */
|
||||
|
||||
/** Callback function for a redraw request */
|
||||
/** Callback function for messages to client */
|
||||
textarea_client_callback callback;
|
||||
|
||||
void *data; /**< Client data for callback */
|
||||
@ -122,30 +130,32 @@ struct textarea {
|
||||
static void textarea_normalise_text(struct textarea *ta,
|
||||
unsigned int b_start, unsigned int b_len)
|
||||
{
|
||||
bool multi = (ta->flags & TEXTAREA_MULTILINE) ? true:false;
|
||||
bool multi = (ta->flags & TEXTAREA_MULTILINE) ? true : false;
|
||||
unsigned int index;
|
||||
|
||||
/* Remove CR characters. If it's a CRLF pair delete it ot replace it
|
||||
* with LF otherwise.
|
||||
/* Remove CR characters. If it's a CRLF pair delete the CR, or replace
|
||||
* CR with LF otherwise.
|
||||
*/
|
||||
for (index = 0; index < b_len; index++) {
|
||||
if (ta->text[b_start + index] == '\r') {
|
||||
if (b_start + index + 1 <= ta->text_len &&
|
||||
ta->text[b_start + index + 1] == '\n') {
|
||||
ta->text_len--;
|
||||
ta->text_utf8_len--;
|
||||
memmove(ta->text + b_start + index,
|
||||
ta->text + b_start + index + 1,
|
||||
ta->text_len - b_start - index);
|
||||
if (ta->text.data[b_start + index] == '\r') {
|
||||
if (b_start + index + 1 <= ta->text.len &&
|
||||
ta->text.data[b_start + index + 1] ==
|
||||
'\n') {
|
||||
ta->text.len--;
|
||||
ta->text.utf8_len--;
|
||||
memmove(ta->text.data + b_start + index,
|
||||
ta->text.data + b_start +
|
||||
index + 1,
|
||||
ta->text.len - b_start - index);
|
||||
}
|
||||
else
|
||||
ta->text[b_start + index] = '\n';
|
||||
ta->text.data[b_start + index] = '\n';
|
||||
}
|
||||
/* Replace newlines with spaces if this is a single line
|
||||
* textarea.
|
||||
*/
|
||||
if (!multi && (ta->text[b_start + index] == '\n'))
|
||||
ta->text[b_start + index] = ' ';
|
||||
if (!multi && (ta->text.data[b_start + index] == '\n'))
|
||||
ta->text.data[b_start + index] = ' ';
|
||||
}
|
||||
|
||||
}
|
||||
@ -211,22 +221,22 @@ static bool textarea_select_fragment(struct textarea * ta)
|
||||
|
||||
/* Compute byte offset of caret position */
|
||||
for (b_start = 0, index = 0; index < caret_pos;
|
||||
b_start = utf8_next(ta->text, ta->text_len,
|
||||
b_start = utf8_next(ta->show->data, ta->show->len,
|
||||
b_start),
|
||||
index++) {
|
||||
/* Cache the character offset of the last separator */
|
||||
if (strchr(sep, ta->text[b_start]) != NULL) {
|
||||
if (strchr(sep, ta->show->data[b_start]) != NULL) {
|
||||
/* Add one to start to skip over separator */
|
||||
sel_start = index + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Search for next separator, if any */
|
||||
for (b_end = b_start; b_end < ta->text_len;
|
||||
b_end = utf8_next(ta->text, ta->text_len,
|
||||
for (b_end = b_start; b_end < ta->show->len;
|
||||
b_end = utf8_next(ta->show->data, ta->show->len,
|
||||
b_end),
|
||||
index++) {
|
||||
if (strchr(sep, ta->text[b_end]) != NULL) {
|
||||
if (strchr(sep, ta->show->data[b_end]) != NULL) {
|
||||
sel_end = index;
|
||||
break;
|
||||
}
|
||||
@ -417,12 +427,50 @@ static bool textarea_reflow(struct textarea *ta, unsigned int start)
|
||||
/* Single line */
|
||||
int w = ta->vis_width - 2 * ta->border_width -
|
||||
ta->pad_left - ta->pad_right;
|
||||
ta->lines[0].b_start = 0;
|
||||
ta->lines[0].b_length = ta->text_len - 1;
|
||||
|
||||
nsfont.font_width(&ta->fstyle, ta->text, ta->text_len, &x);
|
||||
if (ta->flags & TEXTAREA_PASSWORD &&
|
||||
ta->text.utf8_len != ta->password.utf8_len) {
|
||||
/* Make password-obscured text have same number of
|
||||
* characters as underlying text */
|
||||
unsigned int c, b;
|
||||
int diff = ta->text.utf8_len - ta->password.utf8_len;
|
||||
unsigned int rep_len = sizeof(PASSWORD_REPLACEMENT) - 1;
|
||||
unsigned int b_len = ta->text.utf8_len * rep_len + 1;
|
||||
|
||||
if (diff > 0 && b_len > ta->password.alloc) {
|
||||
/* Increase password alloaction */
|
||||
char *temp = realloc(ta->password.data,
|
||||
b_len + 64);
|
||||
if (temp == NULL) {
|
||||
LOG(("realloc failed"));
|
||||
return false;
|
||||
}
|
||||
|
||||
ta->password.data = temp;
|
||||
ta->password.alloc = b_len + 64;
|
||||
}
|
||||
|
||||
b_len--;
|
||||
for (c = 0; c < b_len; c += rep_len) {
|
||||
for (b = 0; b < rep_len; b++) {
|
||||
ta->password.data[c + b] =
|
||||
PASSWORD_REPLACEMENT[b];
|
||||
}
|
||||
}
|
||||
ta->password.data[b_len] = '\0';
|
||||
ta->password.len = b_len + 1;
|
||||
ta->password.utf8_len = ta->text.utf8_len;
|
||||
}
|
||||
|
||||
ta->lines[0].b_start = 0;
|
||||
ta->lines[0].b_length = ta->show->len - 1;
|
||||
|
||||
nsfont.font_width(&ta->fstyle, ta->show->data,
|
||||
ta->show->len, &x);
|
||||
|
||||
if (x > w)
|
||||
w = x;
|
||||
|
||||
ta->h_extent = w + ta->pad_left - ta->pad_right;
|
||||
ta->line_count = 1;
|
||||
|
||||
@ -451,7 +499,7 @@ static bool textarea_reflow(struct textarea *ta, unsigned int start)
|
||||
h_extent = avail_width;
|
||||
|
||||
restart = false;
|
||||
for (len = ta->text_len - 1, text = ta->text; len > 0;
|
||||
for (len = ta->text.len - 1, text = ta->text.data; len > 0;
|
||||
len -= b_off, text += b_off) {
|
||||
|
||||
/* Find end of paragraph */
|
||||
@ -503,7 +551,7 @@ static bool textarea_reflow(struct textarea *ta, unsigned int start)
|
||||
if (para_end == text + b_off && *para_end == '\n') {
|
||||
/* Not found any spaces to wrap at, and we
|
||||
* have a newline char */
|
||||
ta->lines[line].b_start = text - ta->text;
|
||||
ta->lines[line].b_start = text - ta->text.data;
|
||||
ta->lines[line++].b_length = para_end - text;
|
||||
|
||||
/* Jump newline */
|
||||
@ -512,8 +560,8 @@ static bool textarea_reflow(struct textarea *ta, unsigned int start)
|
||||
if (len - b_off == 0) {
|
||||
/* reached end of input;
|
||||
* add last line */
|
||||
ta->lines[line].b_start =
|
||||
text + b_off - ta->text;
|
||||
ta->lines[line].b_start = text +
|
||||
b_off - ta->text.data;
|
||||
ta->lines[line++].b_length = 0;
|
||||
}
|
||||
|
||||
@ -534,7 +582,7 @@ static bool textarea_reflow(struct textarea *ta, unsigned int start)
|
||||
b_off = space + 1 - text;
|
||||
}
|
||||
|
||||
ta->lines[line].b_start = text - ta->text;
|
||||
ta->lines[line].b_start = text - ta->text.data;
|
||||
ta->lines[line++].b_length = b_off;
|
||||
|
||||
if (line > scroll_lines && ta->bar_y == NULL)
|
||||
@ -614,14 +662,14 @@ static bool textarea_reflow(struct textarea *ta, unsigned int start)
|
||||
* \param c_off Updated to character offset
|
||||
*/
|
||||
static void textarea_get_xy_offset(struct textarea *ta, int x, int y,
|
||||
size_t *b_off, unsigned int *c_off)
|
||||
unsigned int *c_off)
|
||||
{
|
||||
size_t bpos, temp; /* Byte positions in utf8 string */
|
||||
unsigned int cpos; /* Character positions in utf8 string */
|
||||
int line;
|
||||
|
||||
if (!ta->line_count) {
|
||||
*b_off = *c_off = 0;
|
||||
*c_off = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -640,7 +688,7 @@ static void textarea_get_xy_offset(struct textarea *ta, int x, int y,
|
||||
|
||||
/* Get byte position */
|
||||
nsfont.font_position_in_string(&ta->fstyle,
|
||||
ta->text + ta->lines[line].b_start,
|
||||
ta->show->data + ta->lines[line].b_start,
|
||||
ta->lines[line].b_length, x, &bpos, &x);
|
||||
|
||||
|
||||
@ -652,17 +700,16 @@ static void textarea_get_xy_offset(struct textarea *ta, int x, int y,
|
||||
*/
|
||||
if (ta->flags & TEXTAREA_MULTILINE &&
|
||||
bpos == (unsigned)ta->lines[line].b_length &&
|
||||
ta->text[ta->lines[line].b_start +
|
||||
ta->show->data[ta->lines[line].b_start +
|
||||
ta->lines[line].b_length - 1] == ' ')
|
||||
bpos--;
|
||||
|
||||
/* Get character position */
|
||||
for (temp = 0, cpos = 0; temp < bpos + ta->lines[line].b_start;
|
||||
temp = utf8_next(ta->text, ta->text_len, temp))
|
||||
temp = utf8_next(ta->show->data, ta->show->len, temp))
|
||||
cpos++;
|
||||
|
||||
/* Set the return values */
|
||||
*b_off = bpos;
|
||||
*c_off = cpos;
|
||||
}
|
||||
|
||||
@ -677,13 +724,12 @@ static void textarea_get_xy_offset(struct textarea *ta, int x, int y,
|
||||
*/
|
||||
static bool textarea_set_caret_xy(struct textarea *ta, int x, int y)
|
||||
{
|
||||
size_t b_off;
|
||||
unsigned int c_off;
|
||||
|
||||
if (ta->flags & TEXTAREA_READONLY)
|
||||
return true;
|
||||
|
||||
textarea_get_xy_offset(ta, x, y, &b_off, &c_off);
|
||||
textarea_get_xy_offset(ta, x, y, &c_off);
|
||||
|
||||
return textarea_set_caret(ta, c_off);
|
||||
}
|
||||
@ -693,12 +739,12 @@ static bool textarea_set_caret_xy(struct textarea *ta, int x, int y)
|
||||
* Insert text into the text area
|
||||
*
|
||||
* \param ta Text area
|
||||
* \param index 0-based character index to insert at
|
||||
* \param c_index 0-based character index to insert at
|
||||
* \param text UTF-8 text to insert
|
||||
* \param b_len Byte length of UTF-8 text
|
||||
* \return false on memory exhaustion, true otherwise
|
||||
*/
|
||||
static bool textarea_insert_text(struct textarea *ta, unsigned int index,
|
||||
static bool textarea_insert_text(struct textarea *ta, unsigned int c_index,
|
||||
const char *text, size_t b_len)
|
||||
{
|
||||
size_t b_off;
|
||||
@ -707,32 +753,32 @@ static bool textarea_insert_text(struct textarea *ta, unsigned int index,
|
||||
return true;
|
||||
|
||||
/* Find insertion point */
|
||||
if (index > ta->text_utf8_len)
|
||||
index = ta->text_utf8_len;
|
||||
if (c_index > ta->text.utf8_len)
|
||||
c_index = ta->text.utf8_len;
|
||||
|
||||
/* find byte offset of insertion point */
|
||||
for (b_off = 0; index > 0;
|
||||
b_off = utf8_next(ta->text, ta->text_len, b_off))
|
||||
index--;
|
||||
for (b_off = 0; c_index > 0;
|
||||
b_off = utf8_next(ta->text.data, ta->text.len, b_off))
|
||||
c_index--;
|
||||
|
||||
if (b_len + ta->text_len >= ta->text_alloc) {
|
||||
char *temp = realloc(ta->text, b_len + ta->text_len + 64);
|
||||
if (b_len + ta->text.len >= ta->text.alloc) {
|
||||
char *temp = realloc(ta->text.data, b_len + ta->text.len + 64);
|
||||
if (temp == NULL) {
|
||||
LOG(("realloc failed"));
|
||||
return false;
|
||||
}
|
||||
|
||||
ta->text = temp;
|
||||
ta->text_alloc = b_len + ta->text_len + 64;
|
||||
ta->text.data = temp;
|
||||
ta->text.alloc = b_len + ta->text.len + 64;
|
||||
}
|
||||
|
||||
/* Shift text following up */
|
||||
memmove(ta->text + b_off + b_len, ta->text + b_off,
|
||||
ta->text_len - b_off);
|
||||
memmove(ta->text.data + b_off + b_len, ta->text.data + b_off,
|
||||
ta->text.len - b_off);
|
||||
/* Insert new text */
|
||||
memcpy(ta->text + b_off, text, b_len);
|
||||
ta->text_len += b_len;
|
||||
ta->text_utf8_len += utf8_bounded_length(text, b_len);
|
||||
memcpy(ta->text.data + b_off, text, b_len);
|
||||
ta->text.len += b_len;
|
||||
ta->text.utf8_len += utf8_bounded_length(text, b_len);
|
||||
|
||||
textarea_normalise_text(ta, b_off, b_len);
|
||||
|
||||
@ -742,6 +788,23 @@ static bool textarea_insert_text(struct textarea *ta, unsigned int index,
|
||||
}
|
||||
|
||||
|
||||
static inline void textarea_char_to_byte_offset(struct textarea_utf8 *text,
|
||||
unsigned int start, unsigned int end,
|
||||
size_t *b_start, size_t *b_end)
|
||||
{
|
||||
size_t diff = end - start;
|
||||
/* find byte offset of replace start */
|
||||
for (*b_start = 0; start-- > 0;
|
||||
*b_start = utf8_next(text->data, text->len, *b_start))
|
||||
; /* do nothing */
|
||||
|
||||
/* find byte length of replaced text */
|
||||
for (*b_end = *b_start; diff-- > 0;
|
||||
*b_end = utf8_next(text->data, text->len, *b_end))
|
||||
; /* do nothing */
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Replace text in a text area
|
||||
*
|
||||
@ -757,15 +820,15 @@ static bool textarea_replace_text(struct textarea *ta, unsigned int start,
|
||||
unsigned int end, const char *rep, size_t rep_len,
|
||||
bool add_to_clipboard)
|
||||
{
|
||||
size_t b_start, b_end, diff;
|
||||
size_t b_start, b_end;
|
||||
|
||||
if (ta->flags & TEXTAREA_READONLY)
|
||||
return true;
|
||||
|
||||
if (start > ta->text_utf8_len)
|
||||
start = ta->text_utf8_len;
|
||||
if (end > ta->text_utf8_len)
|
||||
end = ta->text_utf8_len;
|
||||
if (start > ta->text.utf8_len)
|
||||
start = ta->text.utf8_len;
|
||||
if (end > ta->text.utf8_len)
|
||||
end = ta->text.utf8_len;
|
||||
|
||||
if (start == end && rep != NULL)
|
||||
return textarea_insert_text(ta, start, rep, rep_len);
|
||||
@ -773,22 +836,15 @@ static bool textarea_replace_text(struct textarea *ta, unsigned int start,
|
||||
if (start > end)
|
||||
return false;
|
||||
|
||||
diff = end - start;
|
||||
|
||||
/* find byte offset of replace start */
|
||||
for (b_start = 0; start-- > 0;
|
||||
b_start = utf8_next(ta->text, ta->text_len, b_start))
|
||||
; /* do nothing */
|
||||
|
||||
/* find byte length of replaced text */
|
||||
for (b_end = b_start; diff-- > 0;
|
||||
b_end = utf8_next(ta->text, ta->text_len, b_end))
|
||||
; /* do nothing */
|
||||
|
||||
/* Place CUTs on clipboard */
|
||||
if (add_to_clipboard)
|
||||
gui_set_clipboard(ta->text + b_start, b_end - b_start,
|
||||
if (add_to_clipboard) {
|
||||
textarea_char_to_byte_offset(ta->show, start, end,
|
||||
&b_start, &b_end);
|
||||
gui_set_clipboard(ta->show->data + b_start, b_end - b_start,
|
||||
NULL, 0);
|
||||
}
|
||||
|
||||
textarea_char_to_byte_offset(&ta->text, start, end, &b_start, &b_end);
|
||||
|
||||
if (rep == NULL) {
|
||||
/* No replacement text */
|
||||
@ -796,28 +852,28 @@ static bool textarea_replace_text(struct textarea *ta, unsigned int start,
|
||||
}
|
||||
|
||||
/* Ensure textarea's text buffer is large enough */
|
||||
if (rep_len + ta->text_len - (b_end - b_start) >= ta->text_alloc) {
|
||||
char *temp = realloc(ta->text,
|
||||
rep_len + ta->text_len - (b_end - b_start) + 64);
|
||||
if (rep_len + ta->text.len - (b_end - b_start) >= ta->text.alloc) {
|
||||
char *temp = realloc(ta->text.data,
|
||||
rep_len + ta->text.len - (b_end - b_start) + 64);
|
||||
if (temp == NULL) {
|
||||
LOG(("realloc failed"));
|
||||
return false;
|
||||
}
|
||||
|
||||
ta->text = temp;
|
||||
ta->text_alloc =
|
||||
rep_len + ta->text_len - (b_end - b_start) + 64;
|
||||
ta->text.data = temp;
|
||||
ta->text.alloc =
|
||||
rep_len + ta->text.len - (b_end - b_start) + 64;
|
||||
}
|
||||
|
||||
/* Shift text following to new position */
|
||||
memmove(ta->text + b_start + rep_len, ta->text + b_end,
|
||||
ta->text_len - b_end);
|
||||
memmove(ta->text.data + b_start + rep_len, ta->text.data + b_end,
|
||||
ta->text.len - b_end);
|
||||
|
||||
/* Insert new text */
|
||||
memcpy(ta->text + b_start, rep, rep_len);
|
||||
memcpy(ta->text.data + b_start, rep, rep_len);
|
||||
|
||||
ta->text_len += (int)rep_len - (b_end - b_start);
|
||||
ta->text_utf8_len = utf8_length(ta->text);
|
||||
ta->text.len += (int)rep_len - (b_end - b_start);
|
||||
ta->text.utf8_len = utf8_length(ta->text.data);
|
||||
textarea_normalise_text(ta, b_start, rep_len);
|
||||
|
||||
/** \todo calculate line to reflow from */
|
||||
@ -838,7 +894,6 @@ static bool textarea_drag_end(struct textarea *ta, browser_mouse_state mouse,
|
||||
int x, int y)
|
||||
{
|
||||
int c_end;
|
||||
size_t b_off;
|
||||
unsigned int c_off;
|
||||
struct textarea_msg msg;
|
||||
|
||||
@ -865,7 +920,7 @@ static bool textarea_drag_end(struct textarea *ta, browser_mouse_state mouse,
|
||||
case TEXTAREA_DRAG_SELECTION:
|
||||
ta->drag_info.type = TEXTAREA_DRAG_NONE;
|
||||
|
||||
textarea_get_xy_offset(ta, x, y, &b_off, &c_off);
|
||||
textarea_get_xy_offset(ta, x, y, &c_off);
|
||||
c_end = c_off;
|
||||
|
||||
if (!textarea_select(ta, ta->drag_start_char, c_end))
|
||||
@ -898,6 +953,10 @@ struct textarea *textarea_create(const textarea_setup *setup,
|
||||
{
|
||||
struct textarea *ret;
|
||||
|
||||
/* Sanity check flags */
|
||||
assert(!(setup->flags & TEXTAREA_MULTILINE &&
|
||||
setup->flags & TEXTAREA_PASSWORD));
|
||||
|
||||
if (callback == NULL) {
|
||||
LOG(("no callback provided"));
|
||||
return NULL;
|
||||
@ -938,16 +997,40 @@ struct textarea *textarea_create(const textarea_setup *setup,
|
||||
ret->drag_info.type = TEXTAREA_DRAG_NONE;
|
||||
|
||||
|
||||
ret->text = malloc(64);
|
||||
if (ret->text == NULL) {
|
||||
ret->text.data = malloc(64);
|
||||
if (ret->text.data == NULL) {
|
||||
LOG(("malloc failed"));
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
ret->text[0] = '\0';
|
||||
ret->text_alloc = 64;
|
||||
ret->text_len = 1;
|
||||
ret->text_utf8_len = 0;
|
||||
ret->text.data[0] = '\0';
|
||||
ret->text.alloc = 64;
|
||||
ret->text.len = 1;
|
||||
ret->text.utf8_len = 0;
|
||||
|
||||
if (setup->flags & TEXTAREA_PASSWORD) {
|
||||
ret->password.data = malloc(64);
|
||||
if (ret->password.data == NULL) {
|
||||
LOG(("malloc failed"));
|
||||
free(ret->text.data);
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
ret->password.data[0] = '\0';
|
||||
ret->password.alloc = 64;
|
||||
ret->password.len = 1;
|
||||
ret->password.utf8_len = 0;
|
||||
|
||||
ret->show = &ret->password;
|
||||
|
||||
} else {
|
||||
ret->password.data = NULL;
|
||||
ret->password.alloc = 0;
|
||||
ret->password.len = 0;
|
||||
ret->password.utf8_len = 0;
|
||||
|
||||
ret->show = &ret->text;
|
||||
}
|
||||
|
||||
ret->line_height = FIXTOINT(FDIV((FMUL(FLTTOFIX(1.2),
|
||||
FMUL(nscss_screen_dpi,
|
||||
@ -974,7 +1057,11 @@ void textarea_destroy(struct textarea *ta)
|
||||
scrollbar_destroy(ta->bar_x);
|
||||
if (ta->bar_y)
|
||||
scrollbar_destroy(ta->bar_y);
|
||||
free(ta->text);
|
||||
|
||||
if (ta->flags & TEXTAREA_PASSWORD)
|
||||
free(ta->password.data);
|
||||
|
||||
free(ta->text.data);
|
||||
free(ta->lines);
|
||||
free(ta);
|
||||
}
|
||||
@ -985,19 +1072,19 @@ bool textarea_set_text(struct textarea *ta, const char *text)
|
||||
{
|
||||
unsigned int len = strlen(text) + 1;
|
||||
|
||||
if (len >= ta->text_alloc) {
|
||||
char *temp = realloc(ta->text, len + 64);
|
||||
if (len >= ta->text.alloc) {
|
||||
char *temp = realloc(ta->text.data, len + 64);
|
||||
if (temp == NULL) {
|
||||
LOG(("realloc failed"));
|
||||
return false;
|
||||
}
|
||||
ta->text = temp;
|
||||
ta->text_alloc = len + 64;
|
||||
ta->text.data = temp;
|
||||
ta->text.alloc = len + 64;
|
||||
}
|
||||
|
||||
memcpy(ta->text, text, len);
|
||||
ta->text_len = len;
|
||||
ta->text_utf8_len = utf8_length(ta->text);
|
||||
memcpy(ta->text.data, text, len);
|
||||
ta->text.len = len;
|
||||
ta->text.utf8_len = utf8_length(ta->text.data);
|
||||
|
||||
textarea_normalise_text(ta, 0, len);
|
||||
|
||||
@ -1010,20 +1097,21 @@ int textarea_get_text(struct textarea *ta, char *buf, unsigned int len)
|
||||
{
|
||||
if (buf == NULL && len == 0) {
|
||||
/* want length */
|
||||
return ta->text_len;
|
||||
return ta->text.len;
|
||||
|
||||
} else if (buf == NULL) {
|
||||
/* Can't write to NULL */
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (len < ta->text_len) {
|
||||
if (len < ta->text.len) {
|
||||
LOG(("buffer too small"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(buf, ta->text, ta->text_len);
|
||||
memcpy(buf, ta->text.data, ta->text.len);
|
||||
|
||||
return ta->text_len;
|
||||
return ta->text.len;
|
||||
}
|
||||
|
||||
|
||||
@ -1043,7 +1131,7 @@ bool textarea_set_caret(struct textarea *ta, int caret)
|
||||
if (ta->flags & TEXTAREA_READONLY)
|
||||
return true;
|
||||
|
||||
c_len = ta->text_utf8_len;
|
||||
c_len = ta->show->utf8_len;
|
||||
|
||||
if (caret != -1 && caret > (signed)c_len)
|
||||
caret = c_len;
|
||||
@ -1078,7 +1166,7 @@ bool textarea_set_caret(struct textarea *ta, int caret)
|
||||
if (caret != -1) {
|
||||
/* Find byte offset of caret position */
|
||||
for (b_off = 0; caret > 0; caret--)
|
||||
b_off = utf8_next(ta->text, ta->text_len, b_off);
|
||||
b_off = utf8_next(ta->show->data, ta->show->len, b_off);
|
||||
|
||||
/* Now find line in which byte offset appears */
|
||||
for (i = 0; i < ta->line_count - 1; i++)
|
||||
@ -1090,7 +1178,7 @@ bool textarea_set_caret(struct textarea *ta, int caret)
|
||||
/* Now calculate the char. offset of the caret in this line */
|
||||
for (c_len = 0, ta->caret_pos.char_off = 0;
|
||||
c_len < b_off - ta->lines[i].b_start;
|
||||
c_len = utf8_next(ta->text +
|
||||
c_len = utf8_next(ta->show->data +
|
||||
ta->lines[i].b_start,
|
||||
ta->lines[i].b_length, c_len))
|
||||
ta->caret_pos.char_off++;
|
||||
@ -1102,12 +1190,12 @@ bool textarea_set_caret(struct textarea *ta, int caret)
|
||||
|
||||
/* find byte offset of caret position */
|
||||
for (b_off = 0; index-- > 0;
|
||||
b_off = utf8_next(ta->text,
|
||||
ta->text_len, b_off))
|
||||
b_off = utf8_next(ta->show->data,
|
||||
ta->show->len, b_off))
|
||||
; /* do nothing */
|
||||
|
||||
nsfont.font_width(&ta->fstyle,
|
||||
ta->text +
|
||||
ta->show->data +
|
||||
ta->lines[ta->caret_pos.line].b_start,
|
||||
b_off - ta->lines[ta->caret_pos.line].b_start,
|
||||
&x);
|
||||
@ -1157,12 +1245,12 @@ int textarea_get_caret(struct textarea *ta)
|
||||
textarea_set_caret(ta, 0);
|
||||
|
||||
/* if the text is a trailing NUL only */
|
||||
if (ta->text_utf8_len == 0)
|
||||
if (ta->text.utf8_len == 0)
|
||||
return 0;
|
||||
|
||||
/* Calculate character offset of this line's start */
|
||||
for (b_off = 0; b_off < ta->lines[ta->caret_pos.line].b_start;
|
||||
b_off = utf8_next(ta->text, ta->text_len, b_off))
|
||||
b_off = utf8_next(ta->text.data, ta->text.len, b_off))
|
||||
c_off++;
|
||||
|
||||
return c_off + ta->caret_pos.char_off;
|
||||
@ -1253,7 +1341,8 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg,
|
||||
(ta->bar_x != NULL ? SCROLLBAR_WIDTH : 0);
|
||||
|
||||
if (line0 > 0)
|
||||
c_pos = utf8_bounded_length(ta->text, ta->lines[line0].b_start);
|
||||
c_pos = utf8_bounded_length(ta->show->data,
|
||||
ta->lines[line0].b_start);
|
||||
else
|
||||
c_pos = 0;
|
||||
|
||||
@ -1282,7 +1371,7 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg,
|
||||
plot->clip(&r);
|
||||
|
||||
c_len = utf8_bounded_length(
|
||||
&(ta->text[ta->lines[line].b_start]),
|
||||
&(ta->show->data[ta->lines[line].b_start]),
|
||||
ta->lines[line].b_length);
|
||||
|
||||
b_end = 0;
|
||||
@ -1323,7 +1412,7 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg,
|
||||
assert(0);
|
||||
}
|
||||
|
||||
line_text = &(ta->text[ta->lines[line].b_start]);
|
||||
line_text = &(ta->show->data[ta->lines[line].b_start]);
|
||||
line_len = ta->lines[line].b_length;
|
||||
|
||||
/* find b_start and b_end for this part of the line */
|
||||
@ -1364,7 +1453,8 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg,
|
||||
ta->scroll_x,
|
||||
y + line * ta->line_height +
|
||||
text_y_offset_baseline - ta->scroll_y,
|
||||
ta->text + ta->lines[line].b_start,
|
||||
ta->show->data +
|
||||
ta->lines[line].b_start,
|
||||
ta->lines[line].b_length, fstyle);
|
||||
|
||||
c_pos += c_len_part;
|
||||
@ -1441,7 +1531,7 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
|
||||
|
||||
caret_init = caret = textarea_get_caret(ta);
|
||||
line = ta->caret_pos.line;
|
||||
readonly = (ta->flags & TEXTAREA_READONLY ? true:false);
|
||||
readonly = (ta->flags & TEXTAREA_READONLY ? true : false);
|
||||
|
||||
if (!(key <= 0x001F || (0x007F <= key && key <= 0x009F))) {
|
||||
/* normal character insertion */
|
||||
@ -1468,10 +1558,10 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
|
||||
|
||||
} else switch (key) {
|
||||
case KEY_SELECT_ALL:
|
||||
caret = ta->text_utf8_len;
|
||||
caret = ta->text.utf8_len;
|
||||
|
||||
ta->sel_start = 0;
|
||||
ta->sel_end = ta->text_utf8_len;
|
||||
ta->sel_end = ta->text.utf8_len;
|
||||
redraw = true;
|
||||
break;
|
||||
case KEY_COPY_SELECTION:
|
||||
@ -1587,7 +1677,7 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
|
||||
case KEY_RIGHT:
|
||||
if (readonly)
|
||||
break;
|
||||
if (caret < ta->text_utf8_len)
|
||||
if (caret < ta->text.utf8_len)
|
||||
caret++;
|
||||
if (ta->sel_start != -1) {
|
||||
ta->sel_start = ta->sel_end = -1;
|
||||
@ -1625,11 +1715,12 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
|
||||
c_line = ta->caret_pos.line;
|
||||
c_chars = ta->caret_pos.char_off;
|
||||
|
||||
if (ta->text[b_off + b_len - 1] == ' '
|
||||
if (ta->text.data[b_off + b_len - 1] == ' '
|
||||
&& line < ta->line_count - 1)
|
||||
b_len--;
|
||||
|
||||
l_len = utf8_bounded_length(&(ta->text[b_off]),
|
||||
l_len = utf8_bounded_length(
|
||||
&(ta->text.data[b_off]),
|
||||
b_len);
|
||||
|
||||
|
||||
@ -1675,11 +1766,12 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
|
||||
c_line = ta->caret_pos.line;
|
||||
c_chars = ta->caret_pos.char_off;
|
||||
|
||||
if (ta->text[b_off + b_len - 1] == ' '
|
||||
if (ta->text.data[b_off + b_len - 1] == ' '
|
||||
&& line < ta->line_count - 1)
|
||||
b_len--;
|
||||
|
||||
l_len = utf8_bounded_length(&(ta->text[b_off]),
|
||||
l_len = utf8_bounded_length(
|
||||
&(ta->text.data[b_off]),
|
||||
b_len);
|
||||
|
||||
|
||||
@ -1707,7 +1799,7 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
|
||||
ta->sel_start = ta->sel_end = -1;
|
||||
redraw = true;
|
||||
} else {
|
||||
if (caret < ta->text_utf8_len) {
|
||||
if (caret < ta->text.utf8_len) {
|
||||
if (!textarea_replace_text(ta,
|
||||
caret, caret + 1,
|
||||
"", 0, false))
|
||||
@ -1729,10 +1821,11 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
|
||||
if (readonly)
|
||||
break;
|
||||
|
||||
caret = utf8_bounded_length(ta->text,
|
||||
caret = utf8_bounded_length(ta->text.data,
|
||||
ta->lines[ta->caret_pos.line].b_start +
|
||||
ta->lines[ta->caret_pos.line].b_length);
|
||||
if (ta->text[ta->lines[ta->caret_pos.line].b_start +
|
||||
if (ta->text.data[ta->lines[ta->caret_pos.line].
|
||||
b_start +
|
||||
ta->lines[ta->caret_pos.line].b_length
|
||||
- 1] == ' ')
|
||||
caret--;
|
||||
@ -1753,7 +1846,7 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
|
||||
case KEY_TEXT_END:
|
||||
if (readonly)
|
||||
break;
|
||||
caret = ta->text_utf8_len;
|
||||
caret = ta->text.utf8_len;
|
||||
if (ta->sel_start != -1) {
|
||||
ta->sel_start = ta->sel_end = -1;
|
||||
redraw = true;
|
||||
@ -1774,7 +1867,8 @@ bool textarea_keypress(struct textarea *ta, uint32_t key)
|
||||
} else {
|
||||
b_off = ta->lines[ta->caret_pos.line].b_start;
|
||||
b_len = ta->lines[ta->caret_pos.line].b_length;
|
||||
l_len = utf8_bounded_length(&(ta->text[b_off]),
|
||||
l_len = utf8_bounded_length(
|
||||
&(ta->text.data[b_off]),
|
||||
b_len);
|
||||
if (!textarea_replace_text(ta, caret,
|
||||
caret + l_len, "", 0, false))
|
||||
@ -1830,7 +1924,6 @@ bool textarea_mouse_action(struct textarea *ta, browser_mouse_state mouse,
|
||||
int c_start, c_end;
|
||||
int sx, sy; /* xy coord offset for scrollbar */
|
||||
int sl; /* scrollbar length */
|
||||
size_t b_off;
|
||||
unsigned int c_off;
|
||||
struct textarea_msg msg;
|
||||
|
||||
@ -1888,7 +1981,7 @@ bool textarea_mouse_action(struct textarea *ta, browser_mouse_state mouse,
|
||||
/* mouse button pressed above the text area, move caret */
|
||||
if (mouse & BROWSER_MOUSE_PRESS_1) {
|
||||
if (!(ta->flags & TEXTAREA_READONLY)) {
|
||||
textarea_get_xy_offset(ta, x, y, &b_off, &c_off);
|
||||
textarea_get_xy_offset(ta, x, y, &c_off);
|
||||
ta->drag_start_char = c_off;
|
||||
|
||||
textarea_set_caret(ta, c_off);
|
||||
@ -1914,7 +2007,7 @@ bool textarea_mouse_action(struct textarea *ta, browser_mouse_state mouse,
|
||||
}
|
||||
|
||||
} else if (mouse & (BROWSER_MOUSE_DRAG_1 | BROWSER_MOUSE_HOLDING_1)) {
|
||||
textarea_get_xy_offset(ta, x, y, &b_off, &c_off);
|
||||
textarea_get_xy_offset(ta, x, y, &c_off);
|
||||
c_start = ta->drag_start_char;
|
||||
c_end = c_off;
|
||||
ta->drag_info.type = TEXTAREA_DRAG_SELECTION;
|
||||
|
@ -37,7 +37,8 @@ typedef enum {
|
||||
TEXTAREA_DEFAULT = (1 << 0), /**< Standard input */
|
||||
TEXTAREA_MULTILINE = (1 << 1), /**< Multiline area */
|
||||
TEXTAREA_READONLY = (1 << 2), /**< Non-editable */
|
||||
TEXTAREA_INTERNAL_CARET = (1 << 3) /**< Render own caret */
|
||||
TEXTAREA_INTERNAL_CARET = (1 << 3), /**< Render own caret */
|
||||
TEXTAREA_PASSWORD = (1 << 4) /**< Obscured display */
|
||||
} textarea_flags;
|
||||
|
||||
typedef enum {
|
||||
|
Loading…
x
Reference in New Issue
Block a user