summaryrefslogtreecommitdiff
path: root/render
diff options
context:
space:
mode:
authorAdrian Lees <adrian@aemulor.com>2006-02-15 23:09:55 +0000
committerAdrian Lees <adrian@aemulor.com>2006-02-15 23:09:55 +0000
commitdbfdafdf1820a95995c3b260e147c55125468874 (patch)
tree8ef69f8cbc4733490f82b462edeb167c0ee08fb8 /render
parent07d55db910095415d15cc2b6509fd44efa79a875 (diff)
downloadnetsurf-dbfdafdf1820a95995c3b260e147c55125468874.tar.gz
netsurf-dbfdafdf1820a95995c3b260e147c55125468874.tar.bz2
[project @ 2006-02-15 23:09:53 by adrianl]
Extend text selection, copying, saving and searching code to handle textplain contents; modified textplain code to accept other line terminators svn path=/import/netsurf/; revision=2081
Diffstat (limited to 'render')
-rw-r--r--render/box.c27
-rw-r--r--render/box.h7
-rw-r--r--render/html.h14
-rw-r--r--render/html_redraw.c164
-rw-r--r--render/textplain.c294
-rw-r--r--render/textplain.h23
6 files changed, 456 insertions, 73 deletions
diff --git a/render/box.c b/render/box.c
index e527cdde3..5ceb0376c 100644
--- a/render/box.c
+++ b/render/box.c
@@ -47,8 +47,9 @@ struct box * box_create(struct css_style *style,
struct box *box;
box = talloc(context, struct box);
- if (!box)
+ if (!box) {
return 0;
+ }
box->type = BOX_INLINE;
box->style = style;
@@ -232,6 +233,27 @@ void box_coords(struct box *box, int *x, int *y)
/**
+ * Find the bounds of a box.
+ *
+ * \param box the box to calculate bounds of
+ * \param r receives bounds
+ */
+
+void box_bounds(struct box *box, struct rect *r)
+{
+ int width, height;
+
+ box_coords(box, &r->x0, &r->y0);
+
+ width = box->padding[LEFT] + box->width + box->padding[RIGHT];
+ height = box->padding[TOP] + box->height + box->padding[BOTTOM];
+
+ r->x1 = r->x0 + width;
+ r->y1 = r->y0 + height;
+}
+
+
+/**
* Find the boxes at a point.
*
* \param box box to search children of
@@ -244,7 +266,7 @@ void box_coords(struct box *box, int *x, int *y)
* \param content updated to content of object that returned box is in, if any
* \return box at given point, or 0 if none found
*
- * To find all the boxes in the heirarchy at a certain point, use code like
+ * To find all the boxes in the hierarchy at a certain point, use code like
* this:
* \code
* struct box *box = top_of_document_to_search;
@@ -469,6 +491,7 @@ void box_dump(struct box *box, unsigned int depth)
default: fprintf(stderr, "Unknown box type ");
}
+ fprintf(stderr, "ofst %d", box->byte_offset);
if (box->text)
fprintf(stderr, "'%.*s' ", (int) box->length, box->text);
if (box->space)
diff --git a/render/box.h b/render/box.h
index 92a48379c..3c62ecffe 100644
--- a/render/box.h
+++ b/render/box.h
@@ -96,6 +96,12 @@ typedef enum {
BOX_INLINE_END
} box_type;
+struct rect {
+ int x0, y0;
+ int x1, y1;
+};
+
+
/** Node in box tree. All dimensions are in pixels. */
struct box {
/** Type of box. */
@@ -254,6 +260,7 @@ void box_unlink_and_free(struct box *box);
void box_free(struct box *box);
void box_free_box(struct box *box);
void box_free_object_params(struct object_params *op);
+void box_bounds(struct box *box, struct rect *r);
void box_coords(struct box *box, int *x, int *y);
struct box *box_at_point(struct box *box, int x, int y,
int *box_x, int *box_y,
diff --git a/render/html.h b/render/html.h
index 959624d35..8ad0a7742 100644
--- a/render/html.h
+++ b/render/html.h
@@ -20,6 +20,7 @@
#include "netsurf/css/css.h"
struct box;
+struct rect;
struct browser_window;
struct content;
struct form_successful_control;
@@ -125,4 +126,17 @@ bool html_redraw(struct content *c, int x, int y,
int clip_x0, int clip_y0, int clip_x1, int clip_y1,
float scale, unsigned long background_colour);
+
+/* redraw a short text string, complete with highlighting
+ (for selection/search) and ghost caret */
+
+bool text_redraw(const char *utf8_text, size_t utf8_len,
+ size_t offset, bool space,
+ struct css_style *style,
+ int x, int y,
+ struct rect *clip,
+ int height,
+ float scale, colour current_background_color,
+ bool excluded);
+
#endif
diff --git a/render/html_redraw.c b/render/html_redraw.c
index df7d5bfbb..820a56213 100644
--- a/render/html_redraw.c
+++ b/render/html_redraw.c
@@ -18,6 +18,7 @@
#include "netsurf/desktop/gui.h"
#include "netsurf/desktop/plotters.h"
#include "netsurf/desktop/selection.h"
+#include "netsurf/desktop/textinput.h"
#include "netsurf/render/box.h"
#include "netsurf/render/font.h"
#include "netsurf/render/form.h"
@@ -34,6 +35,8 @@ static bool html_redraw_box(struct box *box,
static bool html_redraw_text_box(struct box *box, int x, int y,
int x0, int y0, int x1, int y1,
float scale, colour current_background_color);
+static bool html_redraw_caret(struct caret *caret,
+ os_colour current_background_color, float scale);
static bool html_redraw_borders(struct box *box, int x_parent, int y_parent,
int padding_width, int padding_height, float scale);
static bool html_redraw_border_plot(int i, int *p, colour c,
@@ -370,25 +373,76 @@ bool html_redraw_text_box(struct box *box, int x, int y,
int x0, int y0, int x1, int y1,
float scale, colour current_background_color)
{
+ bool excluded = (box->object != NULL);
+ struct rect clip;
+
+ clip.x0 = x0;
+ clip.y0 = y0;
+ clip.x1 = x1;
+ clip.y1 = y1;
+
+ if (!text_redraw(box->text, box->length, box->byte_offset,
+ box->space, box->style, x, y,
+ &clip, box->height, scale,
+ current_background_color, excluded))
+ return false;
+
+ /* does this textbox contain the ghost caret? */
+ if (ghost_caret.defined && box == ghost_caret.text_box) {
+
+ if (!html_redraw_caret(&ghost_caret, current_background_color, scale))
+ return false;
+ }
+ return true;
+}
+
+
+/**
+ * Redraw a short text string, complete with highlighting
+ * (for selection/search) and ghost caret
+ *
+ * \param utf8_text pointer to UTF-8 text string
+ * \param utf8_len length of string, in bytes
+ * \param offset byte offset within textual representation
+ * \param space indicates whether string is followed by a space
+ * \param style text style to use
+ * \param x x ordinate at which to plot text
+ * \param y y ordinate at which to plot text
+ * \param clip pointer to current clip rectangle
+ * \param height height of text string
+ * \param scale current display scale (1.0 = 100%)
+ * \param current_background_color
+ * \param excluded exclude this text string from the selection
+ * \return true iff successful and redraw should proceed
+ */
+
+bool text_redraw(const char *utf8_text, size_t utf8_len,
+ size_t offset, bool space, struct css_style *style,
+ int x, int y, struct rect *clip,
+ int height,
+ float scale, colour current_background_color,
+ bool excluded)
+{
bool highlighted = false;
/* is this box part of a selection? */
- if (!box->object && current_redraw_browser) {
+ if (!excluded && current_redraw_browser) {
+ unsigned len = utf8_len + (space ? 1 : 0);
unsigned start_idx;
unsigned end_idx;
/* first try the browser window's current selection */
if (selection_defined(current_redraw_browser->sel) &&
selection_highlighted(current_redraw_browser->sel,
- box, &start_idx, &end_idx)) {
+ offset, offset + len, &start_idx, &end_idx)) {
highlighted = true;
}
- /* what about the current search operation, if any */
+ /* what about the current search operation, if any? */
if (!highlighted &&
search_current_window == current_redraw_browser->window &&
gui_search_term_highlighted(current_redraw_browser->window,
- box, &start_idx, &end_idx)) {
+ offset, offset + len, &start_idx, &end_idx)) {
highlighted = true;
}
@@ -400,23 +454,23 @@ bool html_redraw_text_box(struct box *box, int x, int y,
bool text_visible = true;
int startx, endx;
- if (end_idx > box->length) {
- /* adjust for trailing space, not present in box->text */
- assert(end_idx == box->length + 1);
- endtxt_idx = box->length;
+ if (end_idx > utf8_len) {
+ /* adjust for trailing space, not present in utf8_text */
+ assert(end_idx == utf8_len + 1);
+ endtxt_idx = utf8_len;
}
- if (!nsfont_width(box->style, box->text, start_idx, &startx))
+ if (!nsfont_width(style, utf8_text, start_idx, &startx))
startx = 0;
- if (!nsfont_width(box->style, box->text, endtxt_idx, &endx))
+ if (!nsfont_width(style, utf8_text, endtxt_idx, &endx))
endx = 0;
/* is there a trailing space that should be highlighted as well? */
- if (end_idx > box->length) {
+ if (end_idx > utf8_len) {
int spc_width;
/* \todo is there a more elegant/efficient solution? */
- if (nsfont_width(box->style, " ", 1, &spc_width))
+ if (nsfont_width(style, " ", 1, &spc_width))
endx += spc_width;
}
@@ -427,10 +481,10 @@ bool html_redraw_text_box(struct box *box, int x, int y,
/* draw any text preceding highlighted portion */
if (start_idx > 0 &&
- !plot.text(x, y + (int) (box->height * 0.75 * scale),
- box->style, box->text, start_idx,
+ !plot.text(x, y + (int) (height * 0.75 * scale),
+ style, utf8_text, start_idx,
current_background_color,
- /*print_text_black ? 0 :*/ box->style->color))
+ /*print_text_black ? 0 :*/ style->color))
return false;
/* decide whether highlighted portion is to be white-on-black or
@@ -442,16 +496,16 @@ bool html_redraw_text_box(struct box *box, int x, int y,
hfore_col = hback_col ^ 0xffffff;
/* highlighted portion */
- if (!plot.fill(x + startx, y, x + endx, y + box->height * scale,
+ if (!plot.fill(x + startx, y, x + endx, y + height * scale,
hback_col))
return false;
if (start_idx > 0) {
- int px0 = max(x + startx, x0);
- int px1 = min(x + endx, x1);
+ int px0 = max(x + startx, clip->x0);
+ int px1 = min(x + endx, clip->x1);
if (px0 < px1) {
- if (!plot.clip(px0, y0, px1, y1))
+ if (!plot.clip(px0, clip->y0, px1, clip->y1))
return false;
clip_changed = true;
} else
@@ -459,47 +513,76 @@ bool html_redraw_text_box(struct box *box, int x, int y,
}
if (text_visible &&
- !plot.text(x, y + (int) (box->height * 0.75 * scale),
- box->style, box->text, endtxt_idx,
+ !plot.text(x, y + (int) (height * 0.75 * scale),
+ style, utf8_text, endtxt_idx,
hback_col, hfore_col))
return false;
/* draw any text succeeding highlighted portion */
- if (endtxt_idx < box->length) {
- int px0 = max(x + endx, x0);
- if (px0 < x1) {
+ if (endtxt_idx < utf8_len) {
+ int px0 = max(x + endx, clip->x0);
+ if (px0 < clip->x1) {
- if (!plot.clip(px0, y0, x1, y1))
+ if (!plot.clip(px0, clip->y0, clip->x1, clip->y1))
return false;
clip_changed = true;
- if (!plot.text(x, y + (int) (box->height * 0.75 * scale),
- box->style, box->text, box->length,
+ if (!plot.text(x, y + (int) (height * 0.75 * scale),
+ style, utf8_text, utf8_len,
current_background_color,
- /*print_text_black ? 0 :*/ box->style->color))
+ /*print_text_black ? 0 :*/ style->color))
return false;
}
}
- if (clip_changed && !plot.clip(x0, y0, x1, y1))
+ if (clip_changed &&
+ !plot.clip(clip->x0, clip->y0, clip->x1, clip->y1))
return false;
}
}
if (!highlighted) {
- if (!plot.text(x, y + (int) (box->height * 0.75 * scale),
- box->style, box->text, box->length,
+ if (!plot.text(x, y + (int) (height * 0.75 * scale),
+ style, utf8_text, utf8_len,
current_background_color,
- /*print_text_black ? 0 :*/ box->style->color))
+ /*print_text_black ? 0 :*/ style->color))
return false;
}
-
return true;
}
/**
+ * Draw text caret.
+ *
+ * \param c structure describing text caret
+ * \param current_background_color background colour under the caret
+ * \param scale current scale setting (1.0 = 100%)
+ * \return true iff successful and redraw should proceed
+ */
+
+bool html_redraw_caret(struct caret *c, os_colour current_background_color,
+ float scale)
+{
+ os_colour caret_color = 0x808080; /* todo - choose a proper colour */
+ int xc = c->x, y = c->y;
+ int h = c->height - 1;
+ int w = (h + 7) / 8;
+
+ return (plot.line(xc * scale, y * scale,
+ xc * scale, (y + h) * scale,
+ 0, caret_color, false, false) &&
+ plot.line((xc - w) * scale, y * scale,
+ (xc + w) * scale, y * scale,
+ 0, caret_color, false, false) &&
+ plot.line((xc - w) * scale, (y + h) * scale,
+ (xc + w) * scale, (y + h) * scale,
+ 0, caret_color, false, false));
+}
+
+
+/**
* Draw borders for a box.
*
* \param box box to draw
@@ -514,10 +597,17 @@ bool html_redraw_text_box(struct box *box, int x, int y,
bool html_redraw_borders(struct box *box, int x_parent, int y_parent,
int padding_width, int padding_height, float scale)
{
- int top = box->border[TOP] * scale;
- int right = box->border[RIGHT] * scale;
- int bottom = box->border[BOTTOM] * scale;
- int left = box->border[LEFT] * scale;
+ int top = box->border[TOP];
+ int right = box->border[RIGHT];
+ int bottom = box->border[BOTTOM];
+ int left = box->border[LEFT];
+
+ if (scale != 1.0) {
+ top *= scale;
+ right *= scale;
+ bottom *= scale;
+ left *= scale;
+ }
assert(box->style);
diff --git a/render/textplain.c b/render/textplain.c
index 26f98b671..d7561abd1 100644
--- a/render/textplain.c
+++ b/render/textplain.c
@@ -3,12 +3,14 @@
* Licensed under the GNU General Public License,
* http://www.opensource.org/licenses/gpl-license
* Copyright 2006 James Bursa <bursa@users.sourceforge.net>
+ * Copyright 2006 Adrian Lees <adrianl@users.sourceforge.net>
*/
/** \file
* Content for text/plain (implementation).
*/
+#include <assert.h>
#include <errno.h>
#include <stddef.h>
#include <iconv.h>
@@ -16,6 +18,7 @@
#include "netsurf/css/css.h"
#include "netsurf/desktop/gui.h"
#include "netsurf/desktop/plotters.h"
+#include "netsurf/render/box.h"
#include "netsurf/render/font.h"
#include "netsurf/render/textplain.h"
#include "netsurf/utils/log.h"
@@ -76,8 +79,9 @@ bool textplain_create(struct content *c, const char *params[])
c->data.textplain.utf8_data = utf8_data;
c->data.textplain.utf8_data_size = 0;
c->data.textplain.utf8_data_allocated = CHUNK;
- c->data.textplain.physical_line_start = 0;
+ c->data.textplain.physical_line = 0;
c->data.textplain.physical_line_count = 0;
+ c->data.textplain.formatted_width = 0;
return true;
@@ -169,11 +173,12 @@ void textplain_reformat(struct content *c, int width, int height)
char *utf8_data = c->data.textplain.utf8_data;
size_t utf8_data_size = c->data.textplain.utf8_data_size;
unsigned long line_count = 0;
- size_t *line_start = c->data.textplain.physical_line_start;
- size_t *line_start1;
+ struct textplain_line *line = c->data.textplain.physical_line;
+ struct textplain_line *line1;
size_t i, space, col;
size_t columns = 80;
int character_width;
+ size_t line_start;
/* compute available columns (assuming monospaced font) - use 8
* characters for better accuracy */
@@ -181,30 +186,49 @@ void textplain_reformat(struct content *c, int width, int height)
return;
columns = (width - MARGIN - MARGIN) * 8 / character_width;
+ c->data.textplain.formatted_width = width;
+
c->data.textplain.physical_line_count = 0;
- if (!line_start) {
- c->data.textplain.physical_line_start = line_start =
- talloc_array(c, size_t, 1024 + 3);
- if (!line_start)
+ if (!line) {
+ c->data.textplain.physical_line = line =
+ talloc_array(c, struct textplain_line, 1024 + 3);
+ if (!line)
goto no_memory;
}
- line_start[line_count++] = 0;
+ line[line_count++].start = line_start = 0;
space = 0;
for (i = 0, col = 0; i != utf8_data_size; i++) {
- if (utf8_data[i] == '\n' || col + 1 == columns) {
+ bool term = (utf8_data[i] == '\n' || utf8_data[i] == '\r');
+ if (term || col + 1 == columns) {
if (line_count % 1024 == 0) {
- line_start1 = talloc_realloc(c, line_start,
- size_t, line_count + 1024 + 3);
- if (!line_start1)
+ line1 = talloc_realloc(c, line,
+ struct textplain_line, line_count + 1024 + 3);
+ if (!line1)
goto no_memory;
- c->data.textplain.physical_line_start =
- line_start = line_start1;
- }
- if (utf8_data[i] != '\n' && space)
- i = space;
- line_start[line_count++] = i + 1;
+ c->data.textplain.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 {
@@ -213,7 +237,8 @@ void textplain_reformat(struct content *c, int width, int height)
space = i;
}
}
- line_start[line_count] = utf8_data_size;
+ line[line_count-1].length = i - line[line_count-1].start;
+ line[line_count].start = utf8_data_size;
c->data.textplain.physical_line_count = line_count;
c->width = width;
@@ -266,14 +291,21 @@ bool textplain_redraw(struct content *c, int x, int y,
float scale, unsigned long background_colour)
{
char *utf8_data = c->data.textplain.utf8_data;
- long line;
+ long lineno;
unsigned long line_count = c->data.textplain.physical_line_count;
float line_height = css_len2px(&textplain_style.font_size.value.length,
- &textplain_style) * 1.2 * scale;
- long line0 = clip_y0 / line_height - 1;
- long line1 = clip_y1 / line_height + 1;
- size_t *line_start = c->data.textplain.physical_line_start;
+ &textplain_style) * 1.2;
+ float scaled_line_height = line_height * scale;
+ long line0 = clip_y0 / scaled_line_height - 1;
+ long line1 = clip_y1 / scaled_line_height + 1;
+ struct textplain_line *line = c->data.textplain.physical_line;
size_t length;
+ struct rect clip;
+
+ clip.x0 = clip_x0;
+ clip.y0 = clip_y0;
+ clip.x1 = clip_x1;
+ clip.y1 = clip_y1;
if (line0 < 0)
line0 = 0;
@@ -289,23 +321,219 @@ bool textplain_redraw(struct content *c, int x, int y,
if (!plot.clg(0xffffff))
return false;
- if (!line_start)
+ if (!line)
return true;
x += MARGIN * scale;
y += MARGIN * scale;
- for (line = line0; line != line1; line++) {
- length = line_start[line + 1] - line_start[line];
+ for (lineno = line0; lineno != line1; lineno++) {
+ length = line[lineno].length;
if (!length)
continue;
- if (utf8_data[line_start[line] + length - 1] == '\n')
- length--;
- if (!plot.text(x, y + (line + 1) * line_height,
- &textplain_style,
- utf8_data + line_start[line], length,
- 0xffffff, 0x000000))
+ if (!text_redraw(utf8_data + line[lineno].start, length,
+ line[lineno].start, false, &textplain_style,
+ x, y + (lineno * scaled_line_height),
+ &clip, line_height, scale,
+ background_colour, false))
return false;
}
return true;
}
+
+
+/**
+ * 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 ptr to start of line containing (or nearest to) point
+ */
+
+unsigned textplain_offset_from_coords(struct content *c, int x, int y, int dir)
+{
+ float line_height = css_len2px(&textplain_style.font_size.value.length,
+ &textplain_style) * 1.2;
+ struct textplain_line *line;
+ int pixel_offset;
+ unsigned nlines;
+ int idx;
+
+ assert(c->type == CONTENT_TEXTPLAIN);
+
+ y = (int)((float)(y - MARGIN) / line_height);
+ x -= MARGIN;
+
+ nlines = c->data.textplain.physical_line_count;
+ if (!nlines)
+ return 0;
+
+ if (y < 0) y = 0;
+ else if (y >= nlines)
+ y = nlines - 1;
+ line = &c->data.textplain.physical_line[y];
+
+ if (x < 0) x = 0;
+
+ nsfont_position_in_string(&textplain_style,
+ c->data.textplain.utf8_data + line->start,
+ line->length,
+ x,
+ &idx,
+ &pixel_offset);
+
+ return line->start + idx;
+}
+
+
+/**
+ * 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)
+{
+ struct textplain_line *line = c->data.textplain.physical_line;
+ int nlines = c->data.textplain.physical_line_count;
+ int lineno = 0;
+
+ assert(c->type == CONTENT_TEXTPLAIN);
+
+ if (offset > c->data.textplain.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;
+}
+
+
+/**
+ * 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)
+{
+ float line_height = css_len2px(&textplain_style.font_size.value.length,
+ &textplain_style) * 1.2;
+ char *utf8_data = c->data.textplain.utf8_data;
+ struct textplain_line *line;
+ unsigned lineno = 0;
+ unsigned nlines;
+
+ assert(c->type == CONTENT_TEXTPLAIN);
+ assert(start <= end);
+ assert(end <= c->data.textplain.utf8_data_size);
+
+ nlines = c->data.textplain.physical_line_count;
+ line = c->data.textplain.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 = c->data.textplain.formatted_width;
+ }
+ else {
+ /* single line */
+ nsfont_width(&textplain_style,
+ utf8_data + line[lineno].start,
+ start - line[lineno].start,
+ &r->x0);
+
+ nsfont_width(&textplain_style,
+ utf8_data + line[lineno].start,
+ min(line[lineno].length, end - line[lineno].start),
+ &r->x1);
+ }
+
+ 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)
+{
+ struct textplain_line *line;
+
+ assert(c->type == CONTENT_TEXTPLAIN);
+
+ if (lineno >= c->data.textplain.physical_line_count)
+ return NULL;
+ line = &c->data.textplain.physical_line[lineno];
+
+ *poffset = line->start;
+ *plen = line->length;
+ return c->data.textplain.utf8_data + line->start;
+}
+
+
+/**
+ * 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
+ */
+
+char *textplain_get_raw_data(struct content *c, unsigned start, unsigned end,
+ size_t *plen)
+{
+ size_t utf8_size = c->data.textplain.utf8_data_size;
+
+ assert(c->type == CONTENT_TEXTPLAIN);
+
+ /* 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 c->data.textplain.utf8_data + start;
+}
diff --git a/render/textplain.h b/render/textplain.h
index 27da768ee..0775381fc 100644
--- a/render/textplain.h
+++ b/render/textplain.h
@@ -3,6 +3,7 @@
* Licensed under the GNU General Public License,
* http://www.opensource.org/licenses/gpl-license
* Copyright 2006 James Bursa <bursa@users.sourceforge.net>
+ * Copyright 2006 Adrian Lees <adrianl@users.sourceforge.net>
*/
/** \file
@@ -12,10 +13,16 @@
#ifndef _NETSURF_RENDER_TEXTPLAIN_H_
#define _NETSURF_RENDER_TEXTPLAIN_H_
+#include <stddef.h>
#include <iconv.h>
struct content;
+struct textplain_line {
+ size_t start;
+ size_t length;
+};
+
struct content_textplain_data {
const char *encoding;
iconv_t iconv_cd;
@@ -24,7 +31,8 @@ struct content_textplain_data {
size_t utf8_data_size;
size_t utf8_data_allocated;
unsigned long physical_line_count;
- size_t *physical_line_start;
+ struct textplain_line *physical_line;
+ int formatted_width;
};
bool textplain_create(struct content *c, const char *params[]);
@@ -37,4 +45,17 @@ bool textplain_redraw(struct content *c, int x, int y,
int clip_x0, int clip_y0, int clip_x1, int clip_y1,
float scale, unsigned long background_colour);
+/* access to lines for text selection and searching */
+#define textplain_line_count(c) ((c)->data.textplain.physical_line_count)
+#define textplain_size(c) ((c)->data.textplain.utf8_data_size)
+
+size_t textplain_offset_from_coords(struct content *c, int x, int y, int dir);
+void textplain_coords_from_range(struct content *c,
+ unsigned start, unsigned end, struct rect *r);
+char *textplain_get_line(struct content *c, unsigned lineno,
+ size_t *poffset, size_t *plen);
+int textplain_find_line(struct content *c, unsigned offset);
+char *textplain_get_raw_data(struct content *c,
+ unsigned start, unsigned end, size_t *plen);
+
#endif