From 2a03ea30490892ac52b3da325ab78e1aa888f83e Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Thu, 10 May 2018 11:34:26 +0100 Subject: move html and text content handlers where they belong --- render/textplain.c | 1351 ---------------------------------------------------- 1 file changed, 1351 deletions(-) delete mode 100644 render/textplain.c (limited to 'render/textplain.c') diff --git a/render/textplain.c b/render/textplain.c deleted file mode 100644 index 0036eb5c0..000000000 --- a/render/textplain.c +++ /dev/null @@ -1,1351 +0,0 @@ -/* - * Copyright 2006 James Bursa - * Copyright 2006 Adrian Lees - * - * This file is part of NetSurf, http://www.netsurf-browser.org/ - * - * NetSurf is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * NetSurf is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** - * \file - * - * plain text content handling implementation. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "utils/corestrings.h" -#include "utils/http.h" -#include "utils/log.h" -#include "utils/messages.h" -#include "utils/utils.h" -#include "utils/utf8.h" -#include "netsurf/content.h" -#include "netsurf/keypress.h" -#include "netsurf/browser_window.h" -#include "netsurf/plotters.h" -#include "netsurf/layout.h" -#include "content/content_protected.h" -#include "content/hlcache.h" -#include "css/utils.h" -#include "utils/nsoption.h" -#include "desktop/search.h" -#include "desktop/selection.h" -#include "desktop/gui_internal.h" - -#include "render/search.h" -#include "render/textplain.h" -#include "render/html.h" -#include "render/search.h" - -struct textplain_line { - size_t start; - size_t length; -}; - -typedef struct textplain_content { - struct content base; - - lwc_string *encoding; - void *inputstream; - char *utf8_data; - size_t utf8_data_size; - size_t utf8_data_allocated; - unsigned long physical_line_count; - struct textplain_line *physical_line; - int formatted_width; - struct browser_window *bw; - - struct selection sel; /** Selection state */ - - /** Context for free text search, or NULL if none */ - struct search_context *search; - /** Current search string, or NULL if none */ - char *search_string; -} 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 */ - -static plot_font_style_t textplain_style = { - .family = PLOT_FONT_FAMILY_MONOSPACE, - .size = TEXT_SIZE, - .weight = 400, - .flags = FONTF_NONE, - .background = 0xffffff, - .foreground = 0x000000, -}; - -static int textplain_tab_width = 256; /* try for a sensible default */ - -static lwc_string *textplain_default_charset; - - -/** - * Clean up after the text content handler - */ -static void textplain_fini(void) -{ - if (textplain_default_charset != NULL) { - lwc_string_unref(textplain_default_charset); - textplain_default_charset = NULL; - } -} - - -/** - * 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. - * - * Avoid this by providing a callback that does precisely nothing, - * thus preserving whatever charset information we decided on in - * textplain_create. - */ -static parserutils_error -textplain_charset_hack(const uint8_t *data, - size_t len, - uint16_t *mibenum, - uint32_t *source) -{ - return PARSERUTILS_OK; -} - - -/** - * 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; - parserutils_error error; - - textplain_style.size = (nsoption_int(font_size) * FONT_SIZE_SCALE) / 10; - - utf8_data = malloc(CHUNK); - if (utf8_data == NULL) - goto no_memory; - - 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); - } - if (error != PARSERUTILS_OK) { - free(utf8_data); - goto no_memory; - } - - c->encoding = lwc_string_ref(encoding); - c->inputstream = stream; - c->utf8_data = utf8_data; - c->utf8_data_size = 0; - c->utf8_data_allocated = CHUNK; - c->physical_line = 0; - c->physical_line_count = 0; - c->formatted_width = 0; - c->bw = NULL; - - selection_prepare(&c->sel, (struct content *)c, false); - - return NSERROR_OK; - -no_memory: - content_broadcast_errorcode(&c->base, NSERROR_NOMEM); - - return NSERROR_NOMEM; -} - - -/** - * 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) { - /* 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); - /* Copy from it up to the start of the NUL */ - if (textplain_copy_utf8_data(c, ch, - offset) == false) - return false; - } - - /* Emit U+FFFD */ - if (textplain_copy_utf8_data(c, u_fffd, 3) == false) - return false; - - /* Advance inputstream past the NUL we just read */ - parserutils_inputstream_advance(stream, offset + 1); - /* Reset the read offset */ - offset = 0; - } else { - /* Accumulate input */ - offset += chlen; - - if (offset > CHUNK) { - /* Obtain pointer to start of input data */ - parserutils_inputstream_peek(stream, 0, - &ch, &chlen); - - /* Emit the data we've read */ - if (textplain_copy_utf8_data(c, ch, - offset) == false) - return false; - - /* Advance the inputstream */ - parserutils_inputstream_advance(stream, offset); - /* Reset the read offset */ - offset = 0; - } - } - } - - if (offset > 0) { - /* Obtain pointer to start of input data */ - parserutils_inputstream_peek(stream, 0, &ch, &chlen); - /* Emit any data remaining */ - if (textplain_copy_utf8_data(c, ch, offset) == false) - return false; - - /* Advance the inputstream past the data we've read */ - parserutils_inputstream_advance(stream, offset); - } - - return true; -} - - -/** - * Process data for CONTENT_TEXTPLAIN. - */ -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; - parserutils_error error; - - error = parserutils_inputstream_append(stream, - (const uint8_t *) data, size); - if (error != PARSERUTILS_OK) { - goto no_memory; - } - - if (textplain_drain_input(text, stream, PARSERUTILS_NEEDDATA) == false) - goto no_memory; - - return true; - -no_memory: - content_broadcast_errorcode(c, NSERROR_NOMEM); - return false; -} - - -/** - * Convert a CONTENT_TEXTPLAIN for display. - */ -static bool textplain_convert(struct content *c) -{ - textplain_content *text = (textplain_content *) c; - parserutils_inputstream *stream = text->inputstream; - parserutils_error error; - - error = parserutils_inputstream_append(stream, NULL, 0); - if (error != PARSERUTILS_OK) { - return false; - } - - if (textplain_drain_input(text, stream, PARSERUTILS_EOF) == false) - return false; - - parserutils_inputstream_destroy(stream); - text->inputstream = NULL; - - content_set_ready(c); - content_set_done(c); - content_set_status(c, messages_get("Done")); - - return true; -} - - -/** - * 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)); -} - - -/** - * 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; - size_t utf8_data_size = text->utf8_data_size; - unsigned long line_count = 0; - struct textplain_line *line = text->physical_line; - struct textplain_line *line1; - size_t i, space, col; - size_t columns = 80; - int character_width; - size_t line_start; - nserror res; - - NSLOG(netsurf, INFO, "content %p w:%d h:%d", c, width, height); - - /* compute available columns (assuming monospaced font) - use 8 - * characters for better accuracy - */ - res = guit->layout->width(&textplain_style, - "ABCDEFGH", 8, - &character_width); - if (res != NSERROR_OK) { - return; - } - - columns = (width - MARGIN - MARGIN) * 8 / character_width; - textplain_tab_width = (TAB_WIDTH * character_width) / 8; - - text->formatted_width = width; - - text->physical_line_count = 0; - - if (!line) { - text->physical_line = line = - malloc(sizeof(struct textplain_line) * (1024 + 3)); - if (!line) - goto no_memory; - } - - line[line_count++].start = line_start = 0; - space = 0; - i = 0; - col = 0; - while (i < utf8_data_size) { - size_t csize; /* number of bytes in character */ - uint32_t chr; - bool term; - size_t next_col; - parserutils_error perror; - - perror = parserutils_charset_utf8_to_ucs4((const uint8_t *)utf8_data + i, utf8_data_size - i, &chr, &csize); - if (perror != PARSERUTILS_OK) { - chr = 0xfffd; - } - - term = (chr == '\n' || chr == '\r'); - - next_col = col + 1; - - if (chr == '\t') { - next_col = (next_col + TAB_WIDTH - 1) & ~(TAB_WIDTH - 1); - } - - if (term || next_col >= columns) { - if (line_count % 1024 == 0) { - 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')) { - i++; - } - } else { - if (space) { - /* break at last space in line */ - i = space; - line[line_count-1].length = (i + 1) - line_start; - } else - line[line_count-1].length = i - line_start; - } - - line[line_count++].start = line_start = i + 1; - col = 0; - space = 0; - } else { - col++; - if (chr == ' ') - space = i; - } - i += csize; - } - line[line_count-1].length = i - line[line_count-1].start; - line[line_count].start = utf8_data_size; - - text->physical_line_count = line_count; - c->width = width; - c->height = line_count * textplain_line_height() + MARGIN + MARGIN; - - return; - -no_memory: - NSLOG(netsurf, INFO, "out of memory (line_count %lu)", line_count); - return; -} - - -/** - * Destroy a CONTENT_TEXTPLAIN and free all resources it owns. - */ - -static void textplain_destroy(struct content *c) -{ - textplain_content *text = (textplain_content *) c; - - lwc_string_unref(text->encoding); - - if (text->inputstream != NULL) { - parserutils_inputstream_destroy(text->inputstream); - } - - if (text->physical_line != NULL) { - free(text->physical_line); - } - - if (text->utf8_data != NULL) { - free(text->utf8_data); - } -} - - -static nserror textplain_clone(const struct content *old, struct content **newc) -{ - const textplain_content *old_text = (textplain_content *) old; - textplain_content *text; - nserror error; - const char *data; - unsigned long size; - - text = calloc(1, sizeof(textplain_content)); - if (text == NULL) - return NSERROR_NOMEM; - - error = content__clone(old, &text->base); - if (error != NSERROR_OK) { - content_destroy(&text->base); - return error; - } - - /* Simply replay create/process/convert */ - error = textplain_create_internal(text, old_text->encoding); - if (error != NSERROR_OK) { - content_destroy(&text->base); - return error; - } - - data = content__get_source_data(&text->base, &size); - if (size > 0) { - if (textplain_process_data(&text->base, data, size) == false) { - content_destroy(&text->base); - return NSERROR_NOMEM; - } - } - - if (old->status == CONTENT_STATUS_READY || - old->status == CONTENT_STATUS_DONE) { - if (textplain_convert(&text->base) == false) { - content_destroy(&text->base); - return NSERROR_CLONE_FAILED; - } - } - - return NSERROR_OK; -} - - -static content_type textplain_content_type(void) -{ - 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 - */ -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; - union content_msg_data msg_data; - const char *status = 0; - size_t idx; - int dir = 0; - - browser_window_set_drag_type(bw, DRAGGING_NONE, NULL); - - idx = textplain_offset_from_coords(c, x, y, dir); - if (selection_click(&text->sel, mouse, idx)) { - - if (selection_dragging(&text->sel)) { - browser_window_set_drag_type(bw, - DRAGGING_SELECTION, NULL); - status = messages_get("Selecting"); - } - - } else { - if (mouse & (BROWSER_MOUSE_DRAG_1 | BROWSER_MOUSE_DRAG_2)) { - browser_window_page_drag_start(bw, x, y); - pointer = BROWSER_POINTER_MOVE; - } - } - - msg_data.explicit_status_text = status; - content_broadcast(c, CONTENT_MSG_STATUS, &msg_data); - - msg_data.pointer = pointer; - content_broadcast(c, CONTENT_MSG_POINTER, &msg_data); -} - - -/** - * 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 - */ -static bool textplain_keypress(struct content *c, uint32_t key) -{ - textplain_content *text = (textplain_content *) c; - struct selection *sel = &text->sel; - - switch (key) { - case NS_KEY_COPY_SELECTION: - selection_copy_to_clipboard(sel); - return true; - - case NS_KEY_CLEAR_SELECTION: - selection_clear(sel, true); - return true; - - case NS_KEY_SELECT_ALL: - selection_select_all(sel); - return true; - - case NS_KEY_ESCAPE: - if (selection_defined(sel)) { - selection_clear(sel, true); - return true; - } - - /* if there's no selection, leave Escape for the caller */ - return false; - } - - return false; -} - - -/** - * 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 - * \param gui_data front end private data - * \param flags search flags - * \param string search 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) { - /* Continue prev. search */ - search_step(text->search, flags, string); - - } else if (string != NULL) { - /* New search */ - free(text->search_string); - text->search_string = strdup(string); - if (text->search_string == NULL) - return; - - if (text->search != NULL) { - search_destroy_context(text->search); - text->search = NULL; - } - - text->search = search_create_context(c, CONTENT_TEXTPLAIN, - gui_data); - - if (text->search == NULL) - return; - - search_step(text->search, flags, string); - - } else { - /* Clear search */ - textplain_search_clear(c); - - free(text->search_string); - text->search_string = 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 - */ -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; - char *utf8_data = text->utf8_data; - long lineno; - int x = data->x; - int y = data->y; - unsigned long line_count = text->physical_line_count; - float line_height = textplain_line_height(); - float scaled_line_height = line_height * data->scale; - long line0 = (clip->y0 - y * data->scale) / scaled_line_height - 1; - long line1 = (clip->y1 - y * data->scale) / scaled_line_height + 1; - struct textplain_line *line = text->physical_line; - size_t length; - plot_style_t *plot_style_highlight; - nserror res; - - if (line0 < 0) - line0 = 0; - if (line1 < 0) - line1 = 0; - if (line_count < (unsigned long) line0) - line0 = line_count; - if (line_count < (unsigned long) line1) - line1 = line_count; - if (line1 < line0) - line1 = line0; - - res = ctx->plot->rectangle(ctx, plot_style_fill_white, clip); - if (res != NSERROR_OK) { - return false; - } - - if (!line) - return true; - - /* choose a suitable background colour for any highlighted text */ - if ((data->background_colour & 0x808080) == 0x808080) - plot_style_highlight = plot_style_fill_black; - else - plot_style_highlight = plot_style_fill_white; - - /* Set up font plot style */ - textplain_style.background = data->background_colour; - - x = (x + MARGIN) * data->scale; - y = (y + MARGIN) * data->scale; - for (lineno = line0; lineno != line1; lineno++) { - const char *text_d = utf8_data + line[lineno].start; - int tab_width = textplain_tab_width * data->scale; - size_t offset = 0; - int tx = x; - - if (!tab_width) tab_width = 1; - - length = line[lineno].length; - if (!length) - continue; - - while (offset < length) { - size_t next_offset = offset; - int width; - int ntx; - nserror res; - - while (next_offset < length && text_d[next_offset] != '\t') - 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)) - return false; - - if (next_offset >= length) - break; - - res = guit->layout->width(&textplain_style, - &text_d[offset], - next_offset - offset, - &width); - /* locate end of string and align to next tab position */ - if (res == NSERROR_OK) { - tx += (int)(width * data->scale); - } - - 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 (bw) { - unsigned tab_ofst = line[lineno].start + next_offset; - struct selection *sel = &text->sel; - bool highlighted = false; - - if (selection_defined(sel)) { - unsigned start_idx, end_idx; - if (selection_highlighted(sel, - 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)) - highlighted = true; - } - - if (highlighted) { - struct rect rect; - rect.x0 = tx; - rect.y0 = y + (lineno * scaled_line_height); - rect.x1 = ntx; - rect.y1 = rect.y0 + scaled_line_height; - res = ctx->plot->rectangle(ctx, - plot_style_highlight, - &rect); - if (res != NSERROR_OK) { - return false; - } - } - } - - offset = next_offset + 1; - tx = ntx; - } - } - - return true; -} - - -/** - * Handle a window containing a CONTENT_TEXTPLAIN being opened. - */ -static void -textplain_open(struct content *c, - struct browser_window *bw, - struct content *page, - struct object_params *params) -{ - textplain_content *text = (textplain_content *) c; - - text->bw = bw; - - /* text selection */ - selection_init(&text->sel, NULL, NULL); -} - - -/** - * Handle a window containing a CONTENT_TEXTPLAIN being closed. - */ -static void textplain_close(struct content *c) -{ - textplain_content *text = (textplain_content *) c; - - if (text->search != NULL) { - search_destroy_context(text->search); - } - - text->bw = NULL; -} - - -/** - * Return an textplain content's selection context - */ -static char *textplain_get_selection(struct content *c) -{ - textplain_content *text = (textplain_content *) c; - - return selection_get_copy(&text->sel); -} - - -/** - * 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 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; - - assert(c != NULL); - - return text->physical_line_count; -} - - -/* exported interface documented in render/textplain.h */ -size_t textplain_size(struct content *c) -{ - textplain_content *text = (textplain_content *) c; - - assert(c != NULL); - - return text->utf8_data_size; -} - - -/* 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; - float line_height = textplain_line_height(); - struct textplain_line *line; - const char *text; - unsigned nlines; - size_t length; - int idx; - - assert(c != NULL); - - y = (int)((float)(y - MARGIN) / line_height); - x -= MARGIN; - - nlines = textc->physical_line_count; - if (!nlines) - return 0; - - if (y <= 0) y = 0; - else if ((unsigned)y >= nlines) - y = nlines - 1; - - line = &textc->physical_line[y]; - text = textc->utf8_data + line->start; - length = line->length; - idx = 0; - - while (x > 0) { - size_t next_offset = 0; - int width = INT_MAX; - - 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, - text, - next_offset, - &width); - } - - if (x <= width) { - int pixel_offset; - size_t char_offset; - - guit->layout->position(&textplain_style, - text, next_offset, x, - &char_offset, &pixel_offset); - - idx += char_offset; - break; - } - - x -= width; - length -= next_offset; - text += next_offset; - idx += next_offset; - - /* check if it's within the tab */ - width = textplain_tab_width - (width % textplain_tab_width); - if (x <= width) break; - - x -= width; - length--; - text++; - idx++; - } - - return line->start + idx; -} - - -/* 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(); - char *utf8_data; - struct textplain_line *line; - unsigned lineno = 0; - unsigned nlines; - - assert(c != NULL); - assert(start <= end); - assert(end <= text->utf8_data_size); - - utf8_data = text->utf8_data; - nlines = text->physical_line_count; - line = text->physical_line; - - /* find start */ - lineno = textplain_find_line(c, 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 - */ - - /* find end */ - lineno = textplain_find_line(c, end); - - r->x0 = 0; - r->x1 = text->formatted_width; - } 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->x1 = textplain_coord_from_offset(text, - end - line[lineno].start, - line[lineno].length); - } - - r->y1 = (int)(MARGIN + (lineno + 1) * line_height); -} - - -/* 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; - - assert(c != NULL); - - if (lineno >= text->physical_line_count) - return NULL; - line = &text->physical_line[lineno]; - - *poffset = line->start; - *plen = line->length; - return text->utf8_data + line->start; -} - - -/* 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--; - } - - 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; - - assert(c != NULL); - - utf8_size = text->utf8_data_size; - - /* any text at all? */ - if (!utf8_size) return NULL; - - /* clamp to valid offset range */ - if (start >= utf8_size) start = utf8_size; - if (end >= utf8_size) end = utf8_size; - - *plen = end - start; - - return text->utf8_data + start; -} - - -/* exported interface documented in render/textplain.h */ -struct browser_window *textplain_get_browser_window(struct content *c) -{ - textplain_content *text = (textplain_content *) c; - - assert(c != NULL); - assert(c->handler == &textplain_content_handler); - - return text->bw; -} -- cgit v1.2.3