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 lwc_string_unref(textplain_default_charset);
105}
106
107
108/**
109 * Work around feature in libparserutils
110 *
111 * if the client provides an encoding up front, but does not provide a
112 * charset detection callback, then libparserutils will replace the
113 * provided encoding with UTF-8. This breaks our input handling.
114 *
115 * Avoid this by providing a callback that does precisely nothing,
116 * thus preserving whatever charset information we decided on in
117 * textplain_create.
118 */
119static parserutils_error
120textplain_charset_hack(const uint8_t *data,
121 size_t len,
122 uint16_t *mibenum,
123 uint32_t *source)
124{
125 return PARSERUTILS_OK;
126}
127
128
129/**
130 * setup plain text render.
131 *
132 * \param[in] c content object.
133 * \param[in] encoding the encoding of the content.
134 * \return NSERROR_OK else appropriate error code.
135 */
136static nserror
138{
139 char *utf8_data;
140 parserutils_inputstream *stream;
141 parserutils_error error;
142
144
145 utf8_data = malloc(CHUNK);
146 if (utf8_data == NULL)
147 goto no_memory;
148
149 error = parserutils_inputstream_create(lwc_string_data(encoding), 0,
150 textplain_charset_hack, &stream);
151 if (error == PARSERUTILS_BADENCODING) {
152 /* Fall back to Windows-1252 */
153 error = parserutils_inputstream_create("Windows-1252", 0,
154 textplain_charset_hack, &stream);
155 }
156 if (error != PARSERUTILS_OK) {
157 free(utf8_data);
158 goto no_memory;
159 }
160
161 c->encoding = lwc_string_ref(encoding);
162 c->inputstream = stream;
163 c->utf8_data = utf8_data;
164 c->utf8_data_size = 0;
165 c->utf8_data_allocated = CHUNK;
166 c->physical_line = 0;
167 c->physical_line_count = 0;
168 c->formatted_width = 0;
169 c->bw = NULL;
170 c->sel = selection_create((struct content *)c);
171
172 return NSERROR_OK;
173
174no_memory:
176
177 return NSERROR_NOMEM;
178}
179
180
181/**
182 * Create a CONTENT_TEXTPLAIN.
183 */
184static nserror
186 lwc_string *imime_type,
187 const struct http_parameter *params,
189 const char *fallback_charset,
190 bool quirks,
191 struct content **c)
192{
194 nserror error;
195 lwc_string *encoding;
196
197 text = calloc(1, sizeof(textplain_content));
198 if (text == NULL) {
199 return NSERROR_NOMEM;
200 }
201
202 error = content__init(&text->base, handler, imime_type, params,
203 llcache, fallback_charset, quirks);
204 if (error != NSERROR_OK) {
205 free(text);
206 return error;
207 }
208
209 error = http_parameter_list_find_item(params, corestring_lwc_charset,
210 &encoding);
211 if (error != NSERROR_OK) {
212 encoding = lwc_string_ref(textplain_default_charset);
213 }
214
215 error = textplain_create_internal(text, encoding);
216 if (error != NSERROR_OK) {
217 lwc_string_unref(encoding);
218 free(text);
219 return error;
220 }
221
222 lwc_string_unref(encoding);
223
224 *c = (struct content *) text;
225
226 return NSERROR_OK;
227}
228
229
230/**
231 * copy utf8 encoded data
232 */
233static bool
234textplain_copy_utf8_data(textplain_content *c, const uint8_t *buf, size_t len)
235{
236 if (c->utf8_data_size + len >= c->utf8_data_allocated) {
237 /* Compute next multiple of chunk above the required space */
238 size_t allocated;
239 char *utf8_data;
240
241 allocated = (c->utf8_data_size + len + CHUNK - 1) & ~(CHUNK - 1);
242 utf8_data = realloc(c->utf8_data, allocated);
243 if (utf8_data == NULL)
244 return false;
245
246 c->utf8_data = utf8_data;
247 c->utf8_data_allocated = allocated;
248 }
249
250 memcpy(c->utf8_data + c->utf8_data_size, buf, len);
251 c->utf8_data_size += len;
252
253 return true;
254}
255
256
257/**
258 * drain input
259 */
260static bool
262 parserutils_inputstream *stream,
263 parserutils_error terminator)
264{
265 static const uint8_t *u_fffd = (const uint8_t *) "\xef\xbf\xbd";
266 const uint8_t *ch;
267 size_t chlen, offset = 0;
268
269 while (parserutils_inputstream_peek(stream, offset, &ch, &chlen) !=
270 terminator) {
271 /* Replace all instances of NUL with U+FFFD */
272 if (chlen == 1 && *ch == 0) {
273 if (offset > 0) {
274 /* Obtain pointer to start of input data */
275 parserutils_inputstream_peek(stream, 0,
276 &ch, &chlen);
277 /* Copy from it up to the start of the NUL */
278 if (textplain_copy_utf8_data(c, ch,
279 offset) == false)
280 return false;
281 }
282
283 /* Emit U+FFFD */
284 if (textplain_copy_utf8_data(c, u_fffd, 3) == false)
285 return false;
286
287 /* Advance inputstream past the NUL we just read */
288 parserutils_inputstream_advance(stream, offset + 1);
289 /* Reset the read offset */
290 offset = 0;
291 } else {
292 /* Accumulate input */
293 offset += chlen;
294
295 if (offset > CHUNK) {
296 /* Obtain pointer to start of input data */
297 parserutils_inputstream_peek(stream, 0,
298 &ch, &chlen);
299
300 /* Emit the data we've read */
301 if (textplain_copy_utf8_data(c, ch,
302 offset) == false)
303 return false;
304
305 /* Advance the inputstream */
306 parserutils_inputstream_advance(stream, offset);
307 /* Reset the read offset */
308 offset = 0;
309 }
310 }
311 }
312
313 if (offset > 0) {
314 /* Obtain pointer to start of input data */
315 parserutils_inputstream_peek(stream, 0, &ch, &chlen);
316 /* Emit any data remaining */
317 if (textplain_copy_utf8_data(c, ch, offset) == false)
318 return false;
319
320 /* Advance the inputstream past the data we've read */
321 parserutils_inputstream_advance(stream, offset);
322 }
323
324 return true;
325}
326
327
328/**
329 * Process data for CONTENT_TEXTPLAIN.
330 */
331static bool
332textplain_process_data(struct content *c, const char *data, unsigned int size)
333{
335 parserutils_inputstream *stream = text->inputstream;
336 parserutils_error error;
337
338 error = parserutils_inputstream_append(stream,
339 (const uint8_t *) data, size);
340 if (error != PARSERUTILS_OK) {
341 goto no_memory;
342 }
343
344 if (textplain_drain_input(text, stream, PARSERUTILS_NEEDDATA) == false)
345 goto no_memory;
346
347 return true;
348
349no_memory:
351 return false;
352}
353
354
355/**
356 * Convert a CONTENT_TEXTPLAIN for display.
357 */
358static bool textplain_convert(struct content *c)
359{
361 parserutils_inputstream *stream = text->inputstream;
362 parserutils_error error;
363
364 error = parserutils_inputstream_append(stream, NULL, 0);
365 if (error != PARSERUTILS_OK) {
366 return false;
367 }
368
369 if (textplain_drain_input(text, stream, PARSERUTILS_EOF) == false)
370 return false;
371
372 parserutils_inputstream_destroy(stream);
373 text->inputstream = NULL;
374
378
379 return true;
380}
381
382
383/**
384 * Calculate the line height, in pixels
385 *
386 * \return Line height, in pixels
387 */
388static float textplain_line_height(void)
389{
390 /* Size is in points, so convert to pixels.
391 * Then use a constant line height of 1.2 x font size.
392 */
393 return FIXTOFLT(FDIV((FMUL(FLTTOFIX(1.2), FMUL(nscss_screen_dpi, INTTOFIX((textplain_style.size / PLOT_STYLE_SCALE))))), F_72));
394}
395
396
397/**
398 * Reformat a CONTENT_TEXTPLAIN to a new width.
399 */
400static void textplain_reformat(struct content *c, int width, int height)
401{
403 char *utf8_data = text->utf8_data;
404 size_t utf8_data_size = text->utf8_data_size;
405 unsigned long line_count = 0;
406 struct textplain_line *line = text->physical_line;
407 struct textplain_line *line1;
408 size_t i, space, col;
409 size_t columns = 80;
410 int character_width;
411 size_t line_start;
412 nserror res;
413
414 NSLOG(netsurf, INFO, "content %p w:%d h:%d", c, width, height);
415
416 /* compute available columns (assuming monospaced font) - use 8
417 * characters for better accuracy
418 */
420 "ABCDEFGH", 8,
421 &character_width);
422 if (res != NSERROR_OK) {
423 return;
424 }
425
426 columns = (width - MARGIN - MARGIN) * 8 / character_width;
427 textplain_tab_width = (TAB_WIDTH * character_width) / 8;
428
429 text->formatted_width = width;
430
431 text->physical_line_count = 0;
432
433 if (!line) {
434 text->physical_line = line =
435 malloc(sizeof(struct textplain_line) * (1024 + 3));
436 if (!line)
437 goto no_memory;
438 }
439
440 line[line_count++].start = line_start = 0;
441 space = 0;
442 i = 0;
443 col = 0;
444 while (i < utf8_data_size) {
445 size_t csize; /* number of bytes in character */
446 uint32_t chr;
447 bool term;
448 size_t next_col;
449 parserutils_error perror;
450
451 perror = parserutils_charset_utf8_to_ucs4((const uint8_t *)utf8_data + i, utf8_data_size - i, &chr, &csize);
452 if (perror != PARSERUTILS_OK) {
453 chr = 0xfffd;
454 }
455
456 term = (chr == '\n' || chr == '\r');
457
458 next_col = col + 1;
459
460 if (chr == '\t') {
461 next_col = (next_col + TAB_WIDTH - 1) & ~(TAB_WIDTH - 1);
462 }
463
464 if (term || next_col >= columns) {
465 if (line_count % 1024 == 0) {
466 line1 = realloc(line,
467 sizeof(struct textplain_line) *
468 (line_count + 1024 + 3));
469 if (!line1)
470 goto no_memory;
471 text->physical_line = line = line1;
472 }
473
474 if (term) {
475 line[line_count-1].length = i - line_start;
476
477 /* skip second char of CR/LF or LF/CR pair */
478 if (i + 1 < utf8_data_size &&
479 utf8_data[i+1] != utf8_data[i] &&
480 (utf8_data[i+1] == '\n' ||
481 utf8_data[i+1] == '\r')) {
482 i++;
483 }
484 } else {
485 if (space) {
486 /* break at last space in line */
487 i = space;
488 line[line_count-1].length = (i + 1) - line_start;
489 } else
490 line[line_count-1].length = i - line_start;
491 }
492
493 line[line_count++].start = line_start = i + 1;
494 col = 0;
495 space = 0;
496 } else {
497 col++;
498 if (chr == ' ')
499 space = i;
500 }
501 i += csize;
502 }
503 line[line_count-1].length = i - line[line_count-1].start;
504 line[line_count].start = utf8_data_size;
505
506 text->physical_line_count = line_count;
507 c->width = width;
508 c->height = line_count * textplain_line_height() + MARGIN + MARGIN;
509
510 return;
511
512no_memory:
513 NSLOG(netsurf, INFO, "out of memory (line_count %lu)", line_count);
514 return;
515}
516
517
518/**
519 * Destroy a CONTENT_TEXTPLAIN and free all resources it owns.
520 */
521
522static void textplain_destroy(struct content *c)
523{
525
526 lwc_string_unref(text->encoding);
527
528 if (text->inputstream != NULL) {
529 parserutils_inputstream_destroy(text->inputstream);
530 }
531
532 if (text->physical_line != NULL) {
533 free(text->physical_line);
534 }
535
536 if (text->utf8_data != NULL) {
537 free(text->utf8_data);
538 }
539
540 if (text->sel != NULL) {
542 }
543}
544
545
546static nserror textplain_clone(const struct content *old, struct content **newc)
547{
548 const textplain_content *old_text = (textplain_content *) old;
550 nserror error;
551 const uint8_t *data;
552 size_t size;
553
554 text = calloc(1, sizeof(textplain_content));
555 if (text == NULL)
556 return NSERROR_NOMEM;
557
558 error = content__clone(old, &text->base);
559 if (error != NSERROR_OK) {
560 content_destroy(&text->base);
561 return error;
562 }
563
564 /* Simply replay create/process/convert */
565 error = textplain_create_internal(text, old_text->encoding);
566 if (error != NSERROR_OK) {
567 content_destroy(&text->base);
568 return error;
569 }
570
571 data = content__get_source_data(&text->base, &size);
572 if (size > 0) {
573 if (textplain_process_data(&text->base,
574 (const char *)data,
575 size) == false) {
576 content_destroy(&text->base);
577 return NSERROR_NOMEM;
578 }
579 }
580
581 if (old->status == CONTENT_STATUS_READY ||
582 old->status == CONTENT_STATUS_DONE) {
583 if (textplain_convert(&text->base) == false) {
584 content_destroy(&text->base);
586 }
587 }
588
589 return NSERROR_OK;
590}
591
592
594{
595 return CONTENT_TEXTPLAIN;
596}
597
598
599/**
600 * Return byte offset within UTF8 textplain content.
601 *
602 * given the co-ordinates of a point within a textplain content. 'dir'
603 * specifies the direction in which to search (-1 = above-left, +1 =
604 * below-right) if the co-ordinates are not contained within a line.
605 *
606 * \param[in] c content of type CONTENT_TEXTPLAIN
607 * \param[in] x x ordinate of point
608 * \param[in] y y ordinate of point
609 * \param[in] dir direction of search if not within line
610 * \return byte offset of character containing (or nearest to) point
611 */
612static size_t
613textplain_offset_from_coords(struct content *c, int x, int y, int dir)
614{
617 struct textplain_line *line;
618 const char *text;
619 unsigned nlines;
620 size_t length;
621 int idx;
622
623 assert(c != NULL);
624
625 y = (int)((float)(y - MARGIN) / line_height);
626 x -= MARGIN;
627
628 nlines = textc->physical_line_count;
629 if (!nlines)
630 return 0;
631
632 if (y <= 0) y = 0;
633 else if ((unsigned)y >= nlines)
634 y = nlines - 1;
635
636 line = &textc->physical_line[y];
637 text = textc->utf8_data + line->start;
638 length = line->length;
639 idx = 0;
640
641 while (x > 0) {
642 size_t next_offset = 0;
643 int width = INT_MAX;
644
645 while (next_offset < length && text[next_offset] != '\t') {
646 next_offset = utf8_next(text, length, next_offset);
647 }
648
649 if (next_offset < length) {
651 text,
652 next_offset,
653 &width);
654 }
655
656 if (x <= width) {
657 int pixel_offset;
658 size_t char_offset;
659
661 text, next_offset, x,
662 &char_offset, &pixel_offset);
663
664 idx += char_offset;
665 break;
666 }
667
668 x -= width;
669 length -= next_offset;
670 text += next_offset;
671 idx += next_offset;
672
673 /* check if it's within the tab */
675 if (x <= width) break;
676
677 x -= width;
678 length--;
679 text++;
680 idx++;
681 }
682
683 return line->start + idx;
684}
685
686
687/**
688 * Handle mouse clicks and movements in a TEXTPLAIN content window.
689 *
690 * \param c content of type textplain
691 * \param bw browser window
692 * \param mouse mouse state on action
693 * \param x coordinate of mouse
694 * \param y coordinate of mouse
695 */
696static nserror
698 struct browser_window *bw,
700 int x, int y)
701{
704 union content_msg_data msg_data;
705 const char *status = 0;
706 size_t idx;
707 int dir = 0;
708
710
711 idx = textplain_offset_from_coords(c, x, y, dir);
712 if (selection_click(text->sel, text->bw, mouse, idx)) {
713
714 if (selection_dragging(text->sel)) {
716 DRAGGING_SELECTION, NULL);
717 status = messages_get("Selecting");
718 }
719
720 } else {
724 }
725 }
726
727 msg_data.explicit_status_text = status;
729
730 msg_data.pointer = pointer;
732
733 return NSERROR_OK;
734}
735
736
737/**
738 * Handle mouse tracking (including drags) in a TEXTPLAIN content window.
739 *
740 * \param c content of type textplain
741 * \param bw browser window
742 * \param mouse state of mouse buttons and modifier keys
743 * \param x coordinate of mouse
744 * \param y coordinate of mouse
745 */
746static nserror
748 struct browser_window *bw,
750 int x, int y)
751{
753
755 int dir = -1;
756 size_t idx;
757
759 dir = 1;
760
761 idx = textplain_offset_from_coords(c, x, y, dir);
762 selection_track(text->sel, mouse, idx);
763
765 }
766
767 switch (browser_window_get_drag_type(bw)) {
768
769 case DRAGGING_SELECTION: {
770 int dir = -1;
771 size_t idx;
772
773 if (selection_dragging_start(text->sel)) dir = 1;
774
775 idx = textplain_offset_from_coords(c, x, y, dir);
776 selection_track(text->sel, mouse, idx);
777 }
778 break;
779
780 default:
781 textplain_mouse_action(c, bw, mouse, x, y);
782 break;
783 }
784
785 return NSERROR_OK;
786}
787
788
789/**
790 * Handle keypresses.
791 *
792 * \param c content of type CONTENT_TEXTPLAIN
793 * \param key The UCS4 character codepoint
794 * \return true if key handled, false otherwise
795 */
796static bool textplain_keypress(struct content *c, uint32_t key)
797{
799 struct selection *sel = text->sel;
800
801 switch (key) {
804 return true;
805
807 selection_clear(sel, true);
808 return true;
809
812 return true;
813
814 case NS_KEY_ESCAPE:
815 /* if there's no selection, leave Escape for the caller */
816 return selection_clear(sel, true);
817 }
818
819 return false;
820}
821
822
823/**
824 * Redraw a text string with highlighting
825 * (for selection/search)
826 *
827 * \param utf8_text pointer to UTF-8 text string
828 * \param utf8_len length of string, in bytes
829 * \param offset byte offset within textual representation
830 * \param x x ordinate at which to plot text
831 * \param y y ordinate at which to plot text
832 * \param clip pointer to current clip rectangle
833 * \param height height of text string
834 * \param scale current display scale (1.0 = 100%)
835 * \param text Content being redrawn.
836 * \param sel Selection context
837 * \param search Search context
838 * \param ctx current redraw context
839 * \return true iff successful and redraw should proceed
840 */
841static bool
842text_draw(const char *utf8_text,
843 size_t utf8_len,
844 size_t offset,
845 int x,
846 int y,
847 const struct rect *clip,
848 int height,
849 float scale,
851 const struct selection *sel,
852 const struct redraw_context *ctx)
853{
854 bool highlighted = false;
855 plot_font_style_t plot_fstyle;
856 nserror res;
857
858 /* Need scaled text size to pass to plotters */
859 plot_fstyle = textplain_style;
860 plot_fstyle.size *= scale;
861
862 /* is this box part of a selection? */
863 if (ctx->interactive == true) {
864 unsigned len = utf8_len;
865 unsigned start_idx;
866 unsigned end_idx;
867
868 /* first try the browser window's current selection */
869 if (selection_highlighted(sel,
870 offset,
871 offset + len,
872 &start_idx,
873 &end_idx)) {
874 highlighted = true;
875 }
876
877 /* what about the current search operation, if any? */
878 if (!highlighted &&
879 (text->base.textsearch.context != NULL) &&
880 content_textsearch_ishighlighted(text->base.textsearch.context,
881 offset,
882 offset + len,
883 &start_idx,
884 &end_idx)) {
885 highlighted = true;
886 }
887
888 /* \todo make search terms visible within selected text */
889 if (highlighted) {
890 struct rect r;
891 unsigned endtxt_idx = end_idx;
892 bool clip_changed = false;
893 bool text_visible = true;
894 int startx, endx;
895 plot_style_t pstyle_fill_hback = *plot_style_fill_white;
896 plot_font_style_t fstyle_hback = plot_fstyle;
897
898 if (end_idx > utf8_len) {
899 /* adjust for trailing space, not present in
900 * utf8_text
901 */
902 assert(end_idx == utf8_len + 1);
903 endtxt_idx = utf8_len;
904 }
905
907 utf8_text,
908 start_idx,
909 &startx);
910 if (res != NSERROR_OK) {
911 startx = 0;
912 }
913
915 utf8_text,
916 endtxt_idx,
917 &endx);
918 if (res != NSERROR_OK) {
919 endx = 0;
920 }
921
922 if (scale != 1.0) {
923 startx *= scale;
924 endx *= scale;
925 }
926
927 /* draw any text preceding highlighted portion */
928 if (start_idx > 0) {
929 res = ctx->plot->text(ctx,
930 &plot_fstyle,
931 x,
932 y + (int)(height * 0.75 * scale),
933 utf8_text,
934 start_idx);
935 if (res != NSERROR_OK) {
936 return false;
937 }
938 }
939
940 pstyle_fill_hback.fill_colour = textplain_style.foreground;
941
942 /* highlighted portion */
943 r.x0 = x + startx;
944 r.y0 = y;
945 r.x1 = x + endx;
946 r.y1 = y + height * scale;
947 res = ctx->plot->rectangle(ctx, &pstyle_fill_hback, &r);
948 if (res != NSERROR_OK) {
949 return false;
950 }
951
952 if (start_idx > 0) {
953 int px0 = max(x + startx, clip->x0);
954 int px1 = min(x + endx, clip->x1);
955
956 if (px0 < px1) {
957 r.x0 = px0;
958 r.y0 = clip->y0;
959 r.x1 = px1;
960 r.y1 = clip->y1;
961 res = ctx->plot->clip(ctx, &r);
962 if (res != NSERROR_OK) {
963 return false;
964 }
965
966 clip_changed = true;
967 } else {
968 text_visible = false;
969 }
970 }
971
972 fstyle_hback.background =
973 pstyle_fill_hback.fill_colour;
974 fstyle_hback.foreground = colour_to_bw_furthest(
975 pstyle_fill_hback.fill_colour);
976
977 if (text_visible &&
978 (ctx->plot->text(ctx,
979 &fstyle_hback,
980 x,
981 y + (int)(height * 0.75 * scale),
982 utf8_text,
983 endtxt_idx) != NSERROR_OK)) {
984 return false;
985 }
986
987 /* draw any text succeeding highlighted portion */
988 if (endtxt_idx < utf8_len) {
989 int px0 = max(x + endx, clip->x0);
990 if (px0 < clip->x1) {
991
992 r.x0 = px0;
993 r.y0 = clip->y0;
994 r.x1 = clip->x1;
995 r.y1 = clip->y1;
996 res = ctx->plot->clip(ctx, &r);
997 if (res != NSERROR_OK) {
998 return false;
999 }
1000
1001 clip_changed = true;
1002
1003 res = ctx->plot->text(ctx,
1004 &plot_fstyle,
1005 x,
1006 y + (int)(height * 0.75 * scale),
1007 utf8_text,
1008 utf8_len);
1009 if (res != NSERROR_OK) {
1010 return false;
1011 }
1012 }
1013 }
1014
1015 if (clip_changed &&
1016 (ctx->plot->clip(ctx, clip) != NSERROR_OK)) {
1017 return false;
1018 }
1019 }
1020 }
1021
1022 if (!highlighted) {
1023 res = ctx->plot->text(ctx,
1024 &plot_fstyle,
1025 x,
1026 y + (int) (height * 0.75 * scale),
1027 utf8_text,
1028 utf8_len);
1029 if (res != NSERROR_OK) {
1030 return false;
1031 }
1032 }
1033 return true;
1034}
1035
1036
1037/**
1038 * Draw a CONTENT_TEXTPLAIN using the current set of plotters (plot).
1039 *
1040 * x, y, clip_[xy][01] are in target coordinates.
1041 *
1042 * \param c content of type CONTENT_TEXTPLAIN
1043 * \param data redraw data for this content redraw
1044 * \param clip current clip region
1045 * \param ctx current redraw context
1046 * \return true if successful, false otherwise
1047 */
1048static bool
1050 struct content_redraw_data *data,
1051 const struct rect *clip,
1052 const struct redraw_context *ctx)
1053{
1055 struct browser_window *bw = text->bw;
1056 char *utf8_data = text->utf8_data;
1057 long lineno;
1058 int x = data->x;
1059 int y = data->y;
1060 unsigned long line_count = text->physical_line_count;
1062 float scaled_line_height = line_height * data->scale;
1063 long line0 = (clip->y0 - y * data->scale) / scaled_line_height - 1;
1064 long line1 = (clip->y1 - y * data->scale) / scaled_line_height + 1;
1065 struct textplain_line *line = text->physical_line;
1066 size_t length;
1067 plot_style_t *plot_style_highlight;
1068 nserror res;
1069
1070 if (line0 < 0)
1071 line0 = 0;
1072 if (line1 < 0)
1073 line1 = 0;
1074 if (line_count < (unsigned long) line0)
1075 line0 = line_count;
1076 if (line_count < (unsigned long) line1)
1077 line1 = line_count;
1078 if (line1 < line0)
1079 line1 = line0;
1080
1081 res = ctx->plot->rectangle(ctx, plot_style_fill_white, clip);
1082 if (res != NSERROR_OK) {
1083 return false;
1084 }
1085
1086 if (!line)
1087 return true;
1088
1089 /* choose a suitable background colour for any highlighted text */
1090 if ((data->background_colour & 0x808080) == 0x808080)
1091 plot_style_highlight = plot_style_fill_black;
1092 else
1093 plot_style_highlight = plot_style_fill_white;
1094
1095 /* Set up font plot style */
1097
1098 x = (x + MARGIN) * data->scale;
1099 y = (y + MARGIN) * data->scale;
1100 for (lineno = line0; lineno != line1; lineno++) {
1101 const char *text_d = utf8_data + line[lineno].start;
1102 int tab_width = textplain_tab_width * data->scale;
1103 size_t offset = 0;
1104 int tx = x;
1105
1106 if (!tab_width) tab_width = 1;
1107
1108 length = line[lineno].length;
1109 if (!length)
1110 continue;
1111
1112 while (offset < length) {
1113 size_t next_offset = offset;
1114 int width;
1115 int ntx;
1116 nserror res;
1117
1118 while ((next_offset < length) &&
1119 (text_d[next_offset] != '\t')) {
1120 next_offset = utf8_next(text_d,
1121 length,
1122 next_offset);
1123 }
1124
1125 if (!text_draw(text_d + offset,
1126 next_offset - offset,
1127 line[lineno].start + offset,
1128 tx,
1129 y + (lineno * scaled_line_height),
1130 clip,
1132 data->scale,
1133 text,
1134 text->sel,
1135 ctx)) {
1136 return false;
1137 }
1138
1139 if (next_offset >= length)
1140 break;
1141
1143 &text_d[offset],
1144 next_offset - offset,
1145 &width);
1146 /* locate end of string and align to next tab position */
1147 if (res == NSERROR_OK) {
1148 tx += (int)(width * data->scale);
1149 }
1150
1151 ntx = x + ((1 + (tx - x) / tab_width) * tab_width);
1152
1153 /* if the tab character lies within the
1154 * selection, if any, then we must draw it as
1155 * a filled rectangle so that it's consistent
1156 * with background of the selected text
1157 */
1158
1159 if (bw) {
1160 unsigned tab_ofst = line[lineno].start + next_offset;
1161 struct selection *sel = text->sel;
1162 bool highlighted = false;
1163
1164 unsigned start_idx, end_idx;
1165 if (selection_highlighted(sel,
1166 tab_ofst,
1167 tab_ofst + 1,
1168 &start_idx,
1169 &end_idx)) {
1170 highlighted = true;
1171 }
1172
1173
1174 if (!highlighted &&
1175 (c->textsearch.context != NULL)) {
1176 unsigned start_idx, end_idx;
1179 tab_ofst,
1180 tab_ofst + 1,
1181 &start_idx,
1182 &end_idx)) {
1183 highlighted = true;
1184 }
1185 }
1186
1187 if (highlighted) {
1188 struct rect rect;
1189 rect.x0 = tx;
1190 rect.y0 = y + (lineno * scaled_line_height);
1191 rect.x1 = ntx;
1192 rect.y1 = rect.y0 + scaled_line_height;
1193 res = ctx->plot->rectangle(ctx,
1194 plot_style_highlight,
1195 &rect);
1196 if (res != NSERROR_OK) {
1197 return false;
1198 }
1199 }
1200 }
1201
1202 offset = next_offset + 1;
1203 tx = ntx;
1204 }
1205 }
1206
1207 return true;
1208}
1209
1210
1211/**
1212 * Handle a window containing a CONTENT_TEXTPLAIN being opened.
1213 */
1214static nserror
1216 struct browser_window *bw,
1217 struct content *page,
1218 struct object_params *params)
1219{
1221
1222 text->bw = bw;
1223
1224 /* text selection */
1225 selection_init(text->sel);
1226
1227 return NSERROR_OK;
1228}
1229
1230
1231/**
1232 * Handle a window containing a CONTENT_TEXTPLAIN being closed.
1233 */
1235{
1237
1238 text->bw = NULL;
1239
1240 return NSERROR_OK;
1241}
1242
1243
1244/**
1245 * Return an textplain content's selection context
1246 */
1247static char *textplain_get_selection(struct content *c)
1248{
1250
1251 return selection_get_copy(text->sel);
1252}
1253
1254
1255/**
1256 * Convert a character offset within a line of text into the
1257 * horizontal co-ordinate
1258 *
1259 * The conversion takes into account the font being used and any tabs
1260 * in the text
1261 *
1262 * \param text line of text
1263 * \param offset char offset within text
1264 * \param length line length
1265 * \return x ordinate
1266 */
1267static int
1268textplain_coord_from_offset(const char *text, size_t offset, size_t length)
1269{
1270 int x = 0;
1271
1272 while (offset > 0) {
1273 size_t next_offset = 0;
1274 int tx;
1275
1276 while (next_offset < offset && text[next_offset] != '\t') {
1277 next_offset = utf8_next(text, length, next_offset);
1278 }
1279
1280 guit->layout->width(&textplain_style, text, next_offset, &tx);
1281
1282 x += tx;
1283
1284 if (next_offset >= offset)
1285 break;
1286
1287 /* align to next tab boundary */
1288 next_offset++;
1289 x = (1 + (x / textplain_tab_width)) * textplain_tab_width;
1290 offset -= next_offset;
1291 text += next_offset;
1292 length -= next_offset;
1293 }
1294
1295 return x;
1296}
1297
1298
1299/**
1300 * Retrieve number of lines in content
1301 *
1302 * \param[in] c Content to retrieve line count from
1303 * \return Number of lines
1304 */
1305static unsigned long textplain_line_count(struct content *c)
1306{
1308
1309 assert(c != NULL);
1310
1311 return text->physical_line_count;
1312}
1313
1314
1315/**
1316 * Return a pointer to the requested line of text.
1317 *
1318 * \param[in] c content of type CONTENT_TEXTPLAIN
1319 * \param[in] lineno line number
1320 * \param[out] poffset receives byte offset of line start within text
1321 * \param[out] plen receives length of returned line
1322 * \return pointer to text, or NULL if invalid line number
1323 */
1324static char *
1326 unsigned lineno,
1327 size_t *poffset,
1328 size_t *plen)
1329{
1331 struct textplain_line *line;
1332
1333 assert(c != NULL);
1334
1335 if (lineno >= text->physical_line_count)
1336 return NULL;
1337 line = &text->physical_line[lineno];
1338
1339 *poffset = line->start;
1340 *plen = line->length;
1341 return text->utf8_data + line->start;
1342}
1343
1344
1345/**
1346 * Find line number of byte in text
1347 *
1348 * Given a byte offset within the text, return the line number
1349 * of the line containing that offset.
1350 *
1351 * \param[in] c content of type CONTENT_TEXTPLAIN
1352 * \param[in] offset byte offset within textual representation
1353 * \return line number, or -1 if offset invalid (larger than size)
1354 */
1355static int textplain_find_line(struct content *c, unsigned offset)
1356{
1358 struct textplain_line *line;
1359 int nlines;
1360 int lineno = 0;
1361
1362 assert(c != NULL);
1363
1364 line = text->physical_line;
1365 nlines = text->physical_line_count;
1366
1367 if (offset > text->utf8_data_size) {
1368 return -1;
1369 }
1370
1371/* \todo - implement binary search here */
1372 while (lineno < nlines && line[lineno].start < offset) {
1373 lineno++;
1374 }
1375 if (line[lineno].start > offset) {
1376 lineno--;
1377 }
1378
1379 return lineno;
1380}
1381
1382
1383/**
1384 * Finds all occurrences of a given string in a textplain content
1385 *
1386 * \param c the content to be searched
1387 * \param context The search context to add the entry to.
1388 * \param pattern the string pattern to search for
1389 * \param p_len pattern length
1390 * \param case_sens whether to perform a case sensitive search
1391 * \return NSERROR_OK on success else error code on faliure
1392 */
1393static nserror
1395 struct textsearch_context *context,
1396 const char *pattern,
1397 int p_len,
1398 bool case_sens)
1399{
1400 int nlines = textplain_line_count(c);
1401 int line;
1402 nserror res = NSERROR_OK;
1403
1404 for(line = 0; line < nlines; line++) {
1405 size_t offset, length;
1406 const char *text;
1407
1408 text = textplain_get_line(c, line, &offset, &length);
1409 if (text) {
1410 while (length > 0) {
1411 unsigned match_length;
1412 size_t start_idx;
1413 const char *new_text;
1414 const char *pos;
1415
1417 text,
1418 length,
1419 pattern,
1420 p_len,
1421 case_sens,
1422 &match_length);
1423 if (!pos)
1424 break;
1425
1426 /* found string in line => add to list */
1427 start_idx = offset + (pos - text);
1428 res = content_textsearch_add_match(context,
1429 start_idx,
1430 start_idx + match_length,
1431 NULL,
1432 NULL);
1433 if (res != NSERROR_OK) {
1434 return res;
1435 }
1436
1437 new_text = pos + match_length;
1438 offset += (new_text - text);
1439 length -= (new_text - text);
1440 text = new_text;
1441 }
1442 }
1443 }
1444
1445 return res;
1446}
1447
1448
1449/**
1450 * Given a range of byte offsets within a UTF8 textplain content,
1451 * return a box that fully encloses the text
1452 *
1453 * \param[in] c content of type CONTENT_TEXTPLAIN
1454 * \param[in] start byte offset of start of text range
1455 * \param[in] end byte offset of end
1456 * \param[out] r rectangle to be completed
1457 */
1458static void
1460 unsigned start,
1461 unsigned end,
1462 struct rect *r)
1463{
1466 char *utf8_data;
1467 struct textplain_line *line;
1468 unsigned lineno = 0;
1469 unsigned nlines;
1470
1471 assert(c != NULL);
1472 assert(start <= end);
1473 assert(end <= text->utf8_data_size);
1474
1475 utf8_data = text->utf8_data;
1476 nlines = text->physical_line_count;
1477 line = text->physical_line;
1478
1479 /* find start */
1480 lineno = textplain_find_line(c, start);
1481
1482 r->y0 = (int)(MARGIN + lineno * line_height);
1483
1484 if (lineno + 1 <= nlines || line[lineno + 1].start >= end) {
1485 /* \todo - it may actually be more efficient just to
1486 * run forwards most of the time
1487 */
1488
1489 /* find end */
1490 lineno = textplain_find_line(c, end);
1491
1492 r->x0 = 0;
1493 r->x1 = text->formatted_width;
1494 } else {
1495 /* single line */
1496 const char *text = utf8_data + line[lineno].start;
1497
1499 start - line[lineno].start,
1500 line[lineno].length);
1501
1503 end - line[lineno].start,
1504 line[lineno].length);
1505 }
1506
1507 r->y1 = (int)(MARGIN + (lineno + 1) * line_height);
1508}
1509
1510
1511/**
1512 * Return a pointer to the raw UTF-8 data, as opposed to the reformatted
1513 * text to fit the window width. Thus only hard newlines are preserved
1514 * in the saved/copied text of a selection.
1515 *
1516 * \param[in] c content of type CONTENT_TEXTPLAIN
1517 * \param[in] start starting byte offset within UTF-8 text
1518 * \param[in] end ending byte offset
1519 * \param[out] plen receives validated length
1520 * \return pointer to text, or NULL if no text
1521 */
1522static char *
1524 unsigned start,
1525 unsigned end,
1526 size_t *plen)
1527{
1529 size_t utf8_size;
1530
1531 assert(c != NULL);
1532
1533 utf8_size = text->utf8_data_size;
1534
1535 /* any text at all? */
1536 if (!utf8_size) return NULL;
1537
1538 /* clamp to valid offset range */
1539 if (start >= utf8_size) start = utf8_size;
1540 if (end >= utf8_size) end = utf8_size;
1541
1542 *plen = end - start;
1543
1544 return text->utf8_data + start;
1545}
1546
1547
1548/**
1549 * get bounds of a free text search match
1550 */
1551static nserror
1553 unsigned start_idx,
1554 unsigned end_idx,
1555 struct box *start_box,
1556 struct box *end_box,
1557 struct rect *bounds)
1558{
1559 textplain_coords_from_range(c, start_idx, end_idx, bounds);
1560
1561 return NSERROR_OK;
1562}
1563
1564
1565/**
1566 * invalidate a region based on offsets into the text cauing a redraw
1567 */
1568static nserror
1570 unsigned start_idx,
1571 unsigned end_idx)
1572{
1573 struct rect r;
1574
1575 if (end_idx <= start_idx) {
1576 return NSERROR_BAD_PARAMETER;
1577 }
1578
1579 textplain_coords_from_range(c, start_idx, end_idx, &r);
1580
1581 content__request_redraw(c, r.x0, r.y0, r.x1 - r.x0, r.y1 - r.y0);
1582
1583 return NSERROR_OK;
1584}
1585
1586static nserror
1588 unsigned start_idx,
1589 unsigned end_idx,
1590 struct selection_string *selstr)
1591{
1592 const char *text;
1593 size_t length;
1594 bool res = false;
1595
1596 text = textplain_get_raw_data(c, start_idx, end_idx, &length);
1597 if (text != NULL) {
1598 res = selection_string_append(text, length, false, NULL, selstr);
1599 }
1600 if (res == false) {
1601 return NSERROR_NOMEM;
1602 }
1603 return NSERROR_OK;
1604}
1605
1606
1607/**
1608 * Retrieve the index of the end of the text
1609 *
1610 * \param[in] c Content to retrieve size of
1611 * \return Size, in bytes, of data
1612 */
1613static nserror
1614textplain_textselection_get_end(struct content *c, unsigned *end_idx)
1615{
1617
1618 *end_idx = text->utf8_data_size;
1619 return NSERROR_OK;
1620}
1621
1622
1623/**
1624 * plain text content handler table
1625 */
1628 .create = textplain_create,
1629 .process_data = textplain_process_data,
1630 .data_complete = textplain_convert,
1631 .reformat = textplain_reformat,
1632 .destroy = textplain_destroy,
1633 .mouse_track = textplain_mouse_track,
1634 .mouse_action = textplain_mouse_action,
1635 .keypress = textplain_keypress,
1636 .redraw = textplain_redraw,
1637 .open = textplain_open,
1638 .close = textplain_close,
1639 .get_selection = textplain_get_selection,
1640 .clone = textplain_clone,
1641 .type = textplain_content_type,
1642 .textsearch_find = textplain_textsearch_find,
1643 .textsearch_bounds = textplain_textsearch_bounds,
1644 .textselection_redraw = textplain_textselection_redraw,
1645 .textselection_copy = textplain_textselection_copy,
1646 .textselection_get_end = textplain_textselection_get_end,
1647 .no_share = true,
1648};
1649
1650
1651/* exported interface documented in html/textplain.h */
1653{
1654 lwc_error lerror;
1655 nserror error;
1656
1657 lerror = lwc_intern_string("Windows-1252",
1658 SLEN("Windows-1252"),
1660 if (lerror != lwc_error_ok) {
1661 return NSERROR_NOMEM;
1662 }
1663
1664 error = content_factory_register_handler("text/plain",
1666 if (error != NSERROR_OK) {
1667 lwc_string_unref(textplain_default_charset);
1668 }
1669
1670 error = content_factory_register_handler("application/json",
1672 if (error != NSERROR_OK) {
1673 lwc_string_unref(textplain_default_charset);
1674 }
1675
1676 return error;
1677}
1678
1679
1680
1681
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:1208
nserror content__clone(const struct content *c, struct content *nc)
Clone a content's data members.
Definition: content.c:1374
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:256
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:161
int height
Definition: gui.c:162
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:290
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:842
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:1394
static bool textplain_convert(struct content *c)
Convert a CONTENT_TEXTPLAIN for display.
Definition: textplain.c:358
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:747
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:1268
#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:1523
static void textplain_reformat(struct content *c, int width, int height)
Reformat a CONTENT_TEXTPLAIN to a new width.
Definition: textplain.c:400
static nserror textplain_textselection_copy(struct content *c, unsigned start_idx, unsigned end_idx, struct selection_string *selstr)
Definition: textplain.c:1587
static bool textplain_copy_utf8_data(textplain_content *c, const uint8_t *buf, size_t len)
copy utf8 encoded data
Definition: textplain.c:234
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:613
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:185
#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:1247
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:1049
static bool textplain_keypress(struct content *c, uint32_t key)
Handle keypresses.
Definition: textplain.c:796
static void textplain_destroy(struct content *c)
Destroy a CONTENT_TEXTPLAIN and free all resources it owns.
Definition: textplain.c:522
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:1459
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:697
static int textplain_find_line(struct content *c, unsigned offset)
Find line number of byte in text.
Definition: textplain.c:1355
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:1325
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:1552
static bool textplain_drain_input(textplain_content *c, parserutils_inputstream *stream, parserutils_error terminator)
drain input
Definition: textplain.c:261
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:1215
static bool textplain_process_data(struct content *c, const char *data, unsigned int size)
Process data for CONTENT_TEXTPLAIN.
Definition: textplain.c:332
static float textplain_line_height(void)
Calculate the line height, in pixels.
Definition: textplain.c:388
static nserror textplain_close(struct content *c)
Handle a window containing a CONTENT_TEXTPLAIN being closed.
Definition: textplain.c:1234
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:120
#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:1614
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:1569
static content_type textplain_content_type(void)
Definition: textplain.c:593
static nserror textplain_create_internal(textplain_content *c, lwc_string *encoding)
setup plain text render.
Definition: textplain.c:137
static unsigned long textplain_line_count(struct content *c)
Retrieve number of lines in content.
Definition: textplain.c:1305
nserror textplain_init(void)
Initialise the text content handler.
Definition: textplain.c:1652
static const content_handler textplain_content_handler
plain text content handler table
Definition: textplain.c:1626
static nserror textplain_clone(const struct content *old, struct content **newc)
Definition: textplain.c:546
#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:317
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