1
0
mirror of https://github.com/rkd77/elinks.git synced 2024-06-25 01:05:37 +00:00

Merge with utf8. src/document/plain/renderer.c replaced by utf8 version

This commit is contained in:
Witold Filipczyk 2006-07-21 13:12:06 +02:00 committed by Witold Filipczyk
commit 2a6125e3d0
48 changed files with 3021 additions and 500 deletions

View File

@ -156,6 +156,7 @@ CONFIG_SPIDERMONKEY = @CONFIG_SPIDERMONKEY@
CONFIG_SSL = @CONFIG_SSL@
CONFIG_SYSMOUSE = @CONFIG_SYSMOUSE@
CONFIG_URI_REWRITE = @CONFIG_URI_REWRITE@
CONFIG_UTF_8 = @CONFIG_UTF_8@
CONFIG_XBEL_BOOKMARKS = @CONFIG_XBEL_BOOKMARKS@
CONFIG_XMLTO = @CONFIG_XMLTO@
CONFIG_GSSAPI = @CONFIG_GSSAPI@

View File

@ -168,6 +168,7 @@ AC_HEADER_STDC
AC_HEADER_SYS_WAIT
AC_HEADER_TIME
AC_CHECK_HEADERS(wctype.h)
AC_CHECK_HEADERS(fcntl.h limits.h time.h unistd.h)
AC_CHECK_HEADERS(sigaction.h)
AC_CHECK_HEADERS(arpa/inet.h)
@ -1283,6 +1284,10 @@ EL_ARG_ENABLE(CONFIG_OWN_LIBC, own-libc, [Own libc stubs],
EL_ARG_ENABLE(CONFIG_SMALL, small, [Small binary],
[ --enable-small reduce binary size as far as possible (but see the bottom of doc/small.txt!)])
EL_ARG_ENABLE(CONFIG_UTF_8, utf-8, [UTF-8],
[ --enable-utf-8 enable UTF-8 support])
AC_ARG_ENABLE(weehoofooboomookerchoo,
[
Also check out the features.conf file for more information about features!

View File

@ -77,18 +77,35 @@ add_dlg_button_do(struct dialog *dlg, unsigned char *text, int flags,
}
}
#ifdef CONFIG_UTF_8
static void
buttons_width(struct widget_data *widget_data, int n,
int *minwidth, int *maxwidth, int utf8)
#else
static void
buttons_width(struct widget_data *widget_data, int n,
int *minwidth, int *maxwidth)
#endif /* CONFIG_UTF_8 */
{
int maxw = -BUTTON_HSPACING;
#ifdef CONFIG_UTF_8
int button_lr_len = utf8_ptr2cells(BUTTON_LEFT, NULL)
+ utf8_ptr2cells(BUTTON_RIGHT, NULL);
#endif /* CONFIG_UTF_8 */
assert(n > 0);
if_assert_failed return;
while (n--) {
int minw = (widget_data++)->widget->info.button.textlen
+ BUTTON_HSPACING + BUTTON_LR_LEN;
int minw;
#ifdef CONFIG_UTF_8
if (utf8)
minw = utf8_ptr2cells((widget_data++)->widget->text, NULL)
+ BUTTON_HSPACING + button_lr_len;
else
#endif /* CONFIG_UTF_8 */
minw = (widget_data++)->widget->info.button.textlen
+ BUTTON_HSPACING + BUTTON_LR_LEN;
maxw += minw;
if (minwidth) int_lower_bound(minwidth, minw);
@ -100,7 +117,7 @@ buttons_width(struct widget_data *widget_data, int n,
void
dlg_format_buttons(struct terminal *term,
struct widget_data *widget_data, int n,
int x, int *y, int w, int *rw, enum format_align align)
int x, int *y, int w, int *rw, enum format_align align, int format_only)
{
int i1 = 0;
@ -111,24 +128,45 @@ dlg_format_buttons(struct terminal *term,
while (i2 < n) {
mw = 0;
#ifdef CONFIG_UTF_8
buttons_width(widget_data1, i2 - i1 + 1, NULL, &mw,
term->utf8);
#else
buttons_width(widget_data1, i2 - i1 + 1, NULL, &mw);
#endif /* CONFIG_UTF_8 */
if (mw <= w) i2++;
else break;
}
mw = 0;
#ifdef CONFIG_UTF_8
buttons_width(widget_data1, i2 - i1, NULL, &mw, term->utf8);
#else
buttons_width(widget_data1, i2 - i1, NULL, &mw);
#endif /* CONFIG_UTF_8 */
if (rw) int_bounds(rw, mw, w);
if (term) {
if (!format_only) {
int i;
int p = x + (align == ALIGN_CENTER ? (w - mw) / 2 : 0);
#ifdef CONFIG_UTF_8
int button_lr_len = utf8_ptr2cells(BUTTON_LEFT, NULL)
+ utf8_ptr2cells(BUTTON_RIGHT, NULL);
#endif /* CONFIG_UTF_8 */
for (i = i1; i < i2; i++) {
set_box(&widget_data[i].box,
p, *y,
widget_data[i].widget->info.button.textlen
+ BUTTON_LR_LEN, BUTTON_HEIGHT);
#ifdef CONFIG_UTF_8
if (term->utf8)
set_box(&widget_data[i].box,
p, *y,
utf8_ptr2cells(widget_data[i].widget->text, NULL)
+ button_lr_len, BUTTON_HEIGHT);
else
#endif /* CONFIG_UTF_8 */
set_box(&widget_data[i].box,
p, *y,
widget_data[i].widget->info.button.textlen
+ BUTTON_LR_LEN, BUTTON_HEIGHT);
p += widget_data[i].box.width + BUTTON_HSPACING;
}
@ -145,8 +183,7 @@ display_button(struct dialog_data *dlg_data, struct widget_data *widget_data)
struct terminal *term = dlg_data->win->term;
struct color_pair *color, *shortcut_color;
struct box *pos = &widget_data->box;
int len = widget_data->box.width - BUTTON_LR_LEN;
int x = pos->x + BUTTON_LEFT_LEN;
int len, x;
int sel = is_selected_widget(dlg_data, widget_data);
if (sel) {
@ -158,6 +195,23 @@ display_button(struct dialog_data *dlg_data, struct widget_data *widget_data)
}
if (!color || !shortcut_color) return EVENT_PROCESSED;
#ifdef CONFIG_UTF_8
if (term->utf8) {
int button_left_len = utf8_ptr2cells(BUTTON_LEFT, NULL);
int button_right_len = utf8_ptr2cells(BUTTON_RIGHT, NULL);
x = pos->x + button_left_len;
len = widget_data->box.width -
(button_left_len + button_right_len);
} else
#endif /* CONFIG_UTF_8 */
{
x = pos->x + BUTTON_LEFT_LEN;
len = widget_data->box.width - BUTTON_LR_LEN;
}
draw_text(term, pos->x, pos->y, BUTTON_LEFT, BUTTON_LEFT_LEN, 0, color);
if (len > 0) {
unsigned char *text = widget_data->widget->text;
@ -167,6 +221,52 @@ display_button(struct dialog_data *dlg_data, struct widget_data *widget_data)
attr = get_opt_bool("ui.dialogs.underline_button_shortcuts")
? SCREEN_ATTR_UNDERLINE : 0;
#ifdef CONFIG_UTF_8
if (term->utf8) {
if (hk_pos >= 0) {
int hk_bytes = utf8charlen(&text[hk_pos+1]);
int cells_to_hk = utf8_ptr2cells(text,
&text[hk_pos]);
int right = widget_data->widget->info.button.truetextlen
- hk_pos
- hk_bytes;
int hk_cells = utf8_char2cells(&text[hk_pos
+ 1],
NULL);
if (hk_pos)
draw_text(term, x, pos->y,
text, hk_pos, 0, color);
draw_text(term, x + cells_to_hk, pos->y,
&text[hk_pos + 1], hk_bytes,
attr, shortcut_color);
if (right > 1)
draw_text(term, x+cells_to_hk+hk_cells,
pos->y,
&text[hk_pos + hk_bytes + 1],
right - 1, 0, color);
} else {
int hk_width = utf8_char2cells(text, NULL);
int hk_len = utf8charlen(text);
int len_to_display =
utf8_cells2bytes(&text[hk_len],
len - hk_width,
NULL);
draw_text(term, x, pos->y,
text, hk_len,
attr, shortcut_color);
draw_text(term, x + hk_width, pos->y,
&text[hk_len], len_to_display,
0, color);
}
} else
#endif /* CONFIG_UTF_8 */
if (hk_pos >= 0) {
int right = widget_data->widget->info.button.truetextlen - hk_pos - 1;
@ -185,8 +285,17 @@ display_button(struct dialog_data *dlg_data, struct widget_data *widget_data)
draw_text(term, x + 1, pos->y, &text[1], len - 1, 0, color);
}
}
draw_text(term, x + len, pos->y, BUTTON_RIGHT, BUTTON_RIGHT_LEN, 0, color);
#ifdef CONFIG_UTF_8
if (term->utf8) {
int text_cells = utf8_ptr2cells(widget_data->widget->text, NULL);
int hk = (widget_data->widget->info.button.hotkey_pos >= 0);
draw_text(term, x + text_cells - hk, pos->y,
BUTTON_RIGHT, BUTTON_RIGHT_LEN, 0, color);
} else
#endif /* CONFIG_UTF_8 */
draw_text(term, x + len, pos->y, BUTTON_RIGHT,
BUTTON_RIGHT_LEN, 0, color);
if (sel) {
set_cursor(term, x, pos->y, 1);
set_window_ptr(dlg_data->win, pos->x, pos->y);

View File

@ -48,6 +48,6 @@ void add_dlg_button_do(struct dialog *dlg, unsigned char *text, int flags, widge
#endif
extern struct widget_ops button_ops;
void dlg_format_buttons(struct terminal *, struct widget_data *, int, int, int *, int, int *, enum format_align);
void dlg_format_buttons(struct terminal *, struct widget_data *, int, int, int *, int, int *, enum format_align, int);
#endif

View File

@ -39,7 +39,7 @@ void
dlg_format_checkbox(struct terminal *term,
struct widget_data *widget_data,
int x, int *y, int w, int *rw,
enum format_align align)
enum format_align align, int format_only)
{
unsigned char *text = widget_data->widget->text;
@ -52,7 +52,7 @@ dlg_format_checkbox(struct terminal *term,
dlg_format_text_do(term, text, x + CHECKBOX_LS, y,
w - CHECKBOX_LS, rw,
get_bfu_color(term, "dialog.checkbox-label"),
align);
align, format_only);
if (rw) *rw += CHECKBOX_LS;
}
}

View File

@ -33,7 +33,7 @@ void
dlg_format_checkbox(struct terminal *term,
struct widget_data *widget_data,
int x, int *y, int w, int *rw,
enum format_align align);
enum format_align align, int format_only);
#define widget_has_group(widget_data) ((widget_data)->widget->type == WIDGET_CHECKBOX \
? (widget_data)->widget->info.checkbox.gid : -1)

View File

@ -12,6 +12,7 @@
#include "bfu/dialog.h"
#include "config/kbdbind.h"
#include "config/options.h"
#include "intl/charsets.h"
#include "intl/gettext/libintl.h"
#include "terminal/draw.h"
#include "main/timer.h"
@ -96,13 +97,33 @@ redraw_dialog(struct dialog_data *dlg_data, int layout)
title_color = get_bfu_color(term, "dialog.title");
if (title_color && box.width > 2) {
unsigned char *title = dlg_data->dlg->title;
int titlelen = int_min(box.width - 2, strlen(title));
int x = (box.width - titlelen) / 2 + box.x;
int y = box.y - 1;
int titlelen = strlen(title);
int titlecells = titlelen;
int x, y;
#ifdef CONFIG_UTF_8
if (term->utf8)
titlecells = utf8_ptr2cells(title,
&title[titlelen]);
#endif /* CONFIG_UTF_8 */
titlecells = int_min(box.width - 2, titlecells);
#ifdef CONFIG_UTF_8
if (term->utf8) {
titlelen = utf8_cells2bytes(title,
titlecells,
NULL);
}
#endif /* CONFIG_UTF_8 */
x = (box.width - titlecells) / 2 + box.x;
y = box.y - 1;
draw_text(term, x - 1, y, " ", 1, 0, title_color);
draw_text(term, x, y, title, titlelen, 0, title_color);
draw_text(term, x + titlelen, y, " ", 1, 0, title_color);
draw_text(term, x + titlecells, y, " ", 1, 0,
title_color);
}
}
@ -499,7 +520,7 @@ clear_dialog(struct dialog_data *dlg_data, struct widget_data *xxx)
static void
format_widgets(struct terminal *term, struct dialog_data *dlg_data,
int x, int *y, int w, int h, int *rw)
int x, int *y, int w, int h, int *rw, int format_only)
{
struct widget_data *wdata = dlg_data->widgets_data;
int widgets = dlg_data->number_of_widgets;
@ -509,15 +530,18 @@ format_widgets(struct terminal *term, struct dialog_data *dlg_data,
switch (wdata->widget->type) {
case WIDGET_FIELD_PASS:
case WIDGET_FIELD:
dlg_format_field(term, wdata, x, y, w, rw, ALIGN_LEFT);
dlg_format_field(term, wdata, x, y, w, rw, ALIGN_LEFT,
format_only);
break;
case WIDGET_LISTBOX:
dlg_format_listbox(term, wdata, x, y, w, h, rw, ALIGN_LEFT);
dlg_format_listbox(term, wdata, x, y, w, h, rw,
ALIGN_LEFT, format_only);
break;
case WIDGET_TEXT:
dlg_format_text(term, wdata, x, y, w, rw, h);
dlg_format_text(term, wdata, x, y, w, rw, h,
format_only);
break;
case WIDGET_CHECKBOX:
@ -535,14 +559,16 @@ format_widgets(struct terminal *term, struct dialog_data *dlg_data,
break;
}
dlg_format_group(term, wdata, size, x, y, w, rw);
dlg_format_group(term, wdata, size, x, y, w, rw,
format_only);
wdata += size - 1;
} else {
/* No horizontal space between checkboxes belonging to
* the same group. */
dlg_format_checkbox(term, wdata, x, y, w, rw, ALIGN_LEFT);
dlg_format_checkbox(term, wdata, x, y, w, rw,
ALIGN_LEFT, format_only);
if (widgets > 1
&& group == widget_has_group(&wdata[1]))
(*y)--;
@ -554,7 +580,7 @@ format_widgets(struct terminal *term, struct dialog_data *dlg_data,
* of the dialog. */
case WIDGET_BUTTON:
dlg_format_buttons(term, wdata, widgets,
x, y, w, rw, ALIGN_CENTER);
x, y, w, rw, ALIGN_CENTER, format_only);
return;
}
}
@ -566,11 +592,17 @@ generic_dialog_layouter(struct dialog_data *dlg_data)
struct terminal *term = dlg_data->win->term;
int w = dialog_max_width(term);
int height = dialog_max_height(term);
int rw = int_min(w, strlen(dlg_data->dlg->title));
int rw;
#ifdef CONFIG_UTF_8
if (term->utf8)
rw = int_min(w, utf8_ptr2cells(dlg_data->dlg->title, NULL));
else
#endif /* CONFIG_UTF_8 */
rw = int_min(w, strlen(dlg_data->dlg->title));
int y = dlg_data->dlg->layout.padding_top ? 0 : -1;
int x = 0;
format_widgets(NULL, dlg_data, x, &y, w, height, &rw);
format_widgets(term, dlg_data, x, &y, w, height, &rw, 1);
/* Update the width to respond to the required minimum width */
if (dlg_data->dlg->layout.fit_datalen) {
@ -585,7 +617,7 @@ generic_dialog_layouter(struct dialog_data *dlg_data)
y = dlg_data->box.y + DIALOG_TB + dlg_data->dlg->layout.padding_top;
x = dlg_data->box.x + DIALOG_LB;
format_widgets(term, dlg_data, x, &y, w, height, NULL);
format_widgets(term, dlg_data, x, &y, w, height, NULL, 0);
}
@ -607,7 +639,15 @@ draw_dialog(struct dialog_data *dlg_data, int width, int height)
/* Draw shadow */
draw_shadow(term, &dlg_data->box,
get_bfu_color(term, "dialog.shadow"), 2, 1);
#ifdef CONFIG_UTF_8
if (term->utf8)
fix_dwchar_around_box(term, &dlg_data->box, 0, 2, 1);
#endif /* CONFIG_UTF_8 */
}
#ifdef CONFIG_UTF_8
else if(term->utf8)
fix_dwchar_around_box(term, &dlg_data->box, 0, 0, 0);
#endif /* CONFIG_UTF_8 */
}
static void

View File

@ -16,10 +16,13 @@
#include "terminal/terminal.h"
#include "util/color.h"
/* Same as in src/bfu/checkbox.c */
#define CHECKBOX_LEN 3 /* "[X]" or "(X)" */
void
dlg_format_group(struct terminal *term,
struct widget_data *widget_data,
int n, int x, int *y, int w, int *rw)
int n, int x, int *y, int w, int *rw, int format_only)
{
int space_between_widgets = 1;
int line_width = 0;
@ -33,13 +36,31 @@ dlg_format_group(struct terminal *term,
int widget_width;
int width;
unsigned char *text = widget_data->widget->text;
int label_length = (text && *text) ? strlen(text) : 0;
int label_padding = (label_length > 0);
int label_length;
int label_padding;
#ifdef CONFIG_UTF_8
if (term->utf8) {
if (text && *text)
label_length = utf8_ptr2cells(text, NULL);
else
label_length = 0;
} else
#endif /* CONFIG_UTF_8 */
label_length = (text && *text) ? strlen(text) : 0;
label_padding = (label_length > 0);
if (widget_data->widget->type == WIDGET_CHECKBOX) {
width = 3;
width = CHECKBOX_LEN;
} else if (widget_is_textfield(widget_data)) {
width = widget_data->widget->datalen;
#ifdef CONFIG_UTF_8
if (term->utf8) {
width = utf8_ptr2cells(widget_data->widget->data,
NULL);
} else
#endif /* CONFIG_UTF_8 */
width = widget_data->widget->datalen;
} else {
/* TODO: handle all widget types. */
widget_data++;
@ -56,22 +77,52 @@ dlg_format_group(struct terminal *term,
xpos = x + line_width;
if (term) {
if (!format_only) {
if (widget_data->widget->type == WIDGET_CHECKBOX) {
/* Draw text at right of checkbox. */
if (label_length)
draw_text(term, xpos + width + label_padding, *y,
text, label_length,
0, color);
if (label_length) {
#ifdef CONFIG_UTF_8
if (term->utf8) {
int lb = utf8_cells2bytes(
text,
label_length,
NULL);
draw_text(term, xpos + width
+ label_padding,
*y, text, lb, 0,
color);
} else
#endif /* CONFIG_UTF_8 */
{
draw_text(term, xpos + width
+ label_padding,
*y, text,
label_length, 0,
color);
}
}
set_box(&widget_data->box, xpos, *y, width, 1);
} else if (widget_is_textfield(widget_data)) {
/* Draw label at left of widget. */
if (label_length)
draw_text(term, xpos, *y,
text, label_length,
0, color);
if (label_length) {
#ifdef CONFIG_UTF_8
if (term->utf8) {
int lb = utf8_cells2bytes(
text,
label_length,
NULL);
draw_text(term, xpos, *y,
text, lb, 0, color);
} else
#endif /* CONFIG_UTF_8 */
{
draw_text(term, xpos, *y,
text, label_length,
0, color);
}
}
set_box(&widget_data->box,
xpos + label_padding + label_length, *y,
@ -93,16 +144,23 @@ group_layouter(struct dialog_data *dlg_data)
{
struct terminal *term = dlg_data->win->term;
int w = dialog_max_width(term);
int rw = int_min(w, strlen(dlg_data->dlg->title));
int rw;
int y = 0;
int n = dlg_data->number_of_widgets - 2;
dlg_format_group(NULL, dlg_data->widgets_data, n,
0, &y, w, &rw);
#ifdef CONFIG_UTF_8
if (term->utf8)
rw = int_min(w, utf8_ptr2cells(dlg_data->dlg->title, NULL));
else
#endif /* CONFIG_UTF_8 */
rw = int_min(w, strlen(dlg_data->dlg->title));
dlg_format_group(term, dlg_data->widgets_data, n,
0, &y, w, &rw, 1);
y++;
dlg_format_buttons(NULL, dlg_data->widgets_data + n, 2, 0, &y, w,
&rw, ALIGN_CENTER);
dlg_format_buttons(term, dlg_data->widgets_data + n, 2, 0, &y, w,
&rw, ALIGN_CENTER, 1);
w = rw;
@ -110,9 +168,9 @@ group_layouter(struct dialog_data *dlg_data)
y = dlg_data->box.y + DIALOG_TB + 1;
dlg_format_group(term, dlg_data->widgets_data, n,
dlg_data->box.x + DIALOG_LB, &y, w, NULL);
dlg_data->box.x + DIALOG_LB, &y, w, NULL, 0);
y++;
dlg_format_buttons(term, dlg_data->widgets_data + n, 2,
dlg_data->box.x + DIALOG_LB, &y, w, &rw, ALIGN_CENTER);
dlg_data->box.x + DIALOG_LB, &y, w, &rw, ALIGN_CENTER, 0);
}

View File

@ -7,7 +7,7 @@ struct widget_data;
void dlg_format_group(struct terminal *term,
struct widget_data *widget_data,
int n, int x, int *y, int w, int *rw);
int n, int x, int *y, int w, int *rw, int format_only);
void group_layouter(struct dialog_data *);

View File

@ -17,6 +17,7 @@
#include "bfu/msgbox.h"
#include "bfu/text.h"
#include "config/kbdbind.h"
#include "intl/charsets.h"
#include "intl/gettext/libintl.h"
#include "osdep/osdep.h"
#include "session/session.h"
@ -104,7 +105,7 @@ check_nonempty(struct dialog_data *dlg_data, struct widget_data *widget_data)
void
dlg_format_field(struct terminal *term,
struct widget_data *widget_data,
int x, int *y, int w, int *rw, enum format_align align)
int x, int *y, int w, int *rw, enum format_align align, int format_only)
{
static int max_label_width;
static int *prev_y; /* Assert the uniqueness of y */ /* TODO: get rid of this !! --Zas */
@ -129,9 +130,9 @@ dlg_format_field(struct terminal *term,
}
if (label && *label) {
if (term) text_color = get_bfu_color(term, "dialog.text");
if (!format_only) text_color = get_bfu_color(term, "dialog.text");
dlg_format_text_do(term, label, x, y, w, rw, text_color, ALIGN_LEFT);
dlg_format_text_do(term, label, x, y, w, rw, text_color, ALIGN_LEFT, format_only);
}
/* XXX: We want the field and label on the same line if the terminal
@ -141,7 +142,7 @@ dlg_format_field(struct terminal *term,
(*y) -= INPUTFIELD_HEIGHT;
dlg_format_text_do(term, INPUTFIELD_FLOAT_SEPARATOR,
x + label_width, y, w, rw,
text_color, ALIGN_LEFT);
text_color, ALIGN_LEFT, format_only);
w -= INPUTFIELD_FLOAT_SEPARATOR_LEN + INPUTFIELD_FLOATLABEL_PADDING;
x += INPUTFIELD_FLOAT_SEPARATOR_LEN + INPUTFIELD_FLOATLABEL_PADDING;
}
@ -265,11 +266,27 @@ display_field_do(struct dialog_data *dlg_data, struct widget_data *widget_data,
struct terminal *term = dlg_data->win->term;
struct color_pair *color;
int sel = is_selected_widget(dlg_data, widget_data);
#ifdef CONFIG_UTF_8
int len = 0, left = 0;
#endif /* CONFIG_UTF_8 */
int_bounds(&widget_data->info.field.vpos,
#ifdef CONFIG_UTF_8
if (term->utf8) {
unsigned char *t = widget_data->cdata;
int p = widget_data->info.field.cpos;
len = utf8_ptr2cells(t, &t[p]);
int_bounds(&left, len - widget_data->box.width + 1, len);
int_lower_bound(&left, 0);
widget_data->info.field.vpos = utf8_cells2bytes(t, left, NULL);
} else
#endif /* CONFIG_UTF_8 */
{
int_bounds(&widget_data->info.field.vpos,
widget_data->info.field.cpos - widget_data->box.width + 1,
widget_data->info.field.cpos);
int_lower_bound(&widget_data->info.field.vpos, 0);
int_lower_bound(&widget_data->info.field.vpos, 0);
}
color = get_bfu_color(term, "dialog.field");
if (color)
@ -277,13 +294,26 @@ display_field_do(struct dialog_data *dlg_data, struct widget_data *widget_data,
color = get_bfu_color(term, "dialog.field-text");
if (color) {
int len = strlen(widget_data->cdata + widget_data->info.field.vpos);
int w = int_min(len, widget_data->box.width);
unsigned char *text = widget_data->cdata + widget_data->info.field.vpos;
int len, w;
#ifdef CONFIG_UTF_8
if (term->utf8 && !hide)
len = utf8_ptr2cells(text, NULL);
else if (term->utf8)
len = utf8_ptr2chars(text, NULL);
else
#endif /* CONFIG_UTF_8 */
len = strlen(text);
w = int_min(len, widget_data->box.width);
if (!hide) {
#ifdef CONFIG_UTF_8
if (term->utf8)
w = utf8_cells2bytes(text, w, NULL);
#endif /* CONFIG_UTF_8 */
draw_text(term, widget_data->box.x, widget_data->box.y,
widget_data->cdata + widget_data->info.field.vpos, w,
0, color);
text, w, 0, color);
} else {
struct box box;
@ -295,7 +325,14 @@ display_field_do(struct dialog_data *dlg_data, struct widget_data *widget_data,
}
if (sel) {
int x = widget_data->box.x + widget_data->info.field.cpos - widget_data->info.field.vpos;
int x;
#ifdef CONFIG_UTF_8
if (term->utf8)
x = widget_data->box.x + len - left;
else
#endif /* CONFIG_UTF_8 */
x = widget_data->box.x + widget_data->info.field.cpos - widget_data->info.field.vpos;
set_cursor(term, x, widget_data->box.y, 0);
set_window_ptr(dlg_data->win, widget_data->box.x, widget_data->box.y);
@ -435,13 +472,39 @@ kbd_field(struct dialog_data *dlg_data, struct widget_data *widget_data)
break;
case ACT_EDIT_RIGHT:
if (widget_data->info.field.cpos < strlen(widget_data->cdata))
widget_data->info.field.cpos++;
if (widget_data->info.field.cpos < strlen(widget_data->cdata)) {
#ifdef CONFIG_UTF_8
if (term->utf8) {
unsigned char *next = widget_data->cdata + widget_data->info.field.cpos;
unsigned char *end = strchr(next, '\0');
utf_8_to_unicode(&next, end);
widget_data->info.field.cpos = (int)(next - widget_data->cdata);
} else
#endif /* CONFIG_UTF_8 */
{
widget_data->info.field.cpos++;
}
}
goto display_field;
case ACT_EDIT_LEFT:
if (widget_data->info.field.cpos > 0)
widget_data->info.field.cpos--;
#ifdef CONFIG_UTF_8
if (widget_data->info.field.cpos && term->utf8) {
unsigned char *t = widget_data->cdata;
unsigned char *t2 = t;
int p = widget_data->info.field.cpos;
unsigned char tmp = t[p];
t[p] = '\0';
strlen_utf8(&t2);
t[p] = tmp;
widget_data->info.field.cpos = (int)(t2 - t);
}
#endif /* CONFIG_UTF_8 */
goto display_field;
case ACT_EDIT_HOME:
@ -453,6 +516,34 @@ kbd_field(struct dialog_data *dlg_data, struct widget_data *widget_data)
goto display_field;
case ACT_EDIT_BACKSPACE:
#ifdef CONFIG_UTF_8
if (widget_data->info.field.cpos && term->utf8) {
/* XXX: stolen from src/viewer/text/form.c */
/* FIXME: This isn't nice. We remove last byte
* from UTF-8 character to detect
* character before it. */
unsigned char *text = widget_data->cdata;
unsigned char *end = widget_data->cdata + widget_data->info.field.cpos - 1;
unicode_val_T data;
int old = widget_data->info.field.cpos;
while(1) {
data = utf_8_to_unicode(&text, end);
if (data == UCS_NO_CHAR)
break;
}
widget_data->info.field.cpos = (int)(text - widget_data->cdata);
if (old != widget_data->info.field.cpos) {
int length;
text = widget_data->cdata;
length = strlen(text + old) + 1;
memmove(text + widget_data->info.field.cpos, text + old, length);
}
goto display_field;
}
#endif /* CONFIG_UTF_8 */
if (widget_data->info.field.cpos) {
memmove(widget_data->cdata + widget_data->info.field.cpos - 1,
widget_data->cdata + widget_data->info.field.cpos,
@ -467,6 +558,20 @@ kbd_field(struct dialog_data *dlg_data, struct widget_data *widget_data)
if (widget_data->info.field.cpos >= cdata_len) goto display_field;
#ifdef CONFIG_UTF_8
if (term->utf8) {
unsigned char *end = widget_data->cdata + cdata_len;
unsigned char *text = widget_data->cdata + widget_data->info.field.cpos;
unsigned char *old = text;
utf_8_to_unicode(&text, end);
if (old != text) {
memmove(old, text,
(int)(end - text) + 1);
}
goto display_field;
}
#endif /* CONFIG_UTF_8 */
memmove(widget_data->cdata + widget_data->info.field.cpos,
widget_data->cdata + widget_data->info.field.cpos + 1,
cdata_len - widget_data->info.field.cpos + 1);
@ -585,7 +690,22 @@ kbd_field(struct dialog_data *dlg_data, struct widget_data *widget_data)
memmove(text + 1, text, textlen + 1);
*text = get_kbd_key(ev);
#ifdef CONFIG_UTF_8
if (term->utf8) {
static unsigned char buf[7];
unsigned char *t = buf;
static int i = 0;
unicode_val_T data;
buf[i++] = *text;
buf[i] = '\0';
data = utf_8_to_unicode(&t, buf + i);
if (i == 6) i = 0;
if (data == UCS_NO_CHAR)
return EVENT_PROCESSED;
else i = 0;
}
#endif /* CONFIG_UTF_8 */
goto display_field;
}
}
@ -641,7 +761,7 @@ input_line_layouter(struct dialog_data *dlg_data)
- ses->status.show_tabs_bar;
dlg_format_field(win->term, dlg_data->widgets_data, 0,
&y, win->term->width, NULL, ALIGN_LEFT);
&y, win->term->width, NULL, ALIGN_LEFT, 0);
}
static widget_handler_status_T

View File

@ -62,7 +62,7 @@ extern struct widget_ops field_pass_ops;
widget_handler_status_T check_number(struct dialog_data *, struct widget_data *);
widget_handler_status_T check_nonempty(struct dialog_data *, struct widget_data *);
void dlg_format_field(struct terminal *, struct widget_data *, int, int *, int, int *, enum format_align);
void dlg_format_field(struct terminal *, struct widget_data *, int, int *, int, int *, enum format_align, int format_only);
void input_field(struct terminal *, struct memory_list *, int, unsigned char *,
unsigned char *, unsigned char *, unsigned char *, void *,

View File

@ -43,7 +43,7 @@ get_listbox_widget_data(struct widget_data *widget_data)
void
dlg_format_listbox(struct terminal *term, struct widget_data *widget_data,
int x, int *y, int w, int max_height, int *rw,
enum format_align align)
enum format_align align, int format_only)
{
int min, optimal_h, height;
@ -453,6 +453,7 @@ display_listbox_item(struct listbox_item *item, void *data_, int *offset)
} else {
unsigned char *text;
struct listbox_ops *ops = data->box->ops;
int len_bytes;
assert(ops && ops->get_info);
@ -461,8 +462,14 @@ display_listbox_item(struct listbox_item *item, void *data_, int *offset)
len = strlen(text);
int_upper_bound(&len, int_max(0, data->widget_data->box.width - depth * 5));
#ifdef CONFIG_UTF_8
if (data->term->utf8)
len_bytes = utf8_cells2bytes(text, len, NULL);
else
#endif /* CONFIG_UTF_8 */
len_bytes = len;
draw_text(data->term, x, y, text, len, 0, text_color);
draw_text(data->term, x, y, text, len_bytes, 0, text_color);
mem_free(text);
}

View File

@ -133,7 +133,7 @@ struct listbox_item {
extern struct widget_ops listbox_ops;
void dlg_format_listbox(struct terminal *, struct widget_data *, int, int *, int, int, int *, enum format_align);
void dlg_format_listbox(struct terminal *, struct widget_data *, int, int *, int, int, int *, enum format_align, int format_only);
struct listbox_item *traverse_listbox_items_list(struct listbox_item *, struct listbox_data *, int, int, int (*)(struct listbox_item *, void *, int *), void *);

View File

@ -200,7 +200,14 @@ get_menuitem_text_width(struct terminal *term, struct menu_item *mi)
if (!text[0]) return 0;
return L_TEXT_SPACE + strlen(text) - !!mi->hotkey_pos + R_TEXT_SPACE;
#ifdef CONFIG_UTF_8
if (term->utf8)
return L_TEXT_SPACE + utf8_ptr2cells(text, NULL)
- !!mi->hotkey_pos + R_TEXT_SPACE;
else
#endif /* CONFIG_UTF_8 */
return L_TEXT_SPACE + strlen(text)
- !!mi->hotkey_pos + R_TEXT_SPACE;
}
/* Get desired width for right text in menu item, accounting spacing. */
@ -360,17 +367,31 @@ set_menu_selection(struct menu *menu, int pos)
int_bounds(&menu->first, 0, menu->size - height);
}
/* width - number of standard terminal cells to be displayed (text + whitespace
* separators). For double-width glyph width == 2.
* len - length of text in bytes */
static inline void
draw_menu_left_text(struct terminal *term, unsigned char *text, int len,
int x, int y, int width, struct color_pair *color)
{
int w = width - (L_TEXT_SPACE + R_TEXT_SPACE);
int max_len;
if (w <= 0) return;
if (len < 0) len = strlen(text);
if (!len) return;
if (len > w) len = w;
#ifdef CONFIG_UTF_8
if (term->utf8) {
max_len = utf8_cells2bytes(text, w, NULL);
if (max_len <= 0)
return;
} else
#endif /* CONFIG_UTF_8 */
max_len = w;
if (len > max_len) len = max_len;
draw_text(term, x + L_TEXT_SPACE, y, text, len, 0, color);
}
@ -389,6 +410,7 @@ draw_menu_left_text_hk(struct terminal *term, unsigned char *text,
int xbase = x + L_TEXT_SPACE;
int w = width - (L_TEXT_SPACE + R_TEXT_SPACE);
int hk_state = 0;
#ifdef CONFIG_DEBUG
/* For redundant hotkeys highlighting. */
int double_hk = 0;
@ -405,6 +427,10 @@ draw_menu_left_text_hk(struct terminal *term, unsigned char *text,
hk_color_sel = tmp;
}
#ifdef CONFIG_UTF_8
if (term->utf8) goto utf8;
#endif /* CONFIG_UTF_8 */
for (x = 0; x - !!hk_state < w && (c = text[x]); x++) {
if (!hk_state && x == hotkey_pos - 1) {
hk_state = 1;
@ -417,12 +443,78 @@ draw_menu_left_text_hk(struct terminal *term, unsigned char *text,
(double_hk ? hk_color_sel : hk_color));
#else
draw_char(term, xbase + x - 1, y, c, hk_attr, hk_color);
#endif
#endif /* CONFIG_DEBUG */
hk_state = 2;
} else {
draw_char(term, xbase + x - !!hk_state, y, c, 0, color);
}
}
return;
#ifdef CONFIG_UTF_8
unsigned char *text2, *end;
utf8:
end = strchr(text, '\0');
text2 = text;
for (x = 0; x - !!hk_state < w && *text2; x++) {
unicode_val_T data;
data = utf_8_to_unicode(&text2, end);
if (!hk_state && (int)(text2 - text) == hotkey_pos) {
hk_state = 1;
continue;
}
if (hk_state == 1) {
if (unicode_to_cell(data) == 2) {
if (x < w && xbase + x < term->width) {
#ifdef CONFIG_DEBUG
draw_char(term, xbase + x - 1, y,
data, hk_attr,
(double_hk ? hk_color_sel
: hk_color));
#else
draw_char(term, xbase + x - 1, y,
data, hk_attr, hk_color);
#endif /* CONFIG_DEBUG */
x++;
draw_char(term, xbase + x - 1, y,
UCS_NO_CHAR, 0, hk_color);
} else {
draw_char(term, xbase + x - 1, y,
' ', 0, hk_color);
}
} else {
#ifdef CONFIG_DEBUG
draw_char(term, xbase + x - 1, y,
data, hk_attr,
(double_hk ? hk_color_sel
: hk_color));
#else
draw_char(term, xbase + x - 1, y,
data, hk_attr, hk_color);
#endif /* CONFIG_DEBUG */
}
hk_state = 2;
} else {
if (unicode_to_cell(data) == 2) {
if (x - !!hk_state + 1 < w &&
xbase + x - !!hk_state + 1 < term->width) {
draw_char(term, xbase + x - !!hk_state,
y, data, 0, color);
x++;
draw_char(term, xbase + x - !!hk_state,
y, UCS_NO_CHAR, 0, color);
} else {
draw_char(term, xbase + x - !!hk_state,
y, ' ', 0, color);
}
} else {
draw_char(term, xbase + x - !!hk_state,
y, data, 0, color);
}
}
}
#endif /* CONFIG_UTF_8 */
}
static inline void
@ -465,7 +557,15 @@ display_menu(struct terminal *term, struct menu *menu)
/* Draw shadow */
draw_shadow(term, &menu->box,
get_bfu_color(term, "dialog.shadow"), 2, 1);
#ifdef CONFIG_UTF_8
if (term->utf8)
fix_dwchar_around_box(term, &box, 1, 2, 1);
#endif /* CONFIG_UTF_8 */
}
#ifdef CONFIG_UTF_8
else if(term->utf8)
fix_dwchar_around_box(term, &box, 1, 0, 0);
#endif /* CONFIG_UTF_8 */
menu_height = box.height;
box.height = 1;
@ -1005,18 +1105,33 @@ display_mainmenu(struct terminal *term, struct menu *menu)
int l = mi->hotkey_pos;
int textlen;
int selected = (i == menu->selected);
int screencnt;
if (mi_text_translate(mi))
text = _(text, term);
textlen = strlen(text) - !!l;
#ifdef CONFIG_UTF_8
if (term->utf8)
screencnt = utf8_ptr2cells(text, NULL) - !!l;
else
#endif /* CONFIG_UTF_8 */
screencnt = textlen;
if (selected) {
color = selected_color;
box.x = p;
box.width = L_MAINTEXT_SPACE + L_TEXT_SPACE
+ textlen
+ R_TEXT_SPACE + R_MAINTEXT_SPACE;
#ifdef CONFIG_UTF_8
if (term->utf8)
box.width = L_MAINTEXT_SPACE + L_TEXT_SPACE
+ screencnt
+ R_TEXT_SPACE + R_MAINTEXT_SPACE;
else
#endif /* CONFIG_UTF_8 */
box.width = L_MAINTEXT_SPACE + L_TEXT_SPACE
+ textlen
+ R_TEXT_SPACE + R_MAINTEXT_SPACE;
draw_box(term, &box, ' ', 0, color);
set_cursor(term, p, 0, 1);
set_window_ptr(menu->win, p, 1);
@ -1034,7 +1149,7 @@ display_mainmenu(struct terminal *term, struct menu *menu)
color);
}
p += textlen;
p += screencnt;
if (p >= term->width - R_MAINMENU_SPACE)
break;
@ -1045,6 +1160,22 @@ display_mainmenu(struct terminal *term, struct menu *menu)
menu->last = i - 1;
int_lower_bound(&menu->last, menu->first);
if (menu->last < menu->size - 1) {
#ifdef CONFIG_UTF_8
if (term->utf8) {
struct screen_char *schar;
schar = get_char(term, term->width - R_MAINMENU_SPACE, 0);
/* Is second cell of double-width char on the place where
* first char of the R_MAINMENU_SPACE will be displayed? */
if (schar->data == UCS_NO_CHAR) {
/* Replace double-width char with ' '. */
schar++;
draw_char_data(term, term->width - R_MAINMENU_SPACE - 1,
0, ' ');
}
}
#endif
set_box(&box,
term->width - R_MAINMENU_SPACE, 0,
R_MAINMENU_SPACE, 1);

View File

@ -19,6 +19,7 @@
#include "terminal/terminal.h"
#include "util/color.h"
/* FIXME: For UTF-8 strings we need better function than isspace. */
#define is_unsplitable(pos) (*(pos) && *(pos) != '\n' && !isspace(*(pos)))
void
@ -35,48 +36,106 @@ add_dlg_text(struct dialog *dlg, unsigned char *text,
}
/* Returns length of substring (from start of @text) before a split. */
#ifdef CONFIG_UTF_8
static inline int
split_line(unsigned char *text, int max_width)
split_line(unsigned char *text, int max_width, int *cells, int utf8)
#else
static inline int
split_line(unsigned char *text, int max_width, int *cells)
#endif /* CONFIG_UTF_8 */
{
unsigned char *split = text;
int cells_save = *cells;
if (max_width <= 0) return 0;
while (*split && *split != '\n') {
unsigned char *next_split = split + 1;
unsigned char *next_split;
#ifdef CONFIG_UTF_8
if (utf8) {
unsigned char *next_char_begin = split
+ utf8charlen(split);
while (is_unsplitable(next_split))
next_split++;
next_split = split;
if (next_split - text > max_width) {
*cells += utf8_char2cells(split, NULL);
while (*next_split && next_split != next_char_begin)
next_split++;
next_char_begin = next_split;
while (is_unsplitable(next_split))
{
if (next_split < next_char_begin) {
next_split++;
continue;
}
*cells += utf8_char2cells(next_split, NULL);
next_char_begin += utf8charlen(next_split);
}
} else
#endif /* CONFIG_UTF_8 */
{
next_split = split + 1;
while (is_unsplitable(next_split))
next_split++;
*cells = next_split - text;
}
if (*cells > max_width) {
/* Force a split if no position was found yet,
* meaning there's no splittable substring under
* requested width. */
if (split == text) {
split = &text[max_width];
#ifdef CONFIG_UTF_8
if (utf8) {
int m_bytes = utf8_cells2bytes(text,
max_width,
NULL);
split = &text[m_bytes];
} else
#endif /* CONFIG_UTF_8 */
split = &text[max_width];
/* Give preference to split on a punctuation
* if any. Note that most of the time
* punctuation char is followed by a space so
* this rule will not match often.
* We match dash and quotes too. */
while (--split != text) {
if (!ispunct(*split)) continue;
split++;
break;
/* FIXME: Function ispunct won't work correctly
* with UTF-8 characters. We need some similar
* function for UTF-8 characters. */
#ifdef CONFIG_UTF_8
if (!utf8)
#endif /* CONFIG_UTF_8 */
{
/* Give preference to split on a
* punctuation if any. Note that most
* of the time punctuation char is
* followed by a space so this rule
* will not match often. We match dash
* and quotes too. */
cells_save--;
while (--split != text) {
cells_save--;
if (!ispunct(*split)) continue;
split++;
cells_save++;
break;
}
}
/* If no way to do a clean split, just return
* requested maximal width. */
if (split == text)
if (split == text) {
*cells = max_width;
return max_width;
}
}
break;
}
cells_save = *cells;
split = next_split;
}
*cells = cells_save;
return split - text;
}
@ -86,8 +145,13 @@ split_line(unsigned char *text, int max_width)
#define realloc_lines(x, o, n) mem_align_alloc(x, o, n, LINES_GRANULARITY)
/* Find the start of each line with the current max width */
#ifdef CONFIG_UTF_8
static unsigned char **
split_lines(struct widget_data *widget_data, int max_width, int utf8)
#else
static unsigned char **
split_lines(struct widget_data *widget_data, int max_width)
#endif /* CONFIG_UTF_8 */
{
unsigned char *text = widget_data->widget->text;
unsigned char **lines = (unsigned char **) widget_data->cdata;
@ -100,19 +164,27 @@ split_lines(struct widget_data *widget_data, int max_width)
while (*text) {
int width;
int cells = 0;
/* Skip first leading \n or space. */
if (isspace(*text)) text++;
if (!*text) break;
width = split_line(text, max_width);
#ifdef CONFIG_UTF_8
width = split_line(text, max_width, &cells, utf8);
#else
width = split_line(text, max_width, &cells);
#endif
/* split_line() may return 0. */
if (width < 1) {
width = 1; /* Infinite loop prevention. */
}
if (cells < 1) {
cells = 1; /* Infinite loop prevention. */
}
int_lower_bound(&widget_data->box.width, width);
int_lower_bound(&widget_data->box.width, cells);
if (!realloc_lines(&lines, line, line + 1))
break;
@ -134,13 +206,15 @@ split_lines(struct widget_data *widget_data, int max_width)
void
dlg_format_text_do(struct terminal *term, unsigned char *text,
int x, int *y, int width, int *real_width,
struct color_pair *color, enum format_align align)
struct color_pair *color, enum format_align align,
int format_only)
{
int line_width;
int firstline = 1;
for (; *text; text += line_width, (*y)++) {
int shift;
int cells = 0;
/* Skip first leading \n or space. */
if (!firstline && isspace(*text))
@ -149,7 +223,11 @@ dlg_format_text_do(struct terminal *term, unsigned char *text,
firstline = 0;
if (!*text) break;
line_width = split_line(text, width);
#ifdef CONFIG_UTF_8
line_width = split_line(text, width, &cells, term->utf8);
#else
line_width = split_line(text, width, &cells);
#endif /* CONFIG_UTF_8 */
/* split_line() may return 0. */
if (line_width < 1) {
@ -157,18 +235,18 @@ dlg_format_text_do(struct terminal *term, unsigned char *text,
continue;
}
if (real_width) int_lower_bound(real_width, line_width);
if (!term || !line_width) continue;
if (real_width) int_lower_bound(real_width, cells);
if (format_only || !line_width) continue;
/* Calculate the number of chars to indent */
if (align == ALIGN_CENTER)
shift = (width - line_width) / 2;
shift = (width - cells) / 2;
else if (align == ALIGN_RIGHT)
shift = width - line_width;
shift = width - cells;
else
shift = 0;
assert(line_width <= width && shift < width);
assert(cells <= width && shift < width);
draw_text(term, x + shift, *y, text, line_width, 0, color);
}
@ -176,7 +254,8 @@ dlg_format_text_do(struct terminal *term, unsigned char *text,
void
dlg_format_text(struct terminal *term, struct widget_data *widget_data,
int x, int *y, int width, int *real_width, int max_height)
int x, int *y, int width, int *real_width, int max_height,
int format_only)
{
unsigned char *text = widget_data->widget->text;
unsigned char saved = 0;
@ -202,9 +281,15 @@ dlg_format_text(struct terminal *term, struct widget_data *widget_data,
/* Ensure that the current split is valid but don't
* split if we don't have to */
#ifdef CONFIG_UTF_8
if (widget_data->box.width != width
&& !split_lines(widget_data, width, term->utf8))
return;
#else
if (widget_data->box.width != width
&& !split_lines(widget_data, width))
return;
#endif
lines = (unsigned char **) widget_data->cdata;
@ -246,7 +331,7 @@ dlg_format_text(struct terminal *term, struct widget_data *widget_data,
dlg_format_text_do(term, text,
x, y, width, real_width,
get_bfu_color(term, "dialog.text"),
widget_data->widget->info.text.align);
widget_data->widget->info.text.align, format_only);
if (widget_data->widget->info.text.is_label) (*y)--;
@ -333,7 +418,7 @@ format_and_display_text(struct widget_data *widget_data,
dlg_format_text(term, widget_data,
widget_data->box.x, &y, widget_data->box.width, NULL,
height);
height, 0);
display_text(dlg_data, widget_data);
redraw_from_window(dlg_data->win);

View File

@ -47,11 +47,11 @@ void add_dlg_text(struct dialog *dlg, unsigned char *text,
extern struct widget_ops text_ops;
void dlg_format_text_do(struct terminal *term,
unsigned char *text, int x, int *y, int w, int *rw,
struct color_pair *scolor, enum format_align align);
struct color_pair *scolor, enum format_align align, int format_only);
void
dlg_format_text(struct terminal *term, struct widget_data *widget_data,
int x, int *y, int dlg_width, int *real_width, int height);
int x, int *y, int dlg_width, int *real_width, int height, int format_only);
#define text_is_scrollable(widget_data) \
((widget_data)->widget->info.text.is_scrollable \

View File

@ -145,15 +145,20 @@ download_dialog_layouter(struct dialog_data *dlg_data)
mem_free(msg);
return;
}
decode_uri_for_display(url);
#ifdef CONFIG_UTF_8
if (term->utf8)
decode_uri(url);
else
#endif /* CONFIG_UTF_8 */
decode_uri_for_display(url);
url_len = strlen(url);
if (show_meter) {
int_lower_bound(&w, DOWN_DLG_MIN);
}
dlg_format_text_do(NULL, url, 0, &y, w, &rw,
dialog_text_color, ALIGN_LEFT);
dlg_format_text_do(term, url, 0, &y, w, &rw,
dialog_text_color, ALIGN_LEFT, 1);
y++;
if (show_meter) y += 2;
@ -161,13 +166,13 @@ download_dialog_layouter(struct dialog_data *dlg_data)
#if CONFIG_BITTORRENT
if (bittorrent) y += 2;
#endif
dlg_format_text_do(NULL, msg, 0, &y, w, &rw,
dialog_text_color, ALIGN_LEFT);
dlg_format_text_do(term, msg, 0, &y, w, &rw,
dialog_text_color, ALIGN_LEFT, 1);
y++;
dlg_format_buttons(NULL, dlg_data->widgets_data,
dlg_format_buttons(term, dlg_data->widgets_data,
dlg_data->number_of_widgets, 0, &y, w,
&rw, ALIGN_CENTER);
&rw, ALIGN_CENTER, 1);
draw_dialog(dlg_data, w, y);
@ -186,7 +191,7 @@ download_dialog_layouter(struct dialog_data *dlg_data)
y = dlg_data->box.y + DIALOG_TB + 1;
x = dlg_data->box.x + DIALOG_LB;
dlg_format_text_do(term, url, x, &y, w, NULL,
dialog_text_color, ALIGN_LEFT);
dialog_text_color, ALIGN_LEFT, 0);
if (show_meter) {
y++;
@ -203,12 +208,12 @@ download_dialog_layouter(struct dialog_data *dlg_data)
#endif
y++;
dlg_format_text_do(term, msg, x, &y, w, NULL,
dialog_text_color, ALIGN_LEFT);
dialog_text_color, ALIGN_LEFT, 0);
y++;
dlg_format_buttons(term, dlg_data->widgets_data,
dlg_data->number_of_widgets, x, &y, w,
NULL, ALIGN_CENTER);
NULL, ALIGN_CENTER, 0);
mem_free(url);
mem_free(msg);
@ -296,7 +301,14 @@ get_file_download_text(struct listbox_item *item, struct terminal *term)
unsigned char *uristring;
uristring = get_uri_string(file_download->uri, URI_PUBLIC);
if (uristring) decode_uri_for_display(uristring);
if (uristring) {
#ifdef CONFIG_UTF_8
if (term->utf8)
decode_uri(uristring);
else
#endif /* CONFIG_UTF_8 */
decode_uri_for_display(uristring);
}
return uristring;
}

View File

@ -581,7 +581,12 @@ query_file(struct session *ses, struct uri *uri, void *data,
add_mime_filename_to_string(&def, uri);
/* Remove the %-ugliness for display */
decode_uri_string_for_display(&def);
#ifdef CONFIG_UTF_8
if (ses->tab->term->utf8)
decode_uri_string(&def);
else
#endif /* CONFIG_UTF_8 */
decode_uri_string_for_display(&def);
if (interactive) {
input_dialog(ses->tab->term, NULL,

View File

@ -59,8 +59,10 @@ charset_list(struct terminal *term, void *xxx, void *ses_)
unsigned char *name = get_cp_name(i);
if (!name) break;
if (is_cp_special(i))
continue;
#ifndef CONFIG_UTF_8
if (is_cp_utf8(i)) continue;
#endif /* CONFIG_UTF_8 */
items++;
add_to_menu(&mi, name, NULL, ACT_MAIN_NONE,

View File

@ -150,15 +150,8 @@ get_current_link_info_and_title(struct session *ses,
link_title = get_current_link_title(doc_view);
if (link_title) {
unsigned char *src;
assert(*link_title);
/* Remove illicit chars. */
for (src = link_title; *src; src++)
if (!isprint(*src) || iscntrl(*src))
*src = '*';
ret = straconcat(link_info, " - ", link_title, NULL);
mem_free(link_info);
mem_free(link_title);
@ -424,11 +417,25 @@ display_title_bar(struct session *ses, struct terminal *term)
if (document->title) {
int maxlen = int_max(term->width - 4 - buflen, 0);
int titlelen = int_min(strlen(document->title), maxlen);
int titlelen, titlewidth;
#ifdef CONFIG_UTF_8
if (term->utf8) {
titlewidth = utf8_ptr2cells(document->title, NULL);
titlewidth = int_min(titlewidth, maxlen);
titlelen = utf8_cells2bytes(document->title,
titlewidth, NULL);
} else
#endif /* CONFIG_UTF_8 */
{
titlewidth = int_min(strlen(document->title), maxlen);
titlelen = titlewidth;
}
add_bytes_to_string(&title, document->title, titlelen);
if (titlelen == maxlen)
if (titlewidth == maxlen)
add_bytes_to_string(&title, "...", 3);
}
@ -436,7 +443,16 @@ display_title_bar(struct session *ses, struct terminal *term)
add_bytes_to_string(&title, buf, buflen);
if (title.length) {
int x = int_max(term->width - 1 - title.length, 0);
int x;
#ifdef CONFIG_UTF_8
if (term->utf8) {
x = int_max(term->width - 1
- utf8_ptr2cells(title.source,
title.source
+ title.length), 0);
} else
#endif /* CONFIG_UTF_8 */
x = int_max(term->width - 1 - title.length, 0);
draw_text(term, x, 0, title.source, title.length, 0,
get_bfu_color(term, "title.title-text"));

View File

@ -118,13 +118,19 @@ struct link {
#define get_link_name(link) \
(!link_is_form(link) ? (link)->data.name : NULL)
#ifdef CONFIG_UTF_8
struct search {
int x, y;
signed int n; /* RAM is cheap nowadays */
unicode_val_T c;
};
#else
struct search {
int x, y;
signed int n:24; /* This structure is size-critical */
unsigned char c;
};
#endif
struct document {
OBJECT_HEAD(struct document);

View File

@ -260,7 +260,12 @@ render_dom_line(struct dom_renderer *renderer, struct screen_char *template,
struct document *document = renderer->document;
struct conv_table *convert = renderer->convert_table;
enum convert_string_mode mode = renderer->convert_mode;
int x;
int x, charlen;
#ifdef CONFIG_UTF_8
int utf8 = document->options.utf8;
unsigned char *end;
#endif /* CONFIG_UTF_8 */
assert(renderer && template && string && length);
@ -275,12 +280,15 @@ render_dom_line(struct dom_renderer *renderer, struct screen_char *template,
add_search_node(renderer, length);
for (x = 0; x < length; x++, renderer->canvas_x++) {
unsigned char data = string[x];
#ifdef CONFIG_UTF_8
end = string + length;
#endif /* CONFIG_UTF_8 */
for (x = 0, charlen = 1; x < length;x += charlen, renderer->canvas_x++) {
unsigned char *text = &string[x];
/* This is mostly to be able to break out so the indentation
* level won't get to high. */
switch (data) {
switch (*text) {
case ASCII_TAB:
{
int tab_width = 7 - (X(renderer) & 7);
@ -295,15 +303,33 @@ render_dom_line(struct dom_renderer *renderer, struct screen_char *template,
* ``main loop'' add the actual tab char. */
for (; tab_width-- > 0; renderer->canvas_x++)
copy_screen_chars(POS(renderer), template, 1);
charlen = 1;
break;
}
default:
template->data = isscreensafe(data) ? data : '.';
#ifdef CONFIG_UTF_8
if (utf8) {
unicode_val_T data;
charlen = utf8charlen(text);
data = utf_8_to_unicode(&text, end);
template->data = (unicode_val_T)data;
if (unicode_to_cell(data) == 2) {
copy_screen_chars(POS(renderer),
template, 1);
X(renderer)++;
template->data = UCS_NO_CHAR;
}
} else
#endif /* CONFIG_UTF_8 */
template->data = isscreensafe(*text) ? *text:'.';
}
copy_screen_chars(POS(renderer), template, 1);
}
mem_free(string);
}
@ -1024,6 +1050,9 @@ render_dom_document(struct cache_entry *cached, struct document *document,
init_dom_renderer(&renderer, document, buffer, convert_table);
document->bgcolor = document->options.default_bg;
#ifdef CONFIG_UTF_8
document->options.utf8 = is_cp_utf8(document->options.cp);
#endif /* CONFIG_UTF_8 */
if (document->options.plain)
parser_type = SGML_PARSER_STREAM;

View File

@ -495,7 +495,13 @@ end_parse:
max_width = 0;
for (i = 0; i < order; i++) {
if (!labels[i]) continue;
int_lower_bound(&max_width, strlen(labels[i]));
#ifdef CONFIG_UTF_8
if (html_context->options->utf8)
int_lower_bound(&max_width,
utf8_ptr2cells(labels[i], NULL));
else
#endif /* CONFIG_UTF_8 */
int_lower_bound(&max_width, strlen(labels[i]));
}
for (i = 0; i < max_width; i++)

View File

@ -23,6 +23,7 @@
#include "document/refresh.h"
#include "document/renderer.h"
#include "intl/charsets.h"
#include "osdep/types.h"
#include "protocol/uri.h"
#include "session/session.h"
#include "terminal/color.h"
@ -209,6 +210,10 @@ realloc_spaces(struct part *part, int length)
if (!ALIGN_SPACES(&part->spaces, part->spaces_len, length))
return -1;
#ifdef CONFIG_UTF_8
if (!ALIGN_SPACES(&part->char_width, part->spaces_len, length))
return -1;
#endif
part->spaces_len = length;
@ -374,6 +379,122 @@ get_format_screen_char(struct html_context *html_context,
return &schar_cache;
}
#ifdef CONFIG_UTF_8
/* First possibly do the format change and then find out what coordinates
* to use since sub- or superscript might change them */
static inline int
set_hline(struct html_context *html_context, unsigned char *chars, int charslen,
enum link_state link_state)
{
struct part *part = html_context->part;
struct screen_char *schar = get_format_screen_char(html_context,
link_state);
int x = part->cx;
int y = part->cy;
int x2 = x;
int len = charslen;
int utf8 = html_context->options->utf8;
assert(part);
if_assert_failed return len;
assert(charslen >= 0);
if (realloc_spaces(part, x + charslen))
return len;
if (part->document) {
if (realloc_line(html_context, part->document,
Y(y), X(x) + charslen - 1))
return len;
if (utf8) {
unsigned char *end;
for (end = chars + charslen; chars < end; x++) {
if (*chars == NBSP_CHAR) {
schar->data = ' ';
part->spaces[x] = html_context->options->wrap_nbsp;
part->char_width[x] = 1;
chars++;
} else {
unicode_val_T data;
part->spaces[x] = (*chars == ' ');
data = utf_8_to_unicode(&chars, end);
if (data == UCS_NO_CHAR) {
/* HR */
unsigned char attr = schar->attr;
schar->data = *chars++;
schar->attr = SCREEN_ATTR_FRAME;
copy_screen_chars(&POS(x, y), schar, 1);
schar->attr = attr;
part->char_width[x] = 0;
continue;
} else {
if (unicode_to_cell(data) == 2) {
schar->data = (unicode_val_T)data;
part->char_width[x] = 2;
copy_screen_chars(&POS(x++, y), schar, 1);
schar->data = UCS_NO_CHAR;
part->spaces[x] = 0;
part->char_width[x] = 0;
} else {
part->char_width[x] = unicode_to_cell(data);
schar->data = (unicode_val_T)data;
}
}
}
copy_screen_chars(&POS(x, y), schar, 1);
}
} else {
for (; charslen > 0; charslen--, x++, chars++) {
part->char_width[x] = 1;
if (*chars == NBSP_CHAR) {
schar->data = ' ';
part->spaces[x] = html_context->options->wrap_nbsp;
} else {
part->spaces[x] = (*chars == ' ');
schar->data = *chars;
}
copy_screen_chars(&POS(x, y), schar, 1);
}
}
len = x - x2;
} else {
if (utf8) {
unsigned char *end;
for (end = chars + charslen; chars < end; x++) {
unicode_val_T data;
part->spaces[x] = (*chars == ' ');
data = utf_8_to_unicode(&chars, end);
part->char_width[x] = unicode_to_cell(data);
if (part->char_width[x] == 2) {
x++;
part->spaces[x] = 0;
part->char_width[x] = 0;
}
if (data == UCS_NO_CHAR) {
chars++;
part->char_width[x] = 0;
x++;
}
}
len = x - x2;
} else {
for (; charslen > 0; charslen--, x++, chars++) {
part->spaces[x] = (*chars == ' ');
part->char_width[x] = 1;
}
}
}
return len;
}
#else
/* First possibly do the format change and then find out what coordinates
* to use since sub- or superscript might change them */
static inline void
@ -405,7 +526,6 @@ set_hline(struct html_context *html_context, unsigned char *chars, int charslen,
part->spaces[x] = (*chars == ' ');
schar->data = *chars;
}
copy_screen_chars(&POS(x, y), schar, 1);
}
} else {
@ -414,6 +534,7 @@ set_hline(struct html_context *html_context, unsigned char *chars, int charslen,
}
}
}
#endif /* CONFIG_UTF_8 */
static void
move_links(struct html_context *html_context, int xf, int yf, int xt, int yt)
@ -645,29 +766,53 @@ split_line_at(struct html_context *html_context, int width)
if (part->document) {
assert(part->document->data);
if_assert_failed return 0;
assertm(POS(width, part->cy).data == ' ',
"bad split: %c", POS(width, part->cy).data);
move_chars(html_context, width + 1, part->cy, par_format.leftmargin, part->cy + 1);
del_chars(html_context, width, part->cy);
#ifdef CONFIG_UTF_8
if (html_context->options->utf8
&& width < part->spaces_len && part->char_width[width] == 2) {
move_chars(html_context, width, part->cy, par_format.leftmargin, part->cy + 1);
del_chars(html_context, width, part->cy);
} else
#endif
{
assertm(POS(width, part->cy).data == ' ',
"bad split: %c", POS(width, part->cy).data);
move_chars(html_context, width + 1, part->cy, par_format.leftmargin, part->cy + 1);
del_chars(html_context, width, part->cy);
}
}
width++; /* Since we were using (x + 1) only later... */
#ifdef CONFIG_UTF_8
if (!(html_context->options->utf8
&& width < part->spaces_len
&& part->char_width[width] == 2))
#endif
width++; /* Since we were using (x + 1) only later... */
tmp = part->spaces_len - width;
if (tmp > 0) {
/* 0 is possible and I'm paranoid ... --Zas */
memmove(part->spaces, part->spaces + width, tmp);
#ifdef CONFIG_UTF_8
memmove(part->char_width, part->char_width + width, tmp);
#endif
}
assert(tmp >= 0);
if_assert_failed tmp = 0;
memset(part->spaces + tmp, 0, width);
#ifdef CONFIG_UTF_8
memset(part->char_width + tmp, 0, width);
#endif
if (par_format.leftmargin > 0) {
tmp = part->spaces_len - par_format.leftmargin;
assertm(tmp > 0, "part->spaces_len - par_format.leftmargin == %d", tmp);
/* So tmp is zero, memmove() should survive that. Don't recover. */
memmove(part->spaces + par_format.leftmargin, part->spaces, tmp);
#ifdef CONFIG_UTF_8
memmove(part->char_width + par_format.leftmargin, part->char_width, tmp);
#endif
}
part->cy++;
@ -705,13 +850,38 @@ split_line(struct html_context *html_context)
assert(part);
if_assert_failed return 0;
for (x = overlap(par_format); x >= par_format.leftmargin; x--)
if (x < part->spaces_len && part->spaces[x])
return split_line_at(html_context, x);
#ifdef CONFIG_UTF_8
if (html_context->options->utf8) {
for (x = overlap(par_format); x >= par_format.leftmargin; x--) {
for (x = par_format.leftmargin; x < part->cx ; x++)
if (x < part->spaces_len && part->spaces[x])
return split_line_at(html_context, x);
if (x < part->spaces_len && (part->spaces[x]
|| (part->char_width[x] == 2
/* Ugly hack. If we haven't place for
* double-width characters we print two
* double-width characters. */
&& x != par_format.leftmargin)))
return split_line_at(html_context, x);
}
for (x = par_format.leftmargin; x < part->cx ; x++) {
if (x < part->spaces_len && (part->spaces[x]
|| (part->char_width[x] == 2
/* We want to break line after _second_
* double-width character. */
&& x > par_format.leftmargin)))
return split_line_at(html_context, x);
}
} else
#endif
{
for (x = overlap(par_format); x >= par_format.leftmargin; x--)
if (x < part->spaces_len && part->spaces[x])
return split_line_at(html_context, x);
for (x = par_format.leftmargin; x < part->cx ; x++)
if (x < part->spaces_len && part->spaces[x])
return split_line_at(html_context, x);
}
/* Make sure that we count the right margin to the total
* actual box width. */
@ -1140,9 +1310,15 @@ done_link_state_info(void)
sizeof(renderer_context.link_state_info));
}
#ifdef CONFIG_UTF_8
static inline void
process_link(struct html_context *html_context, enum link_state link_state,
unsigned char *chars, int charslen)
unsigned char *chars, int charslen, int cells)
#else
static inline void
process_link(struct html_context *html_context, enum link_state link_state,
unsigned char *chars, int charslen)
#endif /* CONFIG_UTF_8 */
{
struct part *part = html_context->part;
struct link *link;
@ -1194,6 +1370,9 @@ process_link(struct html_context *html_context, enum link_state link_state,
if (x_offset) {
charslen -= x_offset;
chars += x_offset;
#ifdef CONFIG_UTF_8
cells -= x_offset;
#endif /* CONFIG_UTF_8 */
}
link = new_link(html_context, chars, charslen);
@ -1208,14 +1387,26 @@ process_link(struct html_context *html_context, enum link_state link_state,
}
/* Add new canvas positions to the link. */
if (realloc_points(link, link->npoints + charslen)) {
#ifdef CONFIG_UTF_8
if (realloc_points(link, link->npoints + cells))
#else
if (realloc_points(link, link->npoints + charslen))
#endif /* CONFIG_UTF_8 */
{
struct point *point = &link->points[link->npoints];
int x = X(part->cx) + x_offset;
int y = Y(part->cy);
#ifdef CONFIG_UTF_8
link->npoints += cells;
for (; cells > 0; cells--, point++, x++)
#else
link->npoints += charslen;
for (; charslen > 0; charslen--, point++, x++) {
for (; charslen > 0; charslen--, point++, x++)
#endif /* CONFIG_UTF_8 */
{
point->x = x;
point->y = y;
}
@ -1266,6 +1457,9 @@ put_chars(struct html_context *html_context, unsigned char *chars, int charslen)
{
enum link_state link_state;
struct part *part;
#ifdef CONFIG_UTF_8
int cells;
#endif /* CONFIG_UTF_8 */
assert(html_context);
if_assert_failed return;
@ -1324,18 +1518,52 @@ put_chars(struct html_context *html_context, unsigned char *chars, int charslen)
else if (html_context->options->links_numbering)
put_link_number(html_context);
}
set_hline(html_context, chars, charslen, link_state);
#ifdef CONFIG_UTF_8
cells =
#endif /* CONFIG_UTF_8 */
set_hline(html_context, chars, charslen, link_state);
if (link_state != LINK_STATE_NONE) {
#define is_drawing_subs_or_sups() \
((format.style.attr & AT_SUBSCRIPT \
&& html_context->options->display_subs) \
|| (format.style.attr & AT_SUPERSCRIPT \
&& html_context->options->display_sups))
/* We need to update the current @link_state because <sub> and
* <sup> tags will output to the canvas using an inner
* put_chars() call which results in their process_link() call
* will ``update'' the @link_state. */
if (link_state == LINK_STATE_NEW
&& (is_drawing_subs_or_sups()
|| update_after_subscript != renderer_context.subscript)) {
link_state = get_link_state(html_context);
}
#undef is_drawing_subs_or_sups
#ifdef CONFIG_UTF_8
process_link(html_context, link_state, chars, charslen,
cells);
#else
process_link(html_context, link_state, chars, charslen);
#endif /* CONFIG_UTF_8 */
}
#ifdef CONFIG_UTF_8
if (renderer_context.nowrap
&& part->cx + charslen > overlap(par_format))
&& part->cx + cells > overlap(par_format))
return;
part->cx += cells;
#else
if (renderer_context.nowrap
&& part->cx + charslen > overlap(par_format))
return;
part->cx += charslen;
#endif /* CONFIG_UTF_8 */
renderer_context.nobreak = 0;
if (!(html_context->options->wrap || html_is_preformatted())) {
@ -1351,7 +1579,11 @@ put_chars(struct html_context *html_context, unsigned char *chars, int charslen)
}
assert(charslen > 0);
#ifdef CONFIG_UTF_8
part->xa += cells;
#else
part->xa += charslen;
#endif /* CONFIG_UTF_8 */
int_lower_bound(&part->max_width, part->xa
+ par_format.leftmargin + par_format.rightmargin
- (chars[charslen - 1] == ' '
@ -1410,6 +1642,9 @@ end:
part->cx = -1;
part->xa = 0;
memset(part->spaces, 0, part->spaces_len);
#ifdef CONFIG_UTF_8
memset(part->char_width, 0, part->spaces_len);
#endif
}
static void
@ -1829,6 +2064,9 @@ format_html_part(struct html_context *html_context,
done_link_state_info();
mem_free_if(part->spaces);
#ifdef CONFIG_UTF_8
mem_free_if(part->char_width);
#endif
if (document) {
struct node *node = document->nodes.next;
@ -1912,6 +2150,9 @@ render_html_document(struct cache_entry *cached, struct document *document,
&document->cp,
&document->cp_status,
document->options.hard_assume);
#ifdef CONFIG_UTF_8
html_context->options->utf8 = is_cp_utf8(document->options.cp);
#endif /* CONFIG_UTF_8 */
if (title.length) {
document->title = convert_string(renderer_context.convert_table,

View File

@ -23,6 +23,10 @@ struct part {
unsigned char *spaces;
int spaces_len;
#ifdef CONFIG_UTF_8
unsigned char *char_width;
#endif
struct box box;

View File

@ -101,6 +101,9 @@ struct document_options {
unsigned int no_cache:1;
unsigned int gradual_rerendering:1;
#ifdef CONFIG_UTF_8
unsigned int utf8:1;
#endif /* CONFIG_UTF_8 */
/* Active link coloring */
/* This is mostly here to make use of this option cache so link
* drawing is faster. --jonas */

View File

@ -175,12 +175,12 @@ get_uri_length(unsigned char *line, int length)
static int
print_document_link(struct plain_renderer *renderer, int lineno,
unsigned char *line, int line_pos, int width,
int expanded, struct screen_char *pos)
int expanded, struct screen_char *pos, int cells)
{
struct document *document = renderer->document;
unsigned char *start = &line[line_pos];
int len = get_uri_length(start, width - line_pos);
int screen_column = line_pos + expanded;
int screen_column = cells + expanded;
struct link *new_link;
int link_end = line_pos + len;
unsigned char saved_char;
@ -226,209 +226,6 @@ print_document_link(struct plain_renderer *renderer, int lineno,
return len;
}
enum mode_16_256 {
COLOR_NONE,
COLOR_16_FOREGROUND,
COLOR_16_BACKGROUND,
COLOR_38,
COLOR_48,
COLOR_256_FOREGROUND,
COLOR_256_BACKGROUND
};
static int
change_colors(struct screen_char *template, unsigned char *line, int line_pos, int width, struct document *document)
{
unsigned char fg, bg, bold;
enum mode_16_256 color = COLOR_NONE;
unsigned char value = 0;
int start = 0;
#if defined(CONFIG_88_COLORS) || defined(CONFIG_256_COLORS)
fg = template->color[0];
bg = template->color[1];
#else
fg = template->color[0] & 15;
bg = template->color[0] >> 4;
#endif
bold = template->attr & SCREEN_ATTR_BOLD;
for (; line_pos < width; line_pos++) {
unsigned char ch = line[line_pos];
switch (color) {
case COLOR_NONE:
switch (ch) {
case '0':
bold = 0;
break;
case '1':
bold = SCREEN_ATTR_BOLD;
break;
case '3':
color = COLOR_16_FOREGROUND;
break;
case '4':
color = COLOR_16_BACKGROUND;
break;
case 'm':
goto end;
default:
break;
}
break;
case COLOR_16_FOREGROUND:
switch (ch) {
case '9':
fg = 7;
color = COLOR_NONE;
break;
case '8':
color = COLOR_38;
break;
case 'm':
goto end;
default:
if (ch >= '0' && ch <= '7') fg = ch - '0';
else goto end;
color = COLOR_NONE;
break;
}
break;
case COLOR_16_BACKGROUND:
switch (ch) {
case '9':
bg = 0;
color = COLOR_NONE;
break;
case '8':
color = COLOR_48;
break;
case 'm':
goto end;
default:
if (ch >= '0' && ch <= '7') bg = ch - '0';
else goto end;
color = COLOR_NONE;
break;
}
break;
case COLOR_38:
switch (ch) {
case '5':
start = 1;
value = 0;
color = COLOR_256_FOREGROUND;
break;
case 'm':
goto end;
case ';':
break;
default:
color = COLOR_NONE;
break;
}
break;
case COLOR_48:
switch (ch) {
case '5':
start = 1;
value = 0;
color = COLOR_256_BACKGROUND;
break;
case 'm':
goto end;
case ';':
break;
default:
color = COLOR_NONE;
break;
}
break;
case COLOR_256_FOREGROUND:
switch (ch) {
case ';':
case 'm':
if (start) {
start = 0;
value = 0;
} else {
#if defined(CONFIG_88_COLORS) || defined(CONFIG_256_COLORS)
#ifdef CONFIG_88_COLORS
if (document->options.color_mode == COLOR_MODE_88) fg = value;
#endif
#ifdef CONFIG_256_COLORS
if (document->options.color_mode == COLOR_MODE_256) fg = value;
#endif
#endif
color = COLOR_NONE;
value = 0;
}
if (ch == 'm') goto end;
break;
default:
if (ch >= '0' && ch <= '9') value *= 10 + ch - '0';
else goto end;
break;
}
break;
case COLOR_256_BACKGROUND:
switch (ch) {
case ';':
case 'm':
if (start) {
start = 0;
value = 0;
} else {
#if defined(CONFIG_88_COLORS) || defined(CONFIG_256_COLORS)
#ifdef CONFIG_88_COLORS
if (document->options.color_mode == COLOR_MODE_88) bg = value;
#endif
#ifdef CONFIG_256_COLORS
if (document->options.color_mode == COLOR_MODE_256) bg = value;
#endif
#endif
color = COLOR_NONE;
value = 0;
}
if (ch == 'm') goto end;
break;
default:
if (ch >= '0' && ch <= '9') value *= 10 + ch - '0';
else goto end;
break;
}
break;
}
}
end:
#if defined(CONFIG_88_COLORS) || defined(CONFIG_256_COLORS)
#ifdef CONFIG_88_COLORS
if (document->options.color_mode == COLOR_MODE_88) {
TERM_COLOR_FOREGROUND(template->color) = fg;
TERM_COLOR_BACKGROUND(template->color) = bg;
}
#endif
#ifdef CONFIG_256_COLORS
if (document->options.color_mode == COLOR_MODE_256) {
TERM_COLOR_FOREGROUND(template->color) = fg;
TERM_COLOR_BACKGROUND(template->color) = bg;
}
#endif
#endif
if (document->options.color_mode == COLOR_MODE_16) {
fg |= bold;
set_term_color16(template, document->options.color_flags, fg, bg);
}
return line_pos;
}
static inline int
add_document_line(struct plain_renderer *renderer,
unsigned char *line, int line_width)
@ -437,6 +234,10 @@ add_document_line(struct plain_renderer *renderer,
struct screen_char *template = &renderer->template;
struct screen_char saved_renderer_template = *template;
struct screen_char *pos, *startpos;
#ifdef CONFIG_UTF_8
int utf8 = document->options.utf8;
#endif /* CONFIG_UTF_8 */
int cells = 0;
int lineno = renderer->lineno;
int expanded = 0;
int width = line_width;
@ -448,13 +249,31 @@ add_document_line(struct plain_renderer *renderer,
if (!line) return 0;
/* Now expand tabs */
for (line_pos = 0; line_pos < width; line_pos++) {
for (line_pos = 0; line_pos < width;) {
unsigned char line_char = line[line_pos];
int charlen = 1;
int cell = 1;
#ifdef CONFIG_UTF_8
unicode_val_T data;
if (utf8) {
unsigned char *line_char2 = &line[line_pos];
charlen = utf8charlen(&line_char);
data = utf_8_to_unicode(&line_char2, &line[width]);
if (data == UCS_NO_CHAR) {
line_pos += charlen;
continue;
}
cell = unicode_to_cell(data);
}
#endif /* CONFIG_UTF_8 */
if (line_char == ASCII_TAB
&& (line_pos + 1 == width
|| line[line_pos + 1] != ASCII_BS)) {
int tab_width = 7 - ((line_pos + expanded) & 7);
&& (line_pos + charlen == width
|| line[line_pos + charlen] != ASCII_BS)) {
int tab_width = 7 - ((cells + expanded) & 7);
expanded += tab_width;
} else if (line_char == ASCII_BS) {
@ -475,6 +294,8 @@ add_document_line(struct plain_renderer *renderer,
expanded--;
#endif
}
line_pos += charlen;
cells += cell;
}
assert(expanded >= 0);
@ -485,24 +306,50 @@ add_document_line(struct plain_renderer *renderer,
return 0;
}
cells = 0;
expanded = 0;
for (line_pos = 0; line_pos < width; line_pos++) {
for (line_pos = 0; line_pos < width;) {
unsigned char line_char = line[line_pos];
unsigned char next_char, prev_char;
int charlen = 1;
int cell = 1;
#ifdef CONFIG_UTF_8
unicode_val_T data;
if (utf8) {
unsigned char *line_char2 = &line[line_pos];
charlen = utf8charlen(&line_char);
data = utf_8_to_unicode(&line_char2, &line[width]);
if (data == UCS_NO_CHAR) {
line_pos += charlen;
continue;
}
cell = unicode_to_cell(data);
}
#endif /* CONFIG_UTF_8 */
prev_char = line_pos > 0 ? line[line_pos - 1] : '\0';
next_char = (line_pos + 1 < width) ? line[line_pos + 1]
: '\0';
next_char = (line_pos + charlen < width) ?
line[line_pos + charlen] : '\0';
/* Do not expand tabs that precede back-spaces; this saves the
* back-space code some trouble. */
if (line_char == ASCII_TAB && next_char != ASCII_BS) {
int tab_width = 7 - ((cells + expanded) & 7);
expanded += tab_width;
template->data = ' ';
do
copy_screen_chars(pos++, template, 1);
while (tab_width--);
switch (line_char) {
case 27:
if (next_char != '[') goto normal;
line_pos += 2;
line_pos = change_colors(&saved_renderer_template, line, line_pos, width, document);
*template = saved_renderer_template;
break;
case ASCII_BS:
if (!(expanded + line_pos)) {
} else if (line_char == ASCII_BS) {
if (!(expanded + cells)) {
/* We've backspaced to the start of the line */
continue;
}
@ -516,8 +363,8 @@ add_document_line(struct plain_renderer *renderer,
/* x^H_ becomes _^Hx */
if (line_pos - 1 >= 0)
line[line_pos - 1] = next_char;
if (line_pos + 1 < width)
line[line_pos + 1] = prev_char;
if (line_pos + charlen < width)
line[line_pos + charlen] = prev_char;
/* Go back and reparse the swapped characters */
if (line_pos - 2 >= 0)
@ -562,62 +409,69 @@ add_document_line(struct plain_renderer *renderer,
/* Handle _^Hx^Hx as both bold and underlined */
if (template->attr)
template->attr |= pos->attr;
break;
case ASCII_TAB:
/* Do not expand tabs that precede back-spaces; this saves the
* back-space code some trouble. */
if (next_char != ASCII_BS) {
int tab_width = 7 - ((line_pos + expanded) & 7);
} else {
int added_chars = 0;
expanded += tab_width;
template->data = ' ';
do
copy_screen_chars(pos++, template, 1);
while (tab_width--);
*template = saved_renderer_template;
break;
}
default:
normal:
{
int added_chars = 0;
if (document->options.plain_display_links
&& isalpha(line_char) && isalpha(next_char)) {
/* We only want to check for a URI if there are
* at least two consecutive alphabetic
* characters, or if we are at the very start of
* the line. It improves performance a bit.
* --Zas */
added_chars = print_document_link(renderer,
if (document->options.plain_display_links
&& isalpha(line_char) && isalpha(next_char)) {
/* We only want to check for a URI if there are
* at least two consecutive alphabetic
* characters, or if we are at the very start of
* the line. It improves performance a bit.
* --Zas */
added_chars = print_document_link(renderer,
lineno, line,
line_pos,
width,
expanded,
pos);
}
pos, cells);
}
if (added_chars) {
line_pos += added_chars - 1;
pos += added_chars;
} else {
if (!isscreensafe(line_char) && line_char != 27)
if (added_chars) {
line_pos += added_chars - 1;
pos += added_chars;
} else {
#ifdef CONFIG_UTF_8
if (utf8) {
unsigned char *text = &line[line_pos];
unicode_val_T data =
utf_8_to_unicode(&text,
&line[width]);
if (data == UCS_NO_CHAR) {
line_pos += charlen;
continue;
}
template->data = (unicode_val_T)data;
copy_screen_chars(pos++, template, 1);
if (unicode_to_cell(data) == 2) {
template->data = UCS_NO_CHAR;
copy_screen_chars(pos++,
template, 1);
cell++;
}
} else
#endif /* CONFIG_UTF_8 */
{
if (!isscreensafe(line_char))
line_char = '.';
template->data = line_char;
copy_screen_chars(pos++, template, 1);
/* Detect copy of nul chars to screen, this
* should not occur. --Zas */
/* Detect copy of nul chars to screen,
* this should not occur. --Zas */
assert(line_char);
}
*template = saved_renderer_template;
}
}
}
*template = saved_renderer_template;
}
line_pos += charlen;
cells += cell;
}
mem_free(line);
realloc_line(document, pos - startpos, lineno);
@ -664,19 +518,20 @@ add_document_lines(struct plain_renderer *renderer)
int length = renderer->length;
int was_empty_line = 0;
int was_wrapped = 0;
#ifdef CONFIG_UTF_8
int utf8 = is_cp_utf8(renderer->document->cp);
#endif
for (; length > 0; renderer->lineno++) {
unsigned char *xsource;
int width, added, only_spaces = 1, spaces = 0, was_spaces = 0;
int last_space = 0;
int tab_spaces = 0;
int step = 0;
int cells = 0;
/* End of line detection: We handle \r, \r\n and \n types. */
for (width = 0;
width + tab_spaces < renderer->max_width
&& width < length;
width++) {
for (width = 0; (width < length) &&
(cells < renderer->max_width);) {
if (source[width] == ASCII_CR)
step++;
if (source[width + step] == ASCII_LF)
@ -695,6 +550,22 @@ add_document_lines(struct plain_renderer *renderer)
only_spaces = 0;
was_spaces = 0;
}
#ifdef CONFIG_UTF_8
if (utf8) {
unsigned char *text = &source[width];
unicode_val_T data = utf_8_to_unicode(&text,
&source[length]);
if (data == UCS_NO_CHAR) return;
cells += unicode_to_cell(data);
width += utf8charlen(&source[width]);
} else
#endif /* CONFIG_UTF_8 */
{
cells++;
width++;
}
}
if (only_spaces && step) {
@ -722,6 +593,7 @@ add_document_lines(struct plain_renderer *renderer)
width -= was_spaces;
step += was_spaces;
}
if (!step && (width < length) && last_space) {
width = last_space;
step = 1;
@ -777,6 +649,9 @@ render_plain_document(struct cache_entry *cached, struct document *document,
document->bgcolor = document->options.default_bg;
document->width = 0;
#ifdef CONFIG_UTF_8
document->options.utf8 = is_cp_utf8(document->options.cp);
#endif /* CONFIG_UTF_8 */
/* Setup the style */
init_template(&renderer.template, &document->options);

View File

@ -345,8 +345,14 @@ render_document(struct view_state *vs, struct document_view *doc_view,
}
document->title = get_uri_string(document->uri, components);
if (document->title)
decode_uri_for_display(document->title);
if (document->title) {
#ifdef CONFIG_UTF_8
if (doc_view->document->options.utf8)
decode_uri(document->title);
else
#endif /* CONFIG_UTF_8 */
decode_uri_for_display(document->title);
}
}
#ifdef CONFIG_CSS

View File

@ -140,6 +140,14 @@ u2cp_(unicode_val_T u, int to, int no_nbsp_hack)
int s;
if (u < 128) return strings[u];
to &= ~SYSTEM_CHARSET_FLAG;
#ifdef CONFIG_UTF_8
if (codepages[to].table == table_utf_8)
return encode_utf_8(u);
#endif /* CONFIG_UTF_8 */
/* To mark non breaking spaces, we use a special char NBSP_CHAR. */
if (u == 0xa0) return no_nbsp_hack ? " " : NBSP_CHAR_STRING;
if (u == 0xad) return "";
@ -151,7 +159,6 @@ u2cp_(unicode_val_T u, int to, int no_nbsp_hack)
return u2cp_(strange, to, no_nbsp_hack);
}
to &= ~SYSTEM_CHARSET_FLAG;
for (j = 0; codepages[to].table[j].c; j++)
if (codepages[to].table[j].u == u)
@ -165,8 +172,13 @@ u2cp_(unicode_val_T u, int to, int no_nbsp_hack)
static unsigned char utf_buffer[7];
#ifdef CONFIG_UTF_8
inline unsigned char *
encode_utf_8(unicode_val_T u)
#else
static unsigned char *
encode_utf_8(unicode_val_T u)
#endif /* CONFIG_UTF_8 */
{
memset(utf_buffer, 0, 7);
@ -200,6 +212,257 @@ encode_utf_8(unicode_val_T u)
return utf_buffer;
}
#ifdef CONFIG_UTF_8
/* Number of bytes utf8 character indexed by first byte. Illegal bytes are
* equal ones and handled different. */
static char utf8char_len_tab[256] =
{
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,
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,
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,
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,
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,
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,
2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,
3,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3, 4,4,4,4,4,4,4,4, 5,5,5,5,6,6,1,1,
};
inline int utf8charlen(const unsigned char *p)
{
int len;
if (p==NULL)
return 0;
len = utf8char_len_tab[*p];
return len;
}
inline int
strlen_utf8(unsigned char **str)
{
unsigned char *s = *str;
unsigned char *end = strchr(s, '\0');
int x;
int len;
for (x = 0;; x++, s += len) {
len = utf8charlen(s);
if (s + len > end) break;
}
*str = s;
return x;
}
#define utf8_issingle(p) (((p) & 0x80) == 0)
#define utf8_islead(p) (utf8_issingle(p) || ((p) & 0xc0) == 0xc0)
/* Start from @current and move back to @pos char. This pointer return. The
* most left pointer is @start. */
inline unsigned char *
utf8_prevchar(unsigned char *current, int pos, unsigned char *start)
{
if (current == NULL || start == NULL || pos < 0)
return NULL;
while (pos > 0 && current != start) {
current--;
if (utf8_islead(*current))
pos--;
}
return current;
}
/* Count number of standard terminal cells needed for displaying UTF-8
* character. */
int
utf8_char2cells(unsigned char *utf8_char, unsigned char *end)
{
unicode_val_T u;
if (end == NULL)
end = strchr(utf8_char, '\0');
if(!utf8_char || !end)
return -1;
u = utf_8_to_unicode(&utf8_char, end);
return unicode_to_cell(u);
}
/* Count number of standard terminal cells needed for displaying string
* with UTF-8 characters. */
int
utf8_ptr2cells(unsigned char *string, unsigned char *end)
{
int charlen, cell, cells = 0;
if (end == NULL)
end = strchr(string, '\0');
if(!string || !end)
return -1;
do {
charlen = utf8charlen(string);
if (string + charlen > end)
break;
cell = utf8_char2cells(string, end);
if (cell < 0)
return -1;
cells += cell;
string += charlen;
} while (1);
return cells;
}
/* Count number of characters in string. */
int
utf8_ptr2chars(unsigned char *string, unsigned char *end)
{
int charlen, chars = 0;
if (end == NULL)
end = strchr(string, '\0');
if(!string || !end)
return -1;
do {
charlen = utf8charlen(string);
if (string + charlen > end)
break;
chars++;
string += charlen;
} while (1);
return chars;
}
/*
* Count number of bytes from begining of the string needed for displaying
* specified number of cells.
*/
int
utf8_cells2bytes(unsigned char *string, int max_cells, unsigned char *end)
{
unsigned int bytes = 0, cells = 0;
assert(max_cells>=0);
if (end == NULL)
end = strchr(string, '\0');
if(!string || !end)
return -1;
do {
int cell = utf8_char2cells(&string[bytes], end);
if (cell < 0)
return -1;
cells += cell;
if (cells > max_cells)
break;
bytes += utf8charlen(&string[bytes]);
if (string + bytes > end) {
bytes = end - string;
break;
}
} while(1);
return bytes;
}
/*
* Find out number of standard terminal collumns needed for displaying symbol
* (glyph) which represents Unicode character c.
* TODO: Use wcwidth when it is available.
*
* @return 2 for double-width glyph, 1 for others.
* TODO: May be extended to return 0 for zero-width glyphs
* (like composing, maybe unprintable too).
*/
inline int
unicode_to_cell(unicode_val_T c)
{
if (c >= 0x1100
&& (c <= 0x115f /* Hangul Jamo */
|| c == 0x2329
|| c == 0x232a
|| (c >= 0x2e80 && c <= 0xa4cf
&& c != 0x303f) /* CJK ... Yi */
|| (c >= 0xac00 && c <= 0xd7a3) /* Hangul Syllables */
|| (c >= 0xf900 && c <= 0xfaff) /* CJK Compatibility
Ideographs */
|| (c >= 0xfe30 && c <= 0xfe6f) /* CJK Compatibility Forms */
|| (c >= 0xff00 && c <= 0xff60) /* Fullwidth Forms */
|| (c >= 0xffe0 && c <= 0xffe6)
|| (c >= 0x20000 && c <= 0x2fffd)
|| (c >= 0x30000 && c <= 0x3fffd)))
return 2;
return 1;
}
inline unicode_val_T
utf_8_to_unicode(unsigned char **string, unsigned char *end)
{
unsigned char *str = *string;
unicode_val_T u;
int length;
length = utf8char_len_tab[str[0]];
if (str + length > end) {
return UCS_NO_CHAR;
}
switch (length) {
case 1:
u = str[0];
break;
case 2:
u = (str[0] & 0x1f) << 6;
u += (str[1] & 0x3f);
break;
case 3:
u = (str[0] & 0x0f) << 12;
u += ((str[1] & 0x3f) << 6);
u += (str[2] & 0x3f);
break;
case 4:
u = (str[0] & 0x0f) << 18;
u += ((str[1] & 0x3f) << 12);
u += ((str[2] & 0x3f) << 6);
u += (str[3] & 0x3f);
break;
case 5:
u = (str[0] & 0x0f) << 24;
u += ((str[1] & 0x3f) << 18);
u += ((str[2] & 0x3f) << 12);
u += ((str[3] & 0x3f) << 6);
u += (str[4] & 0x3f);
break;
case 6:
default:
u = (str[0] & 0x01) << 30;
u += ((str[1] & 0x3f) << 24);
u += ((str[2] & 0x3f) << 18);
u += ((str[3] & 0x3f) << 12);
u += ((str[4] & 0x3f) << 6);
u += (str[5] & 0x3f);
break;
}
*string = str + length;
return u;
}
#endif /* CONFIG_UTF_8 */
/* This slow and ugly code is used by the terminal utf_8_io */
unsigned char *
cp2utf_8(int from, int c)
@ -430,11 +693,18 @@ get_entity_string(const unsigned char *str, const int strlen, int encoding)
static struct entity_cache entity_cache[ENTITY_CACHE_MAXLEN][ENTITY_CACHE_SIZE];
static unsigned int nb_entity_cache[ENTITY_CACHE_MAXLEN];
static int first_time = 1;
unsigned int slen;
unsigned int slen = 0;
unsigned char *result = NULL;
if (strlen <= 0) return NULL;
#ifdef CONFIG_UTF_8
/* TODO: caching UTF-8 */
encoding &= ~SYSTEM_CHARSET_FLAG;
if (codepages[encoding].table == table_utf_8)
goto skip;
#endif /* CONFIG_UTF_8 */
if (first_time) {
memset(&nb_entity_cache, 0, ENTITY_CACHE_MAXLEN * sizeof(unsigned int));
first_time = 0;
@ -488,7 +758,9 @@ get_entity_string(const unsigned char *str, const int strlen, int encoding)
fprintf(stderr, "miss\n");
#endif
}
#ifdef CONFIG_UTF_8
skip:
#endif /* CONFIG_UTF_8 */
if (*str == '#') { /* Numeric entity. */
int l = (int) strlen;
unsigned char *st = (unsigned char *) str;
@ -540,6 +812,11 @@ get_entity_string(const unsigned char *str, const int strlen, int encoding)
if (element) result = u2cp(element->c, encoding);
}
#ifdef CONFIG_UTF_8
if (codepages[encoding].table == table_utf_8) {
return result;
}
#endif /* CONFIG_UTF_8 */
end:
/* Take care of potential buffer overflow. */
if (strlen < sizeof(entity_cache[slen][0].str)) {
@ -865,7 +1142,7 @@ get_cp_mime_name(int cp_index)
}
int
is_cp_special(int cp_index)
is_cp_utf8(int cp_index)
{
cp_index &= ~SYSTEM_CHARSET_FLAG;
return codepages[cp_index].table == table_utf_8;

View File

@ -51,8 +51,21 @@ unsigned char *convert_string(struct conv_table *convert_table,
int get_cp_index(unsigned char *);
unsigned char *get_cp_name(int);
unsigned char *get_cp_mime_name(int);
int is_cp_special(int);
int is_cp_utf8(int);
void free_conv_table(void);
#ifdef CONFIG_UTF_8
inline unsigned char *encode_utf_8(unicode_val_T);
inline unsigned char *utf8_prevchar(unsigned char *, int, unsigned char *);
inline int utf8charlen(const unsigned char *);
int utf8_char2cells(unsigned char *, unsigned char *);
int utf8_ptr2cells(unsigned char *, unsigned char *);
int utf8_ptr2chars(unsigned char *, unsigned char *);
int utf8_cells2bytes(unsigned char *, int, unsigned char *);
inline int unicode_to_cell(unicode_val_T);
inline int strlen_utf8(unsigned char **);
inline unicode_val_T utf_8_to_unicode(unsigned char **, unsigned char *);
#endif /* CONFIG_UTF_8 */
unsigned char *cp2utf_8(int, int);
unsigned char *u2cp_(unicode_val_T, int, int no_nbsp_hack);

View File

@ -118,6 +118,9 @@ get_dyn_full_version(struct terminal *term, int more)
#endif
#ifndef CONFIG_MOUSE
comma, _("No mouse", term),
#endif
#ifdef CONFIG_UTF_8
comma, "UTF-8",
#endif
comma,
NULL

View File

@ -574,7 +574,12 @@ bittorrent_message_dialog(struct session *ses, void *data)
uristring = get_uri_string(message->uri, URI_PUBLIC);
if (uristring) {
decode_uri_for_display(uristring);
#ifdef CONFIG_UTF_8
if (ses->tab->term->utf8)
decode_uri(uristring);
else
#endif /* CONFIG_UTF_8 */
decode_uri_for_display(uristring);
add_format_to_string(&string,
_("Unable to retrieve %s", ses->tab->term),
uristring);
@ -719,7 +724,12 @@ bittorrent_query_callback(void *data, enum connection_state state,
/* Let's make the filename pretty for display & save */
/* TODO: The filename can be the empty string here. See bug 396. */
decode_uri_string_for_display(&filename);
#ifdef CONFIG_UTF_8
if (term->utf8)
decode_uri_string(&filename);
else
#endif /* CONFIG_UTF_8 */
decode_uri_string_for_display(&filename);
}
add_format_to_string(&msg,

View File

@ -649,6 +649,10 @@ init_gopher_index_cache_entry(struct connection *conn)
return S_OUT_OF_MEM;
where = get_uri_string(conn->uri, URI_PUBLIC);
/* TODO: Use different function when using UTF-8
* in terminal (decode_uri_for_display replaces
* bytes of UTF-8 characters width '*'). */
if (where) decode_uri_for_display(where);
add_format_to_string(&buffer,

View File

@ -1134,7 +1134,12 @@ do_type_query(struct type_query *type_query, unsigned char *ct, struct mime_hand
/* Let's make the filename pretty for display & save */
/* TODO: The filename can be the empty string here. See bug 396. */
decode_uri_string_for_display(&filename);
#ifdef CONFIG_UTF_8
if (term->utf8)
decode_uri_string(&filename);
else
#endif /* CONFIG_UTF_8 */
decode_uri_string_for_display(&filename);
}
text = get_dialog_offset(dlg, TYPE_QUERY_WIDGETS_COUNT);

View File

@ -268,7 +268,12 @@ print_error_dialog(struct session *ses, enum connection_state state,
uristring = uri ? get_uri_string(uri, URI_PUBLIC) : NULL;
if (uristring) {
decode_uri_for_display(uristring);
#ifdef CONFIG_UTF_8
if (ses->tab->term->utf8)
decode_uri(uristring);
else
#endif /* CONFIG_UTF_8 */
decode_uri_for_display(uristring);
add_format_to_string(&msg,
_("Unable to retrieve %s", ses->tab->term),
uristring);

View File

@ -7,6 +7,7 @@
#include "elinks.h"
#include "config/options.h"
#include "intl/charsets.h"
#include "terminal/color.h"
#include "terminal/draw.h"
#include "terminal/screen.h"
@ -102,13 +103,30 @@ draw_char_color(struct terminal *term, int x, int y, struct color_pair *color)
}
void
#ifdef CONFIG_UTF_8
draw_char_data(struct terminal *term, int x, int y, unicode_val_T data)
#else
draw_char_data(struct terminal *term, int x, int y, unsigned char data)
#endif /* CONFIG_UTF_8 */
{
struct screen_char *screen_char = get_char(term, x, y);
if (!screen_char) return;
screen_char->data = data;
#ifdef CONFIG_UTF_8
#ifdef CONFIG_DEBUG
/* Detect attempt to draw double-width char on the last
* collumn of terminal. */
if (unicode_to_cell(data) == 2 && x + 1 > term->width)
INTERNAL("Attempt to draw double-width glyph on last collumn!");
#endif /* CONFIG_DEBUG */
if (data == UCS_NO_CHAR)
screen_char->attr = 0;
#endif /* CONFIG_UTF_8 */
set_screen_dirty(term->screen, y, y);
}
@ -127,7 +145,37 @@ draw_line(struct terminal *term, int x, int y, int l, struct screen_char *line)
size = int_min(l, term->width - x);
if (size == 0) return;
copy_screen_chars(screen_char, line, size);
#ifdef CONFIG_UTF_8
if (term->utf8) {
struct screen_char *sc;
if (line->data == UCS_NO_CHAR && x == 0) {
sc = line;
unicode_val_T data_save = sc->data;
sc->data = ' ';
copy_screen_chars(screen_char, line, 1);
sc->data = data_save;
size--;
line++;
screen_char++;
}
/* Instead of displaying double-width character at last collumn
* display only space. */
if (size - 1 > 0 && unicode_to_cell(line[size - 1].data) == 2) {
sc = &line[size - 1];
unicode_val_T data_save = sc->data;
sc->data = ' ';
copy_screen_chars(screen_char, line, size);
sc->data = data_save;
} else {
copy_screen_chars(screen_char, line, size);
}
} else
#endif
copy_screen_chars(screen_char, line, size);
set_screen_dirty(term->screen, y, y);
}
@ -198,10 +246,88 @@ draw_border(struct terminal *term, struct box *box,
set_screen_dirty(term->screen, borderbox.y, borderbox.y + borderbox.height);
}
#ifdef CONFIG_UTF_8
/* Checks cells left and right to the box for broken double-width chars.
* Replace it with ' '.
* 1+---+3
* 1|box|##4
* 1| |##4
* 1| |##4
* 1+---+##4
* 2#####4
* 1,2,3,4 - needs to be checked, # - shadow , +,-,| - border
*/
void
fix_dwchar_around_box(struct terminal *term, struct box *box, int border,
int shadow_width, int shadow_height)
{
struct screen_char *schar;
int height, x, y;
if (!term->utf8)
return;
/* 1 */
x = box->x - border - 1;
if (x > 0) {
y = box->y - border;
height = box->height + 2 * border;
schar = get_char(term, x, y);
for (;height--; schar += term->width)
if (unicode_to_cell(schar->data) == 2)
schar->data = ' ';
}
/* 2 */
x = box->x - border + shadow_width - 1;
if (x > 0 && x < term->width) {
y = box->y + border + box->height;
height = shadow_height;
schar = get_char(term, x, y);
for (;height--; schar += term->width)
if (unicode_to_cell(schar->data) == 2)
schar->data = ' ';
}
/* 3 */
x = box->x + box->width + border;
if (x < term->width) {
y = box->y - border;
height = shadow_height;
schar = get_char(term, x, y);
for (;height--; schar += term->width)
if (schar->data == UCS_NO_CHAR)
schar->data = ' ';
}
/* 4 */
x = box->x + box->width + border + shadow_width;
if (x < term->width) {
y = box->y - border + shadow_height;
height = box->height + 2 * border;
schar = get_char(term, x, y);
for (;height--; schar += term->width)
if (schar->data == UCS_NO_CHAR)
schar->data = ' ';
}
}
#endif
#ifdef CONFIG_UTF_8
void
draw_char(struct terminal *term, int x, int y,
unsigned char data, enum screen_char_attr attr,
unicode_val_T data, enum screen_char_attr attr,
struct color_pair *color)
#else
void
draw_char(struct terminal *term, int x, int y,
unsigned char data, enum screen_char_attr attr,
struct color_pair *color)
#endif /* CONFIG_UTF_8 */
{
struct screen_char *screen_char = get_char(term, x, y);
@ -277,6 +403,80 @@ draw_shadow(struct terminal *term, struct box *box,
draw_box(term, &dbox, ' ', 0, color);
}
#ifdef CONFIG_UTF_8
static void
draw_text_utf8(struct terminal *term, int x, int y,
unsigned char *text, int length,
enum screen_char_attr attr, struct color_pair *color)
{
struct screen_char *start, *pos;
unsigned char *end = text + length;
unicode_val_T data;
assert(text && length >= 0);
if_assert_failed return;
if (length <= 0) return;
if (x >= term->width) return;
data = utf_8_to_unicode(&text, end);
if (data == UCS_NO_CHAR) return;
start = get_char(term, x, y);
if (color) {
start->attr = attr;
set_term_color(start, color, 0,
get_opt_int_tree(term->spec, "colors"));
}
if (start->data == UCS_NO_CHAR && x - 1 > 0)
draw_char_data(term, x - 1, y, ' ');
pos = start;
if (unicode_to_cell(data) == 2) {
/* Is there enough room for whole double-width char? */
if (x + 1 < term->width) {
pos->data = data;
pos++;
x++;
pos->data = UCS_NO_CHAR;
pos->attr = 0;
} else {
pos->data = (unicode_val_T)' ';
}
} else {
pos->data = data;
}
pos++;
x++;
for (; x < term->width; x++, pos++) {
data = utf_8_to_unicode(&text, end);
if (data == UCS_NO_CHAR) break;
if (color) copy_screen_chars(pos, start, 1);
if (unicode_to_cell(data) == 2) {
/* Is there enough room for whole double-width char? */
if (x + 1 < term->width) {
pos->data = data;
x++;
pos++;
pos->data = UCS_NO_CHAR;
pos->attr = 0;
} else {
pos->data = (unicode_val_T)' ';
}
} else {
pos->data = data;
}
}
set_screen_dirty(term->screen, y, y);
}
#endif /* CONFIG_UTF_8 */
void
draw_text(struct terminal *term, int x, int y,
unsigned char *text, int length,
@ -288,6 +488,13 @@ draw_text(struct terminal *term, int x, int y,
assert(text && length >= 0);
if_assert_failed return;
#ifdef CONFIG_UTF_8
if (term->utf8) {
draw_text_utf8(term, x, y, text, length, attr, color);
return;
}
#endif /* CONFIG_UTF_8 */
if (length <= 0) return;
pos = get_char(term, x, y);
if (!pos) return;

View File

@ -1,6 +1,8 @@
#ifndef EL__TERMINAL_DRAW_H
#define EL__TERMINAL_DRAW_H
#include "intl/charsets.h" /* unicode_val_T */
struct color_pair;
struct box;
struct terminal;
@ -19,7 +21,11 @@ enum screen_char_attr {
/* One position in the terminal screen's image. */
struct screen_char {
/* Contains either character value or frame data. */
#ifdef CONFIG_UTF_8
unicode_val_T data;
#else
unsigned char data;
#endif /* CONFIG_UTF_8 */
/* Attributes are screen_char_attr bits. */
unsigned char attr;
@ -202,7 +208,11 @@ void draw_char_color(struct terminal *term, int x, int y,
struct color_pair *color);
/* Sets the data of a screen position. */
#ifdef CONFIG_UTF_8
void draw_char_data(struct terminal *term, int x, int y, unicode_val_T data);
#else
void draw_char_data(struct terminal *term, int x, int y, unsigned char data);
#endif /* CONFIG_UTF_8 */
/* Sets the data to @border and of a screen position. */
void draw_border_char(struct terminal *term, int x, int y,
@ -213,9 +223,15 @@ void draw_border_cross(struct terminal *, int x, int y,
enum border_cross_direction, struct color_pair *color);
/* Draws a char. */
#ifdef CONFIG_UTF_8
void draw_char(struct terminal *term, int x, int y,
unicode_val_T data, enum screen_char_attr attr,
struct color_pair *color);
#else
void draw_char(struct terminal *term, int x, int y,
unsigned char data, enum screen_char_attr attr,
struct color_pair *color);
#endif /* CONFIG_UTF_8 */
/* Draws area defined by @box using the same colors and attributes. */
void draw_box(struct terminal *term, struct box *box,
@ -230,6 +246,11 @@ void draw_shadow(struct terminal *term, struct box *box,
void draw_border(struct terminal *term, struct box *box,
struct color_pair *color, int width);
#ifdef CONFIG_UTF_8
void fix_dwchar_around_box(struct terminal *term, struct box *box, int border,
int shadow_width, int shadow_height);
#endif /* CONFIG_UTF_8 */
/* Draws @length chars from @text. */
void draw_text(struct terminal *term, int x, int y,
unsigned char *text, int length,

View File

@ -162,6 +162,12 @@ check_terminal_name(struct terminal *term, struct terminal_info *info)
object_unlock(term->spec);
term->spec = get_opt_rec(config_options, name);
object_lock(term->spec);
#ifdef CONFIG_UTF_8
/* Probably not best place for set this. But now we finally have
* term->spec and term->utf8 should be set before decode session info.
* --Scrool */
term->utf8 = get_opt_bool_tree(term->spec, "utf_8_io");
#endif /* CONFIG_UTF_8 */
}
#ifdef CONFIG_MOUSE
@ -245,7 +251,9 @@ handle_interlink_event(struct terminal *term, struct term_event *ev)
case EVENT_KBD:
{
#ifndef CONFIG_UTF_8
int utf8_io = -1;
#endif /* CONFIG_UTF_8 */
int key = get_kbd_key(ev);
reset_timer();
@ -260,9 +268,13 @@ handle_interlink_event(struct terminal *term, struct term_event *ev)
}
if (interlink->utf_8.len) {
#ifdef CONFIG_UTF_8
if ((key & 0xC0) == 0x80 && term->utf8)
#else
utf8_io = get_opt_bool_tree(term->spec, "utf_8_io");
if ((key & 0xC0) == 0x80 && utf8_io) {
if ((key & 0xC0) == 0x80 && utf8_io)
#endif /* CONFIG_UTF_8 */
{
interlink->utf_8.ucs <<= 6;
interlink->utf_8.ucs |= key & 0x3F;
if (! --interlink->utf_8.len) {
@ -280,11 +292,15 @@ handle_interlink_event(struct terminal *term, struct term_event *ev)
}
}
#ifdef CONFIG_UTF_8
if (key < 0x80 || key > 0xFF || !term->utf8)
#else
if (key < 0x80 || key > 0xFF
|| (utf8_io == -1
? !get_opt_bool_tree(term->spec, "utf_8_io")
: !utf8_io)) {
|| (utf8_io == -1
? !get_opt_bool_tree(term->spec, "utf_8_io")
: !utf8_io))
#endif /* CONFIG_UTF_8 */
{
term_send_event(term, ev);
break;

View File

@ -31,6 +31,7 @@
unsigned char frame_dumb[48] = " ||||++||++++++--|-+||++--|-+----++++++++ ";
static unsigned char frame_vt100[48] = "aaaxuuukkuxkjjjkmvwtqnttmlvwtqnvvwwmmllnnjla ";
#ifndef CONFIG_UTF_8
/* For UTF8 I/O */
static unsigned char frame_vt100_u[48] = {
177, 177, 177, 179, 180, 180, 180, 191,
@ -40,6 +41,7 @@ static unsigned char frame_vt100_u[48] = {
193, 194, 194, 192, 192, 218, 218, 197,
197, 217, 218, 177, 32, 32, 32, 32
};
#endif /* CONFIG_UTF_8 */
static unsigned char frame_freebsd[48] = {
130, 138, 128, 153, 150, 150, 150, 140,
@ -79,6 +81,13 @@ static struct string m11_hack_frame_seqs[] = {
/* begin border: */ TERM_STRING("\033[11m"),
};
#ifdef CONFIG_UTF_8
static struct string utf8_linux_frame_seqs[] = {
/* end border: */ TERM_STRING("\033[10m\033%G"),
/* begin border: */ TERM_STRING("\033%@\033[11m"),
};
#endif /* CONFIG_UTF_8 */
static struct string vt100_frame_seqs[] = {
/* end border: */ TERM_STRING("\x0f"),
/* begin border: */ TERM_STRING("\x0e"),
@ -100,10 +109,12 @@ struct screen_driver {
* uniquely identify the screen_driver. */
enum term_mode_type type;
#ifndef CONFIG_UTF_8
/* Charsets when doing UTF8 I/O. */
/* [0] is the common charset and [1] is the frame charset.
* Test wether to use UTF8 I/O using the use_utf8_io() macro. */
int charsets[2];
#endif /* CONFIG_UTF_8 */
/* The frame translation table. May be NULL. */
unsigned char *frame;
@ -120,6 +131,11 @@ struct screen_driver {
/* These are directly derived from the terminal options. */
unsigned int transparent:1;
#ifdef CONFIG_UTF_8
/* UTF-8 I/O */
unsigned int utf8:1;
#endif /* CONFIG_UTF_8 */
/* The terminal._template_ name. */
unsigned char name[1]; /* XXX: Keep last! */
};
@ -127,56 +143,81 @@ struct screen_driver {
static struct screen_driver dumb_screen_driver = {
NULL_LIST_HEAD,
/* type: */ TERM_DUMB,
#ifndef CONFIG_UTF_8
/* charsets: */ { -1, -1 }, /* No UTF8 I/O */
#endif /* CONFIG_UTF_8 */
/* frame: */ frame_dumb,
/* frame_seqs: */ NULL,
/* underline: */ underline_seqs,
/* color_mode: */ COLOR_MODE_16,
/* transparent: */ 1,
#ifdef CONFIG_UTF_8
/* utf-8: */ 0,
#endif /* CONFIG_UTF_8 */
};
static struct screen_driver vt100_screen_driver = {
NULL_LIST_HEAD,
/* type: */ TERM_VT100,
#ifndef CONFIG_UTF_8
/* charsets: */ { -1, -1 }, /* No UTF8 I/O */
#endif /* CONFIG_UTF_8 */
/* frame: */ frame_vt100,
/* frame_seqs: */ vt100_frame_seqs,
/* underline: */ underline_seqs,
/* color_mode: */ COLOR_MODE_16,
/* transparent: */ 1,
#ifdef CONFIG_UTF_8
/* utf-8: */ 0,
#endif /* CONFIG_UTF_8 */
};
static struct screen_driver linux_screen_driver = {
NULL_LIST_HEAD,
/* type: */ TERM_LINUX,
#ifndef CONFIG_UTF_8
/* charsets: */ { -1, -1 }, /* No UTF8 I/O */
#endif /* CONFIG_UTF_8 */
/* frame: */ NULL, /* No restrict_852 */
/* frame_seqs: */ NULL, /* No m11_hack */
/* underline: */ underline_seqs,
/* color_mode: */ COLOR_MODE_16,
/* transparent: */ 1,
#ifdef CONFIG_UTF_8
/* utf-8: */ 0,
#endif /* CONFIG_UTF_8 */
};
static struct screen_driver koi8_screen_driver = {
NULL_LIST_HEAD,
/* type: */ TERM_KOI8,
#ifndef CONFIG_UTF_8
/* charsets: */ { -1, -1 }, /* No UTF8 I/O */
#endif /* CONFIG_UTF_8 */
/* frame: */ frame_koi,
/* frame_seqs: */ NULL,
/* underline: */ underline_seqs,
/* color_mode: */ COLOR_MODE_16,
/* transparent: */ 1,
#ifdef CONFIG_UTF_8
/* utf-8: */ 0,
#endif /* CONFIG_UTF_8 */
};
static struct screen_driver freebsd_screen_driver = {
NULL_LIST_HEAD,
/* type: */ TERM_FREEBSD,
#ifndef CONFIG_UTF_8
/* charsets: */ { -1, -1 }, /* No UTF8 I/O */
#endif /* CONFIG_UTF_8 */
/* frame: */ frame_freebsd,
/* frame_seqs: */ NULL, /* No m11_hack */
/* underline: */ underline_seqs,
/* color_mode: */ COLOR_MODE_16,
/* transparent: */ 1,
#ifdef CONFIG_UTF_8
/* utf-8: */ 0,
#endif /* CONFIG_UTF_8 */
};
/* XXX: Keep in sync with enum term_mode_type. */
@ -188,13 +229,22 @@ static struct screen_driver *screen_drivers[] = {
/* TERM_FREEBSD: */ &freebsd_screen_driver,
};
#ifdef CONFIG_UTF_8
#define use_utf8_io(driver) ((driver)->utf8)
#else
#define use_utf8_io(driver) ((driver)->charsets[0] != -1)
#endif /* CONFIG_UTF_8 */
static INIT_LIST_HEAD(active_screen_drivers);
static void
update_screen_driver(struct screen_driver *driver, struct option *term_spec)
{
#ifdef CONFIG_UTF_8
driver->utf8 = get_opt_bool_tree(term_spec, "utf_8_io");
#else
int utf8_io = get_opt_bool_tree(term_spec, "utf_8_io");
#endif /* CONFIG_UTF_8 */
driver->color_mode = get_opt_int_tree(term_spec, "colors");
driver->transparent = get_opt_bool_tree(term_spec, "transparency");
@ -205,6 +255,25 @@ update_screen_driver(struct screen_driver *driver, struct option *term_spec)
driver->underline = NULL;
}
#ifdef CONFIG_UTF_8
if (driver->type == TERM_LINUX) {
if (get_opt_bool_tree(term_spec, "restrict_852"))
driver->frame = frame_restrict;
if (get_opt_bool_tree(term_spec, "m11_hack"))
driver->frame_seqs = m11_hack_frame_seqs;
if (driver->utf8)
driver->frame_seqs = utf8_linux_frame_seqs;
} else if (driver->type == TERM_FREEBSD) {
if (get_opt_bool_tree(term_spec, "m11_hack"))
driver->frame_seqs = m11_hack_frame_seqs;
} else if (driver->type == TERM_VT100) {
driver->frame = frame_vt100;
}
#else
if (utf8_io) {
driver->charsets[0] = get_opt_codepage_tree(term_spec, "charset");
if (driver->type == TERM_LINUX) {
@ -239,11 +308,11 @@ update_screen_driver(struct screen_driver *driver, struct option *term_spec)
} else if (driver->type == TERM_FREEBSD) {
if (get_opt_bool_tree(term_spec, "m11_hack"))
driver->frame_seqs = m11_hack_frame_seqs;
} else if (driver->type == TERM_VT100) {
driver->frame = frame_vt100;
}
}
}
#endif /* CONFIG_UTF_8 */
}
static int
@ -282,6 +351,10 @@ add_screen_driver(enum term_mode_type type, struct terminal *term, int env_len)
term->spec->change_hook = screen_driver_change_hook;
#ifdef CONFIG_UTF_8
term->utf8 = use_utf8_io(driver);
#endif /* CONFIG_UTF_8 */
return driver;
}
@ -300,6 +373,9 @@ get_screen_driver(struct terminal *term)
/* Some simple probably useless MRU ;) */
move_to_top_of_list(active_screen_drivers, driver);
#ifdef CONFIG_UTF_8
term->utf8 = use_utf8_io(driver);
#endif /* CONFIG_UTF_8 */
return driver;
}
@ -366,11 +442,15 @@ struct screen_state {
#define compare_bg_color(a, b) (TERM_COLOR_BACKGROUND(a) == TERM_COLOR_BACKGROUND(b))
#define compare_fg_color(a, b) (TERM_COLOR_FOREGROUND(a) == TERM_COLOR_FOREGROUND(b))
#define use_utf8_io(driver) ((driver)->charsets[0] != -1)
#ifdef CONFIG_UTF_8
static inline void
add_char_data(struct string *screen, struct screen_driver *driver,
unicode_val_T data, unsigned char border)
#else
static inline void
add_char_data(struct string *screen, struct screen_driver *driver,
unsigned char data, unsigned char border)
#endif /* CONFIG_UTF_8 */
{
if (!isscreensafe(data)) {
add_char_to_string(screen, ' ');
@ -381,13 +461,21 @@ add_char_data(struct string *screen, struct screen_driver *driver,
data = driver->frame[data - 176];
if (use_utf8_io(driver)) {
#ifdef CONFIG_UTF_8
if (border)
add_char_to_string(screen, (unsigned char)data);
else
if (data != UCS_NO_CHAR)
add_to_string(screen, encode_utf_8(data));
#else
int charset = driver->charsets[!!border];
add_to_string(screen, cp2utf_8(charset, data));
#endif /* CONFIG_UTF_8 */
return;
}
add_char_to_string(screen, data);
add_char_to_string(screen, (unsigned char)data);
}
/* Time critical section. */
@ -399,17 +487,32 @@ add_char16(struct string *screen, struct screen_driver *driver,
unsigned char underline = (ch->attr & SCREEN_ATTR_UNDERLINE);
unsigned char bold = (ch->attr & SCREEN_ATTR_BOLD);
if (border != state->border && driver->frame_seqs) {
if (
#ifdef CONFIG_UTF_8
(!use_utf8_io(driver) || ch->data != UCS_NO_CHAR) &&
#endif /* CONFIG_UTF_8 */
border != state->border && driver->frame_seqs
) {
state->border = border;
add_term_string(screen, driver->frame_seqs[!!border]);
}
if (underline != state->underline && driver->underline) {
if (
#ifdef CONFIG_UTF_8
(!use_utf8_io(driver) || ch->data != UCS_NO_CHAR) &&
#endif /* CONFIG_UTF_8 */
underline != state->underline && driver->underline
) {
state->underline = underline;
add_term_string(screen, driver->underline[!!underline]);
}
if (bold != state->bold) {
if (
#ifdef CONFIG_UTF_8
(!use_utf8_io(driver) || ch->data != UCS_NO_CHAR) &&
#endif /* CONFIG_UTF_8 */
bold != state->bold
) {
state->bold = bold;
if (bold) {
add_bytes_to_string(screen, "\033[1m", 4);
@ -419,7 +522,12 @@ add_char16(struct string *screen, struct screen_driver *driver,
}
}
if (!compare_color(ch->color, state->color)) {
if (
#ifdef CONFIG_UTF_8
(!use_utf8_io(driver) || ch->data != UCS_NO_CHAR) &&
#endif /* CONFIG_UTF_8 */
!compare_color(ch->color, state->color)
) {
copy_color(state->color, ch->color);
add_bytes_to_string(screen, "\033[0", 3);
@ -521,7 +629,12 @@ add_char256(struct string *screen, struct screen_driver *driver,
{
unsigned char attr_delta = (ch->attr ^ state->attr);
if (attr_delta) {
if (
#ifdef CONFIG_UTF_8
(!use_utf8_io(driver) || ch->data != UCS_NO_CHAR) &&
#endif /* CONFIG_UTF_8 */
attr_delta
) {
if ((attr_delta & SCREEN_ATTR_FRAME) && driver->frame_seqs) {
state->border = !!(ch->attr & SCREEN_ATTR_FRAME);
add_term_string(screen, driver->frame_seqs[state->border]);
@ -544,7 +657,12 @@ add_char256(struct string *screen, struct screen_driver *driver,
state->attr = ch->attr;
}
if (!compare_color(ch->color, state->color)) {
if (
#ifdef CONFIG_UTF_8
(!use_utf8_io(driver) || ch->data != UCS_NO_CHAR) &&
#endif /* CONFIG_UTF_8 */
!compare_color(ch->color, state->color)
) {
copy_color(state->color, ch->color);
add_foreground_color(screen, color256_seqs, ch);

View File

@ -126,6 +126,11 @@ struct terminal {
* work and even maintaining these structures ;-). */
unsigned int master:1;
#ifdef CONFIG_UTF_8
/* Indicates whether UTF-8 I/O is used */
unsigned int utf8:1;
#endif /* CONFIG_UTF_8 */
/* The current tab number. */
int current_tab;

View File

@ -26,6 +26,7 @@
#include "document/options.h"
#include "document/renderer.h"
#include "document/view.h"
#include "intl/charsets.h"
#include "intl/gettext/libintl.h"
#include "main/select.h"
#include "main/main.h"
@ -346,6 +347,11 @@ add_document_to_string(struct string *string, struct document *document)
assert(string && document);
if_assert_failed return NULL;
#ifdef CONFIG_UTF_8
if (is_cp_utf8(document->options.cp))
goto utf_8;
#endif /* CONFIG_UTF_8 */
for (y = 0; y < document->height; y++) {
int white = 0;
int x;
@ -378,7 +384,45 @@ add_document_to_string(struct string *string, struct document *document)
add_char_to_string(string, '\n');
}
#ifdef CONFIG_UTF_8
goto end;
utf_8:
for (y = 0; y < document->height; y++) {
struct screen_char *pos = document->data[y].chars;
int white = 0;
int x;
for (x = 0; x < document->data[y].length; x++) {
unicode_val_T data = pos->data;
unsigned int frame = (pos->attr & SCREEN_ATTR_FRAME);
if (!isscreensafe(data)) {
white++;
continue;
} else if (frame && data >= 176 && data < 224) {
data = frame_dumb[data - 176];
if (data <= ' ') {
/* Count spaces. */
white++;
} else {
/* Print spaces if any. */
if (white) {
add_xchar_to_string(string, ' ', white);
white = 0;
}
if (frame)
add_char_to_string(string, data);
else
add_to_string(string, encode_utf_8(data));
}
}
}
add_char_to_string(string, '\n');
}
end:
#endif /* CONFIG_UTF_8 */
return string;
}
@ -666,6 +710,11 @@ dump_to_file(struct document *document, int fd)
if (!buf) return -1;
#ifdef CONFIG_UTF_8
if (is_cp_utf8(document->options.cp))
goto utf_8;
#endif /* CONFIG_UTF_8 */
for (y = 0; y < document->height; y++) {
int white = 0;
int x;
@ -702,13 +751,64 @@ dump_to_file(struct document *document, int fd)
if (write_char('\n', fd, buf, &bptr))
goto fail;
}
#ifdef CONFIG_UTF_8
goto ref;
utf_8:
for (y = 0; y < document->height; y++) {
int white = 0;
int x;
for (x = 0; x < document->data[y].length; x++) {
unicode_val_T c;
unsigned char attr = document->data[y].chars[x].attr;
c = document->data[y].chars[x].data;
if ((attr & SCREEN_ATTR_FRAME)
&& c >= 176 && c < 224)
c = frame_dumb[c - 176];
else {
unsigned char *utf8_buf = encode_utf_8(c);
while (*utf8_buf) {
if (write_char(*utf8_buf++,
fd, buf, &bptr)) goto fail;
}
continue;
}
if (c <= ' ') {
/* Count spaces. */
white++;
continue;
}
/* Print spaces if any. */
while (white) {
if (write_char(' ', fd, buf, &bptr))
goto fail;
white--;
}
/* Print normal char. */
if (write_char(c, fd, buf, &bptr))
goto fail;
}
/* Print end of line. */
if (write_char('\n', fd, buf, &bptr))
goto fail;
}
#endif /* CONFIG_UTF_8 */
if (hard_write(fd, buf, bptr) != bptr) {
fail:
mem_free(buf);
return -1;
}
#ifdef CONFIG_UTF_8
ref:
#endif /* CONFIG_UTF_8 */
if (document->nlinks && get_opt_bool("document.dump.references")) {
int x;
unsigned char *header = "\nReferences\n\n Visible links\n";

View File

@ -163,11 +163,22 @@ init_form_state(struct form_control *fc, struct form_state *fs)
case FC_TEXTAREA:
fs->value = stracpy(fc->default_value);
fs->state = strlen(fc->default_value);
#ifdef CONFIG_UTF_8
if (fc->type == FC_TEXT)
fs->state_cell = utf8_ptr2cells(fs->value, NULL);
if (fc->type == FC_PASSWORD)
fs->state_cell = utf8_ptr2chars(fs->value, NULL);
if (fc->type == FC_TEXTAREA)
fs->state_cell = 0;
#endif /* CONFIG_UTF_8 */
fs->vpos = 0;
break;
case FC_FILE:
fs->value = stracpy("");
fs->state = 0;
#ifdef CONFIG_UTF_8
fs->state_cell = 0;
#endif /* CONFIG_UTF_8 */
fs->vpos = 0;
break;
case FC_SELECT:
@ -330,21 +341,27 @@ draw_form_entry(struct terminal *term, struct document_view *doc_view,
dy = box->y - vs->y;
switch (fc->type) {
unsigned char *s;
#ifdef CONFIG_UTF_8
unsigned char *text, *end;
#endif /* CONFIG_UTF_8 */
int len;
int i, x, y;
case FC_TEXT:
case FC_PASSWORD:
case FC_FILE:
int_bounds(&fs->vpos, fs->state - fc->size + 1, fs->state);
if (!link->npoints) break;
y = link->points[0].y + dy;
if (!row_is_in_box(box, y))
break;
len = strlen(fs->value) - fs->vpos;
x = link->points[0].x + dx;
#ifdef CONFIG_UTF_8
if (term->utf8) goto utf_8;
#endif /* CONFIG_UTF_8 */
int_bounds(&fs->vpos, fs->state - fc->size + 1, fs->state);
len = strlen(fs->value) - fs->vpos;
for (i = 0; i < fc->size; i++, x++) {
unsigned char data;
@ -360,6 +377,43 @@ draw_form_entry(struct terminal *term, struct document_view *doc_view,
draw_char_data(term, x, y, data);
}
break;
#ifdef CONFIG_UTF_8
utf_8:
end = NULL; /* Shut up the compiler. */
int_bounds(&fs->vpos, fs->state_cell - fc->size + 1, fs->state_cell);
if (fc->type == FC_PASSWORD)
len = utf8_ptr2chars(fs->value + fs->vpos, NULL);
else
len = utf8_ptr2cells(fs->value + fs->vpos, NULL);
text = fs->value;
end = strchr(text, '\0');
for (i = 0; i < fc->size; i++, x++) {
unicode_val_T data;
if (!col_is_in_box(box, x)) continue;
if (fs->value && i >= -fs->vpos && i < len) {
if (fc->type != FC_PASSWORD)
data = utf_8_to_unicode(&text, end);
else
data = '*';
} else
data = '_';
if (unicode_to_cell(data) == 2) {
if (i + 1 < fc->size) {
draw_char_data(term, x++, y, data);
data = UCS_NO_CHAR;
i++;
} else
data = ' ';
}
draw_char_data(term, x, y, data);
}
break;
#endif /* CONFIG_UTF_8 */
case FC_TEXTAREA:
draw_textarea(term, fs, doc_view, link);
break;
@ -378,6 +432,9 @@ draw_form_entry(struct terminal *term, struct document_view *doc_view,
else
/* XXX: when can this happen? --pasky */
s = "";
#ifdef CONFIG_UTF_8
if (term->utf8) goto utf_8_select;
#endif /* CONFIG_UTF_8 */
len = s ? strlen(s) : 0;
for (i = 0; i < link->npoints; i++) {
x = link->points[i].x + dx;
@ -386,6 +443,36 @@ draw_form_entry(struct terminal *term, struct document_view *doc_view,
draw_char_data(term, x, y, i < len ? s[i] : '_');
}
break;
#ifdef CONFIG_UTF_8
utf_8_select:
text = s;
end = strchr(s, '\0');
len = utf8_ptr2cells(text, end);
for (i = 0; i < link->npoints; i++) {
x = link->points[i].x + dx;
y = link->points[i].y + dy;
if (is_in_box(box, x, y)) {
unicode_val_T data;
if (i < len) {
int cell;
data = utf_8_to_unicode(&s, end);
cell = unicode_to_cell(data);
if (i + 1 < len && cell == 2) {
draw_char_data(term, x++, y, data);
data = UCS_NO_CHAR;
i++;
} else if (cell == 2) {
data = ' ';
}
} else
data = '_';
draw_char_data(term, x, y, data);
}
}
break;
#endif /* CONFIG_UTF_8 */
case FC_SUBMIT:
case FC_IMAGE:
case FC_RESET:
@ -1195,6 +1282,9 @@ field_op(struct session *ses, struct document_view *doc_view,
unsigned char *text;
int length;
enum frame_event_status status = FRAME_EVENT_REFRESH;
#ifdef CONFIG_UTF_8
int utf8 = ses->tab->term->utf8;
#endif /* CONFIG_UTF_8 */
assert(ses && doc_view && link && ev);
if_assert_failed return FRAME_EVENT_OK;
@ -1214,49 +1304,136 @@ field_op(struct session *ses, struct document_view *doc_view,
switch (action_id) {
case ACT_EDIT_LEFT:
fs->state = int_max(fs->state - 1, 0);
#ifdef CONFIG_UTF_8
if (fc->type == FC_TEXTAREA) {
status = textarea_op_left(fs, fc, utf8);
break;
}
if (utf8) {
int old_state = fs->state;
unsigned char *new_value;
new_value = utf8_prevchar(fs->value + fs->state, 1, fs->value);
fs->state = new_value - fs->value;
if (old_state != fs->state) {
if (fc->type == FC_PASSWORD)
fs->state_cell = int_max(fs->state_cell - 1, 0);
else
fs->state_cell = int_max(utf8_char2cells(new_value, NULL) - 1, 0);
}
} else
#endif /* CONFIG_UTF_8 */
fs->state = int_max(fs->state - 1, 0);
break;
case ACT_EDIT_RIGHT:
fs->state = int_min(fs->state + 1, strlen(fs->value));
#ifdef CONFIG_UTF_8
if (utf8) {
unsigned char *text = fs->value + fs->state;
unsigned char *end = strchr(text, '\0');
int old_state = fs->state;
unicode_val_T data = utf_8_to_unicode(&text, end);
fs->state = (int)(text - fs->value);
if (old_state != fs->state) {
if (fc->type == FC_PASSWORD)
fs->state_cell = int_min(fs->state_cell + 1,
utf8_ptr2cells(fs->value, NULL));
else
fs->state_cell += unicode_to_cell(data);
}
} else
#endif /* CONFIG_UTF_8 */
fs->state = int_min(fs->state + 1, strlen(fs->value));
break;
case ACT_EDIT_HOME:
#ifdef CONFIG_UTF_8
if (fc->type == FC_TEXTAREA) {
status = textarea_op_home(fs, fc, utf8);
} else {
fs->state = 0;
fs->state_cell = 0;
}
#else
if (fc->type == FC_TEXTAREA) {
status = textarea_op_home(fs, fc);
} else {
fs->state = 0;
}
#endif /* CONFIG_UTF_8 */
break;
case ACT_EDIT_UP:
if (fc->type != FC_TEXTAREA)
status = FRAME_EVENT_IGNORED;
else
#ifdef CONFIG_UTF_8
status = textarea_op_up(fs, fc, utf8);
#else
status = textarea_op_up(fs, fc);
#endif /* CONFIG_UTF_8 */
break;
case ACT_EDIT_DOWN:
if (fc->type != FC_TEXTAREA)
status = FRAME_EVENT_IGNORED;
else
#ifdef CONFIG_UTF_8
status = textarea_op_down(fs, fc, utf8);
#else
status = textarea_op_down(fs, fc);
#endif /* CONFIG_UTF_8 */
break;
case ACT_EDIT_END:
if (fc->type == FC_TEXTAREA) {
#ifdef CONFIG_UTF_8
status = textarea_op_end(fs, fc, utf8);
#else
status = textarea_op_end(fs, fc);
#endif /* CONFIG_UTF_8 */
} else {
fs->state = strlen(fs->value);
#ifdef CONFIG_UTF_8
if (utf8 && fc->type != FC_PASSWORD)
fs->state_cell = utf8_ptr2cells(fs->value,
fs->value + fs->state);
else if(utf8)
fs->state_cell = utf8_ptr2chars(fs->value,
fs->value + fs->state);
#endif /* CONFIG_UTF_8 */
}
break;
case ACT_EDIT_BEGINNING_OF_BUFFER:
if (fc->type == FC_TEXTAREA) {
#ifdef CONFIG_UTF_8
status = textarea_op_bob(fs, fc, utf8);
#else
status = textarea_op_bob(fs, fc);
#endif /* CONFIG_UTF_8 */
} else {
fs->state = 0;
}
#ifdef CONFIG_UTF_8
fs->state_cell = 0;
#endif /* CONFIG_UTF_8 */
break;
case ACT_EDIT_END_OF_BUFFER:
if (fc->type == FC_TEXTAREA) {
#ifdef CONFIG_UTF_8
status = textarea_op_eob(fs, fc, utf8);
#else
status = textarea_op_eob(fs, fc);
#endif /* CONFIG_UTF_8 */
} else {
fs->state = strlen(fs->value);
#ifdef CONFIG_UTF_8
if (utf8 && fc->type != FC_PASSWORD)
fs->state_cell = utf8_ptr2cells(fs->value,
fs->value + fs->state);
else if(utf8)
fs->state_cell = utf8_ptr2chars(fs->value,
fs->value + fs->state);
#endif /* CONFIG_UTF_8 */
}
break;
case ACT_EDIT_OPEN_EXTERNAL:
@ -1274,6 +1451,9 @@ field_op(struct session *ses, struct document_view *doc_view,
if (!form_field_is_readonly(fc))
fs->value[0] = 0;
fs->state = 0;
#ifdef CONFIG_UTF_8
fs->state_cell = 0;
#endif /* CONFIG_UTF_8 */
break;
case ACT_EDIT_PASTE_CLIPBOARD:
if (form_field_is_readonly(fc)) break;
@ -1289,13 +1469,27 @@ field_op(struct session *ses, struct document_view *doc_view,
fs->value = v;
memmove(v, text, length + 1);
fs->state = strlen(fs->value);
#ifdef CONFIG_UTF_8
if(utf8 && fc->type == FC_PASSWORD)
fs->state_cell = utf8_ptr2chars(fs->value,
fs->value + fs->state);
else if (utf8 && fc->type == FC_TEXTAREA)
fs->state_cell = 0;
else if (utf8)
fs->state_cell = utf8_ptr2cells(fs->value,
fs->value + fs->state);
#endif /* CONFIG_UTF_8 */
}
}
mem_free(text);
break;
case ACT_EDIT_ENTER:
if (fc->type == FC_TEXTAREA) {
#ifdef CONFIG_UTF_8
status = textarea_op_enter(fs, fc, utf8);
#else
status = textarea_op_enter(fs, fc);
#endif /* CONFIG_UTF_8 */
break;
}
@ -1320,12 +1514,33 @@ field_op(struct session *ses, struct document_view *doc_view,
status = FRAME_EVENT_OK;
break;
}
#ifdef CONFIG_UTF_8
if (utf8) {
int old_state = fs->state;
unsigned char *new_value;
new_value = utf8_prevchar(fs->value + fs->state, 1, fs->value);
fs->state = new_value - fs->value;
length = strlen(fs->value + fs->state) + 1;
text = fs->value + fs->state;
if (old_state != fs->state) {
if (fc->type == FC_TEXTAREA)
fs->state_cell = 0;
else if (fc->type == FC_PASSWORD)
fs->state_cell = int_max(fs->state_cell - 1, 0);
else
fs->state_cell -= utf8_char2cells(new_value, NULL);
length = strlen(fs->value + old_state) + 1;
memmove(new_value, fs->value + old_state, length);
}
} else
#endif /* CONFIG_UTF_8 */
{
length = strlen(fs->value + fs->state) + 1;
text = fs->value + fs->state;
memmove(text - 1, text, length);
fs->state--;
memmove(text - 1, text, length);
fs->state--;
}
break;
case ACT_EDIT_DELETE:
if (form_field_is_readonly(fc)) {
@ -1338,7 +1553,20 @@ field_op(struct session *ses, struct document_view *doc_view,
status = FRAME_EVENT_OK;
break;
}
#ifdef CONFIG_UTF_8
if (utf8) {
unsigned char *end = fs->value + length;
unsigned char *text = fs->value + fs->state;
unsigned char *old = text;
utf_8_to_unicode(&text, end);
if (old != text) {
memmove(old, text,
(int)(end - text) + 1);
}
break;
}
#endif /* CONFIG_UTF_8 */
text = fs->value + fs->state;
memmove(text, text + 1, length - fs->state);
@ -1368,6 +1596,18 @@ field_op(struct session *ses, struct document_view *doc_view,
memmove(text, fs->value + fs->state, length);
fs->state = (int) (text - fs->value);
#ifdef CONFIG_UTF_8
if (utf8) {
if(fc->type == FC_PASSWORD)
fs->state_cell = utf8_ptr2cells(fs->value,
fs->value + fs->state);
else if (fc->type == FC_TEXTAREA)
fs->state_cell = 0;
else
fs->state_cell = utf8_ptr2cells(fs->value,
fs->value + fs->state);
}
#endif /* CONFIG_UTF_8 */
break;
case ACT_EDIT_KILL_TO_EOL:
if (form_field_is_readonly(fc)) {
@ -1466,13 +1706,55 @@ field_op(struct session *ses, struct document_view *doc_view,
}
if (form_field_is_readonly(fc)
|| strlen(fs->value) >= fc->maxlength
|| !insert_in_string(&fs->value, fs->state, "?", 1)) {
|| strlen(fs->value) >= fc->maxlength
#ifndef CONFIG_UTF_8
|| !insert_in_string(&fs->value, fs->state, "?", 1)
#endif /* CONFIG_UTF_8 */
)
{
status = FRAME_EVENT_OK;
break;
}
#ifdef CONFIG_UTF_8
if (utf8) {
static unsigned char buf[7];
static int i = 0;
unicode_val_T data;
unsigned char *t;
t = buf;
buf[i++] = get_kbd_key(ev);
buf[i] = 0;
data = utf_8_to_unicode(&t, buf + i);
if (data != UCS_NO_CHAR) {
if (!insert_in_string(&fs->value, fs->state, buf, i)) {
i = 0;
return FRAME_EVENT_OK;
}
fs->state += i;
if (fc->type == FC_PASSWORD)
fs->state_cell++;
else if (fc->type == FC_TEXTAREA)
fs->state_cell = 0;
else
fs->state_cell += unicode_to_cell(data);
i = 0;
break;
}
if (i == 6) {
i = 0;
}
return FRAME_EVENT_OK;
} else {
if (!insert_in_string(&fs->value, fs->state, "?", 1))
return FRAME_EVENT_OK;
fs->value[fs->state++] = get_kbd_key(ev);
}
#else
fs->value[fs->state++] = get_kbd_key(ev);
#endif /* CONFIG_UTF_8 */
break;
}

View File

@ -39,6 +39,9 @@ struct form_state {
unsigned char *value;
int state;
#ifdef CONFIG_UTF_8
int state_cell;
#endif /* CONFIG_UTF_8 */
int vpos;
int vypos;

View File

@ -114,6 +114,9 @@ get_link_cursor_offset(struct document_view *doc_view, struct link *link)
{
struct form_control *fc;
struct form_state *fs;
#ifdef CONFIG_UTF_8
int utf8 = doc_view->document->options.utf8;
#endif /* CONFIG_UTF_8 */
switch (link->type) {
case LINK_CHECKBOX:
@ -125,12 +128,21 @@ get_link_cursor_offset(struct document_view *doc_view, struct link *link)
case LINK_FIELD:
fc = get_link_form_control(link);
fs = find_form_state(doc_view, fc);
return fs ? fs->state - fs->vpos : 0;
#ifdef CONFIG_UTF_8
if (utf8) {
return fs ? fs->state_cell - fs->vpos : 0;
} else
#endif /* CONFIG_UTF_8 */
return fs ? fs->state - fs->vpos : 0;
case LINK_AREA:
fc = get_link_form_control(link);
fs = find_form_state(doc_view, fc);
#ifdef CONFIG_UTF_8
return fs ? area_cursor(fc, fs, utf8) : 0;
#else
return fs ? area_cursor(fc, fs) : 0;
#endif /* CONFIG_UTF_8 */
case LINK_HYPERTEXT:
case LINK_MAP:
@ -1342,7 +1354,7 @@ end:
do_menu(term, mi, ses, 1);
}
/* Return current link's title. Pretty trivial. */
/* Return current link's title. */
unsigned char *
get_current_link_title(struct document_view *doc_view)
{
@ -1356,7 +1368,29 @@ get_current_link_title(struct document_view *doc_view)
link = get_current_link(doc_view);
return (link && link->title && *link->title) ? stracpy(link->title) : NULL;
if (link && link->title && *link->title) {
unsigned char *link_title, *src;
struct conv_table *convert_table;
convert_table = get_translation_table(doc_view->document->cp,
doc_view->document->options.cp);
link_title = convert_string(convert_table, link->title,
strlen(link->title),
doc_view->document->options.cp,
CSM_DEFAULT, NULL, NULL, NULL);
/* Remove illicit chars. */
#ifdef CONFIG_UTF_8
if (link_title && !doc_view->document->options.utf8)
#endif /* CONFIG_UTF_8 */
for (src = link_title; *src; src++)
if (!isprint(*src) || iscntrl(*src))
*src = '*';
return link_title;
}
return NULL;
}
unsigned char *
@ -1401,7 +1435,12 @@ get_current_link_info(struct session *ses, struct document_view *doc_view)
add_char_to_string(&str, ')');
}
decode_uri_string_for_display(&str);
#ifdef CONFIG_UTF_8
if (term->utf8)
decode_uri_string(&str);
else
#endif /* CONFIG_UTF_8 */
decode_uri_string_for_display(&str);
return str.source;
}

View File

@ -11,6 +11,7 @@ struct session;
struct term_event;
struct terminal;
struct uri;
struct conv_table;
void set_link(struct document_view *doc_view);
void clear_link(struct terminal *term, struct document_view *doc_view);

View File

@ -9,6 +9,11 @@
#endif
#include <ctype.h> /* tolower(), isprint() */
#if defined(CONFIG_UTF_8) && defined(HAVE_WCTYPE_H)
#include <wctype.h>
#endif
#include <sys/types.h> /* FreeBSD needs this before regex.h */
#ifdef HAVE_REGEX_H
#include <regex.h>
@ -22,6 +27,7 @@
#include "config/kbdbind.h"
#include "document/document.h"
#include "document/view.h"
#include "intl/charsets.h"
#include "intl/gettext/libintl.h"
#include "main/event.h"
#include "main/module.h"
@ -44,9 +50,15 @@
static INIT_INPUT_HISTORY(search_history);
#undef UCHAR
#ifdef CONFIG_UTF_8
#define UCHAR unicode_val_T
#else
#define UCHAR unsigned char
#endif
static inline void
add_srch_chr(struct document *document, unsigned char c, int x, int y, int nn)
add_srch_chr(struct document *document, UCHAR c, int x, int y, int nn)
{
assert(document);
if_assert_failed return;
@ -146,7 +158,7 @@ get_srch(struct document *document)
x++);
for (; x < width; x++) {
unsigned char c = document->data[y].chars[x].data;
UCHAR c = document->data[y].chars[x].data;
int count = 0;
int xx;
@ -441,18 +453,58 @@ is_in_range_regex(struct document *document, int y, int height,
}
#endif /* HAVE_REGEX_H */
/* Returns an allocated string which is a lowered copy of passed one. */
static unsigned char *
lowered_string(unsigned char *text, int textlen)
static UCHAR *
memacpy_u(unsigned char *text, int textlen, int utf8)
{
unsigned char *ret;
#ifdef CONFIG_UTF_8
UCHAR *mem = mem_alloc((textlen + 1) * sizeof(UCHAR));
if (textlen < 0) textlen = strlen(text);
if (!mem) return NULL;
if (utf8) {
int i;
ret = mem_calloc(1, textlen + 1);
for (i = 0; i < textlen; i++)
mem[i] = utf_8_to_unicode(&text, text + 7);
} else {
int i;
for (i = 0; i < textlen; i++)
mem[i] = text[i];
}
mem[textlen] = 0;
return mem;
#else
return memacpy(text, textlen);
#endif
}
static int
strlen_u(unsigned char *text, int utf8)
{
#ifdef CONFIG_UTF_8
if (utf8)
return strlen_utf8(&text);
#endif
return strlen(text);
}
/* Returns an allocated string which is a lowered copy of passed one. */
static UCHAR *
lowered_string(unsigned char *text, int textlen, int utf8)
{
UCHAR *ret;
if (textlen < 0) textlen = strlen_u(text, utf8);
ret = memacpy_u(text, textlen, utf8);
if (ret && textlen) {
do {
ret[textlen] = tolower(text[textlen]);
#if defined(CONFIG_UTF_8) && defined(HAVE_WCTYPE_H)
ret[textlen] = utf8 ? towlower(ret[textlen]) : tolower(ret[textlen]);
#else
ret[textlen] = tolower(ret[textlen]);
#endif
} while (textlen--);
}
@ -463,14 +515,14 @@ static int
is_in_range_plain(struct document *document, int y, int height,
unsigned char *text, int textlen,
int *min, int *max,
struct search *s1, struct search *s2)
struct search *s1, struct search *s2, int utf8)
{
int yy = y + height;
unsigned char *txt;
UCHAR *txt;
int found = 0;
int case_sensitive = get_opt_bool("document.browse.search.case");
txt = case_sensitive ? stracpy(text) : lowered_string(text, textlen);
txt = case_sensitive ? memacpy_u(text, textlen, utf8) : lowered_string(text, textlen, utf8);
if (!txt) return -1;
/* TODO: This is a great candidate for nice optimizations. Fresh CS
@ -478,9 +530,11 @@ is_in_range_plain(struct document *document, int y, int height,
* trivial, probably a starter; very fast as well) or Turbo-BM (or
* maybe some other Boyer-Moore variant, I don't feel that strong in
* this area), hmm? >:) --pasky */
#if defined(CONFIG_UTF_8) && defined(HAVE_WCTYPE_H)
#define maybe_tolower(c) (case_sensitive ? (c) : utf8 ? towlower(c) : tolower(c))
#else
#define maybe_tolower(c) (case_sensitive ? (c) : tolower(c))
#endif
for (; s1 <= s2; s1++) {
int i;
@ -513,18 +567,23 @@ srch_failed:
return found;
}
static int
is_in_range(struct document *document, int y, int height,
unsigned char *text, int *min, int *max)
{
struct search *s1, *s2;
int textlen;
int utf8 = 0;
assert(document && text && min && max);
if_assert_failed return -1;
#ifdef CONFIG_UTF_8
utf8 = document->options.utf8;
#endif
*min = INT_MAX, *max = 0;
textlen = strlen(text);
textlen = strlen_u(text, utf8);
if (get_range(document, y, height, textlen, &s1, &s2))
return 0;
@ -535,7 +594,7 @@ is_in_range(struct document *document, int y, int height,
min, max, s1, s2);
#endif
return is_in_range_plain(document, y, height, text, textlen,
min, max, s1, s2);
min, max, s1, s2, utf8);
}
#define realloc_points(pts, size) \
@ -543,24 +602,28 @@ is_in_range(struct document *document, int y, int height,
static void
get_searched_plain(struct document_view *doc_view, struct point **pt, int *pl,
int l, struct search *s1, struct search *s2)
int l, struct search *s1, struct search *s2, int utf8)
{
unsigned char *txt;
UCHAR *txt;
struct point *points = NULL;
struct box *box;
int xoffset, yoffset;
int len = 0;
int case_sensitive = get_opt_bool("document.browse.search.case");
txt = case_sensitive ? stracpy(*doc_view->search_word)
: lowered_string(*doc_view->search_word, l);
txt = case_sensitive ? memacpy_u(*doc_view->search_word, l, utf8)
: lowered_string(*doc_view->search_word, l, utf8);
if (!txt) return;
box = &doc_view->box;
xoffset = box->x - doc_view->vs->x;
yoffset = box->y - doc_view->vs->y;
#if defined(CONFIG_UTF_8) && defined(HAVE_WCTYPE_H)
#define maybe_tolower(c) (case_sensitive ? (c) : utf8 ? towlower(c) : tolower(c))
#else
#define maybe_tolower(c) (case_sensitive ? (c) : tolower(c))
#endif
for (; s1 <= s2; s1++) {
int i;
@ -671,7 +734,7 @@ get_searched_regex(struct document_view *doc_view, struct point **pt, int *pl,
#endif /* HAVE_REGEX_H */
static void
get_searched(struct document_view *doc_view, struct point **pt, int *pl)
get_searched(struct document_view *doc_view, struct point **pt, int *pl, int utf8)
{
struct search *s1, *s2;
int l;
@ -683,7 +746,7 @@ get_searched(struct document_view *doc_view, struct point **pt, int *pl)
return;
get_search_data(doc_view->document);
l = strlen(*doc_view->search_word);
l = strlen_u(*doc_view->search_word, utf8);
if (get_range(doc_view->document, doc_view->vs->y,
doc_view->box.height, l, &s1, &s2)) {
*pt = NULL;
@ -697,7 +760,7 @@ get_searched(struct document_view *doc_view, struct point **pt, int *pl)
get_searched_regex(doc_view, pt, pl, l, s1, s2);
else
#endif
get_searched_plain(doc_view, pt, pl, l, s1, s2);
get_searched_plain(doc_view, pt, pl, l, s1, s2, utf8);
}
/* Highlighting of searched strings. */
@ -706,6 +769,7 @@ draw_searched(struct terminal *term, struct document_view *doc_view)
{
struct point *pt = NULL;
int len = 0;
int utf8 = 0;
assert(term && doc_view);
if_assert_failed return;
@ -713,7 +777,10 @@ draw_searched(struct terminal *term, struct document_view *doc_view)
if (!has_search_word(doc_view))
return;
get_searched(doc_view, &pt, &len);
#ifdef CONFIG_UTF_8
utf8 = doc_view->document->options.utf8;
#endif
get_searched(doc_view, &pt, &len, utf8);
if (len) {
int i;
struct color_pair *color = get_bfu_color(term, "searched");
@ -876,10 +943,14 @@ find_next_link_in_search(struct document_view *doc_view, int direction)
struct point *pt = NULL;
struct link *link;
int len;
int utf8 = 0;
#ifdef CONFIG_UTF_8
utf8 = doc_view->document->options.utf8;
#endif
nt:
link = &doc_view->document->links[doc_view->vs->current_link];
get_searched(doc_view, &pt, &len);
get_searched(doc_view, &pt, &len, utf8);
if (point_intersect(pt, len, link->points, link->npoints)) {
mem_free(pt);
return 0;
@ -1174,7 +1245,7 @@ fixup_typeahead_match(struct session *ses, struct document_view *doc_view)
doc_view->box.height += 1;
}
static inline unsigned char
static inline UCHAR
get_document_char(struct document *document, int x, int y)
{
return (document->height > y && document->data[y].length > x)
@ -1196,7 +1267,7 @@ draw_typeahead_match(struct terminal *term, struct document_view *doc_view,
for (i = 0, j = 0; text[j] && i < end; i++, j++) {
int x = link->points[i].x;
int y = link->points[i].y;
unsigned char data = get_document_char(doc_view->document, x, y);
UCHAR data = get_document_char(doc_view->document, x, y);
/* Text wrapping might remove space chars from the link
* position array so try to align the matched typeahead text

View File

@ -40,6 +40,11 @@
struct line_info {
int start;
int end;
#ifdef CONFIG_UTF_8
int last_char_width;
int split_prev:1;
int split_next:1;
#endif /* CONFIG_UTF_8 */
};
/* We add two extra entries to the table so the ending info can be added
@ -47,6 +52,90 @@ struct line_info {
#define realloc_line_info(info, size) \
mem_align_alloc(info, size, (size) + 3, 0xFF)
#ifdef CONFIG_UTF_8
/* Allocates a line_info table describing the layout of the textarea buffer.
*
* @width is max width and the offset at which text will be wrapped
* @wrap controls how the wrapping of text is performed
* @format is non zero the @text will be modified to make it suitable for
* encoding it for form posting
*/
static struct line_info *
format_textutf8(unsigned char *text, int width, enum form_wrap wrap, int format)
{
struct line_info *line = NULL;
int line_number = 0;
int begin = 0;
int pos = 0;
int skip;
unsigned char *wrappos=NULL;
int chars_cells=0; /* Number of console chars on line */
assert(text);
if_assert_failed return NULL;
/* Allocate the ending entries */
if (!realloc_line_info(&line, 0))
return NULL;
while (text[pos]) {
int char_cells = utf8_char2cells(&text[pos], NULL);
if (text[pos] == ' ')
wrappos = &text[pos];
if (text[pos] == '\n') {
skip = 1;
} else if (wrap == FORM_WRAP_NONE || chars_cells + char_cells < width) {
pos += utf8charlen(&text[pos]);
chars_cells += char_cells;
continue;
} else {
if (wrappos) {
/* When formatting text for form submitting we
* have to apply the wrapping mode. */
if (wrap == FORM_WRAP_HARD && format)
*wrappos = '\n';
pos = wrappos - text;
}
skip = !!wrappos;
}
if (!realloc_line_info(&line, line_number)) {
mem_free_if(line);
return NULL;
}
line[line_number].last_char_width = char_cells;
line[line_number].split_next = !skip;
line[line_number].start = begin;
line[line_number++].end = pos;
line[line_number].split_prev = !skip;
begin = pos += skip;
chars_cells = 0;
wrappos = NULL;
}
line[line_number].split_next = 0;
/* Flush the last text before the loop ended */
line[line_number].start = begin;
line[line_number++].end = pos;
/* Add end marker */
line[line_number].start = line[line_number].end = -1;
line[line_number].split_next = line[line_number].split_prev = 0;
line[0].split_prev = 0;
return line;
}
#endif /* CONFIG_UTF_8 */
/* Allocates a line_info table describing the layout of the textarea buffer.
*
* @width is max width and the offset at which text will be wrapped
@ -137,6 +226,59 @@ get_textarea_line_number(struct line_info *line, int cursor_position)
/* Fixes up the vpos and vypos members of the form_state. Returns the
* logical position in the textarea view. */
#ifdef CONFIG_UTF_8
int
area_cursor(struct form_control *fc, struct form_state *fs, int utf8)
{
struct line_info *line;
int x, y;
assert(fc && fs);
if_assert_failed return 0;
if (utf8)
line = format_textutf8(fs->value, fc->cols, fc->wrap, 0);
else
line = format_text(fs->value, fc->cols, fc->wrap, 0);
if (!line) return 0;
if (fs->state_cell)
y = get_textarea_line_number(line, fs->state_cell);
else
y = get_textarea_line_number(line, fs->state);
if (y == -1) {
mem_free(line);
return 0;
}
if (utf8) {
if (fs->state_cell) {
x = utf8_ptr2cells(fs->value + line[y].start,
fs->value + fs->state_cell);
x += line[y].last_char_width;
} else
x = utf8_ptr2cells(fs->value + line[y].start,
fs->value + fs->state);
} else {
x = fs->state - line[y].start;
if (fc->wrap && x == fc->cols) x--;
}
mem_free(line);
int_bounds(&fs->vpos, x - fc->cols + 1, x);
int_bounds(&fs->vypos, y - fc->rows + 1, y);
x -= fs->vpos;
y -= fs->vypos;
return y * fc->cols + x;
}
#else
int
area_cursor(struct form_control *fc, struct form_state *fs)
{
@ -169,6 +311,91 @@ area_cursor(struct form_control *fc, struct form_state *fs)
return y * fc->cols + x;
}
#endif
#ifdef CONFIG_UTF_8
static void
draw_textarea_utf8(struct terminal *term, struct form_state *fs,
struct document_view *doc_view, struct link *link)
{
struct line_info *line, *linex;
struct form_control *fc;
struct box *box;
int vx, vy;
int sl, ye;
int x, xbase, y;
assert(term && doc_view && doc_view->document && doc_view->vs && link);
if_assert_failed return;
fc = get_link_form_control(link);
assertm(fc, "link %d has no form control", (int) (link - doc_view->document->links));
if_assert_failed return;
box = &doc_view->box;
vx = doc_view->vs->x;
vy = doc_view->vs->y;
if (!link->npoints) return;
area_cursor(fc, fs, 1);
linex = format_textutf8(fs->value, fc->cols, fc->wrap, 0);
if (!linex) return;
line = linex;
sl = fs->vypos;
while (line->start != -1 && sl) sl--, line++;
xbase = link->points[0].x + box->x - vx;
y = link->points[0].y + box->y - vy;
ye = y + fc->rows;
for (; line->start != -1 && y < ye; line++, y++) {
int i;
unsigned char *text, *end;
text = fs->value + line->start;
end = fs->value + line->end;
text += utf8_cells2bytes(text, fs->vpos, end);
if (!row_is_in_box(box, y)) continue;
for (i = 0, x = xbase; i < fc->cols; i++, x++) {
unicode_val_T data;
if (!col_is_in_box(box, x))
continue;
if (i >= -fs->vpos && text < end) {
int cell;
data = utf_8_to_unicode(&text, end);
cell = unicode_to_cell(data);
if (cell == 2) {
draw_char_data(term, x++, y, data);
i++;
data = UCS_NO_CHAR;
}
} else
data = '_';
draw_char_data(term, x, y, data);
}
}
for (; y < ye; y++) {
int i;
if (!row_is_in_box(box, y)) continue;
for (i = 0, x = xbase; i < fc->cols; i++, x++) {
if (col_is_in_box(box, x))
draw_char_data(term, x, y, '_');
}
}
mem_free(linex);
}
#endif /* CONFIG_UTF_8 */
void
draw_textarea(struct terminal *term, struct form_state *fs,
@ -183,6 +410,13 @@ draw_textarea(struct terminal *term, struct form_state *fs,
assert(term && doc_view && doc_view->document && doc_view->vs && link);
if_assert_failed return;
#ifdef CONFIG_UTF_8
if (term->utf8) {
draw_textarea_utf8(term, fs, doc_view, link);
return;
}
#endif /* CONFIG_UTF_8 */
fc = get_link_form_control(link);
assertm(fc, "link %d has no form control", (int) (link - doc_view->document->links));
if_assert_failed return;
@ -192,7 +426,11 @@ draw_textarea(struct terminal *term, struct form_state *fs,
vy = doc_view->vs->y;
if (!link->npoints) return;
#ifdef CONFIG_UTF_8
area_cursor(fc, fs, 0);
#else
area_cursor(fc, fs);
#endif /* CONFIG_UTF_8 */
linex = format_text(fs->value, fc->cols, fc->wrap, 0);
if (!linex) return;
line = linex;
@ -257,6 +495,7 @@ encode_textarea(struct submitted_value *sv)
/* We need to reformat text now if it has to be wrapped hard, just
* before encoding it. */
/* TODO: Do we need here UTF-8 format or not? --scrool */
blabla = format_text(sv->value, fc->cols, fc->wrap, 1);
mem_free_if(blabla);
@ -447,6 +686,39 @@ menu_textarea_edit(struct terminal *term, void *xxx, void *ses_)
textarea_edit(0, term, fs, doc_view, link);
}
#ifdef CONFIG_UTF_8
static enum frame_event_status
textarea_op(struct form_state *fs, struct form_control *fc, int utf8,
int (*do_op)(struct form_state *, struct line_info *, int, int))
{
struct line_info *line;
int current, state;
int state_cell;
assert(fs && fs->value && fc);
if_assert_failed return FRAME_EVENT_OK;
if (utf8)
line = format_textutf8(fs->value, fc->cols, fc->wrap, 0);
else
line = format_text(fs->value, fc->cols, fc->wrap, 0);
if (!line) return FRAME_EVENT_OK;
current = get_textarea_line_number(line, fs->state);
state = fs->state;
state_cell = fs->state_cell;
if (do_op(fs, line, current, utf8)) {
mem_free(line);
return FRAME_EVENT_IGNORED;
}
mem_free(line);
return (fs->state == state && fs->state_cell == state_cell)
? FRAME_EVENT_OK : FRAME_EVENT_REFRESH;
}
#else
static enum frame_event_status
textarea_op(struct form_state *fs, struct form_control *fc,
int (*do_op)(struct form_state *, struct line_info *, int))
@ -471,14 +743,86 @@ textarea_op(struct form_state *fs, struct form_control *fc,
return fs->state == state ? FRAME_EVENT_OK : FRAME_EVENT_REFRESH;
}
#endif /* CONFIG_UTF_8 */
#ifdef CONFIG_UTF_8
void
new_pos(struct form_state *fs, struct line_info *line, int current, int max_cells)
{
unsigned char *text = fs->value + line[current].start;
unsigned char *end = fs->value + line[current].end;
int cells = 0;
while(cells < max_cells) {
unicode_val_T data = utf_8_to_unicode(&text, end);
if (data == UCS_NO_CHAR) break;
cells += unicode_to_cell(data);
}
fs->state = (int)(text - fs->value);
}
#endif /* CONFIG_UTF_8 */
static int
#ifdef CONFIG_UTF_8
do_op_home(struct form_state *fs, struct line_info *line, int current, int utf8)
#else
do_op_home(struct form_state *fs, struct line_info *line, int current)
#endif /* CONFIG_UTF_8 */
{
if (current != -1) fs->state = line[current].start;
if (current == -1)
return 0;
#ifdef CONFIG_UTF_8
if (utf8)
fs->state = line[current - !!fs->state_cell].start;
else
#endif /* CONFIG_UTF_8 */
fs->state = line[current].start;
return 0;
}
#ifdef CONFIG_UTF_8
static int
do_op_up(struct form_state *fs, struct line_info *line, int current, int utf8)
{
if (current == -1) return 0;
if (!(current - !!fs->state_cell)) return 1;
if (!utf8) {
fs->state -= line[current].start - line[current-1].start;
int_upper_bound(&fs->state, line[current-1].end);
return 0;
}
int old_state = fs->state;
if (fs->state_cell) {
int len = utf8_ptr2cells(fs->value + line[current - 1].start,
fs->value + fs->state_cell);
new_pos(fs, line, current - 2, len + line[current - 1].last_char_width);
} else {
int len = utf8_ptr2cells(fs->value + line[current].start,
fs->value + fs->state);
new_pos(fs, line, current - 1, len);
}
if (old_state != fs->state ) {
if (fs->state_cell && fs->state == line[current - 1].start) {
unsigned char *new_value;
new_value = utf8_prevchar(fs->value + fs->state, 1, fs->value);
fs->state_cell = new_value - fs->value;
} else
fs->state_cell = 0;
}
return 0;
}
#else
static int
do_op_up(struct form_state *fs, struct line_info *line, int current)
{
@ -489,6 +833,47 @@ do_op_up(struct form_state *fs, struct line_info *line, int current)
int_upper_bound(&fs->state, line[current-1].end);
return 0;
}
#endif /* CONFIG_UTF_8 */
#ifdef CONFIG_UTF_8
static int
do_op_down(struct form_state *fs, struct line_info *line, int current, int utf8)
{
if (current == -1) return 0;
if (line[current + 1 - !!fs->state_cell].start == -1) return 1;
if (!utf8) {
fs->state += line[current+1].start - line[current].start;
int_upper_bound(&fs->state, line[current+1].end);
return 0;
}
int old_state = fs->state;
if (fs->state_cell) {
int len = utf8_ptr2cells(fs->value + line[current - 1].start,
fs->value + fs->state_cell);
new_pos(fs, line, current, len + line[current - 1].last_char_width);
} else {
int len = utf8_ptr2cells(fs->value + line[current].start,
fs->value + fs->state);
new_pos(fs, line, current + 1, len);
}
if (old_state != fs->state ) {
if (fs->state_cell && fs->state == line[current+1].start) {
unsigned char *new_value;
new_value = utf8_prevchar(fs->value + fs->state, 1, fs->value);
fs->state_cell = new_value - fs->value;
} else
fs->state_cell = 0;
}
return 0;
}
#else
static int
do_op_down(struct form_state *fs, struct line_info *line, int current)
@ -500,6 +885,39 @@ do_op_down(struct form_state *fs, struct line_info *line, int current)
int_upper_bound(&fs->state, line[current+1].end);
return 0;
}
#endif /* CONFIG_UTF_8 */
#ifdef CONFIG_UTF_8
static int
do_op_end(struct form_state *fs, struct line_info *line, int current, int utf8)
{
if (current == -1) {
fs->state = strlen(fs->value);
return 0;
}
if (!utf8) {
int wrap = line[current + 1].start == line[current].end;
/* Don't jump to next line when wrapping. */
fs->state = int_max(0, line[current].end - wrap);
return 0;
}
current -= !!fs->state_cell;
fs->state = line[current].end;
if (line[current].split_next) {
unsigned char *new_value;
new_value = utf8_prevchar(fs->value + fs->state, 1, fs->value);
fs->state_cell = new_value - fs->value;
} else {
fs->state_cell = 0;
}
return 0;
}
#else
static int
do_op_end(struct form_state *fs, struct line_info *line, int current)
@ -515,9 +933,14 @@ do_op_end(struct form_state *fs, struct line_info *line, int current)
}
return 0;
}
#endif /* CONFIG_UTF_8 */
static int
#ifdef CONFIG_UTF_8
do_op_bob(struct form_state *fs, struct line_info *line, int current, int utf8)
#else
do_op_bob(struct form_state *fs, struct line_info *line, int current)
#endif /* CONFIG_UTF_8 */
{
if (current == -1) return 0;
@ -527,7 +950,11 @@ do_op_bob(struct form_state *fs, struct line_info *line, int current)
}
static int
#ifdef CONFIG_UTF_8
do_op_eob(struct form_state *fs, struct line_info *line, int current, int utf8)
#else
do_op_eob(struct form_state *fs, struct line_info *line, int current)
#endif /* CONFIG_UTF_8 */
{
if (current == -1) {
fs->state = strlen(fs->value);
@ -543,50 +970,102 @@ do_op_eob(struct form_state *fs, struct line_info *line, int current)
return 0;
}
#ifdef CONFIG_UTF_8
enum frame_event_status
textarea_op_home(struct form_state *fs, struct form_control *fc, int utf8)
{
return textarea_op(fs, fc, utf8, do_op_home);
}
#else
enum frame_event_status
textarea_op_home(struct form_state *fs, struct form_control *fc)
{
return textarea_op(fs, fc, do_op_home);
}
#endif /* CONFIG_UTF_8 */
#ifdef CONFIG_UTF_8
enum frame_event_status
textarea_op_up(struct form_state *fs, struct form_control *fc, int utf8)
{
return textarea_op(fs, fc, utf8, do_op_up);
}
#else
enum frame_event_status
textarea_op_up(struct form_state *fs, struct form_control *fc)
{
return textarea_op(fs, fc, do_op_up);
}
#endif /* CONFIG_UTF_8 */
#ifdef CONFIG_UTF_8
enum frame_event_status
textarea_op_down(struct form_state *fs, struct form_control *fc, int utf8)
{
return textarea_op(fs, fc, utf8, do_op_down);
}
#else
enum frame_event_status
textarea_op_down(struct form_state *fs, struct form_control *fc)
{
return textarea_op(fs, fc, do_op_down);
}
#endif /* CONFIG_UTF_8 */
#ifdef CONFIG_UTF_8
enum frame_event_status
textarea_op_end(struct form_state *fs, struct form_control *fc, int utf8)
{
return textarea_op(fs, fc, utf8, do_op_end);
}
#else
enum frame_event_status
textarea_op_end(struct form_state *fs, struct form_control *fc)
{
return textarea_op(fs, fc, do_op_end);
}
#endif /* CONFIG_UTF_8 */
/* Set the form state so the cursor is on the first line of the buffer.
* Preserve the column if possible. */
#ifdef CONFIG_UTF_8
enum frame_event_status
textarea_op_bob(struct form_state *fs, struct form_control *fc, int utf8)
{
return textarea_op(fs, fc, utf8, do_op_bob);
}
#else
enum frame_event_status
textarea_op_bob(struct form_state *fs, struct form_control *fc)
{
return textarea_op(fs, fc, do_op_bob);
}
#endif /* CONFIG_UTF_8 */
/* Set the form state so the cursor is on the last line of the buffer. Preserve
* the column if possible. This is done by getting current and last line and
* then shifting the state by the delta of both lines start position bounding
* the whole thing to the end of the last line. */
#ifdef CONFIG_UTF_8
enum frame_event_status
textarea_op_eob(struct form_state *fs, struct form_control *fc, int utf8)
{
return textarea_op(fs, fc, utf8, do_op_eob);
}
#else
enum frame_event_status
textarea_op_eob(struct form_state *fs, struct form_control *fc)
{
return textarea_op(fs, fc, do_op_eob);
}
#endif /* CONFIG_UTF_8 */
enum frame_event_status
#ifdef CONFIG_UTF_8
textarea_op_enter(struct form_state *fs, struct form_control *fc, int utf8)
#else
textarea_op_enter(struct form_state *fs, struct form_control *fc)
#endif /* CONFIG_UTF_8 */
{
assert(fs && fs->value && fc);
if_assert_failed return FRAME_EVENT_OK;
@ -600,6 +1079,81 @@ textarea_op_enter(struct form_state *fs, struct form_control *fc)
return FRAME_EVENT_REFRESH;
}
#ifdef CONFIG_UTF_8
static int
do_op_left(struct form_state *fs, struct line_info *line, int current, int utf8)
{
if (!utf8) {
fs->state = int_max(fs->state - 1, 0);
return 0;
}
if (fs->state_cell) {
fs->state = fs->state_cell;
fs->state_cell = 0;
return 0;
}
int old_state = fs->state;
int new_state;
unsigned char *new_value;
new_value = utf8_prevchar(fs->value + fs->state, 1, fs->value);
new_state = new_value - fs->value;
if (old_state != new_state) {
if (old_state == line[current].start && line[current].split_prev)
fs->state_cell = new_state;
else
fs->state = new_state;
}
return 0;
}
static int
do_op_right(struct form_state *fs, struct line_info *line, int current, int utf8)
{
if (!utf8) {
/* TODO: zle */
fs->state = int_min(fs->state + 1, strlen(fs->value));
return 0;
}
if (fs->state_cell) {
fs->state_cell = 0;
return 0;
}
unsigned char *text = fs->value + fs->state;
unsigned char *end = strchr(text, '\0');
int old_state = fs->state;
utf_8_to_unicode(&text, end);
fs->state = text - fs->value;
if (old_state != fs->state && line[current].split_next) {
fs->state_cell = (fs->state == line[current].end) ? old_state:0;
} else if (!line[current].split_next) {
fs->state_cell = 0;
}
return 0;
}
#endif /* CONFIG_UTF_8 */
#ifdef CONFIG_UTF_8
enum frame_event_status
textarea_op_left(struct form_state *fs, struct form_control *fc, int utf8)
{
return textarea_op(fs, fc, utf8, do_op_left);
}
enum frame_event_status
textarea_op_right(struct form_state *fs, struct form_control *fc, int utf8)
{
return textarea_op(fs, fc, utf8, do_op_right);
}
#endif /* CONFIG_UTF_8 */
void
set_textarea(struct document_view *doc_view, int direction)
@ -607,6 +1161,9 @@ set_textarea(struct document_view *doc_view, int direction)
struct form_control *fc;
struct form_state *fs;
struct link *link;
#ifdef CONFIG_UTF_8
int utf8 = doc_view->document->options.utf8;
#endif /* CONFIG_UTF_8 */
assert(doc_view && doc_view->vs && doc_view->document);
assert(direction == 1 || direction == -1);
@ -627,8 +1184,15 @@ set_textarea(struct document_view *doc_view, int direction)
/* Depending on which way we entered the textarea move cursor so that
* it is available at end or start. */
#ifdef CONFIG_UTF_8
if (direction == 1)
textarea_op_eob(fs, fc, utf8);
else
textarea_op_bob(fs, fc, utf8);
#else
if (direction == 1)
textarea_op_eob(fs, fc);
else
textarea_op_bob(fs, fc);
#endif /* CONFIG_UTF_8 */
}

View File

@ -13,7 +13,11 @@ struct link;
struct session;
struct terminal;
#ifdef CONFIG_UTF_8
int area_cursor(struct form_control *fc, struct form_state *fs, int utf8);
#else
int area_cursor(struct form_control *fc, struct form_state *fs);
#endif /* CONFIG_UTF_8 */
void draw_textarea(struct terminal *term, struct form_state *fs, struct document_view *doc_view, struct link *link);
unsigned char *encode_textarea(struct submitted_value *sv);
@ -21,6 +25,17 @@ extern int textarea_editor;
void textarea_edit(int, struct terminal *, struct form_state *, struct document_view *, struct link *);
void menu_textarea_edit(struct terminal *term, void *xxx, void *ses_);
#ifdef CONFIG_UTF_8
enum frame_event_status textarea_op_home(struct form_state *fs, struct form_control *fc, int utf8);
enum frame_event_status textarea_op_up(struct form_state *fs, struct form_control *fc, int utf8);
enum frame_event_status textarea_op_down(struct form_state *fs, struct form_control *fc, int utf8);
enum frame_event_status textarea_op_end(struct form_state *fs, struct form_control *fc, int utf8);
enum frame_event_status textarea_op_bob(struct form_state *fs, struct form_control *fc, int utf8);
enum frame_event_status textarea_op_eob(struct form_state *fs, struct form_control *fc, int utf8);
enum frame_event_status textarea_op_enter(struct form_state *fs, struct form_control *fc, int utf8);
enum frame_event_status textarea_op_left(struct form_state *fs, struct form_control *fc, int utf8);
enum frame_event_status textarea_op_right(struct form_state *fs, struct form_control *fc, int utf8);
#else
enum frame_event_status textarea_op_home(struct form_state *fs, struct form_control *fc);
enum frame_event_status textarea_op_up(struct form_state *fs, struct form_control *fc);
enum frame_event_status textarea_op_down(struct form_state *fs, struct form_control *fc);
@ -28,6 +43,7 @@ enum frame_event_status textarea_op_end(struct form_state *fs, struct form_contr
enum frame_event_status textarea_op_bob(struct form_state *fs, struct form_control *fc);
enum frame_event_status textarea_op_eob(struct form_state *fs, struct form_control *fc);
enum frame_event_status textarea_op_enter(struct form_state *fs, struct form_control *fc);
#endif /* CONFIG_UTF_8 */
void set_textarea(struct document_view *doc_view, int direction);