From a0d511734ae464d6e7b4d2f5e019611c0cdafea9 Mon Sep 17 00:00:00 2001 From: John Tytgat Date: Mon, 5 Jul 2004 20:19:52 +0000 Subject: [project @ 2004-07-05 20:19:51 by joty] Using UTF-8 instead of Latin1 encoding. svn path=/import/netsurf/; revision=1049 --- debug/fontd.c | 30 +- desktop/browser.c | 49 +- desktop/netsurf.c | 15 + desktop/save_text.c | 2 +- gtk/font_pango.c | 12 +- makefile | 2 +- render/box.c | 190 +++++--- render/font.h | 37 +- render/html.c | 36 +- render/layout.c | 10 +- riscos/font.c | 743 +++++++++++++++++++++------- riscos/gui.c | 5 +- riscos/help.c | 4 +- riscos/history.c | 4 +- riscos/htmlredraw.c | 37 +- riscos/menus.c | 12 +- riscos/mouseactions.c | 2 - riscos/save_draw.c | 666 ++++++++++++++----------- riscos/save_draw.h | 2 +- riscos/toolbar.c | 3 +- riscos/ufont.c | 1281 +++++++++++++++++++++++++++++++++++++++++++++++++ riscos/ufont.h | 70 +++ utils/utils.c | 131 ++--- utils/utils.h | 8 +- 24 files changed, 2646 insertions(+), 705 deletions(-) create mode 100644 riscos/ufont.c create mode 100644 riscos/ufont.h 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 * Copyright 2003 James Bursa + * Copyright 2004 John Tytgat */ #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 +#include #include #include #include @@ -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 * Copyright 2003 Phil Mellor + * Copyright 2004 John Tytgat */ /** \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 - #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 + * Copyright 2004 John Tytgat */ #include @@ -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 + * Copyright 2004 John Tytgat + */ + +/** \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 +#include +#include + +#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 onwards + are set using the RISC OS font with handle */ + 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, 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 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 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 + * Copyright 2004 John Tytgat + */ + +#ifndef UFONT_HEADER_INCLUDED +#define UFONT_HEADER_INCLUDED + +#include +#include +#include +#include + +#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 * Copyright 2003 Phil Mellor * Copyright 2003 John M Bell + * Copyright 2004 John Tytgat */ +#include #include #include #include @@ -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 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 of 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 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 + * Copyright 2004 John Tytgat */ #ifndef _NETSURF_UTILS_UTILS_H_ #define _NETSURF_UTILS_UTILS_H_ #include +#include #include #include #include @@ -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); -- cgit v1.2.3