NetSurf
textplain.c
Go to the documentation of this file.
1/*
2 * Copyright 2006 James Bursa <bursa@users.sourceforge.net>
3 * Copyright 2006 Adrian Lees <adrianl@users.sourceforge.net>
4 *
5 * This file is part of NetSurf, http://www.netsurf-browser.org/
6 *
7 * NetSurf is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * NetSurf is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20/**
21 * \file
22 *
23 * plain text content handling implementation.
24 */
25
26#include <string.h>
27#include <parserutils/input/inputstream.h>
28
29#include "utils/errors.h"
30#include "utils/corestrings.h"
31#include "utils/http.h"
32#include "utils/log.h"
33#include "utils/messages.h"
34#include "utils/utils.h"
35#include "utils/utf8.h"
36#include "utils/nsoption.h"
37#include "netsurf/content.h"
38#include "netsurf/keypress.h"
40#include "netsurf/plotters.h"
41#include "netsurf/layout.h"
44#include "content/hlcache.h"
45#include "content/textsearch.h"
47#include "desktop/selection.h"
49
50#include "text/textplain.h"
51
53 size_t start;
54 size_t length;
55};
56
57/**
58 * plain text content
59 */
60typedef struct textplain_content {
61 struct content base;
62
63 lwc_string *encoding;
65 char *utf8_data;
68 unsigned long physical_line_count;
72
73 struct selection *sel; /** Selection state */
74
76
77
78#define CHUNK 32768 /* Must be a power of 2 */
79#define MARGIN 4
80
81#define TAB_WIDTH 8 /* must be power of 2 currently */
82#define TEXT_SIZE 10 * PLOT_STYLE_SCALE /* Unscaled text size in pt */
83
86 .size = TEXT_SIZE,
87 .weight = 400,
88 .flags = FONTF_NONE,
89 .background = 0xffffff,
90 .foreground = 0x000000,
91};
92
93static int textplain_tab_width = 256; /* try for a sensible default */
94
95static lwc_string *textplain_default_charset;
96
97
98/**
99 * Clean up after the text content handler
100 */
101static void textplain_fini(void)
102{
103 if (textplain_default_charset != NULL) {
104 lwc_string_unref(textplain_default_charset);
106 }
107}
108
109
110/**
111 * Work around feature in libparserutils
112 *
113 * if the client provides an encoding up front, but does not provide a
114 * charset detection callback, then libparserutils will replace the
115 * provided encoding with UTF-8. This breaks our input handling.
116 *
117 * Avoid this by providing a callback that does precisely nothing,
118 * thus preserving whatever charset information we decided on in
119 * textplain_create.
120 */
121static parserutils_error
122textplain_charset_hack(const uint8_t *data,
123 size_t len,
124 uint16_t *mibenum,
125 uint32_t *source)
126{
127 return PARSERUTILS_OK;
128}
129
130
131/**
132 * setup plain text render.
133 *
134 * \param[in] c content object.
135 * \param[in] encoding the encoding of the content.
136 * \return NSERROR_OK else appropriate error code.
137 */
138static nserror
140{
141 char *utf8_data;
142 parserutils_inputstream *stream;
143 parserutils_error error;
144
146
147 utf8_data = malloc(CHUNK);
148 if (utf8_data == NULL)
149 goto no_memory;
150
151 error = parserutils_inputstream_create(lwc_string_data(encoding), 0,
152 textplain_charset_hack, &stream);
153 if (error == PARSERUTILS_BADENCODING) {
154 /* Fall back to Windows-1252 */
155 error = parserutils_inputstream_create("Windows-1252", 0,
156 textplain_charset_hack, &stream);
157 }
158 if (error != PARSERUTILS_OK) {
159 free(utf8_data);
160 goto no_memory;
161 }
162
163 c->encoding = lwc_string_ref(encoding);
164 c->inputstream = stream;
165 c->utf8_data = utf8_data;
166 c->utf8_data_size = 0;
167 c->utf8_data_allocated = CHUNK;
168 c->physical_line = 0;
169 c->physical_line_count = 0;
170 c->formatted_width = 0;
171 c->bw = NULL;
172 c->sel = selection_create((struct content *)c);
173
174 return NSERROR_OK;
175
176no_memory:
178
179 return NSERROR_NOMEM;
180}
181
182
183/**
184 * Create a CONTENT_TEXTPLAIN.
185 */
186static nserror
188 lwc_string *imime_type,
189 const struct http_parameter *params,
191 const char *fallback_charset,
192 bool quirks,
193 struct content **c)
194{
196 nserror error;
197 lwc_string *encoding;
198
199 text = calloc(1, sizeof(textplain_content));
200 if (text == NULL) {
201 return NSERROR_NOMEM;
202 }
203
204 error = content__init(&text->base, handler, imime_type, params,
205 llcache, fallback_charset, quirks);
206 if (error != NSERROR_OK) {
207 free(text);
208 return error;
209 }
210
211 error = http_parameter_list_find_item(params, corestring_lwc_charset,
212 &encoding);
213 if (error != NSERROR_OK) {
214 encoding = lwc_string_ref(textplain_default_charset);
215 }
216
217 error = textplain_create_internal(text, encoding);
218 if (error != NSERROR_OK) {
219 lwc_string_unref(encoding);
220 free(text);
221 return error;
222 }
223
224 lwc_string_unref(encoding);
225
226 *c = (struct content *) text;
227
228 return NSERROR_OK;
229}
230
231
232/**
233 * copy utf8 encoded data
234 */
235static bool
236textplain_copy_utf8_data(textplain_content *c, const uint8_t *buf, size_t len)
237{
238 if (c->utf8_data_size + len >= c->utf8_data_allocated) {
239 /* Compute next multiple of chunk above the required space */
240 size_t allocated;
241 char *utf8_data;
242
243 allocated = (c->utf8_data_size + len + CHUNK - 1) & ~(CHUNK - 1);
244 utf8_data = realloc(c->utf8_data, allocated);
245 if (utf8_data == NULL)
246 return false;
247
248 c->utf8_data = utf8_data;
249 c->utf8_data_allocated = allocated;
250 }
251
252 memcpy(c->utf8_data + c->utf8_data_size, buf, len);
253 c->utf8_data_size += len;
254
255 return true;
256}
257
258
259/**
260 * drain input
261 */
262static bool
264 parserutils_inputstream *stream,
265 parserutils_error terminator)
266{
267 static const uint8_t *u_fffd = (const uint8_t *) "\xef\xbf\xbd";
268 const uint8_t *ch;
269 size_t chlen, offset = 0;
270
271 while (parserutils_inputstream_peek(stream, offset, &ch, &chlen) !=
272 terminator) {
273 /* Replace all instances of NUL with U+FFFD */
274 if (chlen == 1 && *ch == 0) {
275 if (offset > 0) {
276 /* Obtain pointer to start of input data */
277 parserutils_inputstream_peek(stream, 0,
278 &ch, &chlen);
279 /* Copy from it up to the start of the NUL */
280 if (textplain_copy_utf8_data(c, ch,
281 offset) == false)
282 return false;
283 }
284
285 /* Emit U+FFFD */
286 if (textplain_copy_utf8_data(c, u_fffd, 3) == false)
287 return false;
288
289 /* Advance inputstream past the NUL we just read */
290 parserutils_inputstream_advance(stream, offset + 1);
291 /* Reset the read offset */
292 offset = 0;
293 } else {
294 /* Accumulate input */
295 offset += chlen;
296
297 if (offset > CHUNK) {
298 /* Obtain pointer to start of input data */
299 parserutils_inputstream_peek(stream, 0,
300 &ch, &chlen);
301
302 /* Emit the data we've read */
303 if (textplain_copy_utf8_data(c, ch,
304 offset) == false)
305 return false;
306
307 /* Advance the inputstream */
308 parserutils_inputstream_advance(stream, offset);
309 /* Reset the read offset */
310 offset = 0;
311 }
312 }
313 }
314
315 if (offset > 0) {
316 /* Obtain pointer to start of input data */
317 parserutils_inputstream_peek(stream, 0, &ch, &chlen);
318 /* Emit any data remaining */
319 if (textplain_copy_utf8_data(c, ch, offset) == false)
320 return false;
321
322 /* Advance the inputstream past the data we've read */
323 parserutils_inputstream_advance(stream, offset);
324 }
325
326 return true;
327}
328
329
330/**
331 * Process data for CONTENT_TEXTPLAIN.
332 */
333static bool
334textplain_process_data(struct content *c, const char *data, unsigned int size)
335{
337 parserutils_inputstream *stream = text->inputstream;
338 parserutils_error error;
339
340 error = parserutils_inputstream_append(stream,
341 (const uint8_t *) data, size);
342 if (error != PARSERUTILS_OK) {
343 goto no_memory;
344 }
345
346 if (textplain_drain_input(text, stream, PARSERUTILS_NEEDDATA) == false)
347 goto no_memory;
348
349 return true;
350
351no_memory:
353 return false;
354}
355
356
357/**
358 * Convert a CONTENT_TEXTPLAIN for display.
359 */
360static bool textplain_convert(struct content *c)
361{
363 parserutils_inputstream *stream = text->inputstream;
364 parserutils_error error;
365
366 error = parserutils_inputstream_append(stream, NULL, 0);
367 if (error != PARSERUTILS_OK) {
368 return false;
369 }
370
371 if (textplain_drain_input(text, stream, PARSERUTILS_EOF) == false)
372 return false;
373
374 parserutils_inputstream_destroy(stream);
375 text->inputstream = NULL;
376
380
381 return true;
382}
383
384
385/**
386 * Calculate the line height, in pixels
387 *
388 * \return Line height, in pixels
389 */
390static float textplain_line_height(void)
391{
392 /* Size is in points, so convert to pixels.
393 * Then use a constant line height of 1.2 x font size.
394 */
395 return FIXTOFLT(FDIV((FMUL(FLTTOFIX(1.2), FMUL(nscss_screen_dpi, INTTOFIX((textplain_style.size / PLOT_STYLE_SCALE))))), F_72));
396}
397
398
399/**
400 * Reformat a CONTENT_TEXTPLAIN to a new width.
401 */
402static void textplain_reformat(struct content *c, int width, int height)
403{
405 char *utf8_data = text->utf8_data;
406 size_t utf8_data_size = text->utf8_data_size;
407 unsigned long line_count = 0;
408 struct textplain_line *line = text->physical_line;
409 struct textplain_line *line1;
410 size_t i, space, col;
411 size_t columns = 80;
412 int character_width;
413 size_t line_start;
414 nserror res;
415
416 NSLOG(netsurf, INFO, "content %p w:%d h:%d", c, width, height);
417
418 /* compute available columns (assuming monospaced font) - use 8
419 * characters for better accuracy
420 */
422 "ABCDEFGH", 8,
423 &character_width);
424 if (res != NSERROR_OK) {
425 return;
426 }
427
428 columns = (width - MARGIN - MARGIN) * 8 / character_width;
429 textplain_tab_width = (TAB_WIDTH * character_width) / 8;
430
431 text->formatted_width = width;
432
433 text->physical_line_count = 0;
434
435 if (!line) {
436 text->physical_line = line =
437 malloc(sizeof(struct textplain_line) * (1024 + 3));
438 if (!line)
439 goto no_memory;
440 }
441
442 line[line_count++].start = line_start = 0;
443 space = 0;
444 i = 0;
445 col = 0;
446 while (i < utf8_data_size) {
447 size_t csize; /* number of bytes in character */
448 uint32_t chr;
449 bool term;
450 size_t next_col;
451 parserutils_error perror;
452
453 perror = parserutils_charset_utf8_to_ucs4((const uint8_t *)utf8_data + i, utf8_data_size - i, &chr, &csize);
454 if (perror != PARSERUTILS_OK) {
455 chr = 0xfffd;
456 }
457
458 term = (chr == '\n' || chr == '\r');
459
460 next_col = col + 1;
461
462 if (chr == '\t') {
463 next_col = (next_col + TAB_WIDTH - 1) & ~(TAB_WIDTH - 1);
464 }
465
466 if (term || next_col >= columns) {
467 if (line_count % 1024 == 0) {
468 line1 = realloc(line,
469 sizeof(struct textplain_line) *
470 (line_count + 1024 + 3));
471 if (!line1)
472 goto no_memory;
473 text->physical_line = line = line1;
474 }
475
476 if (term) {
477 line[line_count-1].length = i - line_start;
478
479 /* skip second char of CR/LF or LF/CR pair */
480 if (i + 1 < utf8_data_size &&
481 utf8_data[i+1] != utf8_data[i] &&
482 (utf8_data[i+1] == '\n' ||
483 utf8_data[i+1] == '\r')) {
484 i++;
485 }
486 } else {
487 if (space) {
488 /* break at last space in line */
489 i = space;
490 line[line_count-1].length = (i + 1) - line_start;
491 } else
492 line[line_count-1].length = i - line_start;
493 }
494
495 line[line_count++].start = line_start = i + 1;
496 col = 0;
497 space = 0;
498 } else {
499 col++;
500 if (chr == ' ')
501 space = i;
502 }
503 i += csize;
504 }
505 line[line_count-1].length = i - line[line_count-1].start;
506 line[line_count].start = utf8_data_size;
507
508 text->physical_line_count = line_count;
509 c->width = width;
510 c->height = line_count * textplain_line_height() + MARGIN + MARGIN;
511
512 return;
513
514no_memory:
515 NSLOG(netsurf, INFO, "out of memory (line_count %lu)", line_count);
516 return;
517}
518
519
520/**
521 * Destroy a CONTENT_TEXTPLAIN and free all resources it owns.
522 */
523
524static void textplain_destroy(struct content *c)
525{
527
528 lwc_string_unref(text->encoding);
529
530 if (text->inputstream != NULL) {
531 parserutils_inputstream_destroy(text->inputstream);
532 }
533
534 if (text->physical_line != NULL) {
535 free(text->physical_line);
536 }
537
538 if (text->utf8_data != NULL) {
539 free(text->utf8_data);
540 }
541
542 if (text->sel != NULL) {
544 }
545}
546
547
548static nserror textplain_clone(const struct content *old, struct content **newc)
549{
550 const textplain_content *old_text = (textplain_content *) old;
552 nserror error;
553 const uint8_t *data;
554 size_t size;
555
556 text = calloc(1, sizeof(textplain_content));
557 if (text == NULL)
558 return NSERROR_NOMEM;
559
560 error = content__clone(old, &text->base);
561 if (error != NSERROR_OK) {
562 content_destroy(&text->base);
563 return error;
564 }
565
566 /* Simply replay create/process/convert */
567 error = textplain_create_internal(text, old_text->encoding);
568 if (error != NSERROR_OK) {
569 content_destroy(&text->base);
570 return error;
571 }
572
573 data = content__get_source_data(&text->base, &size);
574 if (size > 0) {
575 if (textplain_process_data(&text->base,
576 (const char *)data,
577 size) == false) {
578 content_destroy(&text->base);
579 return NSERROR_NOMEM;
580 }
581 }
582
583 if (old->status == CONTENT_STATUS_READY ||
584 old->status == CONTENT_STATUS_DONE) {
585 if (textplain_convert(&text->base) == false) {
586 content_destroy(&text->base);
588 }
589 }
590
591 return NSERROR_OK;
592}
593
594
596{
597 return CONTENT_TEXTPLAIN;
598}
599
600
601/**
602 * Return byte offset within UTF8 textplain content.
603 *
604 * given the co-ordinates of a point within a textplain content. 'dir'
605 * specifies the direction in which to search (-1 = above-left, +1 =
606 * below-right) if the co-ordinates are not contained within a line.
607 *
608 * \param[in] c content of type CONTENT_TEXTPLAIN
609 * \param[in] x x ordinate of point
610 * \param[in] y y ordinate of point
611 * \param[in] dir direction of search if not within line
612 * \return byte offset of character containing (or nearest to) point
613 */
614static size_t
615textplain_offset_from_coords(struct content *c, int x, int y, int dir)
616{
619 struct textplain_line *line;
620 const char *text;
621 unsigned nlines;
622 size_t length;
623 int idx;
624
625 assert(c != NULL);
626
627 y = (int)((float)(y - MARGIN) / line_height);
628 x -= MARGIN;
629
630 nlines = textc->physical_line_count;
631 if (!nlines)
632 return 0;
633
634 if (y <= 0) y = 0;
635 else if ((unsigned)y >= nlines)
636 y = nlines - 1;
637
638 line = &textc->physical_line[y];
639 text = textc->utf8_data + line->start;
640 length = line->length;
641 idx = 0;
642
643 while (x > 0) {
644 size_t next_offset = 0;
645 int width = INT_MAX;
646
647 while (next_offset < length && text[next_offset] != '\t') {
648 next_offset = utf8_next(text, length, next_offset);
649 }
650
651 if (next_offset < length) {
653 text,
654 next_offset,
655 &width);
656 }
657
658 if (x <= width) {
659 int pixel_offset;
660 size_t char_offset;
661
663 text, next_offset, x,
664 &char_offset, &pixel_offset);
665
666 idx += char_offset;
667 break;
668 }
669
670 x -= width;
671 length -= next_offset;
672 text += next_offset;
673 idx += next_offset;
674
675 /* check if it's within the tab */
677 if (x <= width) break;
678
679 x -= width;
680 length--;
681 text++;
682 idx++;
683 }
684
685 return line->start + idx;
686}
687
688
689/**
690 * Handle mouse clicks and movements in a TEXTPLAIN content window.
691 *
692 * \param c content of type textplain
693 * \param bw browser window
694 * \param mouse mouse state on action
695 * \param x coordinate of mouse
696 * \param y coordinate of mouse
697 */
698static nserror
700 struct browser_window *bw,
702 int x, int y)
703{
706 union content_msg_data msg_data;
707 const char *status = 0;
708 size_t idx;
709 int dir = 0;
710
712
713 idx = textplain_offset_from_coords(c, x, y, dir);
714 if (selection_click(text->sel, text->bw, mouse, idx)) {
715
716 if (selection_dragging(text->sel)) {
718 DRAGGING_SELECTION, NULL);
719 status = messages_get("Selecting");
720 }
721
722 } else {
726 }
727 }
728
729 msg_data.explicit_status_text = status;
731
732 msg_data.pointer = pointer;
734
735 return NSERROR_OK;
736}
737
738
739/**
740 * Handle mouse tracking (including drags) in a TEXTPLAIN content window.
741 *
742 * \param c content of type textplain
743 * \param bw browser window
744 * \param mouse state of mouse buttons and modifier keys
745 * \param x coordinate of mouse
746 * \param y coordinate of mouse
747 */
748static nserror
750 struct browser_window *bw,
752 int x, int y)
753{
755
757 int dir = -1;
758 size_t idx;
759
761 dir = 1;
762
763 idx = textplain_offset_from_coords(c, x, y, dir);
764 selection_track(text->sel, mouse, idx);
765
767 }
768
769 switch (browser_window_get_drag_type(bw)) {
770
771 case DRAGGING_SELECTION: {
772 int dir = -1;
773 size_t idx;
774
775 if (selection_dragging_start(text->sel)) dir = 1;
776
777 idx = textplain_offset_from_coords(c, x, y, dir);
778 selection_track(text->sel, mouse, idx);
779 }
780 break;
781
782 default:
783 textplain_mouse_action(c, bw, mouse, x, y);
784 break;
785 }
786
787 return NSERROR_OK;
788}
789
790
791/**
792 * Handle keypresses.
793 *
794 * \param c content of type CONTENT_TEXTPLAIN
795 * \param key The UCS4 character codepoint
796 * \return true if key handled, false otherwise
797 */
798static bool textplain_keypress(struct content *c, uint32_t key)
799{
801 struct selection *sel = text->sel;
802
803 switch (key) {
806 return true;
807
809 selection_clear(sel, true);
810 return true;
811
814 return true;
815
816 case NS_KEY_ESCAPE:
817 /* if there's no selection, leave Escape for the caller */
818 return selection_clear(sel, true);
819 }
820
821 return false;
822}
823
824
825/**
826 * Redraw a text string with highlighting
827 * (for selection/search)
828 *
829 * \param utf8_text pointer to UTF-8 text string
830 * \param utf8_len length of string, in bytes
831 * \param offset byte offset within textual representation
832 * \param x x ordinate at which to plot text
833 * \param y y ordinate at which to plot text
834 * \param clip pointer to current clip rectangle
835 * \param height height of text string
836 * \param scale current display scale (1.0 = 100%)
837 * \param text Content being redrawn.
838 * \param sel Selection context
839 * \param search Search context
840 * \param ctx current redraw context
841 * \return true iff successful and redraw should proceed
842 */
843static bool
844text_draw(const char *utf8_text,
845 size_t utf8_len,
846 size_t offset,
847 int x,
848 int y,
849 const struct rect *clip,
850 int height,
851 float scale,
853 const struct selection *sel,
854 const struct redraw_context *ctx)
855{
856 bool highlighted = false;
857 plot_font_style_t plot_fstyle;
858 nserror res;
859
860 /* Need scaled text size to pass to plotters */
861 plot_fstyle = textplain_style;
862 plot_fstyle.size *= scale;
863
864 /* is this box part of a selection? */
865 if (ctx->interactive == true) {
866 unsigned len = utf8_len;
867 unsigned start_idx;
868 unsigned end_idx;
869
870 /* first try the browser window's current selection */
871 if (selection_highlighted(sel,
872 offset,
873 offset + len,
874 &start_idx,
875 &end_idx)) {
876 highlighted = true;
877 }
878
879 /* what about the current search operation, if any? */
880 if (!highlighted &&
881 (text->base.textsearch.context != NULL) &&
882 content_textsearch_ishighlighted(text->base.textsearch.context,
883 offset,
884 offset + len,
885 &start_idx,
886 &end_idx)) {
887 highlighted = true;
888 }
889
890 /* \todo make search terms visible within selected text */
891 if (highlighted) {
892 struct rect r;
893 unsigned endtxt_idx = end_idx;
894 bool clip_changed = false;
895 bool text_visible = true;
896 int startx, endx;
897 plot_style_t pstyle_fill_hback = *plot_style_fill_white;
898 plot_font_style_t fstyle_hback = plot_fstyle;
899
900 if (end_idx > utf8_len) {
901 /* adjust for trailing space, not present in
902 * utf8_text
903 */
904 assert(end_idx == utf8_len + 1);
905 endtxt_idx = utf8_len;
906 }
907
909 utf8_text,
910 start_idx,
911 &startx);
912 if (res != NSERROR_OK) {
913 startx = 0;
914 }
915
917 utf8_text,
918 endtxt_idx,
919 &endx);
920 if (res != NSERROR_OK) {
921 endx = 0;
922 }
923
924 if (scale != 1.0) {
925 startx *= scale;
926 endx *= scale;
927 }
928
929 /* draw any text preceding highlighted portion */
930 if (start_idx > 0) {
931 res = ctx->plot->text(ctx,
932 &plot_fstyle,
933 x,
934 y + (int)(height * 0.75 * scale),
935 utf8_text,
936 start_idx);
937 if (res != NSERROR_OK) {
938 return false;
939 }
940 }
941
942 pstyle_fill_hback.fill_colour = textplain_style.foreground;
943
944 /* highlighted portion */
945 r.x0 = x + startx;
946 r.y0 = y;
947 r.x1 = x + endx;
948 r.y1 = y + height * scale;
949 res = ctx->plot->rectangle(ctx, &pstyle_fill_hback, &r);
950 if (res != NSERROR_OK) {
951 return false;
952 }
953
954 if (start_idx > 0) {
955 int px0 = max(x + startx, clip->x0);
956 int px1 = min(x + endx, clip->x1);
957
958 if (px0 < px1) {
959 r.x0 = px0;
960 r.y0 = clip->y0;
961 r.x1 = px1;
962 r.y1 = clip->y1;
963 res = ctx->plot->clip(ctx, &r);
964 if (res != NSERROR_OK) {
965 return false;
966 }
967
968 clip_changed = true;
969 } else {
970 text_visible = false;
971 }
972 }
973
974 fstyle_hback.background =
975 pstyle_fill_hback.fill_colour;
976 fstyle_hback.foreground = colour_to_bw_furthest(
977 pstyle_fill_hback.fill_colour);
978
979 if (text_visible &&
980 (ctx->plot->text(ctx,
981 &fstyle_hback,
982 x,
983 y + (int)(height * 0.75 * scale),
984 utf8_text,
985 endtxt_idx) != NSERROR_OK)) {
986 return false;
987 }
988
989 /* draw any text succeeding highlighted portion */
990 if (endtxt_idx < utf8_len) {
991 int px0 = max(x + endx, clip->x0);
992 if (px0 < clip->x1) {
993
994 r.x0 = px0;
995 r.y0 = clip->y0;
996 r.x1 = clip->x1;
997 r.y1 = clip->y1;
998 res = ctx->plot->clip(ctx, &r);
999 if (res != NSERROR_OK) {
1000 return false;
1001 }
1002
1003 clip_changed = true;
1004
1005 res = ctx->plot->text(ctx,
1006 &plot_fstyle,
1007 x,
1008 y + (int)(height * 0.75 * scale),
1009 utf8_text,
1010 utf8_len);
1011 if (res != NSERROR_OK) {
1012 return false;
1013 }
1014 }
1015 }
1016
1017 if (clip_changed &&
1018 (ctx->plot->clip(ctx, clip) != NSERROR_OK)) {
1019 return false;
1020 }
1021 }
1022 }
1023
1024 if (!highlighted) {
1025 res = ctx->plot->text(ctx,
1026 &plot_fstyle,
1027 x,
1028 y + (int) (height * 0.75 * scale),
1029 utf8_text,
1030 utf8_len);
1031 if (res != NSERROR_OK) {
1032 return false;
1033 }
1034 }
1035 return true;
1036}
1037
1038
1039/**
1040 * Draw a CONTENT_TEXTPLAIN using the current set of plotters (plot).
1041 *
1042 * x, y, clip_[xy][01] are in target coordinates.
1043 *
1044 * \param c content of type CONTENT_TEXTPLAIN
1045 * \param data redraw data for this content redraw
1046 * \param clip current clip region
1047 * \param ctx current redraw context
1048 * \return true if successful, false otherwise
1049 */
1050static bool
1052 struct content_redraw_data *data,
1053 const struct rect *clip,
1054 const struct redraw_context *ctx)
1055{
1057 struct browser_window *bw = text->bw;
1058 char *utf8_data = text->utf8_data;
1059 long lineno;
1060 int x = data->x;
1061 int y = data->y;
1062 unsigned long line_count = text->physical_line_count;
1064 float scaled_line_height = line_height * data->scale;
1065 long line0 = (clip->y0 - y * data->scale) / scaled_line_height - 1;
1066 long line1 = (clip->y1 - y * data->scale) / scaled_line_height + 1;
1067 struct textplain_line *line = text->physical_line;
1068 size_t length;
1069 plot_style_t *plot_style_highlight;
1070 nserror res;
1071
1072 if (line0 < 0)
1073 line0 = 0;
1074 if (line1 < 0)
1075 line1 = 0;
1076 if (line_count < (unsigned long) line0)
1077 line0 = line_count;
1078 if (line_count < (unsigned long) line1)
1079 line1 = line_count;
1080 if (line1 < line0)
1081 line1 = line0;
1082
1083 res = ctx->plot->rectangle(ctx, plot_style_fill_white, clip);
1084 if (res != NSERROR_OK) {
1085 return false;
1086 }
1087
1088 if (!line)
1089 return true;
1090
1091 /* choose a suitable background colour for any highlighted text */
1092 if ((data->background_colour & 0x808080) == 0x808080)
1093 plot_style_highlight = plot_style_fill_black;
1094 else
1095 plot_style_highlight = plot_style_fill_white;
1096
1097 /* Set up font plot style */
1099
1100 x = (x + MARGIN) * data->scale;
1101 y = (y + MARGIN) * data->scale;
1102 for (lineno = line0; lineno != line1; lineno++) {
1103 const char *text_d = utf8_data + line[lineno].start;
1104 int tab_width = textplain_tab_width * data->scale;
1105 size_t offset = 0;
1106 int tx = x;
1107
1108 if (!tab_width) tab_width = 1;
1109
1110 length = line[lineno].length;
1111 if (!length)
1112 continue;
1113
1114 while (offset < length) {
1115 size_t next_offset = offset;
1116 int width;
1117 int ntx;
1118 nserror res;
1119
1120 while ((next_offset < length) &&
1121 (text_d[next_offset] != '\t')) {
1122 next_offset = utf8_next(text_d,
1123 length,
1124 next_offset);
1125 }
1126
1127 if (!text_draw(text_d + offset,
1128 next_offset - offset,
1129 line[lineno].start + offset,
1130 tx,
1131 y + (lineno * scaled_line_height),
1132 clip,
1134 data->scale,
1135 text,
1136 text->sel,
1137 ctx)) {
1138 return false;
1139 }
1140
1141 if (next_offset >= length)
1142 break;
1143
1145 &text_d[offset],
1146 next_offset - offset,
1147 &width);
1148 /* locate end of string and align to next tab position */
1149 if (res == NSERROR_OK) {
1150 tx += (int)(width * data->scale);
1151 }
1152
1153 ntx = x + ((1 + (tx - x) / tab_width) * tab_width);
1154
1155 /* if the tab character lies within the
1156 * selection, if any, then we must draw it as
1157 * a filled rectangle so that it's consistent
1158 * with background of the selected text
1159 */
1160
1161 if (bw) {
1162 unsigned tab_ofst = line[lineno].start + next_offset;
1163 struct selection *sel = text->sel;
1164 bool highlighted = false;
1165
1166 unsigned start_idx, end_idx;
1167 if (selection_highlighted(sel,
1168 tab_ofst,
1169 tab_ofst + 1,
1170 &start_idx,
1171 &end_idx)) {
1172 highlighted = true;
1173 }
1174
1175
1176 if (!highlighted &&
1177 (c->textsearch.context != NULL)) {
1178 unsigned start_idx, end_idx;
1181 tab_ofst,
1182 tab_ofst + 1,
1183 &start_idx,
1184 &end_idx)) {
1185 highlighted = true;
1186 }
1187 }
1188
1189 if (highlighted) {
1190 struct rect rect;
1191 rect.x0 = tx;
1192 rect.y0 = y + (lineno * scaled_line_height);
1193 rect.x1 = ntx;
1194 rect.y1 = rect.y0 + scaled_line_height;
1195 res = ctx->plot->rectangle(ctx,
1196 plot_style_highlight,
1197 &rect);
1198 if (res != NSERROR_OK) {
1199 return false;
1200 }
1201 }
1202 }
1203
1204 offset = next_offset + 1;
1205 tx = ntx;
1206 }
1207 }
1208
1209 return true;
1210}
1211
1212
1213/**
1214 * Handle a window containing a CONTENT_TEXTPLAIN being opened.
1215 */
1216static nserror
1218 struct browser_window *bw,
1219 struct content *page,
1220 struct object_params *params)
1221{
1223
1224 text->bw = bw;
1225
1226 /* text selection */
1227 selection_init(text->sel);
1228
1229 return NSERROR_OK;
1230}
1231
1232
1233/**
1234 * Handle a window containing a CONTENT_TEXTPLAIN being closed.
1235 */
1237{
1239
1240 text->bw = NULL;
1241
1242 return NSERROR_OK;
1243}
1244
1245
1246/**
1247 * Return an textplain content's selection context
1248 */
1249static char *textplain_get_selection(struct content *c)
1250{
1252
1253 return selection_get_copy(text->sel);
1254}
1255
1256
1257/**
1258 * Convert a character offset within a line of text into the
1259 * horizontal co-ordinate
1260 *
1261 * The conversion takes into account the font being used and any tabs
1262 * in the text
1263 *
1264 * \param text line of text
1265 * \param offset char offset within text
1266 * \param length line length
1267 * \return x ordinate
1268 */
1269static int
1270textplain_coord_from_offset(const char *text, size_t offset, size_t length)
1271{
1272 int x = 0;
1273
1274 while (offset > 0) {
1275 size_t next_offset = 0;
1276 int tx;
1277
1278 while (next_offset < offset && text[next_offset] != '\t') {
1279 next_offset = utf8_next(text, length, next_offset);
1280 }
1281
1282 guit->layout->width(&textplain_style, text, next_offset, &tx);
1283
1284 x += tx;
1285
1286 if (next_offset >= offset)
1287 break;
1288
1289 /* align to next tab boundary */
1290 next_offset++;
1291 x = (1 + (x / textplain_tab_width)) * textplain_tab_width;
1292 offset -= next_offset;
1293 text += next_offset;
1294 length -= next_offset;
1295 }
1296
1297 return x;
1298}
1299
1300
1301/**
1302 * Retrieve number of lines in content
1303 *
1304 * \param[in] c Content to retrieve line count from
1305 * \return Number of lines
1306 */
1307static unsigned long textplain_line_count(struct content *c)
1308{
1310
1311 assert(c != NULL);
1312
1313 return text->physical_line_count;
1314}
1315
1316
1317/**
1318 * Return a pointer to the requested line of text.
1319 *
1320 * \param[in] c content of type CONTENT_TEXTPLAIN
1321 * \param[in] lineno line number
1322 * \param[out] poffset receives byte offset of line start within text
1323 * \param[out] plen receives length of returned line
1324 * \return pointer to text, or NULL if invalid line number
1325 */
1326static char *
1328 unsigned lineno,
1329 size_t *poffset,
1330 size_t *plen)
1331{
1333 struct textplain_line *line;
1334
1335 assert(c != NULL);
1336
1337 if (lineno >= text->physical_line_count)
1338 return NULL;
1339 line = &text->physical_line[lineno];
1340
1341 *poffset = line->start;
1342 *plen = line->length;
1343 return text->utf8_data + line->start;
1344}
1345
1346
1347/**
1348 * Find line number of byte in text
1349 *
1350 * Given a byte offset within the text, return the line number
1351 * of the line containing that offset.
1352 *
1353 * \param[in] c content of type CONTENT_TEXTPLAIN
1354 * \param[in] offset byte offset within textual representation
1355 * \return line number, or -1 if offset invalid (larger than size)
1356 */
1357static int textplain_find_line(struct content *c, unsigned offset)
1358{
1360 struct textplain_line *line;
1361 int nlines;
1362 int lineno = 0;
1363
1364 assert(c != NULL);
1365
1366 line = text->physical_line;
1367 nlines = text->physical_line_count;
1368
1369 if (offset > text->utf8_data_size) {
1370 return -1;
1371 }
1372
1373/* \todo - implement binary search here */
1374 while (lineno < nlines && line[lineno].start < offset) {
1375 lineno++;
1376 }
1377 if (line[lineno].start > offset) {
1378 lineno--;
1379 }
1380
1381 return lineno;
1382}
1383
1384
1385/**
1386 * Finds all occurrences of a given string in a textplain content
1387 *
1388 * \param c the content to be searched
1389 * \param context The search context to add the entry to.
1390 * \param pattern the string pattern to search for
1391 * \param p_len pattern length
1392 * \param case_sens whether to perform a case sensitive search
1393 * \return NSERROR_OK on success else error code on faliure
1394 */
1395static nserror
1397 struct textsearch_context *context,
1398 const char *pattern,
1399 int p_len,
1400 bool case_sens)
1401{
1402 int nlines = textplain_line_count(c);
1403 int line;
1404 nserror res = NSERROR_OK;
1405
1406 for(line = 0; line < nlines; line++) {
1407 size_t offset, length;
1408 const char *text;
1409
1410 text = textplain_get_line(c, line, &offset, &length);
1411 if (text) {
1412 while (length > 0) {
1413 unsigned match_length;
1414 size_t start_idx;
1415 const char *new_text;
1416 const char *pos;
1417
1419 text,
1420 length,
1421 pattern,
1422 p_len,
1423 case_sens,
1424 &match_length);
1425 if (!pos)
1426 break;
1427
1428 /* found string in line => add to list */
1429 start_idx = offset + (pos - text);
1430 res = content_textsearch_add_match(context,
1431 start_idx,
1432 start_idx + match_length,
1433 NULL,
1434 NULL);
1435 if (res != NSERROR_OK) {
1436 return res;
1437 }
1438
1439 new_text = pos + match_length;
1440 offset += (new_text - text);
1441 length -= (new_text - text);
1442 text = new_text;
1443 }
1444 }
1445 }
1446
1447 return res;
1448}
1449
1450
1451/**
1452 * Given a range of byte offsets within a UTF8 textplain content,
1453 * return a box that fully encloses the text
1454 *
1455 * \param[in] c content of type CONTENT_TEXTPLAIN
1456 * \param[in] start byte offset of start of text range
1457 * \param[in] end byte offset of end
1458 * \param[out] r rectangle to be completed
1459 */
1460static void
1462 unsigned start,
1463 unsigned end,
1464 struct rect *r)
1465{
1468 char *utf8_data;
1469 struct textplain_line *line;
1470 unsigned lineno = 0;
1471 unsigned nlines;
1472
1473 assert(c != NULL);
1474 assert(start <= end);
1475 assert(end <= text->utf8_data_size);
1476
1477 utf8_data = text->utf8_data;
1478 nlines = text->physical_line_count;
1479 line = text->physical_line;
1480
1481 /* find start */
1482 lineno = textplain_find_line(c, start);
1483
1484 r->y0 = (int)(MARGIN + lineno * line_height);
1485
1486 if (lineno + 1 <= nlines || line[lineno + 1].start >= end) {
1487 /* \todo - it may actually be more efficient just to
1488 * run forwards most of the time
1489 */
1490
1491 /* find end */
1492 lineno = textplain_find_line(c, end);
1493
1494 r->x0 = 0;
1495 r->x1 = text->formatted_width;
1496 } else {
1497 /* single line */
1498 const char *text = utf8_data + line[lineno].start;
1499
1501 start - line[lineno].start,
1502 line[lineno].length);
1503
1505 end - line[lineno].start,
1506 line[lineno].length);
1507 }
1508
1509 r->y1 = (int)(MARGIN + (lineno + 1) * line_height);
1510}
1511
1512
1513/**
1514 * Return a pointer to the raw UTF-8 data, as opposed to the reformatted
1515 * text to fit the window width. Thus only hard newlines are preserved
1516 * in the saved/copied text of a selection.
1517 *
1518 * \param[in] c content of type CONTENT_TEXTPLAIN
1519 * \param[in] start starting byte offset within UTF-8 text
1520 * \param[in] end ending byte offset
1521 * \param[out] plen receives validated length
1522 * \return pointer to text, or NULL if no text
1523 */
1524static char *
1526 unsigned start,
1527 unsigned end,
1528 size_t *plen)
1529{
1531 size_t utf8_size;
1532
1533 assert(c != NULL);
1534
1535 utf8_size = text->utf8_data_size;
1536
1537 /* any text at all? */
1538 if (!utf8_size) return NULL;
1539
1540 /* clamp to valid offset range */
1541 if (start >= utf8_size) start = utf8_size;
1542 if (end >= utf8_size) end = utf8_size;
1543
1544 *plen = end - start;
1545
1546 return text->utf8_data + start;
1547}
1548
1549
1550/**
1551 * get bounds of a free text search match
1552 */
1553static nserror
1555 unsigned start_idx,
1556 unsigned end_idx,
1557 struct box *start_box,
1558 struct box *end_box,
1559 struct rect *bounds)
1560{
1561 textplain_coords_from_range(c, start_idx, end_idx, bounds);
1562
1563 return NSERROR_OK;
1564}
1565
1566
1567/**
1568 * invalidate a region based on offsets into the text cauing a redraw
1569 */
1570static nserror
1572 unsigned start_idx,
1573 unsigned end_idx)
1574{
1575 struct rect r;
1576
1577 if (end_idx <= start_idx) {
1578 return NSERROR_BAD_PARAMETER;
1579 }
1580
1581 textplain_coords_from_range(c, start_idx, end_idx, &r);
1582
1583 content__request_redraw(c, r.x0, r.y0, r.x1 - r.x0, r.y1 - r.y0);
1584
1585 return NSERROR_OK;
1586}
1587
1588static nserror
1590 unsigned start_idx,
1591 unsigned end_idx,
1592 struct selection_string *selstr)
1593{
1594 const char *text;
1595 size_t length;
1596 bool res = false;
1597
1598 text = textplain_get_raw_data(c, start_idx, end_idx, &length);
1599 if (text != NULL) {
1600 res = selection_string_append(text, length, false, NULL, selstr);
1601 }
1602 if (res == false) {
1603 return NSERROR_NOMEM;
1604 }
1605 return NSERROR_OK;
1606}
1607
1608
1609/**
1610 * Retrieve the index of the end of the text
1611 *
1612 * \param[in] c Content to retrieve size of
1613 * \return Size, in bytes, of data
1614 */
1615static nserror
1616textplain_textselection_get_end(struct content *c, unsigned *end_idx)
1617{
1619
1620 *end_idx = text->utf8_data_size;
1621 return NSERROR_OK;
1622}
1623
1624
1625/**
1626 * plain text content handler table
1627 */
1630 .create = textplain_create,
1631 .process_data = textplain_process_data,
1632 .data_complete = textplain_convert,
1633 .reformat = textplain_reformat,
1634 .destroy = textplain_destroy,
1635 .mouse_track = textplain_mouse_track,
1636 .mouse_action = textplain_mouse_action,
1637 .keypress = textplain_keypress,
1638 .redraw = textplain_redraw,
1639 .open = textplain_open,
1640 .close = textplain_close,
1641 .get_selection = textplain_get_selection,
1642 .clone = textplain_clone,
1643 .type = textplain_content_type,
1644 .textsearch_find = textplain_textsearch_find,
1645 .textsearch_bounds = textplain_textsearch_bounds,
1646 .textselection_redraw = textplain_textselection_redraw,
1647 .textselection_copy = textplain_textselection_copy,
1648 .textselection_get_end = textplain_textselection_get_end,
1649 .no_share = true,
1650};
1651
1652
1653/* exported interface documented in html/textplain.h */
1655{
1656 lwc_error lerror;
1657 nserror error;
1658
1659 lerror = lwc_intern_string("Windows-1252",
1660 SLEN("Windows-1252"),
1662 if (lerror != lwc_error_ok) {
1663 return NSERROR_NOMEM;
1664 }
1665
1666 error = content_factory_register_handler("text/plain",
1668 if (error != NSERROR_OK) {
1669 lwc_string_unref(textplain_default_charset);
1670 }
1671
1672 error = content_factory_register_handler("application/json",
1674 if (error != NSERROR_OK) {
1675 lwc_string_unref(textplain_default_charset);
1676 }
1677
1678 return error;
1679}
1680
1681
1682
1683
Browser window creation and manipulation interface.
@ DRAGGING_SELECTION
@ DRAGGING_NONE
void browser_window_page_drag_start(struct browser_window *bw, int x, int y)
Start drag scrolling the contents of the browser window.
void browser_window_set_drag_type(struct browser_window *bw, browser_drag_type type, const struct rect *rect)
Set drag type for a browser window, and inform front end.
browser_drag_type browser_window_get_drag_type(struct browser_window *bw)
Get type of any current drag for a browser window.
static int line_height(const css_unit_ctx *unit_len_ctx, const css_computed_style *style)
Calculate line height from a style.
Definition: layout.c:2654
void content_destroy(struct content *c)
Destroy and free a content.
Definition: content.c:354
void content_broadcast(struct content *c, content_msg msg, const union content_msg_data *data)
Send a message to all users.
Definition: content.c:752
void content_set_done(struct content *c)
Put a content in status CONTENT_STATUS_DONE.
Definition: content.c:299
nserror content__init(struct content *c, const content_handler *handler, lwc_string *imime_type, const struct http_parameter *params, llcache_handle *llcache, const char *fallback_charset, bool quirks)
Definition: content.c:190
void content__request_redraw(struct content *c, int x, int y, int width, int height)
Request a redraw of an area of a content.
Definition: content.c:459
const uint8_t * content__get_source_data(struct content *c, size_t *size)
Retrieve source of content.
Definition: content.c:1216
nserror content__clone(const struct content *c, struct content *nc)
Clone a content's data members.
Definition: content.c:1382
void content_set_ready(struct content *c)
Put a content in status CONTENT_STATUS_READY and unlock the content.
Definition: content.c:285
void content_set_status(struct content *c, const char *status_message)
Updates content with new status.
Definition: content.c:270
void content_broadcast_error(struct content *c, nserror errorcode, const char *msg)
Send an error message to all users.
Definition: content.c:769
nserror content_factory_register_handler(const char *mime_type, const content_handler *handler)
Register a handler with the content factory.
Protected interface to Content handling.
@ CONTENT_STATUS_READY
Some parts of content still being loaded, but can be displayed.
Definition: content_type.h:92
@ CONTENT_STATUS_DONE
Content has completed all processing.
Definition: content_type.h:95
content_type
The type of a content.
Definition: content_type.h:53
@ CONTENT_TEXTPLAIN
content is plain text
Definition: content_type.h:61
@ CONTENT_MSG_STATUS
new status string
Definition: content_type.h:128
@ CONTENT_MSG_POINTER
Wants a specific mouse pointer set.
Definition: content_type.h:161
Useful interned string pointers (interface).
css_fixed nscss_screen_dpi
Screen DPI in fixed point units: defaults to 90, which RISC OS uses.
Definition: css.c:44
bool selection_click(struct selection *s, struct browser_window *top, browser_mouse_state mouse, unsigned idx)
Handles mouse clicks (including drag starts) in or near a selection.
Definition: selection.c:319
bool selection_highlighted(const struct selection *s, unsigned start, unsigned end, unsigned *start_idx, unsigned *end_idx)
Tests whether a text range lies partially within the selection, if there is a selection defined,...
Definition: selection.c:562
bool selection_clear(struct selection *s, bool redraw)
Clears the current selection, optionally causing the screen to be updated.
Definition: selection.c:518
struct selection * selection_create(struct content *c)
Creates a new selection object associated with a browser window.
Definition: selection.c:253
bool selection_string_append(const char *text, size_t length, bool space, plot_font_style_t *style, struct selection_string *sel_string)
Append text to selection string.
Definition: selection.c:191
void selection_init(struct selection *s)
Initialise the selection object to use the given box subtree as its root, ie.
Definition: selection.c:302
bool selection_copy_to_clipboard(struct selection *s)
Copy the selected contents to the clipboard.
Definition: selection.c:484
bool selection_dragging_start(struct selection *s)
Definition: selection.c:596
void selection_track(struct selection *s, browser_mouse_state mouse, unsigned idx)
Handles movements related to the selection, eg.
Definition: selection.c:420
bool selection_dragging(struct selection *s)
Definition: selection.c:591
void selection_destroy(struct selection *s)
Destroys a selection object clearing it if nesessary.
Definition: selection.c:269
void selection_select_all(struct selection *s)
Selects all the text within the box subtree controlled by this selection object, updating the screen ...
Definition: selection.c:542
char * selection_get_copy(struct selection *s)
Get copy of selection as string.
Definition: selection.c:457
Text selection within browser windows (interface).
Error codes.
nserror
Enumeration of error codes.
Definition: errors.h:29
@ NSERROR_BAD_PARAMETER
Bad Parameter.
Definition: errors.h:48
@ NSERROR_NOMEM
Memory exhaustion.
Definition: errors.h:32
@ NSERROR_CLONE_FAILED
Failed to clone handle.
Definition: errors.h:37
@ NSERROR_OK
No error.
Definition: errors.h:30
struct netsurf_table * guit
The global interface table.
Definition: gui_factory.c:50
Interface to core interface table.
High-level resource cache interface.
HTTP header parsing functions.
Public content interface.
Interface to platform-specific layout operation table.
browser_pointer_shape
Mouse pointer type.
Definition: mouse.h:135
@ BROWSER_POINTER_MOVE
Definition: mouse.h:149
@ BROWSER_POINTER_DEFAULT
Definition: mouse.h:136
browser_mouse_state
Mouse state: 1 is primary mouse button.
Definition: mouse.h:52
@ BROWSER_MOUSE_DRAG_1
start of button 1 drag
Definition: mouse.h:86
@ BROWSER_MOUSE_DRAG_2
start of button 2 drag
Definition: mouse.h:88
Target independent plotting interface.
Interface to key press operations.
@ NS_KEY_SELECT_ALL
Definition: keypress.h:32
@ NS_KEY_COPY_SELECTION
Definition: keypress.h:33
@ NS_KEY_CLEAR_SELECTION
Definition: keypress.h:45
@ NS_KEY_ESCAPE
Definition: keypress.h:47
static struct llcache_s * llcache
low level cache state
Definition: llcache.c:267
#define NSLOG(catname, level, logmsg, args...)
Definition: log.h:116
const char * messages_get(const char *key)
Fast lookup of a message by key from the standard Messages hash.
Definition: messages.c:241
Localised message support (interface).
nserror http_parameter_list_find_item(const http_parameter *list, lwc_string *name, lwc_string **value)
Find a named item in an HTTP parameter list.
Definition: parameter.c:114
#define colour_to_bw_furthest(c0)
Definition: plot_style.h:193
plot_style_t * plot_style_fill_white
Definition: plot_style.c:32
@ FONTF_NONE
Definition: plot_style.h:102
@ PLOT_FONT_FAMILY_MONOSPACE
Definition: plot_style.h:91
plot_style_t * plot_style_fill_black
Definition: plot_style.c:38
#define PLOT_STYLE_SCALE
Scaling factor for plot styles.
Definition: plot_style.h:45
int width
Definition: gui.c:160
int height
Definition: gui.c:161
Interface to utility string handling.
Node in box tree.
Definition: box.h:177
Browser window data.
int x
Window dimensions.
struct browser_window * bw
Column record for a table.
Definition: box_normalise.c:59
Content operation function table.
void(* fini)(void)
parameters to content redraw
Definition: content.h:40
int y
coordinate for top-left of redraw
Definition: content.h:42
int x
coordinate for top-left of redraw
Definition: content.h:41
colour background_colour
The background colour.
Definition: content.h:51
float scale
Scale for redraw (for scaling contents without intrinsic dimensions)
Definition: content.h:56
Content which corresponds to a single URL.
int height
Height dimension, if applicable.
int width
Width dimension, if applicable.
struct content::@117 textsearch
Free text search state.
struct textsearch_context * context
content_status status
Current status.
unsigned int size
Estimated size of all data associated with this content.
nserror(* position)(const struct plot_font_style *fstyle, const char *string, size_t length, int x, size_t *char_offset, int *actual_x)
Find the position in a string where an x coordinate falls.
Definition: layout.h:63
nserror(* width)(const struct plot_font_style *fstyle, const char *string, size_t length, int *width)
Measure the width of a string.
Definition: layout.h:49
Representation of an HTTP parameter.
Definition: parameter.c:31
Handle to low-level cache object.
Definition: llcache.c:76
struct gui_layout_table * layout
Layout table.
Definition: gui_table.h:163
Parameters for object element and similar elements.
Definition: box.h:164
Font style for plotting.
Definition: plot_style.h:111
plot_font_generic_family_t family
Generic family to plot with.
Definition: plot_style.h:118
colour foreground
Colour of text.
Definition: plot_style.h:123
plot_style_fixed size
Font size, in pt.
Definition: plot_style.h:119
colour background
Background colour to blend to, if appropriate.
Definition: plot_style.h:122
Plot style for stroke/fill plotters.
Definition: plot_style.h:76
colour fill_colour
Colour of fill.
Definition: plot_style.h:81
nserror(* text)(const struct redraw_context *ctx, const plot_font_style_t *fstyle, int x, int y, const char *text, size_t length)
Text plotting.
Definition: plotters.h:278
nserror(* rectangle)(const struct redraw_context *ctx, const plot_style_t *pstyle, const struct rect *rectangle)
Plots a rectangle.
Definition: plotters.h:188
nserror(* clip)(const struct redraw_context *ctx, const struct rect *clip)
Sets a clip rectangle for subsequent plot operations.
Definition: plotters.h:111
Rectangle coordinates.
Definition: types.h:40
int x0
Definition: types.h:41
int y0
Top left.
Definition: types.h:41
int x1
Definition: types.h:42
int y1
Bottom right.
Definition: types.h:42
Redraw context.
Definition: plotters.h:51
const struct plotter_table * plot
Current plot operation table.
Definition: plotters.h:73
bool interactive
Redraw to show interactive features.
Definition: plotters.h:59
struct content * c
Definition: selection.c:56
unsigned start_idx
Definition: selection.c:60
unsigned end_idx
Definition: selection.c:61
plain text content
Definition: textplain.c:60
struct browser_window * bw
Definition: textplain.c:71
size_t utf8_data_size
Definition: textplain.c:66
char * utf8_data
Definition: textplain.c:65
unsigned long physical_line_count
Definition: textplain.c:68
struct textplain_line * physical_line
Definition: textplain.c:69
void * inputstream
Definition: textplain.c:64
lwc_string * encoding
Definition: textplain.c:63
struct selection * sel
Definition: textplain.c:73
size_t utf8_data_allocated
Definition: textplain.c:67
struct content base
Definition: textplain.c:61
size_t length
Definition: textplain.c:54
size_t start
Definition: textplain.c:53
The context for a free text search.
Definition: textsearch.c:84
static bool text_draw(const char *utf8_text, size_t utf8_len, size_t offset, int x, int y, const struct rect *clip, int height, float scale, textplain_content *text, const struct selection *sel, const struct redraw_context *ctx)
Redraw a text string with highlighting (for selection/search)
Definition: textplain.c:844
static nserror textplain_textsearch_find(struct content *c, struct textsearch_context *context, const char *pattern, int p_len, bool case_sens)
Finds all occurrences of a given string in a textplain content.
Definition: textplain.c:1396
static bool textplain_convert(struct content *c)
Convert a CONTENT_TEXTPLAIN for display.
Definition: textplain.c:360
static plot_font_style_t textplain_style
Definition: textplain.c:84
static nserror textplain_mouse_track(struct content *c, struct browser_window *bw, browser_mouse_state mouse, int x, int y)
Handle mouse tracking (including drags) in a TEXTPLAIN content window.
Definition: textplain.c:749
static int textplain_coord_from_offset(const char *text, size_t offset, size_t length)
Convert a character offset within a line of text into the horizontal co-ordinate.
Definition: textplain.c:1270
#define CHUNK
Definition: textplain.c:78
static char * textplain_get_raw_data(struct content *c, unsigned start, unsigned end, size_t *plen)
Return a pointer to the raw UTF-8 data, as opposed to the reformatted text to fit the window width.
Definition: textplain.c:1525
static void textplain_reformat(struct content *c, int width, int height)
Reformat a CONTENT_TEXTPLAIN to a new width.
Definition: textplain.c:402
static nserror textplain_textselection_copy(struct content *c, unsigned start_idx, unsigned end_idx, struct selection_string *selstr)
Definition: textplain.c:1589
static bool textplain_copy_utf8_data(textplain_content *c, const uint8_t *buf, size_t len)
copy utf8 encoded data
Definition: textplain.c:236
static size_t textplain_offset_from_coords(struct content *c, int x, int y, int dir)
Return byte offset within UTF8 textplain content.
Definition: textplain.c:615
static nserror textplain_create(const content_handler *handler, lwc_string *imime_type, const struct http_parameter *params, llcache_handle *llcache, const char *fallback_charset, bool quirks, struct content **c)
Create a CONTENT_TEXTPLAIN.
Definition: textplain.c:187
#define TAB_WIDTH
Definition: textplain.c:81
struct textplain_content textplain_content
plain text content
static char * textplain_get_selection(struct content *c)
Return an textplain content's selection context.
Definition: textplain.c:1249
static bool textplain_redraw(struct content *c, struct content_redraw_data *data, const struct rect *clip, const struct redraw_context *ctx)
Draw a CONTENT_TEXTPLAIN using the current set of plotters (plot).
Definition: textplain.c:1051
static bool textplain_keypress(struct content *c, uint32_t key)
Handle keypresses.
Definition: textplain.c:798
static void textplain_destroy(struct content *c)
Destroy a CONTENT_TEXTPLAIN and free all resources it owns.
Definition: textplain.c:524
static void textplain_coords_from_range(struct content *c, unsigned start, unsigned end, struct rect *r)
Given a range of byte offsets within a UTF8 textplain content, return a box that fully encloses the t...
Definition: textplain.c:1461
static nserror textplain_mouse_action(struct content *c, struct browser_window *bw, browser_mouse_state mouse, int x, int y)
Handle mouse clicks and movements in a TEXTPLAIN content window.
Definition: textplain.c:699
static int textplain_find_line(struct content *c, unsigned offset)
Find line number of byte in text.
Definition: textplain.c:1357
static char * textplain_get_line(struct content *c, unsigned lineno, size_t *poffset, size_t *plen)
Return a pointer to the requested line of text.
Definition: textplain.c:1327
static nserror textplain_textsearch_bounds(struct content *c, unsigned start_idx, unsigned end_idx, struct box *start_box, struct box *end_box, struct rect *bounds)
get bounds of a free text search match
Definition: textplain.c:1554
static bool textplain_drain_input(textplain_content *c, parserutils_inputstream *stream, parserutils_error terminator)
drain input
Definition: textplain.c:263
static int textplain_tab_width
Definition: textplain.c:93
static nserror textplain_open(struct content *c, struct browser_window *bw, struct content *page, struct object_params *params)
Handle a window containing a CONTENT_TEXTPLAIN being opened.
Definition: textplain.c:1217
static bool textplain_process_data(struct content *c, const char *data, unsigned int size)
Process data for CONTENT_TEXTPLAIN.
Definition: textplain.c:334
static float textplain_line_height(void)
Calculate the line height, in pixels.
Definition: textplain.c:390
static nserror textplain_close(struct content *c)
Handle a window containing a CONTENT_TEXTPLAIN being closed.
Definition: textplain.c:1236
static parserutils_error textplain_charset_hack(const uint8_t *data, size_t len, uint16_t *mibenum, uint32_t *source)
Work around feature in libparserutils.
Definition: textplain.c:122
#define MARGIN
Definition: textplain.c:79
static nserror textplain_textselection_get_end(struct content *c, unsigned *end_idx)
Retrieve the index of the end of the text.
Definition: textplain.c:1616
static void textplain_fini(void)
Clean up after the text content handler.
Definition: textplain.c:101
static nserror textplain_textselection_redraw(struct content *c, unsigned start_idx, unsigned end_idx)
invalidate a region based on offsets into the text cauing a redraw
Definition: textplain.c:1571
static content_type textplain_content_type(void)
Definition: textplain.c:595
static nserror textplain_create_internal(textplain_content *c, lwc_string *encoding)
setup plain text render.
Definition: textplain.c:139
static unsigned long textplain_line_count(struct content *c)
Retrieve number of lines in content.
Definition: textplain.c:1307
nserror textplain_init(void)
Initialise the text content handler.
Definition: textplain.c:1654
static const content_handler textplain_content_handler
plain text content handler table
Definition: textplain.c:1628
static nserror textplain_clone(const struct content *old, struct content **newc)
Definition: textplain.c:548
#define TEXT_SIZE
Definition: textplain.c:82
static lwc_string * textplain_default_charset
Definition: textplain.c:95
Interface to content handler for plain text.
const char * content_textsearch_find_pattern(const char *string, int s_len, const char *pattern, int p_len, bool case_sens, unsigned int *m_len)
Find the first occurrence of 'match' in 'string' and return its index.
Definition: textsearch.c:475
bool content_textsearch_ishighlighted(struct textsearch_context *textsearch, unsigned start_offset, unsigned end_offset, unsigned *start_idx, unsigned *end_idx)
Determines whether any portion of the given text box should be selected because it matches the curren...
Definition: textsearch.c:623
nserror content_textsearch_add_match(struct textsearch_context *context, unsigned start_idx, unsigned end_idx, struct box *start_box, struct box *end_box)
Add a new entry to the list of matches.
Definition: textsearch.c:586
Interface to HTML searching.
Extra data for some content_msg messages.
Definition: content.h:60
int x
Carret x-coord.
Definition: content.h:110
browser_pointer_shape pointer
CONTENT_MSG_POINTER - Mouse pointer to set.
Definition: content.h:192
int y
Carret y-coord.
Definition: content.h:110
const char * explicit_status_text
CONTENT_MSG_STATUS - Status message update.
Definition: content.h:128
Option reading and saving interface.
#define nsoption_int(OPTION)
Get the value of an integer option.
Definition: nsoption.h:313
size_t utf8_next(const char *s, size_t l, size_t o)
Find next legal UTF-8 char in string.
Definition: utf8.c:129
UTF-8 manipulation functions (interface).
Interface to a number of general purpose functionality.
#define min(x, y)
Definition: utils.h:46
#define max(x, y)
Definition: utils.h:50
#define SLEN(x)
Calculate length of constant C string.
Definition: utils.h:88
static nserror line(const struct redraw_context *ctx, const plot_style_t *style, const struct rect *line)
Plots a line.
Definition: plot.c:579
static nserror text(const struct redraw_context *ctx, const struct plot_font_style *fstyle, int x, int y, const char *text, size_t length)
Text plotting.
Definition: plot.c:978
static nserror clip(const struct redraw_context *ctx, const struct rect *clip)
Sets a clip rectangle for subsequent plot operations.
Definition: plot.c:357