summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Tytgat <joty@netsurf-browser.org>2004-07-05 20:19:52 +0000
committerJohn Tytgat <joty@netsurf-browser.org>2004-07-05 20:19:52 +0000
commita0d511734ae464d6e7b4d2f5e019611c0cdafea9 (patch)
tree3427f02b2f829492f6bf89d16c7af91726878e9c
parentab11d2c94d0ed5c4ed9ab4f32417e3c1c4cf8fb9 (diff)
downloadnetsurf-a0d511734ae464d6e7b4d2f5e019611c0cdafea9.tar.gz
netsurf-a0d511734ae464d6e7b4d2f5e019611c0cdafea9.tar.bz2
[project @ 2004-07-05 20:19:51 by joty]
Using UTF-8 instead of Latin1 encoding. svn path=/import/netsurf/; revision=1049
-rw-r--r--debug/fontd.c30
-rw-r--r--desktop/browser.c49
-rw-r--r--desktop/netsurf.c15
-rw-r--r--desktop/save_text.c2
-rw-r--r--gtk/font_pango.c12
-rw-r--r--makefile2
-rw-r--r--render/box.c190
-rw-r--r--render/font.h37
-rw-r--r--render/html.c36
-rw-r--r--render/layout.c10
-rw-r--r--riscos/font.c743
-rw-r--r--riscos/gui.c5
-rw-r--r--riscos/help.c4
-rw-r--r--riscos/history.c4
-rw-r--r--riscos/htmlredraw.c37
-rw-r--r--riscos/menus.c12
-rw-r--r--riscos/mouseactions.c2
-rw-r--r--riscos/save_draw.c666
-rw-r--r--riscos/save_draw.h2
-rw-r--r--riscos/toolbar.c3
-rw-r--r--riscos/ufont.c1281
-rw-r--r--riscos/ufont.h70
-rw-r--r--utils/utils.c131
-rw-r--r--utils/utils.h8
24 files changed, 2646 insertions, 705 deletions
diff --git a/debug/fontd.c b/debug/fontd.c
index 0305387ba..1b9ba871c 100644
--- a/debug/fontd.c
+++ b/debug/fontd.c
@@ -28,7 +28,7 @@ static void font_close(struct font_data *data);
* functions
*/
-unsigned long font_width(struct font_data *font, const char * text, unsigned int length)
+unsigned long nsfont_width(struct font_data *font, const char * text, unsigned int length)
{
int width;
@@ -40,7 +40,7 @@ unsigned long font_width(struct font_data *font, const char * text, unsigned int
return length * 10;
}
-void font_position_in_string(const char* text, struct font_data* font,
+void nsfont_position_in_string(struct font_data* font, const char* text,
unsigned int length, unsigned long x, int* char_offset, int* pixel_offset)
{
assert(font != 0 && text != 0);
@@ -52,7 +52,7 @@ void font_position_in_string(const char* text, struct font_data* font,
}
-struct font_set *font_new_set()
+struct font_set *nsfont_new_set()
{
struct font_set *set = xcalloc(1, sizeof(*set));
unsigned int i;
@@ -64,7 +64,7 @@ struct font_set *font_new_set()
}
-struct font_data *font_open(struct font_set *set, struct css_style *style)
+struct font_data *nsfont_open(struct font_set *set, struct css_style *style)
{
struct font_data *data;
unsigned int size = 16 * 11;
@@ -98,12 +98,12 @@ struct font_data *font_open(struct font_set *set, struct css_style *style)
for (data = set->font[f]; data != 0; data = data->next)
if (data->size == size)
- return data;
+ return data;
data = xcalloc(1, sizeof(*data));
data->size = size;
- data->space_width = font_width(data, " ", 1);
+ data->space_width = nsfont_width(data, " ", sizeof(" ")-1);
data->next = set->font[f];
set->font[f] = data;
@@ -112,7 +112,7 @@ struct font_data *font_open(struct font_set *set, struct css_style *style)
}
-void font_free_set(struct font_set *set)
+void nsfont_free_set(struct font_set *set)
{
unsigned int i;
struct font_data *data, *next;
@@ -137,7 +137,7 @@ void font_close(struct font_data *data)
}
-char * font_split(struct font_data *data, const char * text, unsigned int length,
+char *nsfont_split(struct font_data *data, const char * text, unsigned int length,
unsigned int width, unsigned int *used_width)
{
int i = width / 10;
@@ -154,15 +154,9 @@ char * font_split(struct font_data *data, const char * text, unsigned int length
}
-const char *enumerate_fonts(struct font_set *set, int *handle)
+void nsfont_paint(struct font_data *data, const char *text,
+ int xpos, int ypos, void *trfm, int length)
{
- assert(handle);
-
- if (*handle == 0) {
- *handle = 1;
- return "Homerton.Medium";
- }
-
- *handle = -1;
- return 0;
+ assert(data != NULL);
+ assert(text != NULL);
}
diff --git a/desktop/browser.c b/desktop/browser.c
index e6a8f1cbf..929b0a7ab 100644
--- a/desktop/browser.c
+++ b/desktop/browser.c
@@ -364,12 +364,16 @@ void browser_window_stop_throbber(struct browser_window *bw)
void browser_window_update(struct browser_window *bw,
bool scroll_to_top)
{
+ const char *title_local_enc;
+
if (!bw->current_content)
return;
- if (bw->current_content->title)
- gui_window_set_title(bw->window, bw->current_content->title);
- else
+ if (bw->current_content->title != NULL
+ && (title_local_enc = cnv_str_local_enc(bw->current_content->title)) != NULL) {
+ gui_window_set_title(bw->window, title_local_enc);
+ free(title_local_enc);
+ } else
gui_window_set_title(bw->window, bw->current_content->url);
gui_window_set_extent(bw->window, bw->current_content->width,
@@ -739,7 +743,7 @@ void browser_window_textarea_click(struct browser_window* bw,
text_box = inline_container->last;
assert(text_box->type == BOX_INLINE);
assert(text_box->text && text_box->font);
- font_position_in_string(text_box->text, text_box->font,
+ nsfont_position_in_string(text_box->font, text_box->text,
text_box->length,
(unsigned int)textarea->width,
&char_offset, &pixel_offset);
@@ -756,7 +760,8 @@ void browser_window_textarea_click(struct browser_window* bw,
text_box = inline_container->last;
assert(text_box->type == BOX_INLINE);
assert(text_box->text && text_box->font);
- font_position_in_string(text_box->text, text_box->font,
+ nsfont_position_in_string(text_box->font,
+ text_box->text,
text_box->length,
(unsigned int)textarea->width,
&char_offset, &pixel_offset);
@@ -764,7 +769,8 @@ void browser_window_textarea_click(struct browser_window* bw,
/* in a text box */
assert(text_box->type == BOX_INLINE);
assert(text_box->text && text_box->font);
- font_position_in_string(text_box->text, text_box->font,
+ nsfont_position_in_string(text_box->font,
+ text_box->text,
text_box->length,
(unsigned int)(x - text_box->x),
&char_offset, &pixel_offset);
@@ -1098,8 +1104,8 @@ void browser_window_textarea_callback(struct browser_window *bw, char key, void
for (ic = textarea->children; ic; ic = ic->next)
ic->y += dy;
- pixel_offset = font_width(text_box->font, text_box->text,
- (unsigned int)char_offset);
+ pixel_offset = nsfont_width(text_box->font, text_box->text,
+ (unsigned int)char_offset);
textarea->gadget->caret_inline_container = inline_container;
textarea->gadget->caret_text_box = text_box;
@@ -1130,7 +1136,7 @@ void browser_window_input_click(struct browser_window* bw,
int char_offset, pixel_offset;
struct box *text_box = input->children->children;
- font_position_in_string(text_box->text, text_box->font,
+ nsfont_position_in_string(text_box->font, text_box->text,
text_box->length, x - text_box->x,
&char_offset, &pixel_offset);
@@ -1170,7 +1176,7 @@ void browser_window_input_callback(struct browser_window *bw, char key, void *p)
box_coords(input, &actual_x, &actual_y);
- if ((32 <= key && key != 127) && text_box->length < input->gadget->maxlength) {
+ if (32 <= key && key != 127 && text_box->length < input->gadget->maxlength) {
/* normal character insertion */
text_box->text = xrealloc(text_box->text, text_box->length + 2);
input->gadget->value = xrealloc(input->gadget->value, text_box->length + 2);
@@ -1183,7 +1189,7 @@ void browser_window_input_callback(struct browser_window *bw, char key, void *p)
if (input->gadget->type == GADGET_PASSWORD)
text_box->text[char_offset] = '*';
else
- text_box->text[char_offset] = key == ' ' ? 160 : key;
+ text_box->text[char_offset] = key; /* /todo was a test on space -> change into NBSP, still needed ? */
input->gadget->value[char_offset] = key;
text_box->length++;
text_box->text[text_box->length] = 0;
@@ -1282,12 +1288,12 @@ void browser_window_input_callback(struct browser_window *bw, char key, void *p)
return;
}
- text_box->width = font_width(text_box->font, text_box->text,
+ text_box->width = nsfont_width(text_box->font, text_box->text,
(unsigned int)text_box->length);
- pixel_offset = font_width(text_box->font, text_box->text,
- (unsigned int)char_offset);
+ pixel_offset = nsfont_width(text_box->font, text_box->text,
+ (unsigned int)char_offset);
text_box->x = 0;
- if ((input->width < text_box->width) && (input->width / 2 < pixel_offset)) {
+ if (input->width < text_box->width && input->width / 2 < pixel_offset) {
text_box->x = input->width / 2 - pixel_offset;
if (text_box->x < input->width - text_box->width)
text_box->x = input->width - text_box->width;
@@ -1670,15 +1676,10 @@ void browser_window_text_selection(struct browser_window *bw,
if (click_boxes[i].box->text
&& click_boxes[i].box->font) {
- font_position_in_string(click_boxes[i].
- box->text,
- click_boxes[i].
- box->font,
- click_boxes[i].
- box->length,
- click_x -
- click_boxes[i].
- actual_x,
+ nsfont_position_in_string(click_boxes[i].box->font,
+ click_boxes[i].box->text,
+ click_boxes[i].box->length,
+ click_x - click_boxes[i].actual_x,
&click_char_offset,
&click_pixel_offset);
} else {
diff --git a/desktop/netsurf.c b/desktop/netsurf.c
index 55020354f..96745b989 100644
--- a/desktop/netsurf.c
+++ b/desktop/netsurf.c
@@ -26,6 +26,7 @@ bool netsurf_quit = false;
static void netsurf_init(int argc, char** argv);
static void netsurf_poll(void);
static void netsurf_exit(void);
+static void lib_init(void);
#ifndef curl_memdebug
extern void curl_memdebug(const char *logname);
@@ -68,6 +69,7 @@ void netsurf_init(int argc, char** argv)
utsname.nodename, utsname.release,
utsname.version, utsname.machine));
+ lib_init();
gui_init(argc, argv);
setlocale(LC_ALL, "");
fetch_init();
@@ -97,3 +99,16 @@ void netsurf_exit(void)
fetch_quit();
gui_quit();
}
+
+
+/**
+ * Initialises the libraries used in NetSurf.
+ */
+static void lib_init(void)
+{
+ /* Using encoding "X-SJIS" (unknown to libxmp2/iconv) instead as
+ * "Shift-JIS" is rather popular.
+ */
+ if (xmlAddEncodingAlias(xmlGetCharEncodingName(XML_CHAR_ENCODING_SHIFT_JIS), "X-SJIS") != 0)
+ die(("Failed to add encoding alias"));
+}
diff --git a/desktop/save_text.c b/desktop/save_text.c
index 98c0a8a88..9b3ff563f 100644
--- a/desktop/save_text.c
+++ b/desktop/save_text.c
@@ -93,7 +93,7 @@ void extract_text_from_tree(xmlNode *n)
/* do nothing, we just recurse through these nodes */
}
else if (n->type == XML_TEXT_NODE) {
- if ((text = squash_tolat1(n->content)) != NULL) {
+ if ((text = squash_whitespace(n->content)) != NULL) {
fputs(text, out);
free(text);
}
diff --git a/gtk/font_pango.c b/gtk/font_pango.c
index 17ef149c3..a376967a5 100644
--- a/gtk/font_pango.c
+++ b/gtk/font_pango.c
@@ -19,13 +19,13 @@ struct font_set {
};
-struct font_set *font_new_set()
+struct font_set *nsfont_new_set()
{
return 0;
}
-struct font_data *font_open(struct font_set *set, struct css_style *style)
+struct font_data *nsfont_open(struct font_set *set, struct css_style *style)
{
struct font_data *data;
unsigned int size = PANGO_SCALE * 11;
@@ -76,12 +76,12 @@ struct font_data *font_open(struct font_set *set, struct css_style *style)
}
-void font_free_set(struct font_set *set)
+void nsfont_free_set(struct font_set *set)
{
}
-unsigned long font_width(struct font_data *font, const char *text,
+unsigned long nsfont_width(struct font_data *font, const char *text,
unsigned int length)
{
int width;
@@ -107,7 +107,7 @@ unsigned long font_width(struct font_data *font, const char *text,
}
-void font_position_in_string(const char *text, struct font_data *font,
+void nsfont_position_in_string(struct font_data *font, const char *text,
unsigned int length, unsigned long x, int *char_offset,
int *pixel_offset)
{
@@ -134,7 +134,7 @@ void font_position_in_string(const char *text, struct font_data *font,
}
-char *font_split(struct font_data *font, const char *text, unsigned int length,
+char *nsfont_split(struct font_data *font, const char *text, unsigned int length,
unsigned int width, unsigned int *used_width)
{
int index = length;
diff --git a/makefile b/makefile
index 619645a72..714a09030 100644
--- a/makefile
+++ b/makefile
@@ -30,7 +30,7 @@ OBJECTS_RISCOS += 401login.o debugwin.o \
htmlredraw.o jpeg.o menus.o mouseactions.o plugin.o \
png.o save.o save_complete.o save_draw.o save_text.o \
schedule.o sprite.o textselection.o theme.o thumbnail.o \
- toolbar.o uri.o url_protocol.o wimp.o window.o # riscos/
+ toolbar.o ufont.o uri.o url_protocol.o wimp.o window.o # riscos/
OBJECTS_DEBUG = $(OBJECTS_COMMON)
OBJECTS_DEBUG += filetyped.o fontd.o netsurfd.o # debug/
diff --git a/render/box.c b/render/box.c
index 737a6fb93..b1f2edeb5 100644
--- a/render/box.c
+++ b/render/box.c
@@ -110,7 +110,7 @@ static struct box_result box_button(xmlNode *n, struct box_status *status,
struct css_style *style);
static struct box_result box_frameset(xmlNode *n, struct box_status *status,
struct css_style *style);
-static void add_option(xmlNode* n, struct form_control* current_select, char *text);
+static void add_option(xmlNode* n, struct form_control* current_select, const char *text);
static void box_normalise_block(struct box *block, pool box_pool);
static void box_normalise_table(struct box *table, pool box_pool);
void box_normalise_table_row_group(struct box *row_group,
@@ -259,7 +259,7 @@ void xml_to_box(xmlNode *n, struct content *c)
c->data.html.style = xcalloc(1, sizeof(struct css_style));
memcpy(c->data.html.style, &css_base_style, sizeof(struct css_style));
c->data.html.style->font_size.value.length.value = option_font_size * 0.1;
- c->data.html.fonts = font_new_set();
+ c->data.html.fonts = nsfont_new_set();
c->data.html.object_count = 0;
c->data.html.object = xcalloc(0, sizeof(*c->data.html.object));
@@ -346,7 +346,7 @@ struct box * convert_xml_to_box(xmlNode * n, struct content *content,
/* extract title attribute, if present */
if ((title0 = xmlGetProp(n, (const xmlChar *) "title"))) {
- status.title = title = squash_tolat1(title0);
+ status.title = title = squash_whitespace(title0);
xmlFree(title0);
}
@@ -392,7 +392,7 @@ struct box * convert_xml_to_box(xmlNode * n, struct content *content,
if (n->type == XML_TEXT_NODE &&
(parent_style->white_space == CSS_WHITE_SPACE_NORMAL ||
parent_style->white_space == CSS_WHITE_SPACE_NOWRAP)) {
- char *text = squash_tolat1(n->content);
+ char *text = squash_whitespace(n->content);
/* if the text is just a space, combine it with the preceding
* text node, if any */
@@ -418,7 +418,8 @@ struct box * convert_xml_to_box(xmlNode * n, struct content *content,
box->text = text;
box->style_clone = 1;
box->length = strlen(text);
- if (text[box->length - 1] == ' ') {
+ /* strip ending space char off */
+ if (box->length > 1 && text[box->length - 1] == ' ') {
box->space = 1;
box->length--;
}
@@ -427,32 +428,38 @@ struct box * convert_xml_to_box(xmlNode * n, struct content *content,
parent_style->text_transform);
if (parent_style->white_space == CSS_WHITE_SPACE_NOWRAP) {
unsigned int i;
- for (i = 0; i != box->length; i++)
- if (text[i] == ' ')
- text[i] = 160;
+ for (i = 0; i != box->length && text[i] != ' '; ++i)
+ /* no body */;
+ if (i != box->length) {
+ /* there is a space in text block and we
+ * want all spaces to be converted to NBSP
+ */
+ char *org_text = box->text;
+ org_text[box->length] = '\0';
+ box->text = cnv_space2nbsp(org_text);
+ free(org_text);
+ box->length = strlen(box->text);
+ }
}
- box->font = font_open(content->data.html.fonts, box->style);
+ box->font = nsfont_open(content->data.html.fonts, box->style);
box_add_child(inline_container, box);
- if (text[0] == ' ') {
+ if (box->text[0] == ' ') {
box->length--;
- memmove(text, text + 1, box->length);
- if (box->prev != 0)
+ memmove(box->text, &box->text[1], box->length);
+ if (box->prev != NULL)
box->prev->space = 1;
}
goto end;
} else if (n->type == XML_TEXT_NODE) {
/* white-space: pre */
- char *text = tolat1_pre(n->content);
+ char *text = cnv_space2nbsp(n->content);
char *current;
assert(parent_style->white_space == CSS_WHITE_SPACE_PRE);
if (parent_style->text_transform != CSS_TEXT_TRANSFORM_NONE)
box_text_transform(text, strlen(text),
parent_style->text_transform);
- for (current = text; *current; current++)
- if (*current == ' ' || *current == '\t')
- *current = 160;
current = text;
do {
size_t len = strcspn(current, "\r\n");
@@ -470,7 +477,7 @@ struct box * convert_xml_to_box(xmlNode * n, struct content *content,
box->style_clone = 1;
box->text = xstrdup(current);
box->length = strlen(box->text);
- box->font = font_open(content->data.html.fonts, box->style);
+ box->font = nsfont_open(content->data.html.fonts, box->style);
box_add_child(inline_container, box);
current[len] = old;
current += len;
@@ -744,7 +751,7 @@ struct css_style * box_get_style(struct content *c,
/**
- * Apply the CSS text-transform property to some text.
+ * Apply the CSS text-transform property to given text for its ASCII chars.
*
* \param s string to transform
* \param len length of s
@@ -759,17 +766,20 @@ void box_text_transform(char *s, unsigned int len,
return;
switch (tt) {
case CSS_TEXT_TRANSFORM_UPPERCASE:
- for (i = 0; i != len; i++)
- s[i] = toupper(s[i]);
+ for (i = 0; i < len; ++i)
+ if (s[i] < 0x80)
+ s[i] = toupper(s[i]);
break;
case CSS_TEXT_TRANSFORM_LOWERCASE:
- for (i = 0; i != len; i++)
- s[i] = tolower(s[i]);
+ for (i = 0; i < len; ++i)
+ if (s[i] < 0x80)
+ s[i] = tolower(s[i]);
break;
case CSS_TEXT_TRANSFORM_CAPITALIZE:
- s[0] = toupper(s[0]);
- for (i = 1; i != len; i++)
- if (isspace(s[i - 1]))
+ if (s[0] < 0x80)
+ s[0] = toupper(s[0]);
+ for (i = 1; i < len; ++i)
+ if (s[i] < 0x80 && isspace(s[i - 1]))
s[i] = toupper(s[i]);
break;
default:
@@ -838,9 +848,9 @@ struct box_result box_image(xmlNode *n, struct box_status *status,
/* handle alt text */
if ((s2 = xmlGetProp(n, (const xmlChar *) "alt"))) {
- box->text = squash_tolat1(s2);
+ box->text = squash_whitespace(s2);
box->length = strlen(box->text);
- box->font = font_open(status->content->data.html.fonts, style);
+ box->font = nsfont_open(status->content->data.html.fonts, style);
xmlFree(s2);
}
@@ -861,7 +871,6 @@ struct box_result box_image(xmlNode *n, struct box_status *status,
/* remove leading and trailing whitespace */
s1 = strip(s);
-
url = url_join(s1, status->content->data.html.base_url);
if (!url) {
xmlFree(s);
@@ -959,9 +968,16 @@ struct box_result box_textarea(xmlNode *n, struct box_status *status,
status->content->data.html.box_pool);
inline_box->type = BOX_INLINE;
inline_box->style_clone = 1;
- inline_box->text = tolat1(current);
+ if ((inline_box->text = strdup(current)) == NULL) {
+ box_free(inline_box);
+ box_free(inline_container);
+ box_free(box);
+ current[len] = old;
+ xmlFree(content);
+ return (struct box_result) {NULL, false, false};
+ }
inline_box->length = strlen(inline_box->text);
- inline_box->font = font_open(status->content->data.html.fonts, style);
+ inline_box->font = nsfont_open(status->content->data.html.fonts, style);
box_add_child(inline_container, inline_box);
box_add_child(box, inline_container);
current[len] = old;
@@ -1009,14 +1025,14 @@ struct box_result box_select(xmlNode *n, struct box_status *status,
for (c = n->children; c != 0; c = c->next) {
if (strcmp((const char *) c->name, "option") == 0) {
xmlChar *content = xmlNodeGetContent(c);
- add_option(c, gadget, squash_tolat1(content));
+ add_option(c, gadget, content);
xmlFree(content);
gadget->data.select.num_items++;
} else if (strcmp((const char *) c->name, "optgroup") == 0) {
for (c2 = c->children; c2; c2 = c2->next) {
if (strcmp((const char *) c2->name, "option") == 0) {
xmlChar *content = xmlNodeGetContent(c2);
- add_option(c2, gadget, squash_tolat1(content));
+ add_option(c2, gadget, content);
xmlFree(content);
gadget->data.select.num_items++;
}
@@ -1070,15 +1086,20 @@ struct box_result box_select(xmlNode *n, struct box_status *status,
inline_box->text = xstrdup(messages_get("Form_Many"));
inline_box->length = strlen(inline_box->text);
- inline_box->font = font_open(status->content->data.html.fonts, style);
+ inline_box->font = nsfont_open(status->content->data.html.fonts, style);
return (struct box_result) {box, false, false};
}
-void add_option(xmlNode* n, struct form_control* current_select, char *text)
+void add_option(xmlNode* n, struct form_control* current_select, const char *text)
{
struct form_option *option = xcalloc(1, sizeof(struct form_option));
- char *s, *c;
+ const char *s;
+
+ if ((text = squash_whitespace(text)) == NULL) {
+ free(option);
+ return;
+ }
assert(current_select != 0);
@@ -1095,9 +1116,14 @@ void add_option(xmlNode* n, struct form_control* current_select, char *text)
option->value = xstrdup(text);
}
- for (c = text; *c; c++)
- if (*c == ' ')
- *c = 160;
+ /* Convert all spaces into NBSP. */
+ for (s = text; *s != '\0' && *s != ' '; ++s)
+ /* no body */;
+ if (*s == ' ') {
+ const char *org_text = text;
+ text = cnv_space2nbsp(org_text);
+ free(org_text);
+ }
option->selected = option->initial_selected = false;
option->text = text;
@@ -1138,7 +1164,7 @@ struct box_result box_input(xmlNode *n, struct box_status *status,
return (struct box_result) {0, false, true};
}
gadget->box = box;
- box->font = font_open(status->content->data.html.fonts, style);
+ box->font = nsfont_open(status->content->data.html.fonts, style);
} else if (type && strcasecmp(type, "hidden") == 0) {
/* no box for hidden inputs */
@@ -1199,14 +1225,21 @@ struct box_result box_input(xmlNode *n, struct box_status *status,
status->content->data.html.box_pool);
inline_box->type = BOX_INLINE;
inline_box->style_clone = 1;
- if (box->gadget->value)
- inline_box->text = tolat1(box->gadget->value);
+ if (box->gadget->value != NULL)
+ inline_box->text = strdup(box->gadget->value);
else if (box->gadget->type == GADGET_SUBMIT)
- inline_box->text = xstrdup(messages_get("Form_Submit"));
+ inline_box->text = strdup(messages_get("Form_Submit"));
else
- inline_box->text = xstrdup(messages_get("Form_Reset"));
+ inline_box->text = strdup(messages_get("Form_Reset"));
+ if (inline_box->text == NULL) {
+ box_free(inline_box);
+ box_free(inline_container);
+ box_free(box);
+ xmlFree(type);
+ return (struct box_result) {NULL, false, false};
+ }
inline_box->length = strlen(inline_box->text);
- inline_box->font = font_open(status->content->data.html.fonts, style);
+ inline_box->font = nsfont_open(status->content->data.html.fonts, style);
box_add_child(inline_container, inline_box);
box_add_child(box, inline_container);
@@ -1228,7 +1261,7 @@ struct box_result box_input(xmlNode *n, struct box_status *status,
inline_box->text = xstrdup("Button");
}
inline_box->length = strlen(inline_box->text);
- inline_box->font = font_open(status->content->data.html.fonts, style);
+ inline_box->font = nsfont_open(status->content->data.html.fonts, style);
box_add_child(inline_container, inline_box);
box_add_child(box, inline_container);
@@ -1286,7 +1319,6 @@ struct box *box_input_text(xmlNode *n, struct box_status *status,
struct css_style *style, bool password)
{
char *s;
- unsigned int i;
struct box *box = box_create(style, 0, 0,
status->content->data.html.box_pool);
struct box *inline_container, *inline_box;
@@ -1302,10 +1334,14 @@ struct box *box_input_text(xmlNode *n, struct box_status *status,
}
s = (char *) xmlGetProp(n, (const xmlChar *) "value");
- box->gadget->value = s ? tolat1(s) : xstrdup("");
- box->gadget->initial_value = xstrdup(box->gadget->value);
+ box->gadget->value = strdup((s != NULL) ? s : "");
+ box->gadget->initial_value = strdup(box->gadget->value);
if (s)
xmlFree(s);
+ if (box->gadget->value == NULL || box->gadget->initial_value == NULL) {
+ box_free(box);
+ return NULL;
+ }
inline_container = box_create(0, 0, 0,
status->content->data.html.box_pool);
@@ -1314,21 +1350,19 @@ struct box *box_input_text(xmlNode *n, struct box_status *status,
status->content->data.html.box_pool);
inline_box->type = BOX_INLINE;
inline_box->style_clone = 1;
- inline_box->length = strlen(box->gadget->value);
if (password) {
box->gadget->type = GADGET_PASSWORD;
- inline_box->text = xcalloc(inline_box->length + 1, 1);
- for (i = 0; i != inline_box->length; i++)
- inline_box->text[i] = '*';
+ inline_box->length = strlen(box->gadget->value);
+ inline_box->text = malloc(inline_box->length + 1);
+ memset(inline_box->text, '*', inline_box->length);
+ inline_box->text[inline_box->length] = '\0';
} else {
box->gadget->type = GADGET_TEXTBOX;
- inline_box->text = xstrdup(box->gadget->value);
- /* replace spaces with hard spaces to prevent line wrapping */
- for (i = 0; i != inline_box->length; i++)
- if (inline_box->text[i] == ' ')
- inline_box->text[i] = 160;
+ /* replace spaces/TABs with hard spaces to prevent line wrapping */
+ inline_box->text = cnv_space2nbsp(box->gadget->value);
+ inline_box->length = strlen(inline_box->text);
}
- inline_box->font = font_open(status->content->data.html.fonts, style);
+ inline_box->font = nsfont_open(status->content->data.html.fonts, style);
box_add_child(inline_container, inline_box);
box_add_child(box, inline_container);
@@ -1389,7 +1423,7 @@ struct box_result box_button(xmlNode *n, struct box_status *status,
/**
- * print a box tree to standard output
+ * print a box tree to stderr
*/
void box_dump(struct box * box, unsigned int depth)
@@ -1463,9 +1497,9 @@ void box_normalise_block(struct box *block, pool box_pool)
struct css_style *style;
assert(block != 0);
+ LOG(("block %p, block->type %u", block, block->type));
assert(block->type == BOX_BLOCK || block->type == BOX_INLINE_BLOCK ||
block->type == BOX_TABLE_CELL);
- LOG(("block %p, block->type %u", block, block->type));
gui_multitask();
for (child = block->children; child != 0; child = next_child) {
@@ -1496,6 +1530,7 @@ void box_normalise_block(struct box *block, pool box_pool)
case BOX_TABLE_CELL:
/* insert implied table */
style = xcalloc(1, sizeof(struct css_style));
+ assert(block->style != NULL);
memcpy(style, block->style, sizeof(struct css_style));
css_cascade(style, &css_blank_style);
table = box_create(style, block->href, 0, box_pool);
@@ -1558,6 +1593,7 @@ void box_normalise_table(struct box *table, pool box_pool)
case BOX_TABLE_CELL:
/* insert implied table row group */
style = xcalloc(1, sizeof(struct css_style));
+ assert(table->style != NULL);
memcpy(style, table->style, sizeof(struct css_style));
css_cascade(style, &css_blank_style);
row_group = box_create(style, table->href, 0,
@@ -1648,6 +1684,7 @@ void box_normalise_table_row_group(struct box *row_group,
case BOX_TABLE_CELL:
/* insert implied table row */
style = xcalloc(1, sizeof(struct css_style));
+ assert(row_group->style != NULL);
memcpy(style, row_group->style, sizeof(struct css_style));
css_cascade(style, &css_blank_style);
row = box_create(style, row_group->href, 0,
@@ -1735,6 +1772,7 @@ void box_normalise_table_row(struct box *row,
case BOX_TABLE_ROW:
/* insert implied table cell */
style = xcalloc(1, sizeof(struct css_style));
+ assert(row->style != NULL);
memcpy(style, row->style, sizeof(struct css_style));
css_cascade(style, &css_blank_style);
cell = box_create(style, row->href, 0, box_pool);
@@ -1939,15 +1977,15 @@ struct box_result box_object(xmlNode *n, struct box_status *status,
/* object data */
if ((s = (char *) xmlGetProp(n, (const xmlChar *) "data"))) {
- url = url_join(s, status->content->data.html.base_url);
- if (!url) {
- free(po);
- xmlFree(s);
- return (struct box_result) {box, true, true};
- }
- po->data = strdup(s);
- LOG(("object '%s'", po->data));
- xmlFree(s);
+ url = url_join(s, status->content->data.html.base_url);
+ if (!url) {
+ free(po);
+ xmlFree(s);
+ return (struct box_result) {box, true, true};
+ }
+ po->data = strdup(s);
+ LOG(("object '%s'", po->data));
+ xmlFree(s);
}
/* imagemap associated with this object */
@@ -2079,13 +2117,13 @@ struct box_result box_embed(xmlNode *n, struct box_status *status,
/* embed src */
if ((s = (char *) xmlGetProp(n, (const xmlChar *) "src"))) {
- url = url_join(s, status->content->data.html.base_url);
- if (!url) {
- free(po);
- xmlFree(s);
- return (struct box_result) {box, false, true};
- }
- LOG(("embed '%s'", url));
+ url = url_join(s, status->content->data.html.base_url);
+ if (!url) {
+ free(po);
+ xmlFree(s);
+ return (struct box_result) {box, false, true};
+ }
+ LOG(("embed '%s'", url));
po->data = strdup(s);
xmlFree(s);
}
diff --git a/render/font.h b/render/font.h
index 9e76cfdcf..667b177e0 100644
--- a/render/font.h
+++ b/render/font.h
@@ -4,6 +4,7 @@
* http://www.opensource.org/licenses/gpl-license
* Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
* Copyright 2003 James Bursa <bursa@users.sourceforge.net>
+ * Copyright 2004 John Tytgat <John.Tytgat@aaug.net>
*/
#ifndef _NETSURF_RENDER_FONT_H_
@@ -11,22 +12,40 @@
#include "netsurf/css/css.h"
+typedef enum {
+ FONTTYPE_UFONT,
+ FONTTYPE_STANDARD_UTF8ENC,
+ FONTTYPE_STANDARD_LATIN1
+} fonttype_e;
+
struct font_data {
- int id;
+ int id;
int handle;
+ fonttype_e ftype;
unsigned int size;
unsigned int space_width;
struct font_data *next;
};
-struct font_set *font_new_set(void);
-struct font_data *font_open(struct font_set *set, struct css_style *style);
-void font_free_set(struct font_set *set);
-unsigned long font_width(struct font_data *font, const char * text, unsigned int length);
-void font_position_in_string(const char* text, struct font_data *font,
- unsigned int length, unsigned long x, int* char_offset, int* pixel_offset);
-char * font_split(struct font_data *data, const char * text, unsigned int length,
+struct font_set *nsfont_new_set(void);
+struct font_data *nsfont_open(struct font_set *set, struct css_style *style);
+void nsfont_free_set(struct font_set *set);
+unsigned long nsfont_width(struct font_data *font, const char *text,
+ unsigned int length);
+void nsfont_position_in_string(struct font_data *font, const char *text,
+ unsigned int length, unsigned long x, int *char_offset,
+ int *pixel_offset);
+char *nsfont_split(struct font_data *font, const char *text,
+ unsigned int length,
unsigned int width, unsigned int *used_width);
-const char *enumerate_fonts(struct font_set *set, int *handle);
+void nsfont_paint(struct font_data *font, const char *str,
+ int xpos, int ypos, void *trfm, int length);
+void nsfont_txtenum(struct font_data *font, const char *text,
+ unsigned int length,
+ unsigned int *width,
+ const char **rofontname,
+ const char **rotext,
+ unsigned int *rolength,
+ unsigned int *consumed);
#endif
diff --git a/render/html.c b/render/html.c
index dfbc3c106..422528ad0 100644
--- a/render/html.c
+++ b/render/html.c
@@ -10,6 +10,7 @@
*/
#include <assert.h>
+#include <ctype.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
@@ -56,25 +57,44 @@ bool html_create(struct content *c, const char *params[])
unsigned int i;
struct content_html_data *html = &c->data.html;
union content_msg_data msg_data;
- xmlCharEncoding encoding = XML_CHAR_ENCODING_NONE;
+ xmlCharEncoding encXML = XML_CHAR_ENCODING_NONE;
+ const char *encStr = NULL;
html->encoding = NULL;
html->getenc = true;
for (i = 0; params[i]; i += 2) {
if (strcasecmp(params[i], "charset") == 0) {
- encoding = xmlParseCharEncoding(params[i + 1]);
- if (encoding != XML_CHAR_ENCODING_ERROR
- && encoding != XML_CHAR_ENCODING_NONE) {
+ encXML = xmlParseCharEncoding(params[i + 1]);
+ if (encXML != XML_CHAR_ENCODING_ERROR
+ && encXML != XML_CHAR_ENCODING_NONE) {
/* encoding specified - trust the server... */
- html->encoding = xstrdup(xmlGetCharEncodingName(encoding));
+ html->encoding = xstrdup(xmlGetCharEncodingName(encXML));
html->getenc = false;
+ } else {
+ encStr = xstrdup(params[i + 1]);
}
break;
}
}
- html->parser = htmlCreatePushParserCtxt(0, 0, "", 0, 0, encoding);
+ html->parser = htmlCreatePushParserCtxt(0, 0, "", 0, 0, encXML);
+ if (encStr != NULL) {
+ xmlCharEncodingHandlerPtr handler;
+ if ((handler = xmlFindCharEncodingHandler(encStr)) != NULL) {
+ if (xmlSwitchToEncoding(html->parser, handler) == 0) {
+ html->encoding = encStr;
+ html->getenc = false;
+ } else {
+ LOG(("xmlSwitchToEncoding failed for <%s>\n", encStr));
+ free(encStr);
+ }
+ } else {
+ LOG(("xmlFindCharEncodingHandler() failed for <%s>\n", encStr));
+ free(encStr);
+ }
+ }
+ html->base_url = xstrdup(c->url);
html->base_url = strdup(c->url);
html->layout = 0;
html->background_colour = TRANSPARENT;
@@ -267,7 +287,7 @@ void html_head(struct content *c, xmlNode *head)
if (!c->title && strcmp(node->name, "title") == 0) {
xmlChar *title = xmlNodeGetContent(node);
- c->title = squash_tolat1(title);
+ c->title = squash_whitespace(title);
xmlFree(title);
} else if (strcmp(node->name, "base") == 0) {
@@ -852,7 +872,7 @@ void html_destroy(struct content *c)
free(c->data.html.style);
if (c->data.html.fonts)
- font_free_set(c->data.html.fonts);
+ nsfont_free_set(c->data.html.fonts);
/* Free objects */
for (i = 0; i != c->data.html.object_count; i++) {
diff --git a/render/layout.c b/render/layout.c
index 7928f4122..caf76abe9 100644
--- a/render/layout.c
+++ b/render/layout.c
@@ -738,7 +738,7 @@ bool layout_line(struct box *first, int width, int *y,
if (b->text) {
if (b->width == UNKNOWN_WIDTH)
- b->width = font_width(b->font, b->text,
+ b->width = nsfont_width(b->font, b->text,
b->length);
x += b->width + b->space ?
b->font->space_width : 0;
@@ -937,7 +937,7 @@ bool layout_line(struct box *first, int width, int *y,
if (space == 0)
w = split_box->width;
else
- w = font_width(split_box->font, split_box->text, space);
+ w = nsfont_width(split_box->font, split_box->text, space);
LOG(("splitting: split_box %p, space %u, w %i, left %p, "
"right %p, inline_count %u",
@@ -987,7 +987,7 @@ bool layout_line(struct box *first, int width, int *y,
} else {
/* fit as many words as possible */
assert(space != 0);
- space = font_split(split_box->font, split_box->text,
+ space = nsfont_split(split_box->font, split_box->text,
split_box->length,
x1 - x0 - x - space_before, &w)
- split_box->text;
@@ -1654,7 +1654,7 @@ void calculate_inline_widths(struct box *box, int *min, int *line_max)
int width;
/* max = all one line */
- box->width = font_width(box->font, box->text, box->length);
+ box->width = nsfont_width(box->font, box->text, box->length);
*line_max += box->width;
if (box->next && box->space)
*line_max += box->font->space_width;
@@ -1664,7 +1664,7 @@ void calculate_inline_widths(struct box *box, int *min, int *line_max)
do {
for (j = i; j != box->length && box->text[j] != ' '; j++)
;
- width = font_width(box->font, box->text + i, (j - i));
+ width = nsfont_width(box->font, box->text + i, j - i);
if (*min < width) *min = width;
i = j + 1;
} while (j != box->length);
diff --git a/riscos/font.c b/riscos/font.c
index 5a55d28b2..4be4cb6b6 100644
--- a/riscos/font.c
+++ b/riscos/font.c
@@ -4,6 +4,7 @@
* http://www.opensource.org/licenses/gpl-license
* Copyright 2004 James Bursa <bursa@users.sourceforge.net>
* Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
+ * Copyright 2004 John Tytgat <John.Tytgat@aaug.net>
*/
/** \file
@@ -19,6 +20,8 @@
#include "netsurf/desktop/gui.h"
#include "netsurf/render/font.h"
#include "netsurf/riscos/gui.h"
+#include "netsurf/riscos/options.h"
+#include "netsurf/riscos/ufont.h"
#include "netsurf/utils/log.h"
#include "netsurf/utils/utils.h"
@@ -44,128 +47,164 @@ struct font_set {
struct font_data *font[FONT_FAMILIES * FONT_FACES];
};
-/** Table of font names.
+static os_error *nsfont_open_ufont(const char *fontNameP, const char *fbFontNameP, int size, int *handleP, bool *using_fb);
+static os_error *nsfont_open_standard(const char *fontNameP, const char *fbFontNameP, int size, int *handleP, bool *using_fb);
+
+/** Table of font names for UFont and an UTF-8 capable FontManager.
*
* font id = font family * 8 + smallcaps * 4 + bold * 2 + slanted
*
- * font family: 0 = sans-serif, 1 = serif, 2 = monospace, 3 = cursive
- * 4 = fantasy
+ * font family: 0 = sans-serif, 1 = serif, 2 = monospace, 3 = cursive,
+ * 4 = fantasy.
+ * Font family 0 must be available as it is the replacement font when
+ * the other font families can not be found.
*/
+static const char * const ufont_table[FONT_FAMILIES * FONT_FACES] = {
+ /* sans-serif */
+/*0*/ "Homerton.Medium",
+/*1*/ "Homerton.Medium.Oblique",
+/*2*/ "Homerton.Bold",
+/*3*/ "Homerton.Bold.Oblique",
+ "Homerton.Medium.SmallCaps",
+ "Homerton.Medium.Oblique.SmallCaps",
+ "Homerton.Bold.SmallCaps",
+ "Homerton.Bold.Oblique.SmallCaps",
+ /* serif */
+/*8*/ "Trinity.Medium",
+/*9*/ "Trinity.Medium.Italic",
+/*10*/ "Trinity.Bold",
+/*11*/ "Trinity.Bold.Italic",
+ "Trinity.Medium.SmallCaps",
+ "Trinity.Medium.Italic.SmallCaps",
+ "Trinity.Bold.SmallCaps",
+ "Trinity.Bold.Italic.SmallCaps",
+ /* monospace */
+/*16*/ "Corpus.Medium",
+/*17*/ "Corpus.Medium.Oblique",
+/*18*/ "Corpus.Bold",
+/*19*/ "Corpus.Bold.Oblique",
+ "Corpus.Medium.SmallCaps",
+ "Corpus.Medium.Oblique.SmallCaps",
+ "Corpus.Bold.SmallCaps",
+ "Corpus.Bold.Oblique.SmallCaps",
+ /* cursive */
+/*24*/ "Churchill.Medium",
+/*25*/ "Churchill.Medium.Oblique",
+/*26*/ "Churchill.Bold",
+/*27*/ "Churchill.Bold.Oblique",
+ "Churchill.Medium.SmallCaps",
+ "Churchill.Medium.Oblique.SmallCaps",
+ "Churchill.Bold.SmallCaps",
+ "Churchill.Bold.Oblique.SmallCaps",
+ /* fantasy */
+/*32*/ "Sassoon.Primary",
+/*33*/ "Sassoon.Primary.Oblique",
+/*34*/ "Sassoon.Primary.Bold",
+/*35*/ "Sassoon.Primary.Bold.Oblique",
+ "Sassoon.Primary.SmallCaps",
+ "Sassoon.Primary.Oblique.SmallCaps",
+ "Sassoon.Primary.Bold.SmallCaps",
+ "Sassoon.Primary.Bold.Oblique.SmallCaps",
+};
-const char * const font_table[FONT_FAMILIES * FONT_FACES] = {
+/** Table of Latin1 encoded font names for a pre-UTF-8 capable FontManager.
+ *
+ * font id = font family * 8 + smallcaps * 4 + bold * 2 + slanted
+ *
+ * font family: 0 = sans-serif, 1 = serif, 2 = monospace, 3 = cursive,
+ * 4 = fantasy.
+ * Font family 0 must be available as it is the replacement font when
+ * the other font families can not be found.
+ */
+static const char * const font_table[FONT_FAMILIES * FONT_FACES] = {
/* sans-serif */
/*0*/ "Homerton.Medium\\ELatin1",
/*1*/ "Homerton.Medium.Oblique\\ELatin1",
/*2*/ "Homerton.Bold\\ELatin1",
/*3*/ "Homerton.Bold.Oblique\\ELatin1",
- "Homerton.Medium.SmallCaps\\ELatin1",
- "Homerton.Medium.SmallCaps\\ELatin1\\M65536 0 13930 65536 0 0",
- "Homerton.Bold.SmallCaps\\ELatin1",
- "Homerton.Bold.SmallCaps\\ELatin1\\M65536 0 13930 65536 0 0",
+ "Homerton.Medium.SmallCaps\\ELatin1",
+ "Homerton.Medium.SmallCaps\\ELatin1\\M65536 0 13930 65536 0 0",
+ "Homerton.Bold.SmallCaps\\ELatin1",
+ "Homerton.Bold.SmallCaps\\ELatin1\\M65536 0 13930 65536 0 0",
/* serif */
/*8*/ "Trinity.Medium\\ELatin1",
/*9*/ "Trinity.Medium.Italic\\ELatin1",
/*10*/ "Trinity.Bold\\ELatin1",
/*11*/ "Trinity.Bold.Italic\\ELatin1",
- "Trinity.Medium.SmallCaps\\ELatin1",
- "Trinity.Medium.Italic.SmallCaps\\ELatin1",
- "Trinity.Bold.SmallCaps\\ELatin1",
- "Trinity.Bold.Italic.SmallCaps\\ELatin1",
+ "Trinity.Medium.SmallCaps\\ELatin1",
+ "Trinity.Medium.Italic.SmallCaps\\ELatin1",
+ "Trinity.Bold.SmallCaps\\ELatin1",
+ "Trinity.Bold.Italic.SmallCaps\\ELatin1",
/* monospace */
/*16*/ "Corpus.Medium\\ELatin1",
/*17*/ "Corpus.Medium.Oblique\\ELatin1",
/*18*/ "Corpus.Bold\\ELatin1",
/*19*/ "Corpus.Bold.Oblique\\ELatin1",
- "Corpus.Medium.SmallCaps\\ELatin1",
- "Corpus.Medium.SmallCaps\\ELatin1\\M65536 0 13930 65536 0 0",
- "Corpus.Bold.SmallCaps\\ELatin1",
- "Corpus.Bold.SmallCaps\\ELatin1\\M65536 0 13930 65536 0 0",
+ "Corpus.Medium.SmallCaps\\ELatin1",
+ "Corpus.Medium.SmallCaps\\ELatin1\\M65536 0 13930 65536 0 0",
+ "Corpus.Bold.SmallCaps\\ELatin1",
+ "Corpus.Bold.SmallCaps\\ELatin1\\M65536 0 13930 65536 0 0",
/* cursive */
/*24*/ "Churchill.Medium\\ELatin1",
/*25*/ "Churchill.Medium\\ELatin1\\M65536 0 13930 65536 0 0",
/*26*/ "Churchill.Bold\\ELatin1",
/*27*/ "Churchill.Bold\\ELatin1\\M65536 0 13930 65536 0 0",
- "Churchill.Medium.SmallCaps\\ELatin1",
- "Churchill.Medium.SmallCaps\\ELatin1\\M65536 0 13930 65536 0 0",
- "Churchill.Bold.SmallCaps\\ELatin1",
- "Churchill.Bold.SmallCaps\\ELatin1\\M65536 0 13930 65536 0 0",
- /* fantasy */
+ "Churchill.Medium.SmallCaps\\ELatin1",
+ "Churchill.Medium.SmallCaps\\ELatin1\\M65536 0 13930 65536 0 0",
+ "Churchill.Bold.SmallCaps\\ELatin1",
+ "Churchill.Bold.SmallCaps\\ELatin1\\M65536 0 13930 65536 0 0",
+ /* fantasy */
/*32*/ "Sassoon.Primary\\ELatin1",
/*33*/ "Sassoon.Primary\\ELatin1\\M65536 0 13930 65536 0 0",
/*34*/ "Sassoon.Primary.Bold\\ELatin1",
/*35*/ "Sassoon.Primary.Bold\\ELatin1\\M65536 0 13930 65536 0 0",
- "Sassoon.Primary.SmallCaps\\ELatin1",
- "Sassoon.Primary.SmallCaps\\ELatin1\\M65536 0 13930 65536 0 0",
- "Sassoon.Primary.Bold.SmallCaps\\ELatin1",
- "Sassoon.Primary.Bold.SmallCaps\\ELatin1\\M65536 0 13930 65536 0 0",
+ "Sassoon.Primary.SmallCaps\\ELatin1",
+ "Sassoon.Primary.SmallCaps\\ELatin1\\M65536 0 13930 65536 0 0",
+ "Sassoon.Primary.Bold.SmallCaps\\ELatin1",
+ "Sassoon.Primary.Bold.SmallCaps\\ELatin1\\M65536 0 13930 65536 0 0",
};
-
/**
* Create an empty font_set.
*
* \return an opaque struct font_set.
*/
-
-struct font_set *font_new_set()
+struct font_set *nsfont_new_set(void)
{
- struct font_set *set = xcalloc(1, sizeof(*set));
+ struct font_set *set;
unsigned int i;
- for (i = 0; i < FONT_FAMILIES * FONT_FACES; i++)
- set->font[i] = 0;
+ LOG(("nsfont_new_set()\n"));
- return set;
-}
-
-/**
- * Font enumerator
- *
- * Call this multiple times to enumerate all available font names.
- * *handle should be zero (0) on first call.
- *
- * Returns a NULL pointer and a handle of -1 if there are no more fonts.
- */
-const char *enumerate_fonts(struct font_set* set, int *handle)
-{
- int i;
+ if ((set = malloc(sizeof(*set))) == NULL)
+ return NULL;
- assert(set);
- assert(handle);
- assert(0 <= *handle && *handle <= FONT_FAMILIES * FONT_FACES);
-
- for (i = *handle; i!=FONT_FAMILIES*FONT_FACES && set->font[i]==0;
- i++) ; /* find next font in use */
-
- if (i == FONT_FAMILIES*FONT_FACES) { /* no more fonts */
- *handle = -1;
- return NULL;
- }
+ for (i = 0; i < FONT_FAMILIES * FONT_FACES; i++)
+ set->font[i] = NULL;
- *handle = i+1; /* update handle for next call */
- return font_table[i];
+ return set;
}
/**
* Open a font for use based on a css_style.
*
- * \param set a font_set, as returned by font_new_set()
+ * \param set a font_set, as returned by nsfont_new_set()
* \param style a css_style which describes the font
- * \return a struct font_data, with a RISC OS font handle in handle
+ * \return a struct font_data, with an opaque font handle in handle
*
* The set is updated to include the font, if it was not present.
*/
-
-struct font_data *font_open(struct font_set *set, struct css_style *style)
+struct font_data *nsfont_open(struct font_set *set, struct css_style *style)
{
struct font_data *data;
unsigned int size = option_font_size * 1.6;
unsigned int f = 0;
- font_f handle;
+ int fhandle;
os_error *error;
+ bool using_fb;
- assert(set);
- assert(style);
+ assert(set != NULL);
+ assert(style != NULL);
if (style->font_size.size == CSS_FONT_SIZE_LENGTH)
size = len(&style->font_size.value.length, style) *
@@ -176,31 +215,31 @@ struct font_data *font_open(struct font_set *set, struct css_style *style)
size = 1600;
switch (style->font_family) {
- case CSS_FONT_FAMILY_SANS_SERIF:
- f += FONT_SANS_SERIF;
- break;
- case CSS_FONT_FAMILY_SERIF:
- f += FONT_SERIF;
- break;
- case CSS_FONT_FAMILY_MONOSPACE:
- f += FONT_MONOSPACE;
- break;
- case CSS_FONT_FAMILY_CURSIVE:
- f += FONT_CURSIVE;
- break;
- case CSS_FONT_FAMILY_FANTASY:
- f += FONT_FANTASY;
- break;
- default:
- break;
+ case CSS_FONT_FAMILY_SANS_SERIF:
+ f += FONT_SANS_SERIF;
+ break;
+ case CSS_FONT_FAMILY_SERIF:
+ f += FONT_SERIF;
+ break;
+ case CSS_FONT_FAMILY_MONOSPACE:
+ f += FONT_MONOSPACE;
+ break;
+ case CSS_FONT_FAMILY_CURSIVE:
+ f += FONT_CURSIVE;
+ break;
+ case CSS_FONT_FAMILY_FANTASY:
+ f += FONT_FANTASY;
+ break;
+ default:
+ break;
}
switch (style->font_variant) {
- case CSS_FONT_VARIANT_SMALL_CAPS:
- f += FONT_SMALLCAPS;
- break;
- default:
- break;
+ case CSS_FONT_VARIANT_SMALL_CAPS:
+ f += FONT_SMALLCAPS;
+ break;
+ default:
+ break;
}
switch (style->font_weight) {
@@ -224,30 +263,44 @@ struct font_data *font_open(struct font_set *set, struct css_style *style)
break;
}
- for (data = set->font[f]; data != 0; data = data->next)
+ for (data = set->font[f]; data != NULL; data = data->next)
if (data->size == size)
- return data;
-
- data = xcalloc(1, sizeof(*data));
-
- error = xfont_find_font(font_table[f], (int)size, (int)size,
- 0, 0, &handle, 0, 0);
-
- if (error) { /* fall back to Homerton */
- LOG(("font_find_font failed; falling back to Homerton"));
- error = xfont_find_font(font_table[f % 4],
- (int)size, (int)size,
- 0, 0, &handle, 0, 0);
- if (error) {
- LOG(("%i: %s\n", error->errnum, error->errmess));
- die("font_find_font failed");
- }
- }
-
- data->id = f;
- data->handle = handle;
+ return data;
+
+ if ((data = malloc(sizeof(*data))) == NULL)
+ return NULL;
+
+ /* Strategy : first try the UFont font code with given font name
+ * or the default font name if the former fails.
+ * If this still fails, try the use the default RISC OS font open
+ * in UTF-8 encoding (again first with given font name, then with
+ * the default font name).
+ * If this still fails, we repeat the previous step but now using
+ * the Latin 1 encoding.
+ */
+ if ((error = nsfont_open_ufont(ufont_table[f], ufont_table[f % 4], (int)size, &fhandle, &using_fb)) != NULL) {
+ char fontName1[128], fontName2[128];
+ /* Go for the UTF-8 encoding with standard FontManager */
+ strcpy(fontName1, ufont_table[f]);
+ strcat(fontName1, "\\EUTF8");
+ strcpy(fontName2, ufont_table[f % 4]);
+ strcat(fontName2, "\\EUTF8");
+ if ((error = nsfont_open_standard(fontName1, fontName2, (int)size, &fhandle, &using_fb)) != NULL) {
+ /* All UTF-8 font methods failed, only support Latin 1 */
+ if ((error = nsfont_open_standard(font_table[f], font_table[f % 4], (int)size, &fhandle, &using_fb)) != NULL) {
+ LOG(("(u)font_find_font failed : %s\n", error->errmess));
+ die("(u)font_find_font failed");
+ }
+ data->ftype = FONTTYPE_STANDARD_LATIN1;
+ } else
+ data->ftype = FONTTYPE_STANDARD_UTF8ENC;
+ } else
+ data->ftype = FONTTYPE_UFONT;
+
+ data->id = (using_fb) ? f % 4 : f;
+ data->handle = fhandle;
data->size = size;
- data->space_width = font_width(data, " ", 1);
+ data->space_width = nsfont_width(data, " ", sizeof(" ")-1);
data->next = set->font[f];
set->font[f] = data;
@@ -257,25 +310,95 @@ struct font_data *font_open(struct font_set *set, struct css_style *style)
/**
- * Frees all the fonts in a font_set.
+ * Open font via UFont code.
*
- * \param set a font_set as returned by font_new_set()
+ * \param fontNameP UFont font name
+ * \param fbFontNameP fallback UFont font name
+ * \param size font size
+ * \param handle returning UFont handle in case there isn't an error.
+ * \param using_fb returning whether the fallback font was used or not.
+ * \return error in case there was one.
*/
+static os_error *nsfont_open_ufont(const char *fontNameP, const char *fbFontNameP, int size, int *handleP, bool *using_fb)
+{
+ os_error *errorP;
+ *handleP = 0; *using_fb = false;
+ if ((errorP = xufont_find_font(fontNameP, size, size, 0, 0, (ufont_f *)handleP, NULL, NULL)) == NULL)
+ return NULL;
+ LOG(("ufont_find_font(<%s>) failed <%s> (case 1)", fontNameP, errorP->errmess));
+ /* If the fallback font is the same as the first font name, return */
+ if (strcmp(fontNameP, fbFontNameP) == 0)
+ return errorP;
+ *using_fb = true;
+ if ((errorP = xufont_find_font(fbFontNameP, size, size, 0, 0, (ufont_f *)handleP, NULL, NULL)) == NULL)
+ return NULL;
+ LOG(("ufont_find_font(<%s>) failed <%s> (case 2)", fbFontNameP, errorP->errmess));
+ return errorP;
+}
+
-void font_free_set(struct font_set *set)
+/**
+ * Open font via standard FontManager.
+ *
+ * \param fontNameP RISC OS font name
+ * \param fbFontNameP fallback RISC OS font name
+ * \param size font size
+ * \param handle RISC OS handle in case there isn't an error.
+ * \param using_fb returning whether the fallback font was used or not.
+ * \return error in case there was one.
+ */
+static os_error *nsfont_open_standard(const char *fontNameP, const char *fbFontNameP, int size, int *handleP, bool *using_fb)
+{
+ os_error *errorP;
+ *handleP = 0; *using_fb = false;
+ if ((errorP = xfont_find_font(fontNameP, size, size, 0, 0, (font_f *)handleP, NULL, NULL)) == NULL)
+ return NULL;
+ LOG(("font_find_font(<%s>) failed <%s> (case 1)", fontNameP, errorP->errmess));
+ /* If the fallback font is the same as the first font name, return */
+ if (strcmp(fontNameP, fbFontNameP) == 0)
+ return errorP;
+ *using_fb = true;
+ if ((errorP = xfont_find_font(fbFontNameP, size, size, 0, 0, (font_f *)handleP, NULL, NULL)) == NULL)
+ return NULL;
+ LOG(("font_find_font(<%s>) failed <%s> (case 2)", fbFontNameP, errorP->errmess));
+ return errorP;
+}
+
+
+/**
+ * Frees all the fonts in a font_set.
+ *
+ * \param set a font_set as returned by nsfont_new_set()
+ */
+void nsfont_free_set(struct font_set *set)
{
unsigned int i;
- struct font_data *data, *next;
- assert(set != 0);
+ LOG(("nsfont_free_set()\n"));
+ assert(set != NULL);
for (i = 0; i < FONT_FAMILIES * FONT_FACES; i++) {
- for (data = set->font[i]; data != 0; data = next) {
+ struct font_data *data, *next;
+ for (data = set->font[i]; data != NULL; data = next) {
+ os_error *error;
next = data->next;
- font_lose_font((font_f)(data->handle));
+ switch (data->ftype) {
+ case FONTTYPE_UFONT:
+ error = xufont_lose_font((ufont_f)data->handle);
+ break;
+ case FONTTYPE_STANDARD_UTF8ENC:
+ case FONTTYPE_STANDARD_LATIN1:
+ error = xfont_lose_font((font_f)data->handle);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ if (error != NULL)
+ LOG(("(u)font_lose_font() failed : 0x%x <%s>\n", error->errnum, error->errmess));
free(data);
}
- }
+ }
free(set);
}
@@ -284,31 +407,65 @@ void font_free_set(struct font_set *set)
/**
* Find the width of some text in a font.
*
- * \param font a font_data, as returned by font_open()
+ * \param font a font_data, as returned by nsfont_open()
* \param text string to measure
* \param length length of text
* \return width of text in pixels
*/
-
-unsigned long font_width(struct font_data *font, const char * text, unsigned int length)
+unsigned long nsfont_width(struct font_data *font, const char *text,
+ unsigned int length)
{
int width;
- os_error * error;
+ os_error *error;
- assert(font != 0 && text != 0);
+ assert(font != NULL && text != NULL);
if (length == 0)
return 0;
- error = xfont_scan_string((font_f)(font->handle), text,
- font_GIVEN_FONT | font_KERN | font_GIVEN_LENGTH,
- 0x7fffffff, 0x7fffffff,
- 0,
- 0, (int)length,
- 0, &width, 0, 0);
- if (error != 0) {
- fprintf(stderr, "%s\n", error->errmess);
- die("font_width: font_scan_string failed");
+ switch (font->ftype) {
+ case FONTTYPE_UFONT:
+ error = xufont_scan_string((ufont_f)font->handle,
+ text,
+ font_GIVEN_FONT
+ | font_KERN
+ | font_GIVEN_LENGTH,
+ 0x7fffffff, 0x7fffffff,
+ NULL,
+ NULL, (int)length,
+ NULL, &width, NULL, NULL);
+ break;
+ case FONTTYPE_STANDARD_UTF8ENC:
+ error = xfont_scan_string((font_f)font->handle,
+ text,
+ font_GIVEN_FONT
+ | font_KERN
+ | font_GIVEN_LENGTH,
+ 0x7fffffff, 0x7fffffff,
+ NULL,
+ NULL, (int)length,
+ NULL, &width, NULL, NULL);
+ break;
+ case FONTTYPE_STANDARD_LATIN1: {
+ const char *loc_text = cnv_strn_local_enc(text, length, NULL);
+ error = xfont_scan_string((font_f)font->handle,
+ loc_text,
+ font_GIVEN_FONT
+ | font_KERN,
+ 0x7fffffff, 0x7fffffff,
+ NULL,
+ NULL, 0,
+ NULL, &width, NULL, NULL);
+ free(loc_text);
+ break;
+ }
+ default:
+ assert(0);
+ break;
+ }
+ if (error != NULL) {
+ LOG(("(u)font_scan_string failed : %s\n", error->errmess));
+ die("nsfont_width: (u)font_scan_string failed");
}
return width / 800;
@@ -321,43 +478,79 @@ unsigned long font_width(struct font_data *font, const char * text, unsigned int
* For example, used to find where to position the caret in response to mouse
* click.
*
+ * \param font a font_data, as returned by nsfont_open()
* \param text a string
- * \param font a font_data, as returned by font_open()
* \param length length of text
* \param x horizontal position in pixels
* \param char_offset updated to give the offset in the string
* \param pixel_offset updated to give the coordinate of the character in pixels
*/
-
-void font_position_in_string(const char *text, struct font_data *font,
+void nsfont_position_in_string(struct font_data *font, const char *text,
unsigned int length, unsigned long x,
int *char_offset, int *pixel_offset)
{
- font_scan_block block;
- char *split_point;
- int x_out, y_out, length_out;
os_error *error;
+ font_scan_block block;
+ char *split;
+ int x_out;
- assert(font != 0 && text != 0);
+ assert(font != NULL && text != NULL);
- block.space.x = block.space.y = 0;
- block.letter.x = block.letter.y = 0;
+ block.space.x = block.space.y = block.letter.x = block.letter.y = 0;
block.split_char = -1;
- error = xfont_scan_string((font_f)(font->handle), text,
- font_GIVEN_BLOCK | font_GIVEN_FONT | font_KERN |
- font_RETURN_CARET_POS | font_GIVEN_LENGTH,
- x * 2 * 400,
- 0x7fffffff,
- &block, 0, (int)length,
- &split_point, &x_out, &y_out, &length_out);
- if (error) {
- fprintf(stderr, "%s\n", error->errmess);
- die("font_width: font_scan_string failed");
+ switch (font->ftype) {
+ case FONTTYPE_UFONT:
+ error = xufont_scan_string((ufont_f)font->handle,
+ text,
+ font_GIVEN_BLOCK
+ | font_GIVEN_FONT
+ | font_KERN
+ | font_RETURN_CARET_POS
+ | font_GIVEN_LENGTH,
+ x * 2 * 400, 0x7fffffff,
+ &block, NULL, (int)length,
+ &split, &x_out, NULL, NULL);
+ break;
+ case FONTTYPE_STANDARD_UTF8ENC:
+ error = xfont_scan_string((font_f)font->handle,
+ text,
+ font_GIVEN_BLOCK
+ | font_GIVEN_FONT
+ | font_KERN
+ | font_RETURN_CARET_POS
+ | font_GIVEN_LENGTH,
+ x * 2 * 400, 0x7fffffff,
+ &block, NULL, (int)length,
+ &split, &x_out, NULL, NULL);
+ break;
+ case FONTTYPE_STANDARD_LATIN1: {
+ const ptrdiff_t *back_mapP;
+ const char *loc_text = cnv_strn_local_enc(text, length, &back_mapP);
+ error = xfont_scan_string((font_f)font->handle,
+ loc_text,
+ font_GIVEN_BLOCK
+ | font_GIVEN_FONT
+ | font_KERN
+ | font_RETURN_CARET_POS,
+ x * 2 * 400, 0x7fffffff,
+ &block, NULL, 0,
+ &split, &x_out, NULL, NULL);
+ split = &text[back_mapP[split - loc_text]];
+ free(loc_text); free(back_mapP);
+ break;
+ }
+ default:
+ assert(0);
+ break;
+ }
+ if (error != NULL) {
+ LOG(("(u)font_scan_string failed : %s\n", error->errmess));
+ die("nsfont_position_in_string: (u)font_scan_string failed");
}
- *char_offset = (int)(split_point - text);
- *pixel_offset = x_out / 2 / 400;
+ *char_offset = (int)(split - text);
+ *pixel_offset = x_out / 800;
}
@@ -366,36 +559,83 @@ void font_position_in_string(const char *text, struct font_data *font,
*
* For example, used when wrapping paragraphs.
*
- * \param data a font_data, as returned by font_open()
+ * \param font a font_data, as returned by nsfont_open()
* \param text string to split
* \param length length of text
* \param width available width
* \param used_width updated to actual width used
* \return pointer to character which does not fit
*/
-
-char * font_split(struct font_data *data, const char * text, unsigned int length,
+char *nsfont_split(struct font_data *font, const char *text,
+ unsigned int length,
unsigned int width, unsigned int *used_width)
{
os_error *error;
font_scan_block block;
char *split;
+ assert(font != NULL && text != NULL);
+
block.space.x = block.space.y = block.letter.x = block.letter.y = 0;
block.split_char = ' ';
- error = xfont_scan_string((font_f)(data->handle), text,
- font_GIVEN_BLOCK | font_GIVEN_FONT | font_KERN | font_GIVEN_LENGTH,
- width * 2 * 400, 0x7fffffff,
- &block,
- 0,
- (int)length,
- &split,
- used_width, 0, 0);
- if (error != 0) {
- fprintf(stderr, "%s\n", error->errmess);
- die("font_split: font_scan_string failed");
+ switch (font->ftype) {
+ case FONTTYPE_UFONT:
+ error = xufont_scan_string((ufont_f)font->handle,
+ text,
+ font_GIVEN_BLOCK
+ | font_GIVEN_FONT
+ | font_KERN
+ | font_GIVEN_LENGTH,
+ width * 2 * 400, 0x7fffffff,
+ &block,
+ NULL,
+ (int)length,
+ &split,
+ used_width, NULL, NULL);
+ break;
+ case FONTTYPE_STANDARD_UTF8ENC:
+ error = xfont_scan_string((font_f)font->handle,
+ text,
+ font_GIVEN_BLOCK
+ | font_GIVEN_FONT
+ | font_KERN
+ | font_GIVEN_LENGTH,
+ width * 2 * 400, 0x7fffffff,
+ &block,
+ NULL,
+ (int)length,
+ &split,
+ used_width, NULL, NULL);
+ break;
+ case FONTTYPE_STANDARD_LATIN1: {
+ const ptrdiff_t *back_mapP;
+ const char *loc_text = cnv_strn_local_enc(text, length, &back_mapP);
+ error = xfont_scan_string((font_f)font->handle,
+ loc_text,
+ font_GIVEN_BLOCK
+ | font_GIVEN_FONT
+ | font_KERN,
+ width * 2 * 400, 0x7fffffff,
+ &block,
+ NULL,
+ 0,
+ &split,
+ used_width, NULL, NULL);
+ split = &text[back_mapP[split - loc_text]];
+ free(loc_text); free(back_mapP);
+ break;
+ }
+ default:
+ assert(0);
+ break;
}
+ if (error != NULL) {
+ LOG(("(u)font_scan_string failed : %s\n", error->errmess));
+ die("nsfont_split: (u)font_scan_string failed");
+ }
+
+ assert(split == &text[length] || *split == ' ');
*used_width = *used_width / 2 / 400;
@@ -403,30 +643,163 @@ char * font_split(struct font_data *data, const char * text, unsigned int length
}
-#ifdef TEST
-
-int main(void)
+void nsfont_paint(struct font_data *data, const char *text,
+ int xpos, int ypos, void *trfm, int length)
{
- unsigned int i;
- struct font_set *set;
- struct css_style style;
-
- style.font_family = CSS_FONT_FAMILY_SANS_SERIF;
- style.font_size.size = CSS_FONT_SIZE_LENGTH;
- style.font_weight = CSS_FONT_WEIGHT_BOLD;
- style.font_style = CSS_FONT_STYLE_ITALIC;
+ os_error *error;
+ unsigned int flags;
+
+ flags = font_OS_UNITS | font_GIVEN_FONT | font_KERN;
+ if (trfm != NULL)
+ flags |= font_GIVEN_TRFM;
+
+ /* font background blending (RO3.7+) */
+ if (option_background_blending) {
+ int version;
+
+ /* Font manager versions below 3.35 complain
+ * about this flag being set.
+ */
+ error = xfont_cache_addr(&version, 0, 0);
+ /**\todo should we do anything else on error? */
+ if (!error && version >= 335)
+ flags |= font_BLEND_FONT;
+ }
- set = font_new_set();
+ assert(data != NULL);
+ assert(text != NULL);
- for (i = 10; i != 100; i += 10) {
- style.font_size.value.length.value = i;
- font_open(set, &style);
+ switch (data->ftype) {
+ case FONTTYPE_UFONT:
+ flags |= font_GIVEN_LENGTH;
+ error = xufont_paint((ufont_f)data->handle, text,
+ flags, xpos, ypos, NULL,
+ trfm, length);
+ break;
+ case FONTTYPE_STANDARD_UTF8ENC:
+ flags |= font_GIVEN_LENGTH;
+ error = xfont_paint((font_f)data->handle, text,
+ flags, xpos, ypos, NULL,
+ trfm, length);
+ break;
+ case FONTTYPE_STANDARD_LATIN1: {
+ const char *loc_text = cnv_strn_local_enc(text, length, NULL);
+ error = xfont_paint((font_f)data->handle, loc_text,
+ flags, xpos, ypos, NULL,
+ trfm, 0);
+ free(loc_text);
+ break;
+ }
+ default:
+ assert(0);
+ break;
}
+ if (error != NULL) {
+ LOG(("(u)font_paint failed : %s\n", error->errmess));
+ die("nsfont_paint: (u)font_paint failed");
+ }
+}
- font_free_set(set);
- return 0;
-}
+/**
+ * Given a text line, return the number of bytes which can be set using
+ * one RISC OS font and the bounding box fitting that part of the text
+ * only.
+ *
+ * \param font a font_data, as returned by nsfont_open()
+ * \param text string text. Does not have to be NUL terminated.
+ * \param length length in bytes of the text to consider.
+ * \param width returned width of the text which can be set with one RISC OS font. If 0, then error happened or initial text length was 0.
+ * \param rofontname returned name of the RISC OS font which can be used to set the text. If NULL, then error happened or initial text length was 0.
+ * \param rotext returned string containing the characters in returned RISC OS font. Not necessary NUL terminated. free() after use. If NULL, then error happened or initial text length was 0.
+ * \param rolength length of return rotext string. If 0, then error happened or initial text length was 0.
+ * \param consumed number of bytes of the given text which can be set with one RISC OS font. If 0, then error happened or initial text length was 0.
+ */
+void nsfont_txtenum(struct font_data *font, const char *text,
+ unsigned int length,
+ unsigned int *width,
+ const char **rofontname,
+ const char **rotext,
+ unsigned int *rolength,
+ unsigned int *consumed)
+{
+ assert(font != NULL && text != NULL && rofontname != NULL && rotext != NULL && rolength != NULL && consumed != NULL);
-#endif
+ *rotext = *rofontname = NULL;
+ *consumed = *rolength = *width = 0;
+ if (length == 0)
+ return;
+
+ switch (font->ftype) {
+ case FONTTYPE_UFONT:
+ (void)xufont_txtenum((ufont_f)font->handle,
+ text,
+ font_GIVEN_FONT
+ | font_KERN
+ | font_GIVEN_LENGTH,
+ length,
+ (int *)width,
+ rofontname,
+ rotext,
+ rolength,
+ consumed);
+ *width /= 800;
+ break;
+ case FONTTYPE_STANDARD_UTF8ENC: {
+ static char *fontname[128]; /** /todo: not nice */
+ int rowidth;
+ os_error *error;
+
+ error = xfont_scan_string((font_f)font->handle,
+ text,
+ font_GIVEN_FONT
+ | font_KERN
+ | font_GIVEN_LENGTH,
+ 0x7fffffff, 0x7fffffff,
+ NULL,
+ NULL, (int)length,
+ NULL, &rowidth, NULL, NULL);
+ if (error != NULL)
+ return;
+
+ strcpy(fontname, ufont_table[font->id]);
+ strcat(fontname, "\\EUTF8");
+ if ((*rotext = strndup(text, length)) == NULL)
+ return;
+ *rolength = length;
+ *rofontname = fontname;
+ *consumed = length;
+ *width = rowidth / 800;
+ break;
+ }
+ case FONTTYPE_STANDARD_LATIN1: {
+ int rowidth;
+ os_error *error;
+
+ if ((*rotext = cnv_strn_local_enc(text, length, NULL)) == NULL)
+ return;
+
+ error = xfont_scan_string((font_f)font->handle,
+ *rotext,
+ font_GIVEN_FONT
+ | font_KERN,
+ 0x7fffffff, 0x7fffffff,
+ NULL,
+ NULL, 0,
+ NULL, &width, NULL, NULL);
+ if (error != NULL) {
+ free(*rotext); *rotext = NULL;
+ return;
+ }
+ *rolength = strlen(*rotext);
+ *rofontname = font_table[font->id];
+ *consumed = length;
+ *width = rowidth / 800;
+ break;
+ }
+ default:
+ assert(0);
+ break;
+ }
+}
diff --git a/riscos/gui.c b/riscos/gui.c
index 49c71f77e..054defba7 100644
--- a/riscos/gui.c
+++ b/riscos/gui.c
@@ -927,9 +927,10 @@ void gui_gadget_combo(struct browser_window* bw, struct form_control* g, unsigne
combo_menu->entries[count].sub_menu = wimp_NO_SUB_MENU;
combo_menu->entries[count].icon_flags = wimp_ICON_TEXT | wimp_ICON_INDIRECTED | wimp_ICON_FILLED | wimp_ICON_VCENTRED | (wimp_COLOUR_BLACK << wimp_ICON_FG_COLOUR_SHIFT) | (wimp_COLOUR_WHITE << wimp_ICON_BG_COLOUR_SHIFT) | (wimp_BUTTON_MENU_ICON << wimp_ICON_BUTTON_TYPE_SHIFT);
- combo_menu->entries[count].data.indirected_text.text = o->text;
+ /* \todo combo_menu->entries[count].data.indirected_text.text needs to be free() when menu gets closed. */
+ combo_menu->entries[count].data.indirected_text.text = cnv_str_local_enc(o->text);
combo_menu->entries[count].data.indirected_text.validation = "\0";
- combo_menu->entries[count].data.indirected_text.size = strlen(o->text) + 1;
+ combo_menu->entries[count].data.indirected_text.size = strlen(combo_menu->entries[count].data.indirected_text.text) + 1;
}
wimp_get_pointer_info(&pointer);
diff --git a/riscos/help.c b/riscos/help.c
index 5e782a7a8..f7f40c1fe 100644
--- a/riscos/help.c
+++ b/riscos/help.c
@@ -67,7 +67,7 @@ void ro_gui_interactive_help_request(wimp_message *message) {
/* Ensure we have a help request
*/
if ((!message) || (message->action != message_HELP_REQUEST)) return;
-
+
/* Remember the time of the request
*/
xos_read_monotonic_time(&help_time);
@@ -224,7 +224,7 @@ int ro_gui_interactive_help_available() {
int context = 0;
char *end;
os_t time;
-
+
/* Check if we've received a help request in the last 0.5s to test for generic
interactive help applications
*/
diff --git a/riscos/history.c b/riscos/history.c
index 8655b76dc..70951440c 100644
--- a/riscos/history.c
+++ b/riscos/history.c
@@ -446,11 +446,11 @@ void ro_gui_history_redraw_tree(struct history_entry *he,
else
wimp_set_font_colours(wimp_COLOUR_WHITE, wimp_COLOUR_BLACK);
- font_paint(history_font, he->title,
+ xfont_paint(history_font, he->title,
font_OS_UNITS | font_GIVEN_FONT | font_KERN,
x0 + he->x * FULL_WIDTH + (FULL_WIDTH - he->width) / 2,
y0 - he->y * FULL_HEIGHT - HEIGHT - MARGIN - 24,
- 0, 0, 0);
+ NULL, NULL, 0);
colourtrans_set_gcol(os_COLOUR_MID_DARK_GREY, 0,
diff --git a/riscos/htmlredraw.c b/riscos/htmlredraw.c
index f9afd814e..c06444181 100644
--- a/riscos/htmlredraw.c
+++ b/riscos/htmlredraw.c
@@ -22,6 +22,7 @@
#include "netsurf/render/html.h"
#include "netsurf/riscos/gui.h"
#include "netsurf/riscos/options.h"
+#include "netsurf/riscos/ufont.h"
#include "netsurf/riscos/tinct.h"
#include "netsurf/riscos/toolbar.h"
#include "netsurf/riscos/wimp.h"
@@ -105,7 +106,6 @@ void html_redraw_box(struct content *content, struct box * box,
int padding_width, padding_height;
int x0, y0, x1, y1;
int colour;
- font_string_flags font_flags;
x += box->x * 2 * scale;
y -= box->y * 2 * scale;
@@ -373,31 +373,14 @@ void html_redraw_box(struct content *content, struct box * box,
colourtrans_set_gcol((unsigned int)box->style->color << 8, colourtrans_USE_ECFS, os_ACTION_OVERWRITE, 0);
}
- font_flags = font_OS_UNITS | font_GIVEN_FONT | font_KERN |
- font_GIVEN_LENGTH;
-
- /* font background blending (RO3.7+) */
- if (option_background_blending) {
- int version;
- os_error *e;
-
- /* Font manager versions below 3.35 complain
- * about this flag being set.
- */
- e = xfont_cache_addr(&version, 0, 0);
- /**\todo should we do anything else on error? */
- if (!e && version >= 335)
- font_flags |= font_BLEND_FONT;
- }
if (scale == 1)
- font_paint(box->font->handle, box->text, font_flags,
+ nsfont_paint(box->font, box->text,
x, y - (int) (box->height * 1.5),
- 0, 0, (int) box->length);
+ NULL, (int) box->length);
else
- font_paint(box->font->handle, box->text,
- font_flags | font_GIVEN_TRFM,
+ nsfont_paint(box->font, box->text,
x, y - (int) (box->height * 1.5 * scale),
- 0, &trfm, (int) box->length);
+ &trfm, (int) box->length);
} else {
@@ -571,6 +554,7 @@ void html_redraw_file(int x, int y, int width, int height,
int text_width;
const char *text;
const char *sprite;
+ int length;
if (box->gadget->value) {
text = box->gadget->value;
@@ -579,17 +563,16 @@ void html_redraw_file(int x, int y, int width, int height,
text = messages_get("Form_Drop");
sprite = "drophere";
}
+ length = strlen(text);
- text_width = font_width(box->font, text, strlen(text)) * 2 * scale;
+ text_width = nsfont_width(box->font, text, length) * 2 * scale;
if (width < text_width + 8)
x = x + width - text_width - 4;
else
x = x + 4;
- font_paint(box->font->handle, text,
- font_OS_UNITS | font_GIVEN_FONT |
- font_KERN | font_GIVEN_TRFM,
- x, y - height * 0.75, 0, &trfm, 0);
+ nsfont_paint(box->font, text,
+ x, y - height * 0.75, &trfm, length);
/* xwimpspriteop_put_sprite_user_coords(sprite, x + 4, */
/* y - height / 2 - 17, os_ACTION_OVERWRITE); */
diff --git a/riscos/menus.c b/riscos/menus.c
index b64d56798..bc4c7ef37 100644
--- a/riscos/menus.c
+++ b/riscos/menus.c
@@ -1150,9 +1150,12 @@ void ro_gui_menu_pageinfo(wimp_message_menu_warning *warning)
const char *enc = "-";
const char *mime = "-";
- if (c->title != 0) title = c->title;
- if (c->url != 0) url = c->url;
- if (c->mime_type != 0) mime = c->mime_type;
+ if (c->title != NULL)
+ title = cnv_str_local_enc(c->title);
+ if (c->url != NULL)
+ url = c->url;
+ if (c->mime_type != NULL)
+ mime = c->mime_type;
sprintf(icon_buf, "file_%x", ro_content_filetype(c));
@@ -1166,6 +1169,9 @@ void ro_gui_menu_pageinfo(wimp_message_menu_warning *warning)
ro_gui_set_icon_string(dialog_pageinfo, ICON_PAGEINFO_ENC, enc);
ro_gui_set_icon_string(dialog_pageinfo, ICON_PAGEINFO_TYPE, mime);
+ if (title != NULL)
+ free(title);
+
error = xwimp_create_sub_menu((wimp_menu *) dialog_pageinfo,
warning->pos.x, warning->pos.y);
if (error) {
diff --git a/riscos/mouseactions.c b/riscos/mouseactions.c
index a0b0a3143..db5db2af8 100644
--- a/riscos/mouseactions.c
+++ b/riscos/mouseactions.c
@@ -6,9 +6,7 @@
*/
#include <math.h>
-
#include "oslib/os.h"
-
#include "netsurf/utils/config.h"
#include "netsurf/desktop/browser.h"
#include "netsurf/riscos/gui.h"
diff --git a/riscos/save_draw.c b/riscos/save_draw.c
index c2ea3b752..fcc2ee24a 100644
--- a/riscos/save_draw.c
+++ b/riscos/save_draw.c
@@ -3,6 +3,7 @@
* Licensed under the GNU General Public License,
* http://www.opensource.org/licenses/gpl-license
* Copyright 2004 John M Bell <jmb202@ecs.soton.ac.uk>
+ * Copyright 2004 John Tytgat <John.Tytgat@aaug.net>
*/
#include <assert.h>
@@ -12,7 +13,9 @@
#include "oslib/drawfile.h"
#include "oslib/jpeg.h"
+#include "oslib/osgbpb.h"
#include "oslib/osfile.h"
+#include "oslib/osfind.h"
#include "netsurf/utils/config.h"
#include "netsurf/content/content.h"
@@ -30,22 +33,47 @@
#define A4PAGEWIDTH (744)
#define A4PAGEHEIGHT (1052)
-static bool add_font_table(int **d, unsigned int *length,
- struct content *content);
-static bool add_options(int **d, unsigned int *length);
-static bool add_box(int **d, unsigned int *length, struct box *box,
+/* Must be a power of 2 */
+#define DRAWBUF_INITIAL_SIZE (1<<14)
+
+typedef enum {
+ DrawBuf_eHeader,
+ DrawBuf_eFontTable,
+ DrawBuf_eBody
+} drawbuf_type_e;
+
+typedef struct {
+ byte *bufP;
+ size_t currentSize;
+ size_t maxSize;
+} drawbuf_part_t;
+
+typedef struct {
+ drawbuf_part_t header;
+ drawbuf_part_t fontTable;
+ drawbuf_part_t body;
+ void **fontNamesP; /**< 256 element malloc() pointer array */
+ size_t numFonts;
+} drawbuf_t;
+
+static byte *drawbuf_claim(size_t size, drawbuf_type_e type);
+static void drawbuf_free(void);
+static bool drawbuf_add_font(const char *fontNameP, byte *fontIndex);
+static bool drawbuf_save_file(const char *drawfilename);
+
+static bool add_options(void);
+static bool add_box(struct box *box, unsigned long cbc, long x, long y);
+static bool add_graphic(struct content *content, struct box *box,
unsigned long cbc, long x, long y);
-static bool add_graphic(int **d, unsigned int *length,
- struct content *content, struct box *box,
- unsigned long cbc, long x, long y);
-static bool add_rect(int **d, unsigned int *length, struct box *box,
+static bool add_rect(struct box *box,
unsigned long cbc, long x, long y, bool bg);
-static bool add_line(int **d, unsigned int *length, struct box *box,
- unsigned long cbc, long x, long y);
-static bool add_circle(int **d, unsigned int *length, struct box *box,
- unsigned long cbc, long x, long y);
+static bool add_line(struct box *box, unsigned long cbc, long x, long y);
+static bool add_circle(struct box *box, unsigned long cbc, long x, long y);
+static bool add_text(struct box *box, unsigned long cbc, long x, long y);
+static drawbuf_t oDrawBuf; /* static -> complete struct inited to 0 */
+
/**
* Export a content as a Drawfile.
*
@@ -54,178 +82,278 @@ static bool add_circle(int **d, unsigned int *length, struct box *box,
* \return true on success, false on error and error reported
*/
-bool save_as_draw(struct content *c, char *path)
+bool save_as_draw(struct content *c, const char *path)
{
struct box *box;
int current_width;
unsigned long bc;
- int *d;
- unsigned int length;
- drawfile_diagram *diagram;
- os_error *error;
+ drawfile_diagram_base *diagram;
- if (c->type != CONTENT_HTML) {
+ if (c->type != CONTENT_HTML)
return false;
- }
box = c->data.html.layout->children;
current_width = c->available_width;
- bc = 0xffffff;
-
- d = calloc(40, sizeof(char));
- if (!d) {
- warn_user("NoMemory", 0);
- return false;
- }
- length = 40;
+ if ((diagram = drawbuf_claim(sizeof(drawfile_diagram_base), DrawBuf_eHeader)) == NULL)
+ goto draw_save_error;
- diagram = (drawfile_diagram *) d;
+ /* write the Draw diagram */
memcpy(diagram->tag, "Draw", 4);
diagram->major_version = 201;
diagram->minor_version = 0;
memcpy(diagram->source, "NetSurf ", 12);
/* recalculate box widths for an A4 page */
- if (!layout_document(box, A4PAGEWIDTH, c->data.html.box_pool))
- goto no_memory;
+ if (!layout_document(box, A4PAGEWIDTH, c->data.html.box_pool)) {
+ warn_user("NoMemory", 0);
+ goto draw_save_error;
+ }
diagram->bbox.x0 = 0;
diagram->bbox.y0 = 0;
diagram->bbox.x1 = A4PAGEWIDTH*512;
diagram->bbox.y1 = A4PAGEHEIGHT*512;
- if (!add_font_table(&d, &length, c))
- goto no_memory;
-
- if (!add_options(&d, &length))
- goto no_memory;
+ if (!add_options())
+ goto draw_save_error;
+ bc = 0xffffff;
if (c->data.html.background_colour != TRANSPARENT) {
bc = c->data.html.background_colour;
- if (!add_rect(&d, &length, box, bc<<8, 0,
- A4PAGEHEIGHT*512, true))
- goto no_memory;
+ if (!add_rect(box, bc<<8, 0, A4PAGEHEIGHT*512, true))
+ goto draw_save_error;
}
/* right, traverse the tree and grab the contents */
- if (!add_box(&d, &length, box, bc, 0, A4PAGEHEIGHT*512))
- goto no_memory;
+ if (!add_box(box, bc, 0, A4PAGEHEIGHT*512))
+ goto draw_save_error;
- error = xosfile_save_stamped(path, osfile_TYPE_DRAW, (char *) d,
- (char *) d + length);
+ if (!drawbuf_save_file(path))
+ goto draw_save_error;
- free(d);
-
- if (error) {
- LOG(("xosfile_save_stamped: 0x%x: %s",
- error->errnum, error->errmess));
- warn_user("SaveError", error->errmess);
- /* attempt to reflow back on failure */
- layout_document(box, current_width, c->data.html.box_pool);
- return false;
- }
+ drawbuf_free();
/* reset layout to current window width */
- if (!layout_document(box, current_width, c->data.html.box_pool))
+ if (!layout_document(box, current_width, c->data.html.box_pool)) {
warn_user("NoMemory", 0);
+ return false;
+ }
return true;
-no_memory:
- free(d);
+draw_save_error:
+ drawbuf_free();
/* attempt to reflow back on failure */
- layout_document(box, current_width, c->data.html.box_pool);
- warn_user("NoMemory", 0);
+ (void)layout_document(box, current_width, c->data.html.box_pool);
return false;
}
/**
- * add font table
+ * Claim size number of bytes available in that
+ * particular buffer.
+ *
+ * \param size number of bytes to claim
+ * \param type defines which Draw buffer needs its size to be ensured
+ * \return non NULL when buffer size got correctly claimed, NULL on failure
*/
-bool add_font_table(int **d, unsigned int *length,
- struct content *content)
+static byte *drawbuf_claim(size_t size, drawbuf_type_e type)
{
- int *d2;
- unsigned int length0 = *length;
- unsigned int i;
- unsigned int padding;
- int handle = 0;
- int ftlen = 0;
- const char *name;
- drawfile_object *dro;
- drawfile_font_table *ft;
+ drawbuf_part_t *drawBufPartP;
- d2 = realloc(*d, *length += 8);
- if (!d2)
- return false;
- *d = d2;
- dro = (drawfile_object *) (*d + length0 / sizeof *d);
- ft = &dro->data.font_table;
+ switch (type) {
+ case DrawBuf_eHeader:
+ drawBufPartP = &oDrawBuf.header;
+ break;
+ case DrawBuf_eFontTable:
+ drawBufPartP = &oDrawBuf.fontTable;
+ break;
+ case DrawBuf_eBody:
+ drawBufPartP = &oDrawBuf.body;
+ break;
+ default:
+ assert(0);
+ }
- dro->type = drawfile_TYPE_FONT_TABLE;
+ if (drawBufPartP->bufP == NULL) {
+ const size_t sizeNeeded = (size > DRAWBUF_INITIAL_SIZE) ? size : DRAWBUF_INITIAL_SIZE;
+ if ((drawBufPartP->bufP = malloc(sizeNeeded)) == NULL) {
+ warn_user("NoMemory", 0);
+ return NULL;
+ }
+ drawBufPartP->currentSize = size;
+ drawBufPartP->maxSize = sizeNeeded;
+ } else if (drawBufPartP->maxSize < drawBufPartP->currentSize + size) {
+ size_t sizeNeeded = drawBufPartP->maxSize;
+ while ((sizeNeeded *= 2) < drawBufPartP->currentSize + size)
+ ;
+ if ((drawBufPartP->bufP = realloc(drawBufPartP->bufP, sizeNeeded)) == NULL) {
+ warn_user("NoMemory", 0);
+ return NULL;
+ }
+ drawBufPartP->currentSize += size;
+ drawBufPartP->maxSize = sizeNeeded;
+ } else {
+ drawBufPartP->currentSize += size;
+ }
- do {
- name = enumerate_fonts(content->data.html.fonts, &handle);
- if (handle == -1 && name == 0)
- break;
+ return drawBufPartP->bufP + drawBufPartP->currentSize - size;
+}
- /* at this point, handle is always (font_table entry + 1) */
- d2 = realloc(*d, *length += 1 + strlen(name) + 1);
- if (!d2)
- return false;
- *d = d2;
- dro = (drawfile_object *) (*d + length0 / sizeof *d);
- ft = &dro->data.font_table;
- ((char *) ft)[ftlen] = handle;
- strcpy(((char *) ft) + ftlen + 1, name);
+/**
+ * Frees all the Draw buffers.
+ */
+static void drawbuf_free(void)
+{
+ free(oDrawBuf.header.bufP); oDrawBuf.header.bufP = NULL;
+ free(oDrawBuf.fontTable.bufP); oDrawBuf.fontTable.bufP = NULL;
+ free(oDrawBuf.body.bufP); oDrawBuf.body.bufP = NULL;
+ if (oDrawBuf.fontNamesP != NULL) {
+ while (oDrawBuf.numFonts > 0)
+ free(oDrawBuf.fontNamesP[--oDrawBuf.numFonts]);
+ free(oDrawBuf.fontNamesP); oDrawBuf.fontNamesP = NULL;
+ }
+ oDrawBuf.numFonts = 0;
+}
- ftlen += 1 + strlen(name) + 1;
- } while (handle != -1);
- /* word align end of list */
- padding = (ftlen + 3) / 4 * 4 - ftlen;
+/**
+ * Return a font index for given RISC OS font name.
+ *
+ * \param fontNameP NUL terminated RISC OS font name.
+ * \param fontIndex Returned font index 0 - 255 for given font name.
+ * \return true on success, false on error and error reported
+ */
+static bool drawbuf_add_font(const char *fontNameP, byte *fontIndex)
+{
+ size_t index;
- d2 = realloc(*d, *length + padding);
- if (!d2)
+ for (index = 0; index < oDrawBuf.numFonts; ++index) {
+ if (!strcmp(oDrawBuf.fontNamesP[index], fontNameP)) {
+ *fontIndex = (byte)index + 1;
+ return true;
+ }
+ }
+
+ /* Only max 255 RISC OS outline fonts can be stored in a Draw
+ * file.
+ */
+ if (oDrawBuf.numFonts == 255)
+ return false; /** \todo: report GUI error */
+
+ if (oDrawBuf.fontNamesP == NULL
+ && ((oDrawBuf.fontNamesP = malloc(255 * sizeof(void *))) == NULL)) {
+ warn_user("NoMemory", 0);
+ return false;
+ }
+
+ *fontIndex = (byte)oDrawBuf.numFonts + 1;
+ if ((oDrawBuf.fontNamesP[oDrawBuf.numFonts++] = strdup(fontNameP)) == NULL)
return false;
- *d = d2;
- dro = (drawfile_object *) (*d + length0 / sizeof *d);
- ft = &dro->data.font_table;
- for (i = 0; i != padding; i++)
- ((char *) *d)[*length + i] = 0;
- *length += padding;
- ftlen += padding;
+ return true;
+}
+
+
+/**
+ * Save the Draw file from memory to disk.
+ *
+ * \param drawfilename RISC OS filename where to save the Draw file.
+ * \return true on success, false on error and error reported
+ */
+static bool drawbuf_save_file(const char *drawfilename)
+{
+ size_t index;
+ os_fw *handle = NULL;
+ os_error *error;
+
+ /* create font table (if needed). */
+ if (oDrawBuf.numFonts > 0) {
+ drawfile_object *dro;
+
+ if ((dro = drawbuf_claim(8, DrawBuf_eFontTable)) == NULL)
+ goto file_save_error;
+
+ dro->type = drawfile_TYPE_FONT_TABLE;
+ /* we can't write dro->size yet. */
+
+ for (index = 0; index < oDrawBuf.numFonts; ++index) {
+ const char *fontNameP = oDrawBuf.fontNamesP[index];
+ size_t len = 1 + strlen(fontNameP) + 1;
+ byte *bufP;
+
+ if ((bufP = drawbuf_claim(len, DrawBuf_eFontTable)) == NULL)
+ goto file_save_error;
+ *bufP++ = (byte)index + 1;
+ memcpy(bufP, fontNameP, len + 1);
+ }
+ /* align to next word boundary */
+ if (oDrawBuf.fontTable.currentSize % 4) {
+ size_t wordpad = 4 - (oDrawBuf.fontTable.currentSize & 3);
+ byte *bufP;
+
+ if ((bufP = drawbuf_claim(wordpad, DrawBuf_eFontTable)) == NULL)
+ goto file_save_error;
+ memset(bufP, '\0', wordpad);
+ }
+
+ /* note that at the point it can be that
+ * dro != oDrawBuf.fontTable.bufP
+ */
+ ((drawfile_object *)oDrawBuf.fontTable.bufP)->size = oDrawBuf.fontTable.currentSize;
+ }
+
+ if ((error = xosfind_openoutw(osfind_NO_PATH, drawfilename, NULL, &handle)) != NULL)
+ goto file_save_error;
+
+ /* write Draw header */
+ if ((error = xosgbpb_writew(handle, oDrawBuf.header.bufP, oDrawBuf.header.currentSize, NULL)) != NULL)
+ goto file_save_error;
+
+ /* write font table (if needed) */
+ if (oDrawBuf.fontTable.bufP != NULL
+ && (error = xosgbpb_writew(handle, oDrawBuf.fontTable.bufP, oDrawBuf.fontTable.currentSize, NULL)) != NULL)
+ goto file_save_error;
+
+ /* write Draw body */
+ if ((error = xosgbpb_writew(handle, oDrawBuf.body.bufP, oDrawBuf.body.currentSize, NULL)) != NULL)
+ goto file_save_error;
- dro->size = 8 + ftlen;
+ if ((error = xosfind_closew(handle)) != NULL)
+ goto file_save_error;
+
+ if ((error = xosfile_set_type(drawfilename, osfile_TYPE_DRAW)) != NULL)
+ goto file_save_error;
return true;
+
+file_save_error:
+ LOG(("drawbuf_save_file() error: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("SaveError", error->errmess);
+ if (handle != NULL)
+ (void)xosfind_closew(handle);
+ return false;
}
/**
* add options object
*/
-bool add_options(int **d, unsigned int *length)
+bool add_options(void)
{
- int *d2;
- unsigned int length0 = *length;
drawfile_object *dro;
drawfile_options *dfo;
- d2 = realloc(*d, *length += 8 + 80);
- if (!d2)
+ if ((dro = drawbuf_claim(8 + sizeof(drawfile_options), DrawBuf_eBody)) == NULL)
return false;
- *d = d2;
- dro = (drawfile_object *) (*d + length0 / sizeof *d);
- dfo = &dro->data.options;
dro->type = drawfile_TYPE_OPTIONS;
- dro->size = 8 + 80;
+ dro->size = 8 + sizeof(drawfile_options);
+ dfo = &dro->data.options;
dfo->bbox.x0 = dfo->bbox.y0 = dfo->bbox.x1 = dfo->bbox.y1 = 0;
dfo->paper_size = 0x500; /* A4 */
dfo->paper_options = (drawfile_paper_options)0;
@@ -250,33 +378,24 @@ bool add_options(int **d, unsigned int *length)
/**
* Traverses box tree, adding objects to the diagram as it goes.
*/
-bool add_box(int **d, unsigned int *length, struct box *box,
- unsigned long cbc, long x, long y)
+bool add_box(struct box *box, unsigned long cbc, long x, long y)
{
- int *d2;
- unsigned int length0 = *length;
struct box *c;
- int width, height, colour;
- unsigned int i;
- drawfile_object *dro;
- drawfile_text *dt;
x += box->x * 512;
y -= box->y * 512;
- width = (box->padding[LEFT] + box->width + box->padding[RIGHT]) * 2;
- height = (box->padding[TOP] + box->height + box->padding[BOTTOM]) * 2;
if (box->style && box->style->visibility == CSS_VISIBILITY_HIDDEN) {
- for (c = box->children; c; c = c->next) {
- if (!add_box(d, length, c, cbc, x, y))
+ for (c = box->children; c != NULL; c = c->next) {
+ if (!add_box(c, cbc, x, y))
return false;
}
return true;
}
- if (box->style != 0 && box->style->background_color != TRANSPARENT) {
+ if (box->style && box->style->background_color != TRANSPARENT) {
cbc = box->style->background_color;
- if (!add_rect(d, length, box, cbc<<8, x, y, false))
+ if (!add_rect(box, cbc<<8, x, y, false))
return false;
}
@@ -290,28 +409,25 @@ bool add_box(int **d, unsigned int *length, struct box *box,
#ifdef WITH_SPRITE
case CONTENT_SPRITE:
#endif
- return add_graphic(d, length, box->object,
+ return add_graphic(box->object,
box, cbc, x, y);
case CONTENT_HTML:
c = box->object->data.html.layout->children;
- return add_box(d, length, c, cbc, x, y);
-
- default:
- break;
+ return add_box(c, cbc, x, y);
}
} else if (box->gadget && box->gadget->type == GADGET_CHECKBOX) {
- return add_rect(d, length, box, 0xDEDEDE00, x, y, false);
+ return add_rect(box, 0xDEDEDE00, x, y, false);
} else if (box->gadget && box->gadget->type == GADGET_RADIO) {
- return add_circle(d, length, box, 0xDEDEDE00, x, y);
+ return add_circle(box, 0xDEDEDE00, x, y);
} else if (box->text && box->font) {
+ int colour;
- if (box->length == 0) {
+ if (box->length == 0)
return true;
- }
/* text-decoration */
colour = box->style->color;
@@ -319,64 +435,33 @@ bool add_box(int **d, unsigned int *length, struct box *box,
| (((((colour >> 8) & 0xff) +
((cbc >> 8) & 0xff)) / 2) << 8)
| ((((colour & 0xff) + (cbc & 0xff)) / 2) << 0);
- if (box->style->text_decoration & CSS_TEXT_DECORATION_UNDERLINE || (box->parent->parent->style->text_decoration & CSS_TEXT_DECORATION_UNDERLINE && box->parent->parent->type == BOX_BLOCK)) {
- if (!add_line(d, length, box, (unsigned)colour<<8,
+ if (box->style->text_decoration & CSS_TEXT_DECORATION_UNDERLINE
+ || (box->parent->parent->style->text_decoration & CSS_TEXT_DECORATION_UNDERLINE && box->parent->parent->type == BOX_BLOCK)) {
+ if (!add_line(box, (unsigned)colour<<8,
x, (int)(y+(box->height*0.1*512))))
return false;
}
- if (box->style->text_decoration & CSS_TEXT_DECORATION_OVERLINE || (box->parent->parent->style->text_decoration & CSS_TEXT_DECORATION_OVERLINE && box->parent->parent->type == BOX_BLOCK)) {
- if (!add_line(d, length, box, (unsigned)colour<<8,
+ if (box->style->text_decoration & CSS_TEXT_DECORATION_OVERLINE
+ || (box->parent->parent->style->text_decoration & CSS_TEXT_DECORATION_OVERLINE && box->parent->parent->type == BOX_BLOCK)) {
+ if (!add_line(box, (unsigned)colour<<8,
x, (int)(y+(box->height*0.9*512))))
return false;
}
if (box->style->text_decoration & CSS_TEXT_DECORATION_LINE_THROUGH || (box->parent->parent->style->text_decoration & CSS_TEXT_DECORATION_LINE_THROUGH && box->parent->parent->type == BOX_BLOCK)) {
- if (!add_line(d, length, box, (unsigned)colour<<8,
+ if (!add_line(box, (unsigned)colour<<8,
x, (int)(y+(box->height*0.4*512))))
return false;
}
- /* normal text */
- length0 = *length;
- d2 = realloc(*d, *length += 8 + 44 +
- (box->length + 1 + 3) / 4 * 4);
- if (!d2)
- return false;
- *d = d2;
- dro = (drawfile_object *) (*d + length0 / sizeof *d);
- dt = &dro->data.text;
-
- dro->type = drawfile_TYPE_TEXT;
- dro->size = 8 + 44 + (box->length + 1 + 3) / 4 * 4;
-
- dt->bbox.x0 = x;
- dt->bbox.y0 = y-(box->height*1.5*512);
- dt->bbox.x1 = x+(box->width*512);
- dt->bbox.y1 = y;
- dt->fill = box->style->color<<8;
- dt->bg_hint = cbc<<8;
- dt->style.font_index = box->font->id + 1;
- dt->style.reserved[0] = 0;
- dt->style.reserved[1] = 0;
- dt->style.reserved[2] = 0;
- dt->xsize = box->font->size*40;
- dt->ysize = box->font->size*40;
- dt->base.x = x;
- dt->base.y = y-(box->height*512)+1536;
- strncpy(dt->text, box->text, box->length);
- dt->text[box->length] = 0;
- for (i = box->length + 1; i % 4; i++)
- dt->text[i] = 0;
-
- return true;
-
+ return add_text(box, cbc, x, y);
} else {
for (c = box->children; c != 0; c = c->next) {
if (c->type != BOX_FLOAT_LEFT && c->type != BOX_FLOAT_RIGHT)
- if (!add_box(d, length, c, cbc, x, y))
+ if (!add_box(c, cbc, x, y))
return false;
}
for (c = box->float_children; c != 0; c = c->next_float) {
- if (!add_box(d, length, c, cbc, x, y))
+ if (!add_box(c, cbc, x, y))
return false;
}
}
@@ -386,79 +471,68 @@ bool add_box(int **d, unsigned int *length, struct box *box,
/**
- * Add images to the drawfile. Uses add_jpeg as a helper.
+ * Add images to the drawfile.
*/
-bool add_graphic(int **d, unsigned int *length,
- struct content *content, struct box *box,
- unsigned long cbc, long x, long y) {
-
- int *d2;
- unsigned int length0 = *length;
- int sprite_length = 0;
+bool add_graphic(struct content *content, struct box *box,
+ unsigned long cbc, long x, long y)
+{
+ int sprite_length;
drawfile_object *dro;
drawfile_sprite *ds;
/* cast-tastic... */
switch (content->type) {
- case CONTENT_JPEG:
- sprite_length = ((osspriteop_header*)((char*)content->data.jpeg.sprite_area+content->data.jpeg.sprite_area->first))->size;
- break;
+ case CONTENT_JPEG:
+ sprite_length = ((osspriteop_header*)((char*)content->data.jpeg.sprite_area+content->data.jpeg.sprite_area->first))->size;
+ break;
#ifdef WITH_PNG
- case CONTENT_PNG:
- sprite_length = ((osspriteop_header*)((char*)content->data.png.sprite_area+content->data.png.sprite_area->first))->size;
- break;
+ case CONTENT_PNG:
+ sprite_length = ((osspriteop_header*)((char*)content->data.png.sprite_area+content->data.png.sprite_area->first))->size;
+ break;
#endif
- case CONTENT_GIF:
- sprite_length = content->data.gif.gif->frame_image->size;
- break;
+ case CONTENT_GIF:
+ sprite_length = content->data.gif.gif->frame_image->size;
+ break;
#ifdef WITH_SPRITE
- case CONTENT_SPRITE:
- sprite_length = ((osspriteop_header*)((char*)content->data.sprite.data+(((osspriteop_area*)content->data.sprite.data)->first)))->size;
- break;
+ case CONTENT_SPRITE:
+ sprite_length = ((osspriteop_header*)((char*)content->data.sprite.data+(((osspriteop_area*)content->data.sprite.data)->first)))->size;
+ break;
#endif
- default:
- assert(0);
+ default:
+ assert(0);
}
- d2 = realloc(*d, *length += 8 + 16 + sprite_length);
- if (!d2)
+ if ((dro = (drawfile_object *)drawbuf_claim(8 + 16 + sprite_length, DrawBuf_eBody)) == NULL)
return false;
- *d = d2;
- dro = (drawfile_object *) (*d + length0 / sizeof *d);
- ds = &dro->data.sprite;
dro->type = drawfile_TYPE_SPRITE;
dro->size = 8 + 16 + sprite_length;
+ ds = &dro->data.sprite;
ds->bbox.x0 = x;
- ds->bbox.y0 = y-((box->padding[TOP] + box->height + box->padding[BOTTOM])*512);
- ds->bbox.x1 = x+((box->padding[LEFT] + box->width + box->padding[RIGHT])*512);
-
+ ds->bbox.y0 = y - (box->padding[TOP] + box->height + box->padding[BOTTOM])*512;
+ ds->bbox.x1 = x + (box->padding[LEFT] + box->width + box->padding[RIGHT])*512;
ds->bbox.y1 = y;
switch (content->type) {
- case CONTENT_JPEG:
- memcpy((char*)ds+16, (char*)content->data.jpeg.sprite_area+content->data.jpeg.sprite_area->first,
- (unsigned)sprite_length);
- break;
+ case CONTENT_JPEG:
+ memcpy((char*)ds+16, (char*)content->data.jpeg.sprite_area+content->data.jpeg.sprite_area->first, (unsigned)sprite_length);
+ break;
#ifdef WITH_PNG
- case CONTENT_PNG:
- memcpy((char*)ds+16, (char*)content->data.png.sprite_area+content->data.png.sprite_area->first,
- (unsigned)sprite_length);
- break;
+ case CONTENT_PNG:
+ memcpy((char*)ds+16, (char*)content->data.png.sprite_area+content->data.png.sprite_area->first, (unsigned)sprite_length);
+ break;
#endif
- case CONTENT_GIF:
- memcpy((char*)ds+16, (char*)content->data.gif.gif->frame_image,
- (unsigned)sprite_length);
- break;
+ case CONTENT_GIF:
+ memcpy((char*)ds+16, (char*)content->data.gif.gif->frame_image, (unsigned)sprite_length);
+ break;
#ifdef WITH_SPRITE
- case CONTENT_SPRITE:
- memcpy((char*)ds+16, (char*)content->data.sprite.data+((osspriteop_area*)content->data.sprite.data)->first,
- (unsigned)sprite_length);
- break;
+ case CONTENT_SPRITE:
+ memcpy((char*)ds+16, (char*)content->data.sprite.data+((osspriteop_area*)content->data.sprite.data)->first, (unsigned)sprite_length);
+ break;
#endif
- default:
- assert(0);
+ default:
+ assert(0);
}
return true;
@@ -469,25 +543,20 @@ bool add_graphic(int **d, unsigned int *length,
* Add a filled, borderless rectangle to the diagram
* Set bg to true to produce the background rectangle.
*/
-bool add_rect(int **d, unsigned int *length, struct box *box,
- unsigned long cbc, long x, long y, bool bg) {
-
- int *d2;
- unsigned int length0 = *length;
+bool add_rect(struct box *box,
+ unsigned long cbc, long x, long y, bool bg)
+{
drawfile_object *dro;
drawfile_path *dp;
draw_path_element *dpe;
- d2 = realloc(*d, *length += 8 + 96);
- if (!d2)
+ if ((dro = (drawfile_object *)drawbuf_claim(8 + 96, DrawBuf_eBody)) == NULL)
return false;
- *d = d2;
- dro = (drawfile_object *) (*d + length0 / sizeof *d);
- dp = &dro->data.path;
dro->type = drawfile_TYPE_PATH;
dro->size = 8 + 96;
+ dp = &dro->data.path;
if (bg) {
dp->bbox.x0 = 0;
dp->bbox.y0 = 0;
@@ -495,8 +564,8 @@ bool add_rect(int **d, unsigned int *length, struct box *box,
dp->bbox.y1 = A4PAGEHEIGHT*512;
} else {
dp->bbox.x0 = x;
- dp->bbox.y0 = y-((box->padding[TOP] + box->height + box->padding[BOTTOM])*512);
- dp->bbox.x1 = x+((box->padding[LEFT] + box->width + box->padding[RIGHT])*512);
+ dp->bbox.y0 = y - (box->padding[TOP] + box->height + box->padding[BOTTOM])*512;
+ dp->bbox.x1 = x + (box->padding[LEFT] + box->width + box->padding[RIGHT])*512;
dp->bbox.y1 = y;
}
@@ -560,28 +629,22 @@ bool add_rect(int **d, unsigned int *length, struct box *box,
/**
* add a line to the diagram
*/
-bool add_line(int **d, unsigned int *length, struct box *box,
- unsigned long cbc, long x, long y) {
-
- int *d2;
- unsigned int length0 = *length;
+bool add_line(struct box *box, unsigned long cbc, long x, long y)
+{
drawfile_object *dro;
drawfile_path *dp;
draw_path_element *dpe;
- d2 = realloc(*d, *length += 8 + 60);
- if (!d2)
+ if ((dro = (drawfile_object *)drawbuf_claim(8 + 60, DrawBuf_eBody)) == NULL)
return false;
- *d = d2;
- dro = (drawfile_object *) (*d + length0 / sizeof *d);
- dp = &dro->data.path;
dro->type = drawfile_TYPE_PATH;
dro->size = 8 + 60;
+ dp = &dro->data.path;
dp->bbox.x0 = x;
- dp->bbox.y0 = y-((box->padding[TOP] + box->height + box->padding[BOTTOM])*512);
- dp->bbox.x1 = x+((box->padding[LEFT] + box->width + box->padding[RIGHT])*512);
+ dp->bbox.y0 = y - (box->padding[TOP] + box->height + box->padding[BOTTOM])*512;
+ dp->bbox.x1 = x + (box->padding[LEFT] + box->width + box->padding[RIGHT])*512;
dp->bbox.y1 = y;
dp->fill = cbc;
@@ -618,46 +681,39 @@ bool add_line(int **d, unsigned int *length, struct box *box,
/**
* add a circle to the diagram.
*/
-bool add_circle(int **d, unsigned int *length, struct box *box,
- unsigned long cbc, long x, long y) {
-
- int *d2;
- unsigned int length0 = *length;
- double radius = 0, kappa;
+bool add_circle(struct box *box, unsigned long cbc, long x, long y)
+{
+ double radius, kappa;
double cx, cy;
drawfile_object *dro;
drawfile_path *dp;
draw_path_element *dpe;
- d2 = realloc(*d, *length += 8 + 160);
- if (!d2)
+ if ((dro = (drawfile_object *)drawbuf_claim(8 + 160, DrawBuf_eBody)) == NULL)
return false;
- *d = d2;
- dro = (drawfile_object *) (*d + length0 / sizeof *d);
- dp = &dro->data.path;
dro->type = drawfile_TYPE_PATH;
dro->size = 8 + 160;
+ dp = &dro->data.path;
dp->bbox.x0 = x;
- dp->bbox.y0 = y-((box->padding[TOP] + box->height + box->padding[BOTTOM])*512);
- dp->bbox.x1 = x+((box->padding[LEFT] + box->width + box->padding[RIGHT])*512);
+ dp->bbox.y0 = y - (box->padding[TOP] + box->height + box->padding[BOTTOM])*512;
+ dp->bbox.x1 = x + (box->padding[LEFT] + box->width + box->padding[RIGHT])*512;
dp->bbox.y1 = y;
- cx = ((dp->bbox.x1-dp->bbox.x0)/2.0);
- cy = ((dp->bbox.y1-dp->bbox.y0)/2.0);
- if (cx == cy) {
- radius = cx; /* box is square */
- }
+ cx = (dp->bbox.x1 - dp->bbox.x0) / 2.;
+ cy = (dp->bbox.y1 - dp->bbox.y0) / 2.;
+ if (cx == cy)
+ radius = cx; /* box is square */
else if (cx > cy) {
radius = cy;
- dp->bbox.x1 -= (cx-cy); /* reduce box width */
+ dp->bbox.x1 -= cx - cy; /* reduce box width */
}
else if (cy > cx) {
radius = cx;
- dp->bbox.y0 += (cy-cx); /* reduce box height */
+ dp->bbox.y0 += cy - cx; /* reduce box height */
}
- kappa = radius * ((4.0/3.0)*(sqrt(2.0)-1.0)); /* ~= 0.5522847498 */
+ kappa = radius * 4. * (sqrt(2.) - 1.) / 3.; /* ~= 0.5522847498 */
dp->fill = cbc;
dp->outline = cbc;
@@ -665,11 +721,11 @@ bool add_circle(int **d, unsigned int *length, struct box *box,
dp->style.flags = drawfile_PATH_ROUND;
/*
- * Z b Y
+ * Z b Y
*
- * a X c
+ * a X c
*
- * V d W
+ * V d W
*
* V = (x0,y0)
* W = (x1,y0)
@@ -744,4 +800,70 @@ bool add_circle(int **d, unsigned int *length, struct box *box,
return true;
}
+
+/**
+ * Add the text line to the diagram.
+ */
+static bool add_text(struct box *box, unsigned long cbc, long x, long y)
+{
+ const char *txt = box->text;
+ size_t txt_len = box->length;
+
+ while (txt_len != 0) {
+ unsigned int width, rolength, consumed;
+ const char *rofontname, *rotext;
+ byte fontIndex;
+ drawfile_object *dro;
+ drawfile_text *dt;
+
+ nsfont_txtenum(box->font, txt, txt_len,
+ &width,
+ &rofontname,
+ &rotext,
+ &rolength,
+ &consumed);
+ LOG(("txtenum <%.*s> (%d bytes), returned width %d, font name <%s>, RISC OS text <%.*s>, consumed %d\n", txt_len, txt, txt_len, width, rofontname, rolength, rotext, consumed));
+ /* Error happened ? */
+ if (rotext == NULL)
+ return false;
+
+ if (!drawbuf_add_font(rofontname, &fontIndex))
+ return false;
+
+ if ((dro = (drawfile_object *)drawbuf_claim(8 + 44 + ((rolength + 1 + 3) & -4), DrawBuf_eBody)) == NULL)
+ return false;
+
+ dro->type = drawfile_TYPE_TEXT;
+ dro->size = 8 + 44 + ((rolength + 1 + 3) & -4);
+
+ dt = &dro->data.text;
+ dt->bbox.x0 = x;
+ dt->bbox.y0 = y - box->height*1.5*512;
+ dt->bbox.x1 = x + width*512;
+ dt->bbox.y1 = y;
+ dt->fill = box->style->color << 8;
+ dt->bg_hint = cbc << 8;
+ dt->style.font_index = fontIndex;
+ dt->style.reserved[0] = 0;
+ dt->style.reserved[1] = 0;
+ dt->style.reserved[2] = 0;
+ dt->xsize = box->font->size*40;
+ dt->ysize = box->font->size*40;
+ dt->base.x = x;
+ dt->base.y = y - box->height*512 + 1536;
+ strncpy(dt->text, rotext, rolength);
+ dt->text[rolength] = 0;
+ for (++rolength; rolength % 4; ++rolength)
+ dt->text[rolength] = 0;
+
+ free(rotext);
+
+ /* Go to next chunk : */
+ x += width * 512;
+ txt += consumed;
+ txt_len -= consumed;
+ }
+
+ return true;
+}
#endif
diff --git a/riscos/save_draw.h b/riscos/save_draw.h
index 3d333c945..bb31b56d0 100644
--- a/riscos/save_draw.h
+++ b/riscos/save_draw.h
@@ -10,6 +10,6 @@
struct content;
-bool save_as_draw(struct content *c, char *path);
+bool save_as_draw(struct content *c, const char *path);
#endif
diff --git a/riscos/toolbar.c b/riscos/toolbar.c
index f8971283e..3023a1a25 100644
--- a/riscos/toolbar.c
+++ b/riscos/toolbar.c
@@ -70,8 +70,7 @@ static wimp_window empty_window = {
12,
1,
{""},
- 0,
- { }
+ 0
};
/* Holder for quick icon creation
diff --git a/riscos/ufont.c b/riscos/ufont.c
new file mode 100644
index 000000000..37767ccfe
--- /dev/null
+++ b/riscos/ufont.c
@@ -0,0 +1,1281 @@
+/* ufont.c
+ * Licensed under the GNU General Public License,
+ * http://www.opensource.org/licenses/gpl-license
+ * Copyright 2000 James Bursa <bursa@users.sourceforge.net>
+ * Copyright 2004 John Tytgat <John.Tytgat@aaug.net>
+ */
+
+/** \file
+ * UFont - Unicode wrapper for non-Unicode aware FontManager
+ *
+ * This code allows non-Unicode aware FontManager to be used for
+ * displaying Unicode encoded text lines. It needs the !UFont
+ * resource (accessed via UFont$Path).
+ */
+
+#include <assert.h>
+#include <limits.h>
+#include <wchar.h>
+
+#include "oslib/osfile.h"
+
+#include "ufont.h"
+#include "utils/utils.h" /* \todo: has to go ! */
+
+// #define DEBUG_UFONT
+// #define DEBUG_ACTIVATE_SANITY_CHECK
+
+#ifdef DEBUG_UFONT
+# define dbg_fprintf fprintf
+#else
+# define dbg_fprintf (1)?0:fprintf
+#endif
+#ifdef DEBUG_ACTIVATE_SANITY_CHECK
+# define do_sanity_check sanity_check
+#else
+# define do_sanity_check (1)?0:sanity_check
+#endif
+#define MALLOC_CHUNK 256
+
+typedef struct usage_chain_s usage_chain_t;
+typedef struct virtual_fh_s virtual_fh_t;
+/* Virtual font handle :
+ */
+struct virtual_fh_s
+ {
+ const char *fontNameP; /* => malloc'ed block holding RISC OS font name */
+ int xsize, ysize; /* font size */
+ int xres, yres; /* requested or actual resolution */
+ unsigned int usage; /* the higher, the more this font handle is used for setting its glyphs */
+ unsigned int refCount; /* number of times this struct is refered from ufont_f element */
+ usage_chain_t *usageP; /* Ptr to element usage chain; if non NULL, we have a RISC OS font handle allocated. When refCount is 0, this is not necessary NULL. */
+ };
+#define kInitialFHArraySize 20
+static virtual_fh_t *oVirtualFHArrayP;
+static size_t oCurVirtualFHArrayElems;
+static size_t oMaxVirtualFHArrayElems;
+
+/* Usage chain (one element per open RISC OS font handle) :
+ */
+struct usage_chain_s
+ {
+ usage_chain_t *nextP;
+ usage_chain_t *prevP;
+
+ size_t chainTimer; /* When equal to oChainTimer, you can not throw this element out the chain. */
+ font_f ro_fhandle; /* RISC OS font handle (garanteed non zero) */
+ virtual_fh_t *virFHP;
+ };
+
+typedef struct ufont_map_s ufont_map_t;
+
+struct ufont_map_s
+ {
+ byte fontnr[65536]; /* Must be 1st (comes straight from 'Data' file). Each entry is an index in the virtual_font_index array. */
+ byte character[65536]; /* Must be 2nd (comes straight from 'Data' file) */
+
+ const char *uFontNameP; /* => malloc'ed block holding UFont name */
+ unsigned int refCount;
+ ufont_map_t *nextP;
+ };
+static const ufont_map_t *oMapCollectionP;
+
+struct ufont_font
+ {
+ const ufont_map_t *mapP;
+ int virtual_handles_used; /* Number of filled virtual_font_index[] elements */
+ size_t virtual_font_index[256]; /* Index in the oVirtualFHArrayP */
+ };
+
+/* Walking the chain starting with oUsageChain->nextP and continuing via
+ * ->nextP until reaching oUsageChain again, results in equal or
+ * decreasing ->virFHP->usage values.
+ * Also walking the chain starting with oUsageChain->prevP and continuing
+ * via ->prevP until reaching oUsageChain again, results in equal or
+ * increasing ->virFHP->usage values.
+ */
+static usage_chain_t oUsageChain;
+static size_t oCurUsageChainElems;
+/* Maximum number of RISC OS handles open by UFont :
+ */
+#define kMaxUsageChainElems 80
+static size_t oChainTimer;
+
+static os_error *create_map(const char *fontNameP, const ufont_map_t **mapPP);
+static os_error *delete_map(ufont_map_t *mapP);
+static int eat_utf8(wchar_t *pwc, const byte *s, int n);
+static os_error *addref_virtual_fonthandle(const char *fontNameP, int xsize, int ysize, int xres, int yres, int *xresOutP, int *yresOutP, size_t *offsetP);
+static os_error *deref_virtual_fonthandle(size_t offset);
+static os_error *activate_virtual_fh(virtual_fh_t *virFHP);
+static os_error *remove_usage_chain_elem(usage_chain_t *usageElemP);
+static void repos_usage_chain_elem(usage_chain_t *usageElemP);
+static const char *get_rofontname(font_f rofhandle);
+static void dump_internals(void);
+static int sanity_check(const char *testMsgP);
+
+/* UFont error messages :
+ */
+static os_error error_badparams = { error_BAD_PARAMETERS, "Bad parameters" };
+static os_error error_exists = { error_FONT_NOT_FOUND, "UFont Fonts/Data file not found" };
+static os_error error_memory = { error_FONT_NO_ROOM, "Insufficient memory for font" };
+static os_error error_size = { error_FONT_BAD_FONT_FILE, "Wrong size of font file" };
+static os_error error_fnt_corrupt = { 1 /** \todo */, "UFont is corrupt" };
+static os_error error_toomany_handles = { 2 /** \todo */, "Too many UFont handles are needed to fulfill current request" };
+static os_error error_noufont = { 3 /** \todo */, "Unable to find UFont font" };
+static os_error error_badrohandle = { 4 /** \todo */, "Invalid internal RISC OS font handle" };
+
+/*
+ * UFont_FindFont
+ *
+ * => as Font_FindFont, but
+ * font_name does not support '\' qualifiers
+ *
+ * <= as Font_FindFont, but
+ * handle is 32-bit
+ * Results from xres_out and yres_out are questionable because we
+ * delay-loading the real font data.
+ */
+os_error *
+xufont_find_font(char const *fontNameP,
+ int xsize,
+ int ysize,
+ int xres,
+ int yres,
+ ufont_f *font,
+ int *xresOutP,
+ int *yresOutP)
+{
+ ufont_f fontP;
+ const char *old_font;
+ char *fonts_file;
+ char file_name[256]; // \todo: fixed size, i.e. not safe.
+ fileswitch_object_type objType;
+ int size;
+ os_error *errorP;
+
+if (font == NULL)
+ return &error_badparams;
+/* Be sure never to return garbage as result. */
+*font = NULL;
+
+/* Allocate memory for UFont font set */
+if ((fontP = (ufont_f)calloc(1, sizeof(struct ufont_font))) == NULL)
+ return &error_memory;
+
+if ((errorP = create_map(fontNameP, &fontP->mapP)) != NULL)
+ {
+ (void)xufont_lose_font(fontP);
+ return errorP;
+ }
+if (fontP->mapP == NULL)
+ {
+ (void)xufont_lose_font(fontP);
+ return &error_noufont;
+ }
+
+/* Find size of Fonts file :
+ */
+strcpy(file_name, fontNameP);
+strcat(file_name, ".Fonts");
+if ((errorP = xosfile_read_stamped_path(file_name, "UFont:", &objType, NULL, NULL, &size, NULL, NULL)) != NULL)
+ {
+ (void)xufont_lose_font(fontP);
+ return errorP;
+ }
+if (objType != fileswitch_IS_FILE)
+ {
+ (void)xufont_lose_font(fontP);
+ return &error_exists;
+ }
+
+if ((fonts_file = (char *)malloc(size)) == NULL)
+ {
+ (void)xufont_lose_font(fontP);
+ return &error_memory;
+ }
+
+/* Load Fonts :
+ */
+if ((errorP = xosfile_load_stamped_path(file_name, fonts_file, "UFont:", NULL, NULL, NULL, NULL, NULL)) != NULL)
+ {
+ (void)xufont_lose_font(fontP);
+ free((void *)fonts_file);
+ return errorP;
+ }
+
+/* Open all fonts listed in Fonts :
+ */
+for (old_font = fonts_file, fontP->virtual_handles_used = 0;
+ old_font - fonts_file < size;
+ old_font += strlen(old_font) + 1, ++fontP->virtual_handles_used)
+ {
+ /* UFont can maximum have 256 real RISC OS fonts :
+ */
+ if (fontP->virtual_handles_used < 256)
+ {
+ dbg_fprintf(stderr, "%i %s: ", fontP->virtual_handles_used, old_font);
+ errorP = addref_virtual_fonthandle(old_font, xsize, ysize, xres, yres, xresOutP, yresOutP, &fontP->virtual_font_index[fontP->virtual_handles_used]);
+ }
+ else
+ errorP = &error_fnt_corrupt;
+
+ if (errorP != NULL)
+ {
+ (void)xufont_lose_font(fontP);
+ free((void *)fonts_file);
+ return errorP;
+ }
+
+ dbg_fprintf(stderr, "%i\n", fontP->virtual_font_index[fontP->virtual_handles_used]);
+ }
+
+/* free Fonts */
+free((void *)fonts_file); fonts_file = NULL;
+
+*font = fontP;
+if (xresOutP != NULL)
+ *xresOutP = 96;
+if (yresOutP != NULL)
+ *yresOutP = 96;
+return NULL;
+}
+
+
+/*
+ * UFont_LoseFont
+ *
+ * => font handle as returned by UFont_FindFont
+ * Even if there was an error returned, we tried to delete as much
+ * as possible. The ufont_f is definately not reusable afterwards.
+ */
+os_error *
+xufont_lose_font(ufont_f fontP)
+{
+ size_t index;
+ os_error *theErrorP;
+
+theErrorP = (fontP->mapP != NULL) ? delete_map(fontP->mapP) : NULL;
+
+/* Close all fonts used :
+ */
+for (index = 0; index < fontP->virtual_handles_used; ++index)
+ {
+ os_error *errorP;
+ dbg_fprintf(stderr, "About to deref virtual font handle %d\n", fontP->virtual_font_index[index]);
+ if ((errorP = deref_virtual_fonthandle(fontP->virtual_font_index[index])) != NULL)
+ theErrorP = errorP;
+ }
+
+/* Free ufont structure :
+ */
+free((void *)fontP);
+
+return theErrorP;
+}
+
+
+/*
+ * UFont_Paint
+ *
+ * => font handle as returned by UFont_FindFont
+ * string is Unicode UTF-8 encoded
+ * other parameters as Font_Paint
+ */
+os_error *
+xufont_paint(ufont_f fontP,
+ unsigned char const *string,
+ font_string_flags flags,
+ int xpos,
+ int ypos,
+ font_paint_block const *block,
+ os_trfm const *trfm,
+ int length)
+{
+ char *result;
+ os_error *error;
+
+ if ((flags & font_GIVEN_LENGTH) == 0)
+ length = INT_MAX;
+
+ dbg_fprintf(stderr, "xufont_paint() : size %d, consider len %d\n", strlen(string), length);
+ if ((error = xufont_convert(fontP, string, length, &result, NULL)) != NULL)
+ return error;
+ if (result[0] == '\0')
+ return NULL;
+
+ assert(result[0] == font_COMMAND_FONT);
+ error = xfont_paint(result[1], &result[2],
+ (flags & (~font_GIVEN_LENGTH)) | font_GIVEN_FONT,
+ xpos, ypos, block, trfm, 0);
+ return error;
+}
+
+
+/*
+ * UFont_ScanString
+ *
+ * => font handle as returned by UFont_FindFont
+ * string is Unicode UTF-8 encoded
+ * split length is index in string, not pointer
+ * other parameters as Font_ScanString
+ *
+ * <= as Font_ScanString
+ */
+os_error *
+xufont_scan_string(ufont_f fontP,
+ unsigned char const *string,
+ font_string_flags flags,
+ int x,
+ int y,
+ font_scan_block const *block,
+ os_trfm const *trfm,
+ int length,
+ unsigned char const **split_point,
+ int *x_out,
+ int *y_out,
+ int *length_out)
+{
+ char *result;
+ char *split_point_i;
+ unsigned int *table;
+ os_error *error;
+
+ if ((flags & font_GIVEN_LENGTH) == 0)
+ length = INT_MAX;
+
+ dbg_fprintf(stderr, "xufont_scan_string() : size %d, consider len %d\n", strlen(string), length);
+ if ((error = xufont_convert(fontP, string, length, &result, &table)) != NULL)
+ return error;
+ if (result[0] == '\0')
+ {
+ if (split_point != NULL)
+ *split_point = string;
+ if (x_out != NULL)
+ *x_out = 0;
+ if (y_out != NULL)
+ *y_out = 0;
+ if (length_out != NULL)
+ *length_out = 0;
+ return NULL;
+ }
+
+ assert(result[0] == font_COMMAND_FONT);
+ error = xfont_scan_string(result[1], &result[2],
+ (flags & (~font_GIVEN_LENGTH)) | font_GIVEN_FONT,
+ x, y, block, trfm, 0,
+ (split_point) ? &split_point_i : NULL,
+ x_out, y_out, length_out);
+ if (error != NULL)
+ return error;
+
+ if (split_point != NULL)
+ {
+ dbg_fprintf(stderr, "RISC OS scan string split at offset %d (char %d)\n", split_point_i - result, *split_point_i);
+ *split_point = &string[table[split_point_i - result]];
+ dbg_fprintf(stderr, "UTF-8 Split offset at %d (char %d)\n", *split_point - string, **split_point);
+ }
+
+ return NULL;
+}
+
+
+/**
+ * Given a text line, return the number of bytes which can be set using
+ * one RISC OS font and the bounding box fitting that part of the text
+ * only.
+ *
+ * \param font a ufont font handle, as returned by xufont_find_font().
+ * \param string string text. Does not have to be NUL terminated.
+ * \param flags FontManger flags to be used internally
+ * \param length length in bytes of the text to consider.
+ * \param width returned width of the text which can be set with one RISC OS font. If 0, then error happened or initial text length was 0.
+ * \param rofontname returned name of the RISC OS font which can be used to set the text. If NULL, then error happened or initial text length was 0.
+ * \param rotext returned string containing the characters in returned RISC OS font. Not necessary NUL terminated. free() after use. If NULL, then error happened or initial text length was 0.
+ * \param rolength length of return rotext string. If 0, then error happened or initial text length was 0.
+ * \param consumed number of bytes of the given text which can be set with one RISC OS font. If 0, then error happened or initial text length was 0.
+ */
+os_error *xufont_txtenum(ufont_f fontP,
+ unsigned char const *string,
+ font_string_flags flags,
+ size_t length,
+ int *widthP,
+ unsigned char const **rofontnameP,
+ unsigned char const **rotextP,
+ size_t *rolengthP,
+ size_t *consumedP)
+{
+ char *result, *end_result;
+ unsigned int *table;
+ os_error *errorP;
+
+ int width;
+ const char *rofontname;
+ char *rotext;
+ size_t rolength;
+
+ *rotextP = *rofontnameP = NULL;
+ *consumedP = *rolengthP = *widthP = 0;
+
+ if ((flags & font_GIVEN_LENGTH) == 0)
+ length = INT_MAX;
+
+ if (length == 0)
+ return NULL;
+
+ if ((errorP = xufont_convert(fontP, string, length, &result, &table)) != NULL)
+ return errorP;
+ if (result[0] == '\0')
+ return NULL;
+ assert(result[0] == font_COMMAND_FONT);
+
+ /* Find how many characters starting at <result + 2> onwards
+ are set using the RISC OS font with handle <result + 1> */
+ for (end_result = result + 2; *end_result != '\0' && *end_result != font_COMMAND_FONT; ++end_result)
+ ;
+
+ rolength = end_result - result - 2;
+ if ((errorP = xfont_scan_string(result[1], &result[2],
+ flags | font_GIVEN_LENGTH | font_GIVEN_FONT,
+ 0x7fffffff, 0x7fffffff,
+ NULL, NULL,
+ rolength,
+ NULL,
+ &width, NULL,
+ NULL)) != NULL)
+ return errorP;
+ if ((rofontname = get_rofontname(result[1])) == NULL)
+ return &error_badrohandle;
+ if ((rotext = malloc(rolength)) == NULL)
+ return &error_memory;
+ memcpy(rotext, result + 2, rolength);
+
+ *widthP = width;
+ *rofontnameP = rofontname;
+ *rotextP = rotext;
+ *rolengthP = rolength;
+ *consumedP = table[end_result - result];
+
+ return NULL;
+}
+
+
+/*
+ * UFont_Convert
+ *
+ * => initial font
+ * UTF-8 string to convert to RISC OS font numbers and codes.
+ * max length to convert (characters) or NUL char terminated.
+ *
+ * <= string converted to Font_Paint format
+ * table of offsets in UTF-8 string
+ */
+os_error *
+xufont_convert(ufont_f fontP,
+ unsigned char const *string,
+ size_t length,
+ char **presult, /* may not be NULL ! */
+ size_t **ptable /* may be NULL */)
+{
+ static char *resultP;
+ static size_t *tableP;
+ static size_t currentSize;
+
+ size_t max_length;
+ size_t string_index, new_string_index, result_index;
+ virtual_fh_t *curVirFH = NULL;
+
+assert(presult != NULL);
+
+do_sanity_check("xufont_convert() : begin");
+
+/* Find upfront if we're NUL char terminated or length terminated. */
+for (max_length = 0; max_length < length && string[max_length] != '\0'; ++max_length)
+ /* no body */;
+
+/* Increase timer so we can enforce a set of usage elements to remain active.
+ */
+++oChainTimer;
+
+/* Ensure memory block.
+ */
+if (resultP == NULL)
+ {
+ if ((resultP = (char *)malloc(MALLOC_CHUNK)) == NULL)
+ return &error_memory;
+ currentSize = MALLOC_CHUNK;
+ }
+if (tableP == NULL && (tableP = (size_t *)malloc(MALLOC_CHUNK * sizeof(size_t))) == NULL)
+ return &error_memory;
+
+dbg_fprintf(stderr, "xufont_convert() : ");
+for (string_index = 0, result_index = 0;
+ string_index < max_length;
+ string_index = new_string_index)
+ {
+ wchar_t wchar;
+ int result = eat_utf8(&wchar, &string[string_index], max_length - string_index);
+
+ if (result == 0)
+ {
+ /* Too few input bytes : abort conversion */
+ fprintf(stderr, "eat_utf8() : too few input bytes\n");
+ break;
+ }
+ else if (result < 0)
+ {
+ /* Corrupt UTF-8 stream : skip <-result> input characters. */
+ fprintf(stderr, "eat_utf8() : error %d\n", result);
+fprintf(stderr, "String <%.*s> error pos %d\n", length, string, string_index);
+ wchar = '?';
+ new_string_index = string_index - result;
+ }
+ else
+ {
+ /* Normal case : one wchar_t produced, <result> bytes consumed. */
+ if (wchar >= 0x10000)
+ wchar = '?';
+ new_string_index = string_index + result;
+ }
+
+ dbg_fprintf(stderr, "src offset 0x%x : 0x%x ", string_index, wchar);
+
+ /* Reserve room for at least 32 more entries.
+ */
+ if (result_index + 32 > currentSize)
+ {
+ if ((resultP = realloc(resultP, currentSize*2)) == NULL
+ || (tableP = realloc(tableP, currentSize*2 * sizeof(size_t))) == NULL)
+ return &error_memory;
+
+ currentSize *= 2;
+ }
+
+ {
+ const byte fontnr = fontP->mapP->fontnr[wchar];
+ virtual_fh_t *virFHP;
+ usage_chain_t *usageP;
+
+ assert(fontnr < fontP->virtual_handles_used);
+ virFHP = &oVirtualFHArrayP[fontP->virtual_font_index[fontnr]];
+
+ /* Check if current font is ok :
+ */
+ if (virFHP != curVirFH)
+ {
+ os_error *errorP;
+
+ curVirFH = virFHP;
+
+ /* Make sure we have a RISC OS font handle associated :
+ */
+ if ((errorP = activate_virtual_fh(virFHP)) != NULL)
+ return errorP;
+ usageP = virFHP->usageP;
+ assert(usageP != NULL);
+ assert(usageP->ro_fhandle != 0);
+ tableP[result_index] = tableP[result_index + 1] = string_index;
+ resultP[result_index++] = font_COMMAND_FONT;
+ resultP[result_index++] = usageP->ro_fhandle;
+
+ dbg_fprintf(stderr, "{%i} ", resultP[result_index - 1]);
+ }
+ else
+ {
+ usageP = virFHP->usageP;
+ assert(usageP != NULL);
+ }
+
+ ++virFHP->usage;
+ /* By increasing the usage counter, it might that the oUsageChain needs
+ * reordering.
+ */
+ if (usageP != oUsageChain.nextP && virFHP->usage > usageP->prevP->virFHP->usage)
+ repos_usage_chain_elem(usageP);
+
+ tableP[result_index] = string_index;
+ resultP[result_index++] = fontP->mapP->character[wchar];
+ dbg_fprintf(stderr, "[0x%x] ", resultP[result_index - 1]);
+ }
+ }
+resultP[result_index] = 0;
+*presult = resultP;
+
+tableP[result_index] = string_index;
+if (ptable != NULL)
+ *ptable = tableP;
+
+#ifdef DEBUG_UFONT
+fprintf(stderr, "\nRISC OS font string result:\n");
+
+for (result_index = 0; resultP[result_index] != 0; ++result_index)
+ fprintf(stderr, " Dst offset %d : 0x%x (src offset %d)\n", result_index, resultP[result_index], tableP[result_index]);
+#endif
+
+do_sanity_check("xufont_convert() : end");
+
+dbg_fprintf(stderr, "--- After convert()\n");
+//dump_internals();
+
+return NULL;
+}
+
+
+/* Creates or reuses an existing ufont_map_t
+ */
+static os_error *create_map(const char *uFontNameP, const ufont_map_t **mapPP)
+{
+ ufont_map_t *curMapP;
+ size_t uFontNameLen = strlen(uFontNameP);
+ char *fileNameP;
+ os_error *errorP;
+
+/* Make sure we never return garbage results.
+ */
+*mapPP = NULL;
+
+if ((fileNameP = (char *)alloca(uFontNameLen + sizeof(".Data"))) == NULL)
+ return &error_memory;
+memcpy(fileNameP, uFontNameP, uFontNameLen);
+do {
+ fileswitch_object_type objType;
+ int size;
+
+ memcpy(&fileNameP[uFontNameLen], ".Data", sizeof(".Data"));
+ if ((errorP = xosfile_read_stamped_path(fileNameP, "UFont:", &objType, NULL, NULL, &size, NULL, NULL)) != NULL)
+ return errorP;
+
+ if (objType == fileswitch_NOT_FOUND)
+ {
+ /* Look for the Data file one directory level up. */
+ while (uFontNameLen != 0 && fileNameP[--uFontNameLen] != '.')
+ /* no body */;
+ if (uFontNameLen == 0)
+ return &error_exists;
+ }
+ else if (objType == fileswitch_IS_FILE)
+ {
+ if (size != 2*65536)
+ return &error_size;
+ break;
+ }
+ else
+ return &error_exists;
+ } while (1);
+
+/* Try to reuse an existing map :
+ */
+for (curMapP = oMapCollectionP; curMapP != NULL; curMapP = curMapP->nextP)
+ {
+ size_t curUFontNameLen = strlen(curMapP->uFontNameP);
+
+ if (uFontNameLen != curUFontNameLen)
+ continue;
+
+ if (memcmp(fileNameP, curMapP->uFontNameP, curUFontNameLen) != 0)
+ break;
+ }
+if (curMapP != NULL)
+ {
+ ++curMapP->refCount;
+ *mapPP = curMapP;
+ return NULL;
+ }
+
+/* We need to create & load new map into memory :
+ */
+if ((curMapP = (ufont_map_t *)malloc(sizeof(ufont_map_t))) == NULL)
+ return &error_memory;
+
+/* Load Data file :
+ */
+if ((errorP = xosfile_load_stamped_path(fileNameP, (byte *)&curMapP->fontnr[0], "UFont:", NULL, NULL, NULL, NULL, NULL)) != NULL)
+ {
+ free((void *)curMapP);
+ return errorP;
+ }
+fileNameP[uFontNameLen] = '\0';
+if ((curMapP->uFontNameP = strdup(fileNameP)) == NULL)
+ {
+ free((void *)curMapP);
+ return &error_memory;
+ }
+curMapP->refCount = 1;
+curMapP->nextP = oMapCollectionP;
+oMapCollectionP = curMapP;
+
+*mapPP = curMapP;
+return NULL;
+}
+
+
+static os_error *delete_map(ufont_map_t *mapP)
+{
+assert(mapP->refCount > 0);
+--mapP->refCount;
+/* \todo: we don't remove the map from the oMapCollection list. Should we ?
+ */
+
+return NULL;
+}
+
+
+/* Returns:
+ * x > 0: number of bytes consumed at s, valid wchar_t returned at pwc[0]
+ * x = 0: too few input bytes, pwc[0] is undefined
+ * x < 0: illegal UTF-8 stream, skip -x characters at s, pwc[0] is undefined
+ */
+static int eat_utf8(wchar_t *pwc, const byte *s, int n)
+{
+ byte c;
+ int i;
+
+#if 0
+fputs("<", stderr);
+for (i = 0; i < n; ++i)
+ fputc(s[i], stderr);
+fputs(">\n", stderr);
+#endif
+ if (n < 1)
+ return 0; /* not enough input bytes */
+ else if ((c = s[0]) < 0x80) {
+ *pwc = c;
+ return 1;
+ } else if (c < 0xc2)
+ goto do_sync;
+ else if (c < 0xe0) {
+ if (n < 2)
+ return 0; /* not enough input bytes */
+ if (!((s[1] ^ 0x80) < 0x40))
+ goto do_sync;
+ *pwc = ((wchar_t) (c & 0x1f) << 6) | (wchar_t) (s[1] ^ 0x80);
+ return 2;
+ } else if (c < 0xf0) {
+ if (n < 3)
+ return 0; /* not enough input bytes */
+ if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40 && (c >= 0xe1 || s[1] >= 0xa0)))
+ goto do_sync;
+ *pwc = ((wchar_t) (c & 0x0f) << 12) | ((wchar_t) (s[1] ^ 0x80) << 6) | (wchar_t) (s[2] ^ 0x80);
+ return 3;
+ } else if (c < 0xf8) {
+ if (n < 4)
+ return 0; /* not enough input bytes */
+ if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40 && (s[3] ^ 0x80) < 0x40 && (c >= 0xf1 || s[1] >= 0x90)))
+ goto do_sync;
+ *pwc = ((wchar_t) (c & 0x07) << 18) | ((wchar_t) (s[1] ^ 0x80) << 12) | ((wchar_t) (s[2] ^ 0x80) << 6) | (wchar_t) (s[3] ^ 0x80);
+ return 4;
+ } else if (c < 0xfc) {
+ if (n < 5)
+ return 0; /* not enough input bytes */
+ if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40 && (s[3] ^ 0x80) < 0x40 && (s[4] ^ 0x80) < 0x40 && (c >= 0xf9 || s[1] >= 0x88)))
+ goto do_sync;
+ *pwc = ((wchar_t) (c & 0x03) << 24) | ((wchar_t) (s[1] ^ 0x80) << 18) | ((wchar_t) (s[2] ^ 0x80) << 12) | ((wchar_t) (s[3] ^ 0x80) << 6) | (wchar_t) (s[4] ^ 0x80);
+ return 5;
+ } else if (c < 0xfe) {
+ if (n < 6)
+ return 0; /* not enough input bytes */
+ if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40 && (s[3] ^ 0x80) < 0x40 && (s[4] ^ 0x80) < 0x40 && (s[5] ^ 0x80) < 0x40 && (c >= 0xfd || s[1] >= 0x84)))
+ goto do_sync;
+ *pwc = ((wchar_t) (c & 0x01) << 30) | ((wchar_t) (s[1] ^ 0x80) << 24) | ((wchar_t) (s[2] ^ 0x80) << 18) | ((wchar_t) (s[3] ^ 0x80) << 12) | ((wchar_t) (s[4] ^ 0x80) << 6) | (wchar_t) (s[5] ^ 0x80);
+ return 6;
+ }
+
+do_sync:
+ /* The UTF-8 sequence at s is illegal, skipping from s onwards
+ * until first non top character is found or %11xxxxxx is found
+ * (both valid UTF-8 *starts* - not necessary valid sequences).
+ */
+ for (i = 1; i < n && !((s[i] & 0x80) == 0x00 || (s[i] & 0xC0) == 0xC0); ++i)
+ /* no body */;
+ return -i;
+}
+
+
+/* Adds the RISC OS font <fontNameP> to the oVirtualFHArrayP list and
+ * returns the index in that array.
+ * oVirtualFHArrayP can be reallocated (and all virFHP ptrs in oUsageChain).
+ * Results in xresOutP and yresOutP are not always that meaningful because
+ * of the delayed-loading of the real RISC OS font data.
+ * xresOutP and/or yresOutP may be NULL.
+ */
+static os_error *addref_virtual_fonthandle(const char *fontNameP, int xsize, int ysize, int xres, int yres, int *xresOutP, int *yresOutP, size_t *offsetP)
+{
+ size_t curIndex;
+ virtual_fh_t *unusedSlotP;
+
+assert(offsetP != NULL);
+
+do_sanity_check("addref_virtual_fonthandle() : begin");
+
+if (oVirtualFHArrayP == NULL)
+ {
+ if ((oVirtualFHArrayP = (virtual_fh_t *)calloc(kInitialFHArraySize, sizeof(virtual_fh_t))) == NULL)
+ return &error_memory;
+ /* oCurVirtualFHArrayElems = 0; Isn't really necessary because of static */
+ oMaxVirtualFHArrayElems = kInitialFHArraySize;
+ }
+
+/* Check for duplicate (and find first unused slot if any) :
+ */
+for (unusedSlotP = NULL, curIndex = 0;
+ curIndex < oCurVirtualFHArrayElems;
+ ++curIndex)
+ {
+ virtual_fh_t *virFHP = &oVirtualFHArrayP[curIndex];
+
+ if (virFHP->fontNameP != NULL /* case strdup(fontNameP) failed */
+ && stricmp(virFHP->fontNameP, fontNameP) == 0
+ && virFHP->xsize == xsize && virFHP->ysize == ysize)
+ {
+ if (xresOutP != NULL)
+ *xresOutP = virFHP->xres;
+ if (yresOutP != NULL)
+ *yresOutP = virFHP->yres;
+ ++virFHP->refCount;
+ *offsetP = curIndex;
+
+ do_sanity_check("addref_virtual_fonthandle() : case 1");
+ return NULL;
+ }
+
+ if (virFHP->refCount == 0 && unusedSlotP == NULL)
+ unusedSlotP = virFHP;
+ }
+
+/* Can we reuse a slot ?
+ * I.e. a virtual FH which refCount is zero.
+ */
+if (unusedSlotP != NULL)
+ {
+ if (unusedSlotP->usageP != NULL)
+ {
+ os_error *errorP;
+
+ /* This slot is refered in the usage chain, we have to unlink it.
+ */
+ if ((errorP = remove_usage_chain_elem(unusedSlotP->usageP)) != NULL)
+ return errorP;
+ }
+
+ unusedSlotP->usage = 0;
+ if (unusedSlotP->fontNameP != NULL)
+ free((void *)unusedSlotP->fontNameP);
+ if ((unusedSlotP->fontNameP = strdup(fontNameP)) == NULL)
+ return &error_memory;
+
+ unusedSlotP->xsize = xsize;
+ unusedSlotP->ysize = ysize;
+ unusedSlotP->xres = (xres > 1) ? xres : 96;
+ if (xresOutP != NULL)
+ *xresOutP = unusedSlotP->xres;
+ unusedSlotP->yres = (yres > 1) ? yres : 96;
+ if (yresOutP != NULL)
+ *yresOutP = unusedSlotP->yres;
+ unusedSlotP->refCount = 1;
+ *offsetP = unusedSlotP - oVirtualFHArrayP;
+ do_sanity_check("addref_virtual_fonthandle() : case 2");
+ return NULL;
+ }
+
+/* Add new entry :
+ */
+if (oCurVirtualFHArrayElems == oMaxVirtualFHArrayElems)
+ {
+ virtual_fh_t *newVirtualFHArrayP;
+ size_t extraOffset;
+ usage_chain_t *usageP;
+
+ /* Don't use realloc() as when that fails, we don't even have the original
+ * memory block anymore.
+ */
+ if ((newVirtualFHArrayP = (virtual_fh_t *)calloc(2*oMaxVirtualFHArrayElems, sizeof(virtual_fh_t))) == NULL)
+ return &error_memory;
+ memcpy(newVirtualFHArrayP, oVirtualFHArrayP, oMaxVirtualFHArrayElems * sizeof(virtual_fh_t));
+ free((void *)oVirtualFHArrayP);
+ extraOffset = (const char *)newVirtualFHArrayP - (const char *)oVirtualFHArrayP;
+ oVirtualFHArrayP = newVirtualFHArrayP;
+ oMaxVirtualFHArrayElems *= 2;
+
+ /* Update the virFHP pointers in the usage chain :
+ */
+ if (oUsageChain.nextP != NULL)
+ {
+ for (usageP = oUsageChain.nextP; usageP != &oUsageChain; usageP = usageP->nextP)
+ usageP->virFHP = (virtual_fh_t *)&((char *)usageP->virFHP)[extraOffset];
+ }
+ }
+
+unusedSlotP = &oVirtualFHArrayP[oCurVirtualFHArrayElems];
+if ((unusedSlotP->fontNameP = (const char *)strdup(fontNameP)) == NULL)
+ return &error_memory;
+unusedSlotP->xsize = xsize;
+unusedSlotP->ysize = ysize;
+unusedSlotP->xres = (xres > 1) ? xres : 96;
+if (xresOutP != NULL)
+ *xresOutP = unusedSlotP->xres;
+unusedSlotP->yres = (yres > 1) ? yres : 96;
+if (yresOutP != NULL)
+ *yresOutP = unusedSlotP->yres;
+unusedSlotP->refCount = 1;
+*offsetP = oCurVirtualFHArrayElems++;
+
+do_sanity_check("addref_virtual_fonthandle() : case 3");
+return NULL;
+}
+
+
+/* Deref virtual_fh_t element in oVirtualFHArrayP array.
+ */
+static os_error *deref_virtual_fonthandle(size_t offset)
+{
+assert(offset >= 0 && offset < oCurVirtualFHArrayElems);
+assert(oVirtualFHArrayP[offset].refCount > 0);
+
+/* When the refCount reaches 0, it will be reused by preference when a
+ * new usageChain element is needed in addref_virtual_fonthandle().
+ */
+--oVirtualFHArrayP[offset].refCount;
+
+do_sanity_check("deref_virtual_fonthandle()");
+return NULL;
+}
+
+
+/* Virtual font handle <virFHP> needs to have a RISC OS font handle
+ * associated via virFHP->usageP. For this we can throw out all other
+ * usage chain elements which have a chainTimer different from oChainTimer.
+ * However, we may not have more than kMaxUsageChainElems chain elements
+ * active.
+ * Afterwards: either an error, either virFHP->usageP points to an usage chain
+ * element in the oUsageChain linked list and that usage chain element has
+ * a valid RISC OS font handle associated.
+ */
+static os_error *activate_virtual_fh(virtual_fh_t *virFHP)
+{
+ usage_chain_t *usageP;
+
+dbg_fprintf(stderr, "+++ activate_virtual_fh(virFHP %p, usageP ? %p)\n", virFHP, virFHP->usageP);
+do_sanity_check("activate_virtual_fh() : begin");
+
+/* The easiest case : we already have a RISC OS font handle :
+ */
+if ((usageP = virFHP->usageP) != NULL)
+ {
+ usageP->chainTimer = oChainTimer;
+ assert(usageP->ro_fhandle != 0);
+ assert(usageP->virFHP == virFHP);
+ do_sanity_check("activate_virtual_fh() : case 1");
+ dbg_fprintf(stderr, "--- done, activate_virtual_fh(), case 1\n");
+ return NULL;
+ }
+
+/* The second easiest case : we're still allowed to create an extra
+ * chain element :
+ */
+if (oCurUsageChainElems < kMaxUsageChainElems)
+ {
+ os_error *errorP;
+
+ if ((usageP = (usage_chain_t *)malloc(sizeof(usage_chain_t))) == NULL)
+ return &error_memory;
+ usageP->chainTimer = oChainTimer;
+
+ if ((errorP = xfont_find_font(virFHP->fontNameP,
+ virFHP->xsize, virFHP->ysize,
+ virFHP->xres, virFHP->yres,
+ &usageP->ro_fhandle,
+ &virFHP->xres, &virFHP->yres)) != NULL)
+ {
+ free((void *)usageP);
+ return errorP;
+ }
+ usageP->virFHP = virFHP;
+ virFHP->usageP = usageP;
+ ++oCurUsageChainElems;
+
+ /* Make sure oUsageChain nextP and prevP point to at least something (is
+ * only executed once and should probably better be done in a global
+ * init routine).
+ */
+ if (oUsageChain.nextP == NULL)
+ oUsageChain.nextP = oUsageChain.prevP = &oUsageChain;
+ }
+else
+ {
+ os_error *errorP;
+
+ /* The more difficult one : we need to reuse a usage chain element.
+ * Take the last one because that is least used but skip the onces
+ * with chainTimer equal to the current oChainTimer because those
+ * RISC OS font handles are still used in the font string we're
+ * currently processing.
+ */
+ for (usageP = oUsageChain.prevP;
+ usageP != &oUsageChain && usageP->chainTimer == oChainTimer;
+ usageP = usageP->prevP)
+ /* no body */;
+ if (usageP == &oUsageChain)
+ {
+ /* Painful : all usage chain elements are in use and we already have the
+ * maximum of chain elements reached.
+ */
+ return &error_toomany_handles;
+ }
+
+ usageP->chainTimer = oChainTimer;
+ /* The virtual font handle currently in usageP->virFHP no longer has a real
+ * RISC OS font handle anymore.
+ */
+ usageP->virFHP->usageP = NULL;
+ if ((errorP = xfont_lose_font(usageP->ro_fhandle)) != NULL)
+ return errorP;
+ if ((errorP = xfont_find_font(virFHP->fontNameP,
+ virFHP->xsize, virFHP->ysize,
+ virFHP->xres, virFHP->yres,
+ &usageP->ro_fhandle,
+ &virFHP->xres, &virFHP->yres)) != NULL)
+ return errorP;
+ usageP->virFHP = virFHP;
+ virFHP->usageP = usageP;
+
+ /* Delink :
+ */
+ usageP->prevP->nextP = usageP->nextP;
+ usageP->nextP->prevP = usageP->prevP;
+ }
+
+/* Link usageP in the oUsageChain based on its current virFHP->usage value :
+ */
+ {
+ const unsigned int usage = virFHP->usage;
+ usage_chain_t *runUsageP;
+
+ for (runUsageP = &oUsageChain;
+ runUsageP != oUsageChain.nextP && runUsageP->prevP->virFHP->usage <= usage;
+ runUsageP = runUsageP->prevP)
+ /* no body */;
+
+ /* We have to link usageP between runUsageP and runUsageP->prevP
+ * because runUsageP->prevP has higher usage than the one we need to
+ * link in -or- we're at the end/start.
+ */
+ usageP->nextP = runUsageP;
+ usageP->prevP = runUsageP->prevP;
+ runUsageP->prevP->nextP = usageP;
+ runUsageP->prevP = usageP;
+ }
+do_sanity_check("activate_virtual_fh() : case 2");
+dbg_fprintf(stderr, "--- done, activate_virtual_fh(), case 2\n");
+
+return NULL;
+}
+
+
+/* Remove this element from the usage chain :
+ */
+static os_error *remove_usage_chain_elem(usage_chain_t *usageP)
+{
+ os_error *errorP;
+
+assert(usageP != NULL);
+assert(oCurUsageChainElems > 0);
+assert(usageP->ro_fhandle != 0);
+assert(usageP->virFHP != NULL);
+
+if ((errorP = xfont_lose_font(usageP->ro_fhandle)) != NULL)
+ return errorP;
+
+usageP->virFHP->usageP = NULL;
+
+/* Delink it :
+ */
+usageP->prevP->nextP = usageP->nextP;
+usageP->nextP->prevP = usageP->prevP;
+
+--oCurUsageChainElems;
+free((void *)usageP);
+
+do_sanity_check("remove_usage_chain_elem() : end");
+return NULL;
+}
+
+
+/* usageP is no longer in the right place in the chain because its
+ * ->virFHP->usage value increased. Reposition it towards prev
+ * direction.
+ */
+static void repos_usage_chain_elem(usage_chain_t *usageP)
+{
+ usage_chain_t *prev1P, *prev2P;
+ const unsigned int curUsage = usageP->virFHP->usage;
+
+dbg_fprintf(stderr, "+++ repos_usage_chain_elem(%p)\n", usageP);
+
+/* If this assert goes off, then it means that this routine shouldn't
+ * have been called.
+ */
+assert(curUsage > usageP->prevP->virFHP->usage);
+
+/* Delink :
+ */
+usageP->prevP->nextP = usageP->nextP;
+usageP->nextP->prevP = usageP->prevP;
+
+/* Place usageElemP between prev1P and prev2P.
+ */
+for (prev1P = usageP->prevP, prev2P = prev1P->prevP;
+ prev2P != &oUsageChain && curUsage > prev2P->virFHP->usage;
+ prev1P = prev2P, prev2P = prev2P->prevP)
+ {
+ dbg_fprintf(stderr, "> prev1P %p (%d), usageElemP %p (%d), prev2P %p (%d), dummy %p\n", prev1P, prev1P->virFHP->usage, usageP, usageP->virFHP->usage, prev2P, prev2P->virFHP->usage, &oUsageChain);
+ assert(prev1P->virFHP->usage <= prev2P->virFHP->usage);
+ }
+
+dbg_fprintf(stderr, "prev1P %p (%d), usageElemP %p (%d), prev2P %p (%d), dummy %p\n", prev1P, prev1P->virFHP->usage, usageP, usageP->virFHP->usage, prev2P, prev2P->virFHP->usage, &oUsageChain);
+
+/* Relink between prev1P and prev2P :
+ */
+prev1P->prevP = usageP;
+usageP->prevP = prev2P;
+prev2P->nextP = usageP;
+usageP->nextP = prev1P;
+
+do_sanity_check("repos_usage_chain_elem() : end");
+dbg_fprintf(stderr, "--- done, repos_usage_chain_elem()\n");
+}
+
+
+/**
+ * Retrieves the RISC OS font name of given RISC OS fonthandle.
+ *
+ * \param rofhandle RISC OS font handle
+ */
+static const char *get_rofontname(font_f rofhandle)
+{
+ usage_chain_t *usageP;
+
+ if (oUsageChain.nextP == NULL)
+ return NULL;
+
+ for (usageP = oUsageChain.nextP; usageP != &oUsageChain; usageP = usageP->nextP)
+ if (usageP->ro_fhandle == rofhandle)
+ return usageP->virFHP->fontNameP;
+
+ return NULL;
+}
+
+
+static void dump_internals(void)
+{
+fprintf(stderr, "Dump UFont internals:\n - Virtual font handle array at %p (length %d, max length %d)\n - Usage chain elements %d\n - Chain timer is %d\n Dump usage chain (first dummy at %p):\n", oVirtualFHArrayP, oCurVirtualFHArrayElems, oMaxVirtualFHArrayElems, oCurUsageChainElems, oChainTimer, &oUsageChain);
+if (oUsageChain.prevP == NULL || oUsageChain.nextP == NULL)
+ {
+ fprintf(stderr, " Empty usage chain\n");
+ if (oUsageChain.prevP != oUsageChain.nextP)
+ fprintf(stderr, " *** Corrupted empty usage chain: next %p, prev %p\n", oUsageChain.nextP, oUsageChain.prevP);
+ if (oCurUsageChainElems != 0)
+ fprintf(stderr, " *** Current usage chain length is wrong\n");
+ }
+else
+ {
+ size_t usageCount;
+ const usage_chain_t *usageP;
+
+ for (usageCount = 0, usageP = oUsageChain.nextP; usageP != &oUsageChain; ++usageCount, usageP = usageP->nextP)
+ {
+ fprintf(stderr, " -%d- : cur %p, next %p, prev %p, timer %d, RISC OS font handle %d, virtual font %p (%d, %s), usage %d\n", usageCount, usageP, usageP->nextP, usageP->prevP, usageP->chainTimer, usageP->ro_fhandle, usageP->virFHP, usageP->virFHP - oVirtualFHArrayP, usageP->virFHP->fontNameP, usageP->virFHP->usage);
+ if (usageP->nextP->prevP != usageP)
+ fprintf(stderr, " *** Bad usageP->nextP->prevP != usageP\n");
+ if (usageP->prevP->nextP != usageP)
+ fprintf(stderr, " *** Bad usageP->prevP->nextP != usageP\n");
+ if (usageP->virFHP < oVirtualFHArrayP || usageP->virFHP >= &oVirtualFHArrayP[oCurVirtualFHArrayElems])
+ fprintf(stderr, " *** Bad virtual font handle\n");
+ }
+ if (usageCount != oCurUsageChainElems)
+ fprintf(stderr, " *** Current usage chain length is wrong\n");
+ if (usageCount > kMaxUsageChainElems)
+ fprintf(stderr, " *** Current usage chain is too long\n");
+ }
+
+if (oVirtualFHArrayP != NULL)
+ {
+ size_t fhIndex;
+
+ fprintf(stderr, " Dump virtual font handles:\n");
+ for (fhIndex = 0; fhIndex < oCurVirtualFHArrayElems; ++fhIndex)
+ {
+ const virtual_fh_t *virFHP = &oVirtualFHArrayP[fhIndex];
+
+ fprintf(stderr, " -%d (%p)- : <%s>, size %d,%d, res %d,%d, usage %d, ref count %d, usage chain ptr %p\n", fhIndex, virFHP, virFHP->fontNameP, virFHP->xsize, virFHP->ysize, virFHP->xres, virFHP->yres, virFHP->usage, virFHP->refCount, virFHP->usageP);
+ if (virFHP->usageP != NULL)
+ {
+ const usage_chain_t *usageP;
+
+ for (usageP = oUsageChain.nextP;
+ usageP != virFHP->usageP && usageP != &oUsageChain;
+ usageP = usageP->nextP)
+ /* no body */;
+ if (usageP != virFHP->usageP)
+ fprintf(stderr, " *** Usage chain ptr could not be found in usage chain\n");
+ }
+ }
+ }
+}
+
+
+static int sanity_check(const char *testMsgP)
+{
+dbg_fprintf(stderr, "Sanity check <%s>\n", testMsgP);
+if (oUsageChain.prevP == NULL || oUsageChain.nextP == NULL)
+ {
+ assert(oUsageChain.prevP == oUsageChain.nextP);
+ assert(oCurUsageChainElems == 0);
+ }
+else
+ {
+ size_t usageCount;
+ const usage_chain_t *usageP;
+
+ /* We should see equal or decreasing usage values.
+ */
+ for (usageCount = 0, usageP = oUsageChain.nextP; usageP != &oUsageChain; ++usageCount, usageP = usageP->nextP)
+ {
+ assert(usageP->nextP->prevP == usageP);
+ assert(usageP->prevP->nextP == usageP);
+ assert(usageP->chainTimer <= oChainTimer);
+ assert(usageP->ro_fhandle != 0);
+ assert(oVirtualFHArrayP != NULL);
+ assert(usageP->virFHP >= oVirtualFHArrayP && usageP->virFHP < &oVirtualFHArrayP[oCurVirtualFHArrayElems]);
+ assert(usageP->virFHP->usageP == usageP);
+// dbg_fprintf(stderr, "%d: usageP %p (oUsageChain.prevP %p), timer %d, usage %d, next usage %d\n", usageCount, usageP, oUsageChain.prevP, usageP->chainTimer, usageP->virFHP->usage, usageP->nextP->virFHP->usage);
+ assert(usageP == oUsageChain.prevP || usageP->virFHP->usage >= usageP->nextP->virFHP->usage);
+ }
+ assert(usageCount == oCurUsageChainElems);
+ assert(usageCount <= kMaxUsageChainElems);
+ }
+
+if (oVirtualFHArrayP != NULL)
+ {
+ size_t fhIndex;
+
+ for (fhIndex = 0; fhIndex < oCurVirtualFHArrayElems; ++fhIndex)
+ {
+ const virtual_fh_t *virFHP = &oVirtualFHArrayP[fhIndex];
+
+ if (virFHP->usageP != NULL)
+ {
+ const usage_chain_t *usageP;
+
+ assert(virFHP->fontNameP != NULL);
+ assert(virFHP->xsize > 0 && virFHP->ysize > 0);
+ assert(virFHP->xres > 0 && virFHP->yres > 0);
+ for (usageP = oUsageChain.nextP;
+ usageP != virFHP->usageP && usageP != &oUsageChain;
+ usageP = usageP->nextP)
+ /* no body */;
+ assert(usageP == virFHP->usageP);
+ }
+ }
+ }
+
+return 0;
+}
diff --git a/riscos/ufont.h b/riscos/ufont.h
new file mode 100644
index 000000000..620c3db89
--- /dev/null
+++ b/riscos/ufont.h
@@ -0,0 +1,70 @@
+/* ufont.h
+ * Licensed under the GNU General Public License,
+ * http://www.opensource.org/licenses/gpl-license
+ * Copyright 2000 James Bursa <bursa@users.sourceforge.net>
+ * Copyright 2004 John Tytgat <John.Tytgat@aaug.net>
+ */
+
+#ifndef UFONT_HEADER_INCLUDED
+#define UFONT_HEADER_INCLUDED
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "oslib/font.h"
+#include "oslib/os.h"
+
+typedef struct ufont_font *ufont_f;
+
+extern os_error *xufont_find_font(char const *font_name,
+ int xsize,
+ int ysize,
+ int xres,
+ int yres,
+ ufont_f *font,
+ int *xresOutP,
+ int *yresOutP);
+
+extern os_error *xufont_lose_font(ufont_f font);
+
+extern os_error *xufont_paint(ufont_f font,
+ unsigned char const *string,
+ font_string_flags flags,
+ int xpos,
+ int ypos,
+ font_paint_block const *block,
+ os_trfm const *trfm,
+ int length);
+
+extern os_error *xufont_scan_string(ufont_f font,
+ unsigned char const *string,
+ font_string_flags flags,
+ int x,
+ int y,
+ font_scan_block const *block,
+ os_trfm const *trfm,
+ int length,
+ unsigned char const **split_point,
+ int *x_out,
+ int *y_out,
+ int *length_out);
+
+extern os_error *xufont_txtenum(ufont_f font,
+ unsigned char const *string,
+ font_string_flags flags,
+ size_t length,
+ int *width,
+ unsigned char const **rofontname,
+ unsigned char const **rotext,
+ size_t *rolength,
+ size_t *consumed);
+
+extern os_error *xufont_convert(ufont_f font,
+ unsigned char const *string,
+ size_t length,
+ char **presult,
+ size_t **ptable);
+
+#endif
diff --git a/utils/utils.c b/utils/utils.c
index ca33051cf..8d028d5e0 100644
--- a/utils/utils.c
+++ b/utils/utils.c
@@ -5,8 +5,10 @@
* Copyright 2004 James Bursa <bursa@users.sourceforge.net>
* Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
* Copyright 2003 John M Bell <jmb202@ecs.soton.ac.uk>
+ * Copyright 2004 John Tytgat <John.Tytgat@aaug.net>
*/
+#include <assert.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
@@ -68,9 +70,12 @@ void xfree(void* p)
char * xstrdup(const char * const s)
{
- char * c = malloc(strlen(s) + 1);
- if (c == 0) die("Out of memory in xstrdup()");
- strcpy(c, s);
+ char *c;
+ if (s == NULL)
+ fprintf(stderr, "Attempt to strdup() NULL pointer\n");
+ c = malloc(((s == NULL) ? 0 : strlen(s)) + 1);
+ if (c == NULL) die("Out of memory in xstrdup()");
+ strcpy(c, (s == NULL) ? "" : s);
return c;
}
@@ -112,83 +117,97 @@ char * squash_whitespace(const char * s)
return c;
}
-char * tolat1(xmlChar * s)
-{
- unsigned int length = strlen((char*) s);
- unsigned int space = length + 100;
- char *d = xcalloc(space, sizeof(char));
- char *d0 = d;
- char *end = d0 + space - 10;
- int u, chars;
- while (*s != 0) {
- chars = length;
- u = xmlGetUTF8Char((unsigned char *) s, &chars);
- if (chars <= 0) {
- s += 1;
- length -= 1;
- LOG(("UTF-8 error"));
- continue;
- }
- s += chars;
- length -= chars;
- if (u == 0x09 || u == 0x0a || u == 0x0d)
- *d++ = ' ';
- else if ((0x20 <= u && u <= 0x7f) || (0xa0 <= u && u <= 0xff))
- *d++ = u;
- else {
- unicode_transliterate((unsigned int) u, &d);
- if (end < d) {
- space += 100;
- d0 = xrealloc(d0, space);
- end = d0 + space - 10;
- }
- }
+/**
+ * Converts NUL terminated UTF-8 encoded string s containing zero or more
+ * spaces (char 32) or TABs (char 9) to non-breaking spaces
+ * (0xC2 + 0xA0 in UTF-8 encoding).
+ *
+ * Caller needs to free() result. Returns NULL in case of error. No
+ * checking is done on validness of the UTF-8 input string.
+ */
+char *cnv_space2nbsp(const char *s)
+{
+ const char *srcP;
+ char *d, *d0;
+ unsigned int numNBS;
+ /* Convert space & TAB into non breaking space character (0xA0) */
+ for (numNBS = 0, srcP = (const char *)s; *srcP != '\0'; ++srcP)
+ if (*srcP == ' ' || *srcP == '\t')
+ ++numNBS;
+ if ((d = (char *)malloc((srcP - s) + numNBS + 1)) == NULL)
+ return NULL;
+ for (d0 = d, srcP = (const char *)s; *srcP != '\0'; ++srcP) {
+ if (*srcP == ' ' || *srcP == '\t') {
+ *d0++ = 0xC2;
+ *d0++ = 0xA0;
+ } else
+ *d0++ = *srcP;
}
- *d = 0;
+ *d0 = '\0';
+ return d;
+}
- return d0;
+/**
+ * Converts NUL terminated UTF-8 string <s> to the machine local encoding.
+ * Caller needs to free return value.
+ */
+char *cnv_str_local_enc(const char *s)
+{
+return cnv_strn_local_enc(s, strlen(s), NULL);
}
-char * tolat1_pre(xmlChar * s)
+/**
+ * Converts UTF-8 string <s> of <length> bytes to the machine local encoding.
+ * Caller needs to free return value.
+ *
+ * When back_map is non-NULL, a ptr to a ptrdiff_t array is filled in which
+ * needs to be free'd by the caller. The array contains per character
+ * in the return string, a ptrdiff in the <s> UTF-8 encoded string.
+ *
+ * \todo more work is needed here. Only Latin1 is done here.
+ */
+char *cnv_strn_local_enc(const char *s, int length, const ptrdiff_t **back_mapPP)
{
- unsigned int length = strlen((char*) s);
+ /* Buffer at d & back_mapP can be overdimentioned but is certainly
+ * big enough to carry the end result.
+ */
char *d = xcalloc(length + 1, sizeof(char));
+ ptrdiff_t *back_mapP = (back_mapPP != NULL) ? xcalloc(length + 1, sizeof(ptrdiff_t)) : NULL;
char *d0 = d;
- int u, chars;
+ const char * const s0 = s;
+
+ if (back_mapPP != NULL)
+ *back_mapPP = back_mapP;
+
+ while (length != 0) {
+ int u, chars;
- while (*s != 0) {
chars = length;
- u = xmlGetUTF8Char((unsigned char *) s, &chars);
+ u = xmlGetUTF8Char(s, &chars);
if (chars <= 0) {
- s += 1;
- length -= 1;
- continue;
+ s += 1;
+ length -= 1;
+ continue;
}
+ if (back_mapP != NULL)
+ *back_mapP++ = s - s0;
s += chars;
length -= chars;
if (u == 0x09 || u == 0x0a || u == 0x0d ||
(0x20 <= u && u <= 0x7f) ||
(0xa0 <= u && u <= 0xff))
- *d = u;
+ *d++ = u;
else
- *d = '?';
- d++;
+ *d++ = '?';
}
+ if (back_mapP != NULL)
+ *back_mapP = s - s0;
*d = 0;
return d0;
}
-char *squash_tolat1(xmlChar *s)
-{
- /* TODO: optimize */
- char *lat1 = tolat1(s);
- char *squash = squash_whitespace(lat1);
- free(lat1);
- return squash;
-}
-
/**
* Check if a directory exists.
diff --git a/utils/utils.h b/utils/utils.h
index e606baa6c..6b5e88a3a 100644
--- a/utils/utils.h
+++ b/utils/utils.h
@@ -3,12 +3,14 @@
* Licensed under the GNU General Public License,
* http://www.opensource.org/licenses/gpl-license
* Copyright 2004 James Bursa <bursa@users.sourceforge.net>
+ * Copyright 2004 John Tytgat <John.Tytgat@aaug.net>
*/
#ifndef _NETSURF_UTILS_UTILS_H_
#define _NETSURF_UTILS_UTILS_H_
#include <stdbool.h>
+#include <stddef.h>
#include <stdlib.h>
#include <sys/types.h>
#include <regex.h>
@@ -23,9 +25,9 @@ void xfree(void* p);
char * xstrdup(const char * const s);
char * load(const char * const path);
char * squash_whitespace(const char * s);
-char * tolat1(xmlChar * s);
-char * tolat1_pre(xmlChar * s);
-char *squash_tolat1(xmlChar *s);
+char *cnv_space2nbsp(const char *s);
+char *cnv_str_local_enc(const char *s);
+char *cnv_strn_local_enc(const char *s, int length, const ptrdiff_t **back_mapPP);
bool is_dir(const char *path);
void regcomp_wrapper(regex_t *preg, const char *regex, int cflags);
void clean_cookiejar(void);