diff options
Diffstat (limited to 'render/textplain.c')
-rw-r--r-- | render/textplain.c | 918 |
1 files changed, 441 insertions, 477 deletions
diff --git a/render/textplain.c b/render/textplain.c index d3768889d..5d28d9c54 100644 --- a/render/textplain.c +++ b/render/textplain.c @@ -17,8 +17,10 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -/** \file - * Content for text/plain (implementation). +/** + * \file + * + * plain text content handling implementation. */ #include <assert.h> @@ -85,7 +87,6 @@ typedef struct textplain_content { #define CHUNK 32768 /* Must be a power of 2 */ #define MARGIN 4 - #define TAB_WIDTH 8 /* must be power of 2 currently */ #define TEXT_SIZE 10 * FONT_SIZE_SCALE /* Unscaled text size in pt */ @@ -100,96 +101,13 @@ static plot_font_style_t textplain_style = { static int textplain_tab_width = 256; /* try for a sensible default */ -static void textplain_fini(void); -static nserror textplain_create(const content_handler *handler, - lwc_string *imime_type, const http_parameter *params, - llcache_handle *llcache, const char *fallback_charset, - bool quirks, struct content **c); -static nserror textplain_create_internal(textplain_content *c, - lwc_string *charset); -static bool textplain_process_data(struct content *c, - const char *data, unsigned int size); -static bool textplain_convert(struct content *c); -static void textplain_mouse_track(struct content *c, struct browser_window *bw, - browser_mouse_state mouse, int x, int y); -static void textplain_mouse_action(struct content *c, struct browser_window *bw, - browser_mouse_state mouse, int x, int y); -static bool textplain_keypress(struct content *c, uint32_t key); -static void textplain_search(struct content *c, void *gui_data, - search_flags_t flags, const char *string); -static void textplain_search_clear(struct content *c); -static void textplain_reformat(struct content *c, int width, int height); -static void textplain_destroy(struct content *c); -static bool textplain_redraw(struct content *c, struct content_redraw_data *data, - const struct rect *clip, const struct redraw_context *ctx); -static void textplain_open(struct content *c, struct browser_window *bw, - struct content *page, struct object_params *params); -void textplain_close(struct content *c); -char *textplain_get_selection(struct content *c); -static nserror textplain_clone(const struct content *old, - struct content **newc); -static content_type textplain_content_type(void); - -static parserutils_error textplain_charset_hack(const uint8_t *data, size_t len, - uint16_t *mibenum, uint32_t *source); -static bool textplain_drain_input(textplain_content *c, - parserutils_inputstream *stream, parserutils_error terminator); -static bool textplain_copy_utf8_data(textplain_content *c, - const uint8_t *buf, size_t len); -static int textplain_coord_from_offset(const char *text, size_t offset, - size_t length); -static float textplain_line_height(void); - -static const content_handler textplain_content_handler = { - .fini = textplain_fini, - .create = textplain_create, - .process_data = textplain_process_data, - .data_complete = textplain_convert, - .reformat = textplain_reformat, - .destroy = textplain_destroy, - .mouse_track = textplain_mouse_track, - .mouse_action = textplain_mouse_action, - .keypress = textplain_keypress, - .search = textplain_search, - .search_clear = textplain_search_clear, - .redraw = textplain_redraw, - .open = textplain_open, - .close = textplain_close, - .get_selection = textplain_get_selection, - .clone = textplain_clone, - .type = textplain_content_type, - .no_share = true, -}; - static lwc_string *textplain_default_charset; -/** - * Initialise the text content handler - */ -nserror textplain_init(void) -{ - lwc_error lerror; - nserror error; - - lerror = lwc_intern_string("Windows-1252", SLEN("Windows-1252"), - &textplain_default_charset); - if (lerror != lwc_error_ok) { - return NSERROR_NOMEM; - } - - error = content_factory_register_handler("text/plain", - &textplain_content_handler); - if (error != NSERROR_OK) { - lwc_string_unref(textplain_default_charset); - } - - return error; -} /** * Clean up after the text content handler */ -void textplain_fini(void) +static void textplain_fini(void) { if (textplain_default_charset != NULL) { lwc_string_unref(textplain_default_charset); @@ -197,67 +115,37 @@ void textplain_fini(void) } } -/** - * Create a CONTENT_TEXTPLAIN. - */ - -nserror textplain_create(const content_handler *handler, - lwc_string *imime_type, const http_parameter *params, - llcache_handle *llcache, const char *fallback_charset, - bool quirks, struct content **c) -{ - textplain_content *text; - nserror error; - lwc_string *encoding; - - text = calloc(1, sizeof(textplain_content)); - if (text == NULL) - return NSERROR_NOMEM; - - error = content__init(&text->base, handler, imime_type, params, - llcache, fallback_charset, quirks); - if (error != NSERROR_OK) { - free(text); - return error; - } - - error = http_parameter_list_find_item(params, corestring_lwc_charset, - &encoding); - if (error != NSERROR_OK) { - encoding = lwc_string_ref(textplain_default_charset); - } - error = textplain_create_internal(text, encoding); - if (error != NSERROR_OK) { - lwc_string_unref(encoding); - free(text); - return error; - } - - lwc_string_unref(encoding); - - *c = (struct content *) text; - - return NSERROR_OK; -} - -/* - * Hack around bug in libparserutils: if the client provides an - * encoding up front, but does not provide a charset detection - * callback, then libparserutils will replace the provided encoding - * with UTF-8. This breaks our input handling. +/** + * Work around feature in libparserutils + * + * if the client provides an encoding up front, but does not provide a + * charset detection callback, then libparserutils will replace the + * provided encoding with UTF-8. This breaks our input handling. * - * We avoid this by providing a callback that does precisely nothing, + * Avoid this by providing a callback that does precisely nothing, * thus preserving whatever charset information we decided on in * textplain_create. */ -parserutils_error textplain_charset_hack(const uint8_t *data, size_t len, - uint16_t *mibenum, uint32_t *source) +static parserutils_error +textplain_charset_hack(const uint8_t *data, + size_t len, + uint16_t *mibenum, + uint32_t *source) { return PARSERUTILS_OK; -} +} + -nserror textplain_create_internal(textplain_content *c, lwc_string *encoding) +/** + * setup plain text render. + * + * \param[in] c content object. + * \param[in] encoding the encoding of the content. + * \return NSERROR_OK else appropriate error code. + */ +static nserror +textplain_create_internal(textplain_content *c, lwc_string *encoding) { char *utf8_data; parserutils_inputstream *stream; @@ -270,18 +158,18 @@ nserror textplain_create_internal(textplain_content *c, lwc_string *encoding) if (utf8_data == NULL) goto no_memory; - error = parserutils_inputstream_create(lwc_string_data(encoding), 0, - textplain_charset_hack, &stream); + error = parserutils_inputstream_create(lwc_string_data(encoding), 0, + textplain_charset_hack, &stream); if (error == PARSERUTILS_BADENCODING) { /* Fall back to Windows-1252 */ error = parserutils_inputstream_create("Windows-1252", 0, - textplain_charset_hack, &stream); + textplain_charset_hack, &stream); } if (error != PARSERUTILS_OK) { free(utf8_data); goto no_memory; } - + c->encoding = lwc_string_ref(encoding); c->inputstream = stream; c->utf8_data = utf8_data; @@ -299,28 +187,110 @@ nserror textplain_create_internal(textplain_content *c, lwc_string *encoding) no_memory: msg_data.error = messages_get("NoMemory"); content_broadcast(&c->base, CONTENT_MSG_ERROR, msg_data); + return NSERROR_NOMEM; } -bool textplain_drain_input(textplain_content *c, - parserutils_inputstream *stream, - parserutils_error terminator) + +/** + * Create a CONTENT_TEXTPLAIN. + */ +static nserror +textplain_create(const content_handler *handler, + lwc_string *imime_type, + const http_parameter *params, + llcache_handle *llcache, + const char *fallback_charset, + bool quirks, + struct content **c) +{ + textplain_content *text; + nserror error; + lwc_string *encoding; + + text = calloc(1, sizeof(textplain_content)); + if (text == NULL) { + return NSERROR_NOMEM; + } + + error = content__init(&text->base, handler, imime_type, params, + llcache, fallback_charset, quirks); + if (error != NSERROR_OK) { + free(text); + return error; + } + + error = http_parameter_list_find_item(params, corestring_lwc_charset, + &encoding); + if (error != NSERROR_OK) { + encoding = lwc_string_ref(textplain_default_charset); + } + + error = textplain_create_internal(text, encoding); + if (error != NSERROR_OK) { + lwc_string_unref(encoding); + free(text); + return error; + } + + lwc_string_unref(encoding); + + *c = (struct content *) text; + + return NSERROR_OK; +} + + +/** + * copy utf8 encoded data + */ +static bool +textplain_copy_utf8_data(textplain_content *c, const uint8_t *buf, size_t len) +{ + if (c->utf8_data_size + len >= c->utf8_data_allocated) { + /* Compute next multiple of chunk above the required space */ + size_t allocated; + char *utf8_data; + + allocated = (c->utf8_data_size + len + CHUNK - 1) & ~(CHUNK - 1); + utf8_data = realloc(c->utf8_data, allocated); + if (utf8_data == NULL) + return false; + + c->utf8_data = utf8_data; + c->utf8_data_allocated = allocated; + } + + memcpy(c->utf8_data + c->utf8_data_size, buf, len); + c->utf8_data_size += len; + + return true; +} + + +/** + * drain input + */ +static bool +textplain_drain_input(textplain_content *c, + parserutils_inputstream *stream, + parserutils_error terminator) { static const uint8_t *u_fffd = (const uint8_t *) "\xef\xbf\xfd"; const uint8_t *ch; size_t chlen, offset = 0; - while (parserutils_inputstream_peek(stream, offset, &ch, &chlen) != - terminator) { + while (parserutils_inputstream_peek(stream, offset, &ch, &chlen) != + terminator) { /* Replace all instances of NUL with U+FFFD */ if (chlen == 1 && *ch == 0) { if (offset > 0) { /* Obtain pointer to start of input data */ - parserutils_inputstream_peek(stream, 0, - &ch, &chlen); + parserutils_inputstream_peek(stream, 0, + &ch, &chlen); /* Copy from it up to the start of the NUL */ - if (textplain_copy_utf8_data(c, ch, - offset) == false) + if (textplain_copy_utf8_data(c, ch, + offset) == false) return false; } @@ -338,12 +308,12 @@ bool textplain_drain_input(textplain_content *c, if (offset > CHUNK) { /* Obtain pointer to start of input data */ - parserutils_inputstream_peek(stream, 0, - &ch, &chlen); + parserutils_inputstream_peek(stream, 0, + &ch, &chlen); /* Emit the data we've read */ - if (textplain_copy_utf8_data(c, ch, - offset) == false) + if (textplain_copy_utf8_data(c, ch, + offset) == false) return false; /* Advance the inputstream */ @@ -356,7 +326,7 @@ bool textplain_drain_input(textplain_content *c, if (offset > 0) { /* Obtain pointer to start of input data */ - parserutils_inputstream_peek(stream, 0, &ch, &chlen); + parserutils_inputstream_peek(stream, 0, &ch, &chlen); /* Emit any data remaining */ if (textplain_copy_utf8_data(c, ch, offset) == false) return false; @@ -368,44 +338,20 @@ bool textplain_drain_input(textplain_content *c, return true; } -bool textplain_copy_utf8_data(textplain_content *c, - const uint8_t *buf, size_t len) -{ - if (c->utf8_data_size + len >= c->utf8_data_allocated) { - /* Compute next multiple of chunk above the required space */ - size_t allocated; - char *utf8_data; - - allocated = (c->utf8_data_size + len + CHUNK - 1) & ~(CHUNK - 1); - utf8_data = realloc(c->utf8_data, allocated); - if (utf8_data == NULL) - return false; - - c->utf8_data = utf8_data; - c->utf8_data_allocated = allocated; - } - - memcpy(c->utf8_data + c->utf8_data_size, buf, len); - c->utf8_data_size += len; - - return true; -} - /** * Process data for CONTENT_TEXTPLAIN. */ - -bool textplain_process_data(struct content *c, - const char *data, unsigned int size) +static bool +textplain_process_data(struct content *c, const char *data, unsigned int size) { textplain_content *text = (textplain_content *) c; parserutils_inputstream *stream = text->inputstream; union content_msg_data msg_data; parserutils_error error; - error = parserutils_inputstream_append(stream, - (const uint8_t *) data, size); + error = parserutils_inputstream_append(stream, + (const uint8_t *) data, size); if (error != PARSERUTILS_OK) { goto no_memory; } @@ -425,8 +371,7 @@ no_memory: /** * Convert a CONTENT_TEXTPLAIN for display. */ - -bool textplain_convert(struct content *c) +static bool textplain_convert(struct content *c) { textplain_content *text = (textplain_content *) c; parserutils_inputstream *stream = text->inputstream; @@ -452,10 +397,23 @@ bool textplain_convert(struct content *c) /** - * Reformat a CONTENT_TEXTPLAIN to a new width. + * Calculate the line height, in pixels + * + * \return Line height, in pixels */ +static float textplain_line_height(void) +{ + /* Size is in points, so convert to pixels. + * Then use a constant line height of 1.2 x font size. + */ + return FIXTOFLT(FDIV((FMUL(FLTTOFIX(1.2), FMUL(nscss_screen_dpi, INTTOFIX((textplain_style.size / FONT_SIZE_SCALE))))), F_72)); +} -void textplain_reformat(struct content *c, int width, int height) + +/** + * Reformat a CONTENT_TEXTPLAIN to a new width. + */ +static void textplain_reformat(struct content *c, int width, int height) { textplain_content *text = (textplain_content *) c; char *utf8_data = text->utf8_data; @@ -521,23 +479,25 @@ void textplain_reformat(struct content *c, int width, int height) if (term || next_col >= columns) { if (line_count % 1024 == 0) { - line1 = realloc(line, - sizeof(struct textplain_line) * + line1 = realloc(line, + sizeof(struct textplain_line) * (line_count + 1024 + 3)); if (!line1) goto no_memory; text->physical_line = line = line1; } + if (term) { line[line_count-1].length = i - line_start; /* skip second char of CR/LF or LF/CR pair */ if (i + 1 < utf8_data_size && - utf8_data[i+1] != utf8_data[i] && - (utf8_data[i+1] == '\n' || utf8_data[i+1] == '\r')) + utf8_data[i+1] != utf8_data[i] && + (utf8_data[i+1] == '\n' || + utf8_data[i+1] == '\r')) { i++; - } - else { + } + } else { if (space) { /* break at last space in line */ i = space; @@ -545,6 +505,7 @@ void textplain_reformat(struct content *c, int width, int height) } else line[line_count-1].length = i - line_start; } + line[line_count++].start = line_start = i + 1; col = 0; space = 0; @@ -574,7 +535,7 @@ no_memory: * Destroy a CONTENT_TEXTPLAIN and free all resources it owns. */ -void textplain_destroy(struct content *c) +static void textplain_destroy(struct content *c) { textplain_content *text = (textplain_content *) c; @@ -594,7 +555,7 @@ void textplain_destroy(struct content *c) } -nserror textplain_clone(const struct content *old, struct content **newc) +static nserror textplain_clone(const struct content *old, struct content **newc) { const textplain_content *old_text = (textplain_content *) old; textplain_content *text; @@ -628,7 +589,7 @@ nserror textplain_clone(const struct content *old, struct content **newc) } if (old->status == CONTENT_STATUS_READY || - old->status == CONTENT_STATUS_DONE) { + old->status == CONTENT_STATUS_DONE) { if (textplain_convert(&text->base) == false) { content_destroy(&text->base); return NSERROR_CLONE_FAILED; @@ -638,71 +599,27 @@ nserror textplain_clone(const struct content *old, struct content **newc) return NSERROR_OK; } -content_type textplain_content_type(void) -{ - return CONTENT_TEXTPLAIN; -} - -/** - * Handle mouse tracking (including drags) in a TEXTPLAIN content window. - * - * \param c content of type textplain - * \param bw browser window - * \param mouse state of mouse buttons and modifier keys - * \param x coordinate of mouse - * \param y coordinate of mouse - */ -void textplain_mouse_track(struct content *c, struct browser_window *bw, - browser_mouse_state mouse, int x, int y) +static content_type textplain_content_type(void) { - textplain_content *text = (textplain_content *) c; - - if (browser_window_get_drag_type(bw) == DRAGGING_SELECTION && !mouse) { - int dir = -1; - size_t idx; - - if (selection_dragging_start(&text->sel)) - dir = 1; - - idx = textplain_offset_from_coords(c, x, y, dir); - selection_track(&text->sel, mouse, idx); - - browser_window_set_drag_type(bw, DRAGGING_NONE, NULL); - } - - switch (browser_window_get_drag_type(bw)) { - - case DRAGGING_SELECTION: { - int dir = -1; - size_t idx; - - if (selection_dragging_start(&text->sel)) dir = 1; - - idx = textplain_offset_from_coords(c, x, y, dir); - selection_track(&text->sel, mouse, idx); - } - break; - - default: - textplain_mouse_action(c, bw, mouse, x, y); - break; - } + return CONTENT_TEXTPLAIN; } /** * Handle mouse clicks and movements in a TEXTPLAIN content window. * - * \param c content of type textplain - * \param bw browser window - * \param mouse mouse state on action - * \param x coordinate of mouse - * \param y coordinate of mouse + * \param c content of type textplain + * \param bw browser window + * \param mouse mouse state on action + * \param x coordinate of mouse + * \param y coordinate of mouse */ - -void textplain_mouse_action(struct content *c, struct browser_window *bw, - browser_mouse_state mouse, int x, int y) +static void +textplain_mouse_action(struct content *c, + struct browser_window *bw, + browser_mouse_state mouse, + int x, int y) { textplain_content *text = (textplain_content *) c; browser_pointer_shape pointer = BROWSER_POINTER_DEFAULT; @@ -718,7 +635,7 @@ void textplain_mouse_action(struct content *c, struct browser_window *bw, if (selection_dragging(&text->sel)) { browser_window_set_drag_type(bw, - DRAGGING_SELECTION, NULL); + DRAGGING_SELECTION, NULL); status = messages_get("Selecting"); } @@ -738,14 +655,63 @@ void textplain_mouse_action(struct content *c, struct browser_window *bw, /** + * Handle mouse tracking (including drags) in a TEXTPLAIN content window. + * + * \param c content of type textplain + * \param bw browser window + * \param mouse state of mouse buttons and modifier keys + * \param x coordinate of mouse + * \param y coordinate of mouse + */ +static void +textplain_mouse_track(struct content *c, + struct browser_window *bw, + browser_mouse_state mouse, + int x, int y) +{ + textplain_content *text = (textplain_content *) c; + + if (browser_window_get_drag_type(bw) == DRAGGING_SELECTION && !mouse) { + int dir = -1; + size_t idx; + + if (selection_dragging_start(&text->sel)) + dir = 1; + + idx = textplain_offset_from_coords(c, x, y, dir); + selection_track(&text->sel, mouse, idx); + + browser_window_set_drag_type(bw, DRAGGING_NONE, NULL); + } + + switch (browser_window_get_drag_type(bw)) { + + case DRAGGING_SELECTION: { + int dir = -1; + size_t idx; + + if (selection_dragging_start(&text->sel)) dir = 1; + + idx = textplain_offset_from_coords(c, x, y, dir); + selection_track(&text->sel, mouse, idx); + } + break; + + default: + textplain_mouse_action(c, bw, mouse, x, y); + break; + } +} + + +/** * Handle keypresses. * * \param c content of type CONTENT_TEXTPLAIN * \param key The UCS4 character codepoint * \return true if key handled, false otherwise */ - -bool textplain_keypress(struct content *c, uint32_t key) +static bool textplain_keypress(struct content *c, uint32_t key) { textplain_content *text = (textplain_content *) c; struct selection *sel = &text->sel; @@ -778,6 +744,27 @@ bool textplain_keypress(struct content *c, uint32_t key) /** + * Terminate a search. + * + * \param c content of type text + */ +static void textplain_search_clear(struct content *c) +{ + textplain_content *text = (textplain_content *) c; + + assert(c != NULL); + + free(text->search_string); + text->search_string = NULL; + + if (text->search != NULL) { + search_destroy_context(text->search); + } + text->search = NULL; +} + + +/** * Handle search. * * \param c content of type text @@ -785,16 +772,16 @@ bool textplain_keypress(struct content *c, uint32_t key) * \param flags search flags * \param string search string */ -void textplain_search(struct content *c, void *gui_data, - search_flags_t flags, const char *string) +static void textplain_search(struct content *c, void *gui_data, + search_flags_t flags, const char *string) { textplain_content *text = (textplain_content *) c; assert(c != NULL); if (string != NULL && text->search_string != NULL && - strcmp(string, text->search_string) == 0 && - text->search != NULL) { + strcmp(string, text->search_string) == 0 && + text->search != NULL) { /* Continue prev. search */ search_step(text->search, flags, string); @@ -811,7 +798,7 @@ void textplain_search(struct content *c, void *gui_data, } text->search = search_create_context(c, CONTENT_TEXTPLAIN, - gui_data); + gui_data); if (text->search == NULL) return; @@ -829,39 +816,21 @@ void textplain_search(struct content *c, void *gui_data, /** - * Terminate a search. - * - * \param c content of type text - */ -void textplain_search_clear(struct content *c) -{ - textplain_content *text = (textplain_content *) c; - - assert(c != NULL); - - free(text->search_string); - text->search_string = NULL; - - if (text->search != NULL) - search_destroy_context(text->search); - text->search = NULL; -} - - -/** * Draw a CONTENT_TEXTPLAIN using the current set of plotters (plot). * + * x, y, clip_[xy][01] are in target coordinates. + * * \param c content of type CONTENT_TEXTPLAIN * \param data redraw data for this content redraw * \param clip current clip region * \param ctx current redraw context * \return true if successful, false otherwise - * - * x, y, clip_[xy][01] are in target coordinates. */ - -bool textplain_redraw(struct content *c, struct content_redraw_data *data, - const struct rect *clip, const struct redraw_context *ctx) +static bool +textplain_redraw(struct content *c, + struct content_redraw_data *data, + const struct rect *clip, + const struct redraw_context *ctx) { textplain_content *text = (textplain_content *) c; struct browser_window *bw = text->bw; @@ -931,20 +900,20 @@ bool textplain_redraw(struct content *c, struct content_redraw_data *data, next_offset = utf8_next(text_d, length, next_offset); if (!text_redraw(text_d + offset, next_offset - offset, - line[lineno].start + offset, 0, - &textplain_style, - tx, y + (lineno * scaled_line_height), - clip, line_height, data->scale, false, - (struct content *)text, &text->sel, - text->search, ctx)) + line[lineno].start + offset, 0, + &textplain_style, + tx, y + (lineno * scaled_line_height), + clip, line_height, data->scale, false, + (struct content *)text, &text->sel, + text->search, ctx)) return false; if (next_offset >= length) break; res = guit->layout->width(&textplain_style, - &text_d[offset], - next_offset - offset, + &text_d[offset], + next_offset - offset, &width); /* locate end of string and align to next tab position */ if (res == NSERROR_OK) { @@ -953,9 +922,11 @@ bool textplain_redraw(struct content *c, struct content_redraw_data *data, ntx = x + ((1 + (tx - x) / tab_width) * tab_width); - /* if the tab character lies within the selection, if any, - then we must draw it as a filled rectangle so that it's - consistent with background of the selected text */ + /* if the tab character lies within the + * selection, if any, then we must draw it as + * a filled rectangle so that it's consistent + * with background of the selected text + */ if (bw) { unsigned tab_ofst = line[lineno].start + next_offset; @@ -965,17 +936,21 @@ bool textplain_redraw(struct content *c, struct content_redraw_data *data, if (selection_defined(sel)) { unsigned start_idx, end_idx; if (selection_highlighted(sel, - tab_ofst, tab_ofst + 1, - &start_idx, &end_idx)) + tab_ofst, + tab_ofst + 1, + &start_idx, + &end_idx)) highlighted = true; } if (!highlighted && (text->search != NULL)) { unsigned start_idx, end_idx; if (search_term_highlighted(c, - tab_ofst, tab_ofst + 1, - &start_idx, &end_idx, - text->search)) + tab_ofst, + tab_ofst + 1, + &start_idx, + &end_idx, + text->search)) highlighted = true; } @@ -1006,9 +981,11 @@ bool textplain_redraw(struct content *c, struct content_redraw_data *data, /** * Handle a window containing a CONTENT_TEXTPLAIN being opened. */ - -void textplain_open(struct content *c, struct browser_window *bw, - struct content *page, struct object_params *params) +static void +textplain_open(struct content *c, + struct browser_window *bw, + struct content *page, + struct object_params *params) { textplain_content *text = (textplain_content *) c; @@ -1022,13 +999,13 @@ void textplain_open(struct content *c, struct browser_window *bw, /** * Handle a window containing a CONTENT_TEXTPLAIN being closed. */ - -void textplain_close(struct content *c) +static void textplain_close(struct content *c) { textplain_content *text = (textplain_content *) c; - if (text->search != NULL) + if (text->search != NULL) { search_destroy_context(text->search); + } text->bw = NULL; } @@ -1037,20 +1014,107 @@ void textplain_close(struct content *c) /** * Return an textplain content's selection context */ - -char *textplain_get_selection(struct content *c) +static char *textplain_get_selection(struct content *c) { textplain_content *text = (textplain_content *) c; return selection_get_copy(&text->sel); } + /** - * Retrieve number of lines in content + * Convert a character offset within a line of text into the + * horizontal co-ordinate + * + * The conversion takes into account the font being used and any tabs + * in the text * - * \param c Content to retrieve line count from - * \return Number of lines + * \param text line of text + * \param offset char offset within text + * \param length line length + * \return x ordinate */ +static int +textplain_coord_from_offset(const char *text, size_t offset, size_t length) +{ + int x = 0; + + while (offset > 0) { + size_t next_offset = 0; + int tx; + + while (next_offset < offset && text[next_offset] != '\t') { + next_offset = utf8_next(text, length, next_offset); + } + + guit->layout->width(&textplain_style, text, next_offset, &tx); + + x += tx; + + if (next_offset >= offset) + break; + + /* align to next tab boundary */ + next_offset++; + x = (1 + (x / textplain_tab_width)) * textplain_tab_width; + offset -= next_offset; + text += next_offset; + length -= next_offset; + } + + return x; +} + + +/** + * plain text content handler table + */ +static const content_handler textplain_content_handler = { + .fini = textplain_fini, + .create = textplain_create, + .process_data = textplain_process_data, + .data_complete = textplain_convert, + .reformat = textplain_reformat, + .destroy = textplain_destroy, + .mouse_track = textplain_mouse_track, + .mouse_action = textplain_mouse_action, + .keypress = textplain_keypress, + .search = textplain_search, + .search_clear = textplain_search_clear, + .redraw = textplain_redraw, + .open = textplain_open, + .close = textplain_close, + .get_selection = textplain_get_selection, + .clone = textplain_clone, + .type = textplain_content_type, + .no_share = true, +}; + + +/* exported interface documented in render/textplain.h */ +nserror textplain_init(void) +{ + lwc_error lerror; + nserror error; + + lerror = lwc_intern_string("Windows-1252", + SLEN("Windows-1252"), + &textplain_default_charset); + if (lerror != lwc_error_ok) { + return NSERROR_NOMEM; + } + + error = content_factory_register_handler("text/plain", + &textplain_content_handler); + if (error != NSERROR_OK) { + lwc_string_unref(textplain_default_charset); + } + + return error; +} + + +/* exported interface documented in render/textplain.h */ unsigned long textplain_line_count(struct content *c) { textplain_content *text = (textplain_content *) c; @@ -1060,12 +1124,8 @@ unsigned long textplain_line_count(struct content *c) return text->physical_line_count; } -/** - * Retrieve the size (in bytes) of text data - * - * \param c Content to retrieve size of - * \return Size, in bytes, of data - */ + +/* exported interface documented in render/textplain.h */ size_t textplain_size(struct content *c) { textplain_content *text = (textplain_content *) c; @@ -1075,21 +1135,8 @@ size_t textplain_size(struct content *c) return text->utf8_data_size; } -/** - - * Return byte offset within UTF8 textplain content. - * - * given the co-ordinates of a point within a textplain content. 'dir' - * specifies the direction in which to search (-1 = above-left, +1 = - * below-right) if the co-ordinates are not contained within a line. - * - * \param c content of type CONTENT_TEXTPLAIN - * \param x x ordinate of point - * \param y y ordinate of point - * \param dir direction of search if not within line - * \return byte offset of character containing (or nearest to) point - */ +/* exported interface documented in render/textplain.h */ size_t textplain_offset_from_coords(struct content *c, int x, int y, int dir) { textplain_content *textc = (textplain_content *) c; @@ -1122,8 +1169,9 @@ size_t textplain_offset_from_coords(struct content *c, int x, int y, int dir) size_t next_offset = 0; int width = INT_MAX; - while (next_offset < length && text[next_offset] != '\t') + while (next_offset < length && text[next_offset] != '\t') { next_offset = utf8_next(text, length, next_offset); + } if (next_offset < length) { guit->layout->width(&textplain_style, @@ -1163,94 +1211,12 @@ size_t textplain_offset_from_coords(struct content *c, int x, int y, int dir) } -/** - * Given a byte offset within the text, return the line number - * of the line containing that offset (or -1 if offset invalid) - * - * \param c content of type CONTENT_TEXTPLAIN - * \param offset byte offset within textual representation - * \return line number, or -1 if offset invalid (larger than size) - */ - -int textplain_find_line(struct content *c, unsigned offset) -{ - textplain_content *text = (textplain_content *) c; - struct textplain_line *line; - int nlines; - int lineno = 0; - - assert(c != NULL); - - line = text->physical_line; - nlines = text->physical_line_count; - - if (offset > text->utf8_data_size) - return -1; - -/* \todo - implement binary search here */ - while (lineno < nlines && line[lineno].start < offset) - lineno++; - if (line[lineno].start > offset) - lineno--; - - return lineno; -} - - -/** - * Convert a character offset within a line of text into the - * horizontal co-ordinate, taking into account the font being - * used and any tabs in the text - * - * \param text line of text - * \param offset char offset within text - * \param length line length - * \return x ordinate - */ - -int textplain_coord_from_offset(const char *text, size_t offset, size_t length) -{ - int x = 0; - - while (offset > 0) { - size_t next_offset = 0; - int tx; - - while (next_offset < offset && text[next_offset] != '\t') { - next_offset = utf8_next(text, length, next_offset); - } - - guit->layout->width(&textplain_style, text, next_offset, &tx); - - x += tx; - - if (next_offset >= offset) - break; - - /* align to next tab boundary */ - next_offset++; - x = (1 + (x / textplain_tab_width)) * textplain_tab_width; - offset -= next_offset; - text += next_offset; - length -= next_offset; - } - - return x; -} - - -/** - * Given a range of byte offsets within a UTF8 textplain content, - * return a box that fully encloses the text - * - * \param c content of type CONTENT_TEXTPLAIN - * \param start byte offset of start of text range - * \param end byte offset of end - * \param r rectangle to be completed - */ - -void textplain_coords_from_range(struct content *c, unsigned start, - unsigned end, struct rect *r) +/* exported interface documented in render/textplain.h */ +void +textplain_coords_from_range(struct content *c, + unsigned start, + unsigned end, + struct rect *r) { textplain_content *text = (textplain_content *) c; float line_height = textplain_line_height(); @@ -1273,42 +1239,38 @@ void textplain_coords_from_range(struct content *c, unsigned start, r->y0 = (int)(MARGIN + lineno * line_height); if (lineno + 1 <= nlines || line[lineno + 1].start >= end) { - /* \todo - it may actually be more efficient just to run - forwards most of the time */ + /* \todo - it may actually be more efficient just to + * run forwards most of the time + */ /* find end */ lineno = textplain_find_line(c, end); r->x0 = 0; r->x1 = text->formatted_width; - } - else { + } else { /* single line */ const char *text = utf8_data + line[lineno].start; - r->x0 = textplain_coord_from_offset(text, start - line[lineno].start, - line[lineno].length); + r->x0 = textplain_coord_from_offset(text, + start - line[lineno].start, + line[lineno].length); - r->x1 = textplain_coord_from_offset(text, end - line[lineno].start, - line[lineno].length); + r->x1 = textplain_coord_from_offset(text, + end - line[lineno].start, + line[lineno].length); } r->y1 = (int)(MARGIN + (lineno + 1) * line_height); } -/** - * Return a pointer to the requested line of text. - * - * \param c content of type CONTENT_TEXTPLAIN - * \param lineno line number - * \param poffset receives byte offset of line start within text - * \param plen receives length of returned line - * \return pointer to text, or NULL if invalid line number - */ - -char *textplain_get_line(struct content *c, unsigned lineno, - size_t *poffset, size_t *plen) +/* exported interface documented in render/textplain.h */ +char * +textplain_get_line(struct content *c, + unsigned lineno, + size_t *poffset, + size_t *plen) { textplain_content *text = (textplain_content *) c; struct textplain_line *line; @@ -1325,20 +1287,41 @@ char *textplain_get_line(struct content *c, unsigned lineno, } -/** - * Return a pointer to the raw UTF-8 data, as opposed to the reformatted - * text to fit the window width. Thus only hard newlines are preserved - * in the saved/copied text of a selection. - * - * \param c content of type CONTENT_TEXTPLAIN - * \param start starting byte offset within UTF-8 text - * \param end ending byte offset - * \param plen receives validated length - * \return pointer to text, or NULL if no text - */ +/* exported interface documented in render/textplain.h */ +int textplain_find_line(struct content *c, unsigned offset) +{ + textplain_content *text = (textplain_content *) c; + struct textplain_line *line; + int nlines; + int lineno = 0; + + assert(c != NULL); + + line = text->physical_line; + nlines = text->physical_line_count; + + if (offset > text->utf8_data_size) { + return -1; + } + +/* \todo - implement binary search here */ + while (lineno < nlines && line[lineno].start < offset) { + lineno++; + } + if (line[lineno].start > offset) { + lineno--; + } -char *textplain_get_raw_data(struct content *c, unsigned start, unsigned end, - size_t *plen) + return lineno; +} + + +/* exported interface documented in render/textplain.h */ +char * +textplain_get_raw_data(struct content *c, + unsigned start, + unsigned end, + size_t *plen) { textplain_content *text = (textplain_content *) c; size_t utf8_size; @@ -1359,26 +1342,8 @@ char *textplain_get_raw_data(struct content *c, unsigned start, unsigned end, return text->utf8_data + start; } -/** - * Calculate the line height, in pixels - * - * \return Line height, in pixels - */ -float textplain_line_height(void) -{ - /* Size is in points, so convert to pixels. - * Then use a constant line height of 1.2 x font size. - */ - return FIXTOFLT(FDIV((FMUL(FLTTOFIX(1.2), FMUL(nscss_screen_dpi, - INTTOFIX((textplain_style.size / FONT_SIZE_SCALE))))), F_72)); -} -/** - * Get the browser window containing a textplain content - * - * \param c text/plain content - * \return the browser window - */ +/* exported interface documented in render/textplain.h */ struct browser_window *textplain_get_browser_window(struct content *c) { textplain_content *text = (textplain_content *) c; @@ -1388,4 +1353,3 @@ struct browser_window *textplain_get_browser_window(struct content *c) return text->bw; } - |