NetSurf
box_special.c
Go to the documentation of this file.
1/*
2 * Copyright 2005 James Bursa <bursa@users.sourceforge.net>
3 * Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
4 * Copyright 2005 John M Bell <jmb202@ecs.soton.ac.uk>
5 * Copyright 2006 Richard Wilson <info@tinct.net>
6 * Copyright 2008 Michael Drake <tlsa@netsurf-browser.org>
7 * Copyright 2020 Vincent Sanders <vince@netsurf-browser.org>
8 *
9 * This file is part of NetSurf, http://www.netsurf-browser.org/
10 *
11 * NetSurf is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; version 2 of the License.
14 *
15 * NetSurf is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 */
23
24/**
25 * \file
26 * Implementation of special element handling conversion.
27 */
28
29#include <string.h>
30#include <stdbool.h>
31#include <dom/dom.h>
32
33#include "utils/nsoption.h"
34#include "utils/corestrings.h"
35#include "utils/log.h"
36#include "utils/messages.h"
37#include "utils/talloc.h"
38#include "utils/string.h"
39#include "utils/ascii.h"
40#include "utils/nsurl.h"
41#include "netsurf/plot_style.h"
42#include "css/hints.h"
43#include "desktop/frame_types.h"
45
46#include "html/html.h"
47#include "html/private.h"
48#include "html/object.h"
49#include "html/box.h"
50#include "html/box_manipulate.h"
51#include "html/box_construct.h"
52#include "html/box_special.h"
53#include "html/box_textarea.h"
54#include "html/form_internal.h"
55
56
58
59
60/**
61 * determine if a box is the root node
62 *
63 * \param n node to check
64 * \return true if node is root else false.
65 */
66static inline bool box_is_root(dom_node *n)
67{
68 dom_node *parent;
69 dom_node_type type;
70 dom_exception err;
71
72 err = dom_node_get_parent_node(n, &parent);
73 if (err != DOM_NO_ERR)
74 return false;
75
76 if (parent != NULL) {
77 err = dom_node_get_node_type(parent, &type);
78
79 dom_node_unref(parent);
80
81 if (err != DOM_NO_ERR)
82 return false;
83
84 if (type != DOM_DOCUMENT_NODE)
85 return false;
86 }
87
88 return true;
89}
90
91
92/**
93 * Destructor for object_params, for &lt;object&gt; elements
94 *
95 * \param o The object params being destroyed.
96 * \return 0 to allow talloc to continue destroying the tree.
97 */
99{
100 if (o->codebase != NULL)
102 if (o->classid != NULL)
104 if (o->data != NULL)
105 nsurl_unref(o->data);
106
107 return 0;
108}
109
110
111/**
112 * Parse a multi-length-list, as defined by HTML 4.01.
113 *
114 * \param ds dom string to parse
115 * \param count updated to number of entries
116 * \return array of struct box_multi_length, or 0 on memory exhaustion
117 */
118static struct frame_dimension *
119box_parse_multi_lengths(const dom_string *ds, unsigned int *count)
120{
121 char *end;
122 unsigned int i, n;
123 struct frame_dimension *length;
124 const char *s;
125
126 s = dom_string_data(ds);
127
128 for (i = 0, n = 1; s[i]; i++)
129 if (s[i] == ',')
130 n++;
131
132 length = calloc(n, sizeof(struct frame_dimension));
133 if (!length)
134 return NULL;
135
136 for (i = 0; i != n; i++) {
137 while (ascii_is_space(*s)) {
138 s++;
139 }
140 length[i].value = strtof(s, &end);
141 if (length[i].value <= 0) {
142 length[i].value = 1;
143 }
144 s = end;
145 switch (*s) {
146 case '%':
147 length[i].unit = FRAME_DIMENSION_PERCENT;
148 break;
149 case '*':
150 length[i].unit = FRAME_DIMENSION_RELATIVE;
151 break;
152 default:
153 length[i].unit = FRAME_DIMENSION_PIXELS;
154 break;
155 }
156 while (*s && *s != ',') {
157 s++;
158 }
159 if (*s == ',') {
160 s++;
161 }
162 }
163
164 *count = n;
165 return length;
166}
167
168
169/**
170 * Destructor for content_html_frames, for frame elements
171 *
172 * \param f The frame params being destroyed.
173 * \return 0 to allow talloc to continue destroying the tree.
174 */
176{
177 if (f->url != NULL) {
178 nsurl_unref(f->url);
179 f->url = NULL;
180 }
181
182 return 0;
183}
184
185
186/**
187 * create a frameset box tree
188 */
189static bool
191 dom_node *n,
193{
194 unsigned int row, col, index, i;
195 unsigned int rows = 1, cols = 1;
196 dom_string *s;
197 dom_exception err;
198 nsurl *url;
199 struct frame_dimension *row_height = 0, *col_width = 0;
200 dom_node *c, *next;
201 struct content_html_frames *frame;
202 bool default_border = true;
203 colour default_border_colour = 0x000000;
204
205 /* parse rows and columns */
206 err = dom_element_get_attribute(n, corestring_dom_rows, &s);
207 if (err == DOM_NO_ERR && s != NULL) {
208 row_height = box_parse_multi_lengths(s, &rows);
209 dom_string_unref(s);
210 if (row_height == NULL)
211 return false;
212 } else {
213 row_height = calloc(1, sizeof(struct frame_dimension));
214 if (row_height == NULL)
215 return false;
216 row_height->value = 100;
217 row_height->unit = FRAME_DIMENSION_PERCENT;
218 }
219
220 err = dom_element_get_attribute(n, corestring_dom_cols, &s);
221 if (err == DOM_NO_ERR && s != NULL) {
222 col_width = box_parse_multi_lengths(s, &cols);
223 dom_string_unref(s);
224 if (col_width == NULL) {
225 free(row_height);
226 return false;
227 }
228 } else {
229 col_width = calloc(1, sizeof(struct frame_dimension));
230 if (col_width == NULL) {
231 free(row_height);
232 return false;
233 }
234 col_width->value = 100;
235 col_width->unit = FRAME_DIMENSION_PERCENT;
236 }
237
238 /* common extension: border="0|1" to control all children */
239 err = dom_element_get_attribute(n, corestring_dom_border, &s);
240 if (err == DOM_NO_ERR && s != NULL) {
241 if ((dom_string_data(s)[0] == '0') &&
242 (dom_string_data(s)[1] == '\0'))
243 default_border = false;
244 dom_string_unref(s);
245 }
246
247 /* common extension: frameborder="yes|no" to control all children */
248 err = dom_element_get_attribute(n, corestring_dom_frameborder, &s);
249 if (err == DOM_NO_ERR && s != NULL) {
250 if (dom_string_caseless_lwc_isequal(s,
251 corestring_lwc_no) == 0)
252 default_border = false;
253 dom_string_unref(s);
254 }
255
256 /* common extension: bordercolor="#RRGGBB|<named colour>" to control
257 *all children */
258 err = dom_element_get_attribute(n, corestring_dom_bordercolor, &s);
259 if (err == DOM_NO_ERR && s != NULL) {
260 css_color color;
261
262 if (nscss_parse_colour(dom_string_data(s), &color))
263 default_border_colour = nscss_color_to_ns(color);
264
265 dom_string_unref(s);
266 }
267
268 /* update frameset and create default children */
269 f->cols = cols;
270 f->rows = rows;
273 (rows * cols));
274
276
277 for (row = 0; row < rows; row++) {
278 for (col = 0; col < cols; col++) {
279 index = (row * cols) + col;
280 frame = &f->children[index];
281 frame->cols = 0;
282 frame->rows = 0;
283 frame->width = col_width[col];
284 frame->height = row_height[row];
285 frame->margin_width = 0;
286 frame->margin_height = 0;
287 frame->name = NULL;
288 frame->url = NULL;
289 frame->no_resize = false;
291 frame->border = default_border;
292 frame->border_colour = default_border_colour;
293 frame->children = NULL;
294 }
295 }
296 free(col_width);
297 free(row_height);
298
299 /* create the frameset windows */
300 err = dom_node_get_first_child(n, &c);
301 if (err != DOM_NO_ERR)
302 return false;
303
304 for (row = 0; c != NULL && row < rows; row++) {
305 for (col = 0; c != NULL && col < cols; col++) {
306 while (c != NULL) {
307 dom_node_type type;
308 dom_string *name;
309
310 err = dom_node_get_node_type(c, &type);
311 if (err != DOM_NO_ERR) {
312 dom_node_unref(c);
313 return false;
314 }
315
316 err = dom_node_get_node_name(c, &name);
317 if (err != DOM_NO_ERR) {
318 dom_node_unref(c);
319 return false;
320 }
321
322 if (type != DOM_ELEMENT_NODE ||
323 (!dom_string_caseless_lwc_isequal(
324 name,
325 corestring_lwc_frame) &&
326 !dom_string_caseless_lwc_isequal(
327 name,
328 corestring_lwc_frameset
329 ))) {
330 err = dom_node_get_next_sibling(c,
331 &next);
332 if (err != DOM_NO_ERR) {
333 dom_string_unref(name);
334 dom_node_unref(c);
335 return false;
336 }
337
338 dom_string_unref(name);
339 dom_node_unref(c);
340 c = next;
341 } else {
342 /* Got a FRAME or FRAMESET element */
343 dom_string_unref(name);
344 break;
345 }
346 }
347
348 if (c == NULL)
349 break;
350
351 /* get current frame */
352 index = (row * cols) + col;
353 frame = &f->children[index];
354
355 /* nest framesets */
356 err = dom_node_get_node_name(c, &s);
357 if (err != DOM_NO_ERR) {
358 dom_node_unref(c);
359 return false;
360 }
361
362 if (dom_string_caseless_lwc_isequal(s,
363 corestring_lwc_frameset)) {
364 dom_string_unref(s);
365 frame->border = 0;
366 if (box_create_frameset(frame, c,
367 content) == false) {
368 dom_node_unref(c);
369 return false;
370 }
371
372 err = dom_node_get_next_sibling(c, &next);
373 if (err != DOM_NO_ERR) {
374 dom_node_unref(c);
375 return false;
376 }
377
378 dom_node_unref(c);
379 c = next;
380 continue;
381 }
382
383 dom_string_unref(s);
384
385 /* get frame URL (not required) */
386 url = NULL;
387 err = dom_element_get_attribute(c, corestring_dom_src, &s);
388 if (err == DOM_NO_ERR && s != NULL) {
389 box_extract_link(content, s, content->base_url,
390 &url);
391 dom_string_unref(s);
392 }
393
394 /* copy url */
395 if (url != NULL) {
396 /* no self-references */
397 if (nsurl_compare(content->base_url, url,
398 NSURL_COMPLETE) == false)
399 frame->url = url;
400 url = NULL;
401 }
402
403 /* fill in specified values */
404 err = dom_element_get_attribute(c, corestring_dom_name, &s);
405 if (err == DOM_NO_ERR && s != NULL) {
406 frame->name = talloc_strdup(content->bctx,
407 dom_string_data(s));
408 dom_string_unref(s);
409 }
410
411 if (dom_element_has_attribute(c, corestring_dom_noresize,
412 &frame->no_resize) != DOM_NO_ERR) {
413 /* If we can't read the attribute for some reason,
414 * assume we didn't have it.
415 */
416 frame->no_resize = false;
417 }
418
419 err = dom_element_get_attribute(c, corestring_dom_frameborder,
420 &s);
421 if (err == DOM_NO_ERR && s != NULL) {
422 i = atoi(dom_string_data(s));
423 frame->border = (i != 0);
424 dom_string_unref(s);
425 }
426
427 err = dom_element_get_attribute(c, corestring_dom_scrolling, &s);
428 if (err == DOM_NO_ERR && s != NULL) {
429 if (dom_string_caseless_lwc_isequal(s,
430 corestring_lwc_yes))
432 else if (dom_string_caseless_lwc_isequal(s,
433 corestring_lwc_no))
434 frame->scrolling = BW_SCROLLING_NO;
435 dom_string_unref(s);
436 }
437
438 err = dom_element_get_attribute(c, corestring_dom_marginwidth,
439 &s);
440 if (err == DOM_NO_ERR && s != NULL) {
441 frame->margin_width = atoi(dom_string_data(s));
442 dom_string_unref(s);
443 }
444
445 err = dom_element_get_attribute(c, corestring_dom_marginheight,
446 &s);
447 if (err == DOM_NO_ERR && s != NULL) {
448 frame->margin_height = atoi(dom_string_data(s));
449 dom_string_unref(s);
450 }
451
452 err = dom_element_get_attribute(c, corestring_dom_bordercolor,
453 &s);
454 if (err == DOM_NO_ERR && s != NULL) {
455 css_color color;
456
457 if (nscss_parse_colour(dom_string_data(s),
458 &color))
459 frame->border_colour =
460 nscss_color_to_ns(color);
461
462 dom_string_unref(s);
463 }
464
465 /* advance */
466 err = dom_node_get_next_sibling(c, &next);
467 if (err != DOM_NO_ERR) {
468 dom_node_unref(c);
469 return false;
470 }
471
472 dom_node_unref(c);
473 c = next;
474 }
475 }
476
477 /* If the last child wasn't a frame, we still need to unref it */
478 if (c != NULL) {
479 dom_node_unref(c);
480 }
481
482 return true;
483}
484
485
486/**
487 * Destructor for content_html_iframe, for &lt;iframe&gt; elements
488 *
489 * \param f The iframe params being destroyed.
490 * \return 0 to allow talloc to continue destroying the tree.
491 */
493{
494 if (f->url != NULL) {
495 nsurl_unref(f->url);
496 f->url = NULL;
497 }
498
499 return 0;
500}
501
502
503/**
504 * Get the value of a dom node element's attribute.
505 *
506 * \param n dom element node
507 * \param attribute name of attribute
508 * \param context talloc context for result buffer
509 * \param value updated to value, if the attribute is present
510 * \return true on success, false if attribute present but memory exhausted
511 *
512 * \note returning true does not imply that the attribute was found. If the
513 * attribute was not found, *value will be unchanged.
514 */
515static bool
517 const char *attribute,
518 void *context,
519 char **value)
520{
521 char *result;
522 dom_string *attr, *attr_name;
523 dom_exception err;
524
525 err = dom_string_create_interned((const uint8_t *) attribute,
526 strlen(attribute), &attr_name);
527 if (err != DOM_NO_ERR)
528 return false;
529
530 err = dom_element_get_attribute(n, attr_name, &attr);
531 if (err != DOM_NO_ERR) {
532 dom_string_unref(attr_name);
533 return false;
534 }
535
536 dom_string_unref(attr_name);
537
538 if (attr != NULL) {
539 result = talloc_strdup(context, dom_string_data(attr));
540
541 dom_string_unref(attr);
542
543 if (result == NULL)
544 return false;
545
546 *value = result;
547 }
548
549 return true;
550}
551
552
553/**
554 * Helper function for adding textarea widget to box.
555 *
556 * This is a load of hacks to ensure boxes replaced with textareas
557 * can be handled by the layout code.
558 */
559static bool
560box_input_text(html_content *html, struct box *box, struct dom_node *node)
561{
562 struct box *inline_container, *inline_box;
563 uint8_t display = css_computed_display_static(box->style);
564
565 switch (display) {
566 case CSS_DISPLAY_GRID:
567 case CSS_DISPLAY_FLEX:
568 case CSS_DISPLAY_BLOCK:
569 box->type = BOX_BLOCK;
570 break;
571 default:
573 break;
574 }
575
576 inline_container = box_create(NULL, 0, false, 0, 0, 0, 0, html->bctx);
577 if (!inline_container)
578 return false;
579 inline_container->type = BOX_INLINE_CONTAINER;
580 inline_box = box_create(NULL, box->style, false, 0, 0, box->title, 0,
581 html->bctx);
582 if (!inline_box)
583 return false;
584 inline_box->type = BOX_TEXT;
585 inline_box->text = talloc_strdup(html->bctx, "");
586
587 box_add_child(inline_container, inline_box);
588 box_add_child(box, inline_container);
589
591}
592
593
594/**
595 * Add an option to a form select control (helper function for box_select()).
596 *
597 * \param control select containing the &lt;option&gt;
598 * \param n xml element node for &lt;option&gt;
599 * \return true on success, false on memory exhaustion
600 */
601static bool box_select_add_option(struct form_control *control, dom_node *n)
602{
603 char *value = NULL;
604 char *text = NULL;
605 char *text_nowrap = NULL;
606 bool selected;
607 dom_string *content, *s;
608 dom_exception err;
609
610 err = dom_node_get_text_content(n, &content);
611 if (err != DOM_NO_ERR)
612 return false;
613
614 if (content != NULL) {
615 text = squash_whitespace(dom_string_data(content));
616 dom_string_unref(content);
617 } else {
618 text = strdup("");
619 }
620
621 if (text == NULL)
622 goto no_memory;
623
624 err = dom_element_get_attribute(n, corestring_dom_value, &s);
625 if (err == DOM_NO_ERR && s != NULL) {
626 value = strdup(dom_string_data(s));
627 dom_string_unref(s);
628 } else {
629 value = strdup(text);
630 }
631
632 if (value == NULL)
633 goto no_memory;
634
635 if (dom_element_has_attribute(n, corestring_dom_selected, &selected) != DOM_NO_ERR) {
636 /* Assume not selected if we can't read the attribute presence */
637 selected = false;
638 }
639
640 /* replace spaces/TABs with hard spaces to prevent line wrapping */
641 text_nowrap = cnv_space2nbsp(text);
642 if (text_nowrap == NULL)
643 goto no_memory;
644
645 if (form_add_option(control, value, text_nowrap, selected, n) == false)
646 goto no_memory;
647
648 free(text);
649
650 return true;
651
652no_memory:
653 free(value);
654 free(text);
655 free(text_nowrap);
656 return false;
657}
658
659
660/**
661 * \name Special case element handlers
662 *
663 * These functions are called by box_construct_element() when an element is
664 * being converted, according to the entries in element_table.
665 *
666 * The parameters are the xmlNode, the content for the document, and a partly
667 * filled in box structure for the element.
668 *
669 * Return true on success, false on memory exhaustion. Set *convert_children
670 * to false if children of this element in the XML tree should be skipped (for
671 * example, if they have been processed in some special way already).
672 *
673 * Elements ordered as in the HTML 4.01 specification. Section numbers in
674 * brackets [] refer to the spec.
675 *
676 * \{
677 */
678
679/**
680 * special element handler for Anchor [12.2].
681 */
682static bool
683box_a(dom_node *n,
685 struct box *box,
686 bool *convert_children)
687{
688 bool ok;
689 nsurl *url;
690 dom_string *s;
691 dom_exception err;
692
693 err = dom_element_get_attribute(n, corestring_dom_href, &s);
694 if (err == DOM_NO_ERR && s != NULL) {
695 ok = box_extract_link(content, s, content->base_url, &url);
696 dom_string_unref(s);
697 if (!ok)
698 return false;
699 if (url) {
700 if (box->href != NULL)
702 box->href = url;
703 }
704 }
705
706 /* name and id share the same namespace */
707 err = dom_element_get_attribute(n, corestring_dom_name, &s);
708 if (err == DOM_NO_ERR && s != NULL) {
709 lwc_string *lwc_name;
710
711 err = dom_string_intern(s, &lwc_name);
712
713 dom_string_unref(s);
714
715 if (err == DOM_NO_ERR) {
716 /* name replaces existing id
717 * TODO: really? */
718 lwc_string_unref(box->id);
719 box->id = lwc_name;
720 }
721 }
722
723 /* target frame [16.3] */
724 err = dom_element_get_attribute(n, corestring_dom_target, &s);
725 if (err == DOM_NO_ERR && s != NULL) {
726 if (dom_string_caseless_lwc_isequal(s,
727 corestring_lwc__blank))
728 box->target = "_blank";
729 else if (dom_string_caseless_lwc_isequal(s,
730 corestring_lwc__top))
731 box->target = "_top";
732 else if (dom_string_caseless_lwc_isequal(s,
733 corestring_lwc__parent))
734 box->target = "_parent";
735 else if (dom_string_caseless_lwc_isequal(s,
736 corestring_lwc__self))
737 /* the default may have been overridden by a
738 * <base target=...>, so this is different to 0 */
739 box->target = "_self";
740 else {
741 /* 6.16 says that frame names must begin with [a-zA-Z]
742 * This doesn't match reality, so just take anything */
744 dom_string_data(s));
745 if (!box->target) {
746 dom_string_unref(s);
747 return false;
748 }
749 }
750 dom_string_unref(s);
751 }
752
753 return true;
754}
755
756
757/**
758 * Document body special element handler [7.5.1].
759 */
760static bool
761box_body(dom_node *n,
763 struct box *box,
764 bool *convert_children)
765{
766 css_color color;
767
768 css_computed_background_color(box->style, &color);
769 if (nscss_color_is_transparent(color)) {
770 content->background_colour = NS_TRANSPARENT;
771 } else {
772 content->background_colour = nscss_color_to_ns(color);
773 }
774
775 return true;
776}
777
778
779/**
780 * special element handler for forced line break [9.3.2].
781 */
782static bool
783box_br(dom_node *n,
785 struct box *box,
786 bool *convert_children)
787{
788 box->type = BOX_BR;
789 return true;
790}
791
792
793/**
794 * special element handler for Push button [17.5].
795 */
796static bool
797box_button(dom_node *n,
799 struct box *box,
800 bool *convert_children)
801{
802 struct form_control *gadget;
803
804 gadget = html_forms_get_control_for_node(content->forms, n);
805 if (!gadget)
806 return false;
807
808 gadget->html = content;
809 box->gadget = gadget;
811 gadget->box = box;
812
814
815 /* Just render the contents */
816
817 return true;
818}
819
820
821/**
822 * Canvas element
823 */
824static bool
825box_canvas(dom_node *n,
827 struct box *box,
828 bool *convert_children)
829{
830 /* If scripting is not enabled display the contents of canvas */
831 if (!content->enable_scripting) {
832 return true;
833 }
834 *convert_children = false;
835
837 box_is_root(n)) == CSS_DISPLAY_NONE)
838 return true;
839
840 /* This is replaced content */
842
843 return true;
844}
845
846
847/**
848 * Embedded object (not in any HTML specification:
849 * see http://wp.netscape.com/assist/net_sites/new_html3_prop.html )
850 */
851static bool
852box_embed(dom_node *n,
854 struct box *box,
855 bool *convert_children)
856{
857 struct object_params *params;
858 struct object_param *param;
859 dom_namednodemap *attrs;
860 unsigned long idx;
861 uint32_t num_attrs;
862 dom_string *src;
863 dom_exception err;
864
866 box_is_root(n)) == CSS_DISPLAY_NONE)
867 return true;
868
869 params = talloc(content->bctx, struct object_params);
870 if (params == NULL)
871 return false;
872
874
875 params->data = NULL;
876 params->type = NULL;
877 params->codetype = NULL;
878 params->codebase = NULL;
879 params->classid = NULL;
880 params->params = NULL;
881
882 /* src is a URL */
883 err = dom_element_get_attribute(n, corestring_dom_src, &src);
884 if (err != DOM_NO_ERR || src == NULL)
885 return true;
886 if (box_extract_link(content, src, content->base_url,
887 &params->data) == false) {
888 dom_string_unref(src);
889 return false;
890 }
891
892 dom_string_unref(src);
893
894 if (params->data == NULL)
895 return true;
896
897 /* Don't include ourself */
898 if (nsurl_compare(content->base_url, params->data, NSURL_COMPLETE))
899 return true;
900
901 /* add attributes as parameters to linked list */
902 err = dom_node_get_attributes(n, &attrs);
903 if (err != DOM_NO_ERR)
904 return false;
905
906 err = dom_namednodemap_get_length(attrs, &num_attrs);
907 if (err != DOM_NO_ERR) {
908 dom_namednodemap_unref(attrs);
909 return false;
910 }
911
912 for (idx = 0; idx < num_attrs; idx++) {
913 dom_attr *attr;
914 dom_string *name, *value;
915
916 err = dom_namednodemap_item(attrs, idx, (void *) &attr);
917 if (err != DOM_NO_ERR) {
918 dom_namednodemap_unref(attrs);
919 return false;
920 }
921
922 err = dom_attr_get_name(attr, &name);
923 if (err != DOM_NO_ERR) {
924 dom_node_unref(attr);
925 dom_namednodemap_unref(attrs);
926 return false;
927 }
928
929 if (dom_string_caseless_lwc_isequal(name, corestring_lwc_src)) {
930 dom_node_unref(attr);
931 dom_string_unref(name);
932 continue;
933 }
934
935 err = dom_attr_get_value(attr, &value);
936 if (err != DOM_NO_ERR) {
937 dom_node_unref(attr);
938 dom_string_unref(name);
939 dom_namednodemap_unref(attrs);
940 return false;
941 }
942
943 param = talloc(content->bctx, struct object_param);
944 if (param == NULL) {
945 dom_node_unref(attr);
946 dom_string_unref(value);
947 dom_string_unref(name);
948 dom_namednodemap_unref(attrs);
949 return false;
950 }
951
952 param->name = talloc_strdup(content->bctx, dom_string_data(name));
953 param->value = talloc_strdup(content->bctx, dom_string_data(value));
954 param->type = NULL;
955 param->valuetype = talloc_strdup(content->bctx, "data");
956 param->next = NULL;
957
958 dom_string_unref(value);
959 dom_string_unref(name);
960 dom_node_unref(attr);
961
962 if (param->name == NULL || param->value == NULL ||
963 param->valuetype == NULL) {
964 dom_namednodemap_unref(attrs);
965 return false;
966 }
967
968 param->next = params->params;
969 params->params = param;
970 }
971
972 dom_namednodemap_unref(attrs);
973
974 box->object_params = params;
975
976 /* start fetch */
978 return html_fetch_object(content, params->data, box, CONTENT_ANY, false);
979}
980
981
982/**
983 * Window subdivision [16.2.1].
984 */
985static bool
986box_frameset(dom_node *n,
988 struct box *box,
989 bool *convert_children)
990{
991 bool ok;
992
993 if (content->frameset) {
994 NSLOG(netsurf, INFO, "Error: multiple framesets in document.");
995 /* Don't convert children */
996 if (convert_children)
997 *convert_children = false;
998 /* And ignore this spurious frameset */
999 box->type = BOX_NONE;
1000 return true;
1001 }
1002
1003 content->frameset = talloc_zero(content->bctx,
1004 struct content_html_frames);
1005 if (!content->frameset) {
1006 return false;
1007 }
1008
1009 ok = box_create_frameset(content->frameset, n, content);
1010 if (ok) {
1011 box->type = BOX_NONE;
1012 }
1013
1014 if (convert_children) {
1015 *convert_children = false;
1016 }
1017 return ok;
1018}
1019
1020
1021/**
1022 * Inline subwindow [16.5].
1023 */
1024static bool
1025box_iframe(dom_node *n,
1027 struct box *box,
1028 bool *convert_children)
1029{
1030 nsurl *url;
1031 dom_string *s;
1032 dom_exception err;
1033 struct content_html_iframe *iframe;
1034 int i;
1035
1037 box_is_root(n)) == CSS_DISPLAY_NONE)
1038 return true;
1039
1040 if (box->style &&
1041 css_computed_visibility(box->style) == CSS_VISIBILITY_HIDDEN) {
1042 /* Don't create iframe discriptors for invisible iframes
1043 * TODO: handle hidden iframes at browser_window generation
1044 * time instead? */
1045 return true;
1046 }
1047
1048 /* get frame URL */
1049 err = dom_element_get_attribute(n, corestring_dom_src, &s);
1050 if (err != DOM_NO_ERR || s == NULL)
1051 return true;
1052 if (box_extract_link(content, s, content->base_url, &url) == false) {
1053 dom_string_unref(s);
1054 return false;
1055 }
1056 dom_string_unref(s);
1057 if (url == NULL)
1058 return true;
1059
1060 /* don't include ourself */
1061 if (nsurl_compare(content->base_url, url, NSURL_COMPLETE)) {
1063 return true;
1064 }
1065
1066 /* create a new iframe */
1067 iframe = talloc(content->bctx, struct content_html_iframe);
1068 if (iframe == NULL) {
1070 return false;
1071 }
1072
1074
1075 iframe->box = box;
1076 iframe->margin_width = 0;
1077 iframe->margin_height = 0;
1078 iframe->name = NULL;
1079 iframe->url = url;
1080 iframe->scrolling = BW_SCROLLING_AUTO;
1081 iframe->border = true;
1082
1083 /* Add this iframe to the linked list of iframes */
1084 iframe->next = content->iframe;
1085 content->iframe = iframe;
1086
1087 /* fill in specified values */
1088 err = dom_element_get_attribute(n, corestring_dom_name, &s);
1089 if (err == DOM_NO_ERR && s != NULL) {
1090 iframe->name = talloc_strdup(content->bctx, dom_string_data(s));
1091 dom_string_unref(s);
1092 }
1093
1094 err = dom_element_get_attribute(n, corestring_dom_frameborder, &s);
1095 if (err == DOM_NO_ERR && s != NULL) {
1096 i = atoi(dom_string_data(s));
1097 iframe->border = (i != 0);
1098 dom_string_unref(s);
1099 }
1100
1101 err = dom_element_get_attribute(n, corestring_dom_bordercolor, &s);
1102 if (err == DOM_NO_ERR && s != NULL) {
1103 css_color color;
1104
1105 if (nscss_parse_colour(dom_string_data(s), &color))
1106 iframe->border_colour = nscss_color_to_ns(color);
1107
1108 dom_string_unref(s);
1109 }
1110
1111 err = dom_element_get_attribute(n, corestring_dom_scrolling, &s);
1112 if (err == DOM_NO_ERR && s != NULL) {
1113 if (dom_string_caseless_lwc_isequal(s,
1114 corestring_lwc_yes))
1115 iframe->scrolling = BW_SCROLLING_YES;
1116 else if (dom_string_caseless_lwc_isequal(s,
1117 corestring_lwc_no))
1118 iframe->scrolling = BW_SCROLLING_NO;
1119 dom_string_unref(s);
1120 }
1121
1122 err = dom_element_get_attribute(n, corestring_dom_marginwidth, &s);
1123 if (err == DOM_NO_ERR && s != NULL) {
1124 iframe->margin_width = atoi(dom_string_data(s));
1125 dom_string_unref(s);
1126 }
1127
1128 err = dom_element_get_attribute(n, corestring_dom_marginheight, &s);
1129 if (err == DOM_NO_ERR && s != NULL) {
1130 iframe->margin_height = atoi(dom_string_data(s));
1131 dom_string_unref(s);
1132 }
1133
1134 /* box */
1135 assert(box->style);
1136 box->flags |= IFRAME;
1137 box->flags |= IS_REPLACED;
1138
1139 /* Showing iframe, so don't show alternate content */
1140 if (convert_children)
1141 *convert_children = false;
1142 return true;
1143}
1144
1145
1146/**
1147 * Embedded image [13.2].
1148 */
1149static bool
1150box_image(dom_node *n,
1152 struct box *box,
1153 bool *convert_children)
1154{
1155 bool ok;
1156 dom_string *s;
1157 dom_exception err;
1158 nsurl *url;
1159 enum css_width_e wtype;
1160 enum css_height_e htype;
1161 css_fixed value = 0;
1162 css_unit wunit = CSS_UNIT_PX;
1163 css_unit hunit = CSS_UNIT_PX;
1164
1166 box_is_root(n)) == CSS_DISPLAY_NONE)
1167 return true;
1168
1169 /* handle alt text */
1170 err = dom_element_get_attribute(n, corestring_dom_alt, &s);
1171 if (err == DOM_NO_ERR && s != NULL) {
1172 char *alt = squash_whitespace(dom_string_data(s));
1173 dom_string_unref(s);
1174 if (alt == NULL)
1175 return false;
1176 box->text = talloc_strdup(content->bctx, alt);
1177 free(alt);
1178 if (box->text == NULL)
1179 return false;
1180 box->length = strlen(box->text);
1181 }
1182
1183 if (nsoption_bool(foreground_images) == false) {
1184 return true;
1185 }
1186
1187 /* imagemap associated with this image */
1188 if (!box_get_attribute(n, "usemap", content->bctx, &box->usemap))
1189 return false;
1190 if (box->usemap && box->usemap[0] == '#')
1191 box->usemap++;
1192
1193 /* get image URL */
1194 err = dom_element_get_attribute(n, corestring_dom_src, &s);
1195 if (err != DOM_NO_ERR || s == NULL)
1196 return true;
1197
1198 if (box_extract_link(content, s, content->base_url, &url) == false) {
1199 dom_string_unref(s);
1200 return false;
1201 }
1202
1203 dom_string_unref(s);
1204
1205 if (url == NULL)
1206 return true;
1207
1208 /* start fetch */
1209 box->flags |= IS_REPLACED;
1212
1213 wtype = css_computed_width(box->style, &value, &wunit);
1214 htype = css_computed_height(box->style, &value, &hunit);
1215
1216 if (wtype == CSS_WIDTH_SET &&
1217 wunit != CSS_UNIT_PCT &&
1218 htype == CSS_HEIGHT_SET &&
1219 hunit != CSS_UNIT_PCT) {
1220 /* We know the dimensions the image will be shown at
1221 * before it's fetched. */
1222 box->flags |= REPLACE_DIM;
1223 }
1224
1225 return ok;
1226}
1227
1228
1229/**
1230 * Form control [17.4].
1231 */
1232static bool
1233box_input(dom_node *n,
1235 struct box *box,
1236 bool *convert_children)
1237{
1238 struct form_control *gadget;
1239 dom_string *type = NULL;
1240 dom_exception err;
1241 nsurl *url;
1242 nserror error;
1243
1244 gadget = html_forms_get_control_for_node(content->forms, n);
1245 if (gadget == NULL) {
1246 return false;
1247 }
1248
1249 box->gadget = gadget;
1250 box->flags |= IS_REPLACED;
1251 gadget->box = box;
1252 gadget->html = content;
1253
1254 /* get entry type */
1255 err = dom_element_get_attribute(n, corestring_dom_type, &type);
1256 if ((err != DOM_NO_ERR) || (type == NULL)) {
1257 /* no type so "text" is assumed */
1258 if (box_input_text(content, box, n) == false) {
1259 return false;
1260 }
1261 *convert_children = false;
1262 return true;
1263 }
1264
1265 if (dom_string_caseless_lwc_isequal(type, corestring_lwc_password)) {
1266 if (box_input_text(content, box, n) == false)
1267 goto no_memory;
1268
1269 } else if (dom_string_caseless_lwc_isequal(type, corestring_lwc_file)) {
1271
1272 } else if (dom_string_caseless_lwc_isequal(type,
1273 corestring_lwc_hidden)) {
1274 /* no box for hidden inputs */
1275 box->type = BOX_NONE;
1276
1277 } else if ((dom_string_caseless_lwc_isequal(type,
1278 corestring_lwc_checkbox) ||
1279 dom_string_caseless_lwc_isequal(type,
1280 corestring_lwc_radio))) {
1281
1282 } else if (dom_string_caseless_lwc_isequal(type,
1283 corestring_lwc_submit) ||
1284 dom_string_caseless_lwc_isequal(type,
1285 corestring_lwc_reset) ||
1286 dom_string_caseless_lwc_isequal(type,
1287 corestring_lwc_button)) {
1288 struct box *inline_container, *inline_box;
1289
1290 if (box_button(n, content, box, 0) == false)
1291 goto no_memory;
1292
1293 inline_container = box_create(NULL, 0, false, 0, 0, 0, 0,
1294 content->bctx);
1295 if (inline_container == NULL)
1296 goto no_memory;
1297
1298 inline_container->type = BOX_INLINE_CONTAINER;
1299
1300 inline_box = box_create(NULL, box->style, false, 0, 0,
1301 box->title, 0, content->bctx);
1302 if (inline_box == NULL)
1303 goto no_memory;
1304
1305 inline_box->type = BOX_TEXT;
1306
1307 if (box->gadget->value != NULL)
1308 inline_box->text = talloc_strdup(content->bctx,
1309 box->gadget->value);
1310 else if (box->gadget->type == GADGET_SUBMIT)
1311 inline_box->text = talloc_strdup(content->bctx,
1312 messages_get("Form_Submit"));
1313 else if (box->gadget->type == GADGET_RESET)
1314 inline_box->text = talloc_strdup(content->bctx,
1315 messages_get("Form_Reset"));
1316 else
1317 inline_box->text = talloc_strdup(content->bctx,
1318 "Button");
1319
1320 if (inline_box->text == NULL)
1321 goto no_memory;
1322
1323 inline_box->length = strlen(inline_box->text);
1324
1325 box_add_child(inline_container, inline_box);
1326
1327 box_add_child(box, inline_container);
1328
1329 } else if (dom_string_caseless_lwc_isequal(type,
1330 corestring_lwc_image)) {
1332
1334 box_is_root(n)) != CSS_DISPLAY_NONE &&
1335 nsoption_bool(foreground_images) == true) {
1336 dom_string *s;
1337
1338 err = dom_element_get_attribute(n, corestring_dom_src, &s);
1339 if (err == DOM_NO_ERR && s != NULL) {
1340 error = nsurl_join(content->base_url,
1341 dom_string_data(s), &url);
1342 dom_string_unref(s);
1343 if (error != NSERROR_OK)
1344 goto no_memory;
1345
1346 /* if url is equivalent to the parent's url,
1347 * we've got infinite inclusion. stop it here
1348 */
1349 if (nsurl_compare(url, content->base_url,
1350 NSURL_COMPLETE) == false) {
1352 url,
1353 box,
1355 false)) {
1356 nsurl_unref(url);
1357 goto no_memory;
1358 }
1359 }
1360 nsurl_unref(url);
1361 }
1362 }
1363 } else {
1364 /* unhandled type the default is "text" */
1365 if (box_input_text(content, box, n) == false)
1366 goto no_memory;
1367 }
1368
1369 dom_string_unref(type);
1370
1371 *convert_children = false;
1372
1373 return true;
1374
1375no_memory:
1376 dom_string_unref(type);
1377
1378 return false;
1379}
1380
1381
1382/**
1383 * Noscript element
1384 */
1385static bool
1386box_noscript(dom_node *n,
1388 struct box *box,
1389 bool *convert_children)
1390{
1391 /* If scripting is enabled, do not display the contents of noscript */
1392 if (content->enable_scripting) {
1393 *convert_children = false;
1394 }
1395
1396 return true;
1397}
1398
1399
1400/**
1401 * Generic embedded object [13.3].
1402 */
1403static bool
1404box_object(dom_node *n,
1406 struct box *box,
1407 bool *convert_children)
1408{
1409 struct object_params *params;
1410 struct object_param *param;
1411 dom_string *codebase, *classid, *data;
1412 dom_node *c;
1413 dom_exception err;
1414
1416 box_is_root(n)) == CSS_DISPLAY_NONE)
1417 return true;
1418
1419 if (box_get_attribute(n, "usemap", content->bctx, &box->usemap) ==
1420 false)
1421 return false;
1422 if (box->usemap && box->usemap[0] == '#')
1423 box->usemap++;
1424
1425 params = talloc(content->bctx, struct object_params);
1426 if (params == NULL)
1427 return false;
1428
1430
1431 params->data = NULL;
1432 params->type = NULL;
1433 params->codetype = NULL;
1434 params->codebase = NULL;
1435 params->classid = NULL;
1436 params->params = NULL;
1437
1438 /* codebase, classid, and data are URLs
1439 * (codebase is the base for the other two) */
1440 err = dom_element_get_attribute(n, corestring_dom_codebase, &codebase);
1441 if (err == DOM_NO_ERR && codebase != NULL) {
1442 if (box_extract_link(content, codebase, content->base_url,
1443 &params->codebase) == false) {
1444 dom_string_unref(codebase);
1445 return false;
1446 }
1447 dom_string_unref(codebase);
1448 }
1449 if (params->codebase == NULL)
1450 params->codebase = nsurl_ref(content->base_url);
1451
1452 err = dom_element_get_attribute(n, corestring_dom_classid, &classid);
1453 if (err == DOM_NO_ERR && classid != NULL) {
1454 if (box_extract_link(content, classid,
1455 params->codebase, &params->classid) == false) {
1456 dom_string_unref(classid);
1457 return false;
1458 }
1459 dom_string_unref(classid);
1460 }
1461
1462 err = dom_element_get_attribute(n, corestring_dom_data, &data);
1463 if (err == DOM_NO_ERR && data != NULL) {
1464 if (box_extract_link(content, data,
1465 params->codebase, &params->data) == false) {
1466 dom_string_unref(data);
1467 return false;
1468 }
1469 dom_string_unref(data);
1470 }
1471
1472 if (params->classid == NULL && params->data == NULL)
1473 /* nothing to embed; ignore */
1474 return true;
1475
1476 /* Don't include ourself */
1477 if (params->classid != NULL && nsurl_compare(content->base_url,
1478 params->classid, NSURL_COMPLETE))
1479 return true;
1480
1481 if (params->data != NULL && nsurl_compare(content->base_url,
1482 params->data, NSURL_COMPLETE))
1483 return true;
1484
1485 /* codetype and type are MIME types */
1486 if (box_get_attribute(n, "codetype", params,
1487 &params->codetype) == false)
1488 return false;
1489 if (box_get_attribute(n, "type", params, &params->type) == false)
1490 return false;
1491
1492 /* classid && !data => classid is used (consult codetype)
1493 * (classid || !classid) && data => data is used (consult type)
1494 * !classid && !data => invalid; ignored */
1495
1496 if (params->classid != NULL && params->data == NULL &&
1497 params->codetype != NULL) {
1498 lwc_string *icodetype;
1499 lwc_error lerror;
1500
1501 lerror = lwc_intern_string(params->codetype,
1502 strlen(params->codetype), &icodetype);
1503 if (lerror != lwc_error_ok)
1504 return false;
1505
1506 if (content_factory_type_from_mime_type(icodetype) ==
1507 CONTENT_NONE) {
1508 /* can't handle this MIME type */
1509 lwc_string_unref(icodetype);
1510 return true;
1511 }
1512
1513 lwc_string_unref(icodetype);
1514 }
1515
1516 if (params->data != NULL && params->type != NULL) {
1517 lwc_string *itype;
1518 lwc_error lerror;
1519
1520 lerror = lwc_intern_string(params->type, strlen(params->type),
1521 &itype);
1522 if (lerror != lwc_error_ok)
1523 return false;
1524
1526 CONTENT_NONE) {
1527 /* can't handle this MIME type */
1528 lwc_string_unref(itype);
1529 return true;
1530 }
1531
1532 lwc_string_unref(itype);
1533 }
1534
1535 /* add parameters to linked list */
1536 err = dom_node_get_first_child(n, &c);
1537 if (err != DOM_NO_ERR)
1538 return false;
1539
1540 while (c != NULL) {
1541 dom_node *next;
1542 dom_node_type type;
1543
1544 err = dom_node_get_node_type(c, &type);
1545 if (err != DOM_NO_ERR) {
1546 dom_node_unref(c);
1547 return false;
1548 }
1549
1550 if (type == DOM_ELEMENT_NODE) {
1551 dom_string *name;
1552
1553 err = dom_node_get_node_name(c, &name);
1554 if (err != DOM_NO_ERR) {
1555 dom_node_unref(c);
1556 return false;
1557 }
1558
1559 if (!dom_string_caseless_lwc_isequal(name,
1560 corestring_lwc_param)) {
1561 /* The first non-param child is the start of
1562 * the alt html. Therefore, we should break
1563 * out of this loop. */
1564 dom_string_unref(name);
1565 dom_node_unref(c);
1566 break;
1567 }
1568 dom_string_unref(name);
1569
1570 param = talloc(params, struct object_param);
1571 if (param == NULL) {
1572 dom_node_unref(c);
1573 return false;
1574 }
1575 param->name = NULL;
1576 param->value = NULL;
1577 param->type = NULL;
1578 param->valuetype = NULL;
1579 param->next = NULL;
1580
1581 if (box_get_attribute(c, "name", param,
1582 &param->name) == false) {
1583 dom_node_unref(c);
1584 return false;
1585 }
1586
1587 if (box_get_attribute(c, "value", param,
1588 &param->value) == false) {
1589 dom_node_unref(c);
1590 return false;
1591 }
1592
1593 if (box_get_attribute(c, "type", param,
1594 &param->type) == false) {
1595 dom_node_unref(c);
1596 return false;
1597 }
1598
1599 if (box_get_attribute(c, "valuetype", param,
1600 &param->valuetype) == false) {
1601 dom_node_unref(c);
1602 return false;
1603 }
1604
1605 if (param->valuetype == NULL) {
1606 param->valuetype = talloc_strdup(param, "data");
1607 if (param->valuetype == NULL) {
1608 dom_node_unref(c);
1609 return false;
1610 }
1611 }
1612
1613 param->next = params->params;
1614 params->params = param;
1615 }
1616
1617 err = dom_node_get_next_sibling(c, &next);
1618 if (err != DOM_NO_ERR) {
1619 dom_node_unref(c);
1620 return false;
1621 }
1622
1623 dom_node_unref(c);
1624 c = next;
1625 }
1626
1627 box->object_params = params;
1628
1629 /* start fetch (MIME type is ok or not specified) */
1630 box->flags |= IS_REPLACED;
1632 params->data ? params->data : params->classid,
1633 box,
1635 false))
1636 return false;
1637
1638 *convert_children = false;
1639 return true;
1640}
1641
1642
1643/**
1644 * Preformatted text [9.3.4].
1645 */
1646static bool
1647box_pre(dom_node *n,
1649 struct box *box,
1650 bool *convert_children)
1651{
1652 box->flags |= PRE_STRIP;
1653 return true;
1654}
1655
1656
1657/**
1658 * Option selector [17.6].
1659 */
1660static bool
1661box_select(dom_node *n,
1663 struct box *box,
1664 bool *convert_children)
1665{
1666 struct box *inline_container;
1667 struct box *inline_box;
1668 struct form_control *gadget;
1669 dom_node *c, *c2;
1670 dom_node *next, *next2;
1671 dom_exception err;
1672
1673 gadget = html_forms_get_control_for_node(content->forms, n);
1674 if (gadget == NULL)
1675 return false;
1676
1677 gadget->html = content;
1678 err = dom_node_get_first_child(n, &c);
1679 if (err != DOM_NO_ERR) {
1680 form_free_control(gadget);
1681 return false;
1682 }
1683
1684 while (c != NULL) {
1685 dom_string *name;
1686
1687 err = dom_node_get_node_name(c, &name);
1688 if (err != DOM_NO_ERR) {
1689 dom_node_unref(c);
1690 form_free_control(gadget);
1691 return false;
1692 }
1693
1694 if (dom_string_caseless_lwc_isequal(name,
1695 corestring_lwc_option)) {
1696 dom_string_unref(name);
1697
1698 if (box_select_add_option(gadget, c) == false) {
1699 dom_node_unref(c);
1700 form_free_control(gadget);
1701 return false;
1702 }
1703 } else if (dom_string_caseless_lwc_isequal(name,
1704 corestring_lwc_optgroup)) {
1705 dom_string_unref(name);
1706
1707 err = dom_node_get_first_child(c, &c2);
1708 if (err != DOM_NO_ERR) {
1709 dom_node_unref(c);
1710 form_free_control(gadget);
1711 return false;
1712 }
1713
1714 while (c2 != NULL) {
1715 dom_string *c2_name;
1716
1717 err = dom_node_get_node_name(c2, &c2_name);
1718 if (err != DOM_NO_ERR) {
1719 dom_node_unref(c2);
1720 dom_node_unref(c);
1721 form_free_control(gadget);
1722 return false;
1723 }
1724
1725 if (dom_string_caseless_lwc_isequal(c2_name,
1726 corestring_lwc_option)) {
1727 dom_string_unref(c2_name);
1728
1729 if (box_select_add_option(gadget,
1730 c2) == false) {
1731 dom_node_unref(c2);
1732 dom_node_unref(c);
1733 form_free_control(gadget);
1734 return false;
1735 }
1736 } else {
1737 dom_string_unref(c2_name);
1738 }
1739
1740 err = dom_node_get_next_sibling(c2, &next2);
1741 if (err != DOM_NO_ERR) {
1742 dom_node_unref(c2);
1743 dom_node_unref(c);
1744 form_free_control(gadget);
1745 return false;
1746 }
1747
1748 dom_node_unref(c2);
1749 c2 = next2;
1750 }
1751 } else {
1752 dom_string_unref(name);
1753 }
1754
1755 err = dom_node_get_next_sibling(c, &next);
1756 if (err != DOM_NO_ERR) {
1757 dom_node_unref(c);
1758 form_free_control(gadget);
1759 return false;
1760 }
1761
1762 dom_node_unref(c);
1763 c = next;
1764 }
1765
1766 if (gadget->data.select.num_items == 0) {
1767 /* no options: ignore entire select */
1768 form_free_control(gadget);
1769 return true;
1770 }
1771
1773 box->gadget = gadget;
1774 box->flags |= IS_REPLACED;
1775 gadget->box = box;
1776
1777 inline_container = box_create(NULL, 0, false, 0, 0, 0, 0, content->bctx);
1778 if (inline_container == NULL)
1779 goto no_memory;
1780 inline_container->type = BOX_INLINE_CONTAINER;
1781 inline_box = box_create(NULL, box->style, false, 0, 0, box->title, 0,
1782 content->bctx);
1783 if (inline_box == NULL)
1784 goto no_memory;
1785 inline_box->type = BOX_TEXT;
1786 box_add_child(inline_container, inline_box);
1787 box_add_child(box, inline_container);
1788
1789 if (gadget->data.select.multiple == false &&
1790 gadget->data.select.num_selected == 0) {
1791 gadget->data.select.current = gadget->data.select.items;
1792 gadget->data.select.current->initial_selected =
1793 gadget->data.select.current->selected = true;
1794 gadget->data.select.num_selected = 1;
1795 dom_html_option_element_set_selected(
1796 gadget->data.select.current->node, true);
1797 }
1798
1799 if (gadget->data.select.num_selected == 0)
1800 inline_box->text = talloc_strdup(content->bctx,
1801 messages_get("Form_None"));
1802 else if (gadget->data.select.num_selected == 1)
1803 inline_box->text = talloc_strdup(content->bctx,
1804 gadget->data.select.current->text);
1805 else
1806 inline_box->text = talloc_strdup(content->bctx,
1807 messages_get("Form_Many"));
1808 if (inline_box->text == NULL)
1809 goto no_memory;
1810
1811 inline_box->length = strlen(inline_box->text);
1812
1813 *convert_children = false;
1814 return true;
1815
1816no_memory:
1817 return false;
1818}
1819
1820
1821/**
1822 * Multi-line text field [17.7].
1823 */
1824static bool box_textarea(dom_node *n,
1826 struct box *box,
1827 bool *convert_children)
1828{
1829 /* Get the form_control for the DOM node */
1831 if (box->gadget == NULL)
1832 return false;
1833
1834 box->flags |= IS_REPLACED;
1835 box->gadget->html = content;
1836 box->gadget->box = box;
1837
1838 if (!box_input_text(content, box, n))
1839 return false;
1840
1841 *convert_children = false;
1842 return true;
1843}
1844
1845
1846/**
1847 * \}
1848 */
1849
1850
1851/* exported interface documented in html/box_special.h */
1852bool
1855 struct box *box,
1856 bool *convert_children)
1857{
1858 dom_exception exc;
1859 dom_html_element_type tag_type;
1860 bool res;
1861
1862 exc = dom_html_element_get_tag_type(node, &tag_type);
1863 if (exc != DOM_NO_ERR) {
1864 tag_type = DOM_HTML_ELEMENT_TYPE__UNKNOWN;
1865 }
1866
1867 switch (tag_type) {
1868 case DOM_HTML_ELEMENT_TYPE_A:
1869 res = box_a(node, content, box, convert_children);
1870 break;
1871
1872 case DOM_HTML_ELEMENT_TYPE_BODY:
1873 res = box_body(node, content, box, convert_children);
1874 break;
1875
1876 case DOM_HTML_ELEMENT_TYPE_BR:
1877 res = box_br(node, content, box, convert_children);
1878 break;
1879
1880 case DOM_HTML_ELEMENT_TYPE_BUTTON:
1881 res = box_button(node, content, box, convert_children);
1882 break;
1883
1884 case DOM_HTML_ELEMENT_TYPE_CANVAS:
1885 res = box_canvas(node, content, box, convert_children);
1886 break;
1887
1888 case DOM_HTML_ELEMENT_TYPE_EMBED:
1889 res = box_embed(node, content, box, convert_children);
1890 break;
1891
1892 case DOM_HTML_ELEMENT_TYPE_FRAMESET:
1893 res = box_frameset(node, content, box, convert_children);
1894 break;
1895
1896 case DOM_HTML_ELEMENT_TYPE_IFRAME:
1897 res = box_iframe(node, content, box, convert_children);
1898 break;
1899
1900 case DOM_HTML_ELEMENT_TYPE_IMG:
1901 res = box_image(node, content, box, convert_children);
1902 break;
1903
1904 case DOM_HTML_ELEMENT_TYPE_INPUT:
1905 res = box_input(node, content, box, convert_children);
1906 break;
1907
1908 case DOM_HTML_ELEMENT_TYPE_NOSCRIPT:
1909 res = box_noscript(node, content, box, convert_children);
1910 break;
1911
1912 case DOM_HTML_ELEMENT_TYPE_OBJECT:
1913 res = box_object(node, content, box, convert_children);
1914 break;
1915
1916 case DOM_HTML_ELEMENT_TYPE_PRE:
1917 res = box_pre(node, content, box, convert_children);
1918 break;
1919
1920 case DOM_HTML_ELEMENT_TYPE_SELECT:
1921 res = box_select(node, content, box, convert_children);
1922 break;
1923
1924 case DOM_HTML_ELEMENT_TYPE_TEXTAREA:
1925 res = box_textarea(node, content, box, convert_children);
1926 break;
1927
1928 default:
1929 res = true;
1930 }
1931
1932 return res;
1933}
STATIC char result[100]
Definition: arexx.c:77
Helpers for ASCII string handling.
static bool ascii_is_space(char c)
Test whether a character is a whitespace character.
Definition: ascii.h:40
Box interface.
@ BOX_BLOCK
Definition: box.h:56
@ BOX_INLINE_BLOCK
Definition: box.h:65
@ BOX_INLINE_CONTAINER
Definition: box.h:57
@ BOX_TEXT
Definition: box.h:67
@ BOX_BR
Definition: box.h:66
@ BOX_NONE
Definition: box.h:69
@ IFRAME
Definition: box.h:89
@ IS_REPLACED
Definition: box.h:91
@ PRE_STRIP
Definition: box.h:82
@ REPLACE_DIM
Definition: box.h:88
bool box_extract_link(const html_content *content, const dom_string *dsrel, nsurl *base, nsurl **result)
HTML Box tree construction interface.
struct box * box_create(css_select_results *styles, css_computed_style *style, bool style_owned, nsurl *href, const char *target, const char *title, lwc_string *id, void *context)
Create a box tree node.
void box_add_child(struct box *parent, struct box *child)
Add a child to a box tree node.
Box tree manipulation interface.
static struct frame_dimension * box_parse_multi_lengths(const dom_string *ds, unsigned int *count)
Parse a multi-length-list, as defined by HTML 4.01.
Definition: box_special.c:119
static bool box_embed(dom_node *n, html_content *content, struct box *box, bool *convert_children)
Embedded object (not in any HTML specification: see http://wp.netscape.com/assist/net_sites/new_html3...
Definition: box_special.c:852
static bool box_textarea(dom_node *n, html_content *content, struct box *box, bool *convert_children)
Multi-line text field [17.7].
Definition: box_special.c:1824
static bool box_canvas(dom_node *n, html_content *content, struct box *box, bool *convert_children)
Canvas element.
Definition: box_special.c:825
static bool box_button(dom_node *n, html_content *content, struct box *box, bool *convert_children)
special element handler for Push button [17.5].
Definition: box_special.c:797
static bool box_noscript(dom_node *n, html_content *content, struct box *box, bool *convert_children)
Noscript element.
Definition: box_special.c:1386
static bool box_a(dom_node *n, html_content *content, struct box *box, bool *convert_children)
special element handler for Anchor [12.2].
Definition: box_special.c:683
bool convert_special_elements(dom_node *node, html_content *content, struct box *box, bool *convert_children)
call an elements special conversion handler
Definition: box_special.c:1853
static int box_iframes_talloc_destructor(struct content_html_iframe *f)
Destructor for content_html_iframe, for <iframe> elements.
Definition: box_special.c:492
static bool box_iframe(dom_node *n, html_content *content, struct box *box, bool *convert_children)
Inline subwindow [16.5].
Definition: box_special.c:1025
static bool box_input_text(html_content *html, struct box *box, struct dom_node *node)
Helper function for adding textarea widget to box.
Definition: box_special.c:560
static bool box_select_add_option(struct form_control *control, dom_node *n)
Add an option to a form select control (helper function for box_select()).
Definition: box_special.c:601
static int box_object_talloc_destructor(struct object_params *o)
Destructor for object_params, for <object> elements.
Definition: box_special.c:98
static int box_frames_talloc_destructor(struct content_html_frames *f)
Destructor for content_html_frames, for frame elements.
Definition: box_special.c:175
static bool box_br(dom_node *n, html_content *content, struct box *box, bool *convert_children)
special element handler for forced line break [9.3.2].
Definition: box_special.c:783
static bool box_object(dom_node *n, html_content *content, struct box *box, bool *convert_children)
Generic embedded object [13.3].
Definition: box_special.c:1404
static bool box_frameset(dom_node *n, html_content *content, struct box *box, bool *convert_children)
Window subdivision [16.2.1].
Definition: box_special.c:986
static bool box_get_attribute(dom_node *n, const char *attribute, void *context, char **value)
Get the value of a dom node element's attribute.
Definition: box_special.c:516
static bool box_is_root(dom_node *n)
determine if a box is the root node
Definition: box_special.c:66
static bool box_select(dom_node *n, html_content *content, struct box *box, bool *convert_children)
Option selector [17.6].
Definition: box_special.c:1661
static bool box_create_frameset(struct content_html_frames *f, dom_node *n, html_content *content)
create a frameset box tree
Definition: box_special.c:190
static bool box_pre(dom_node *n, html_content *content, struct box *box, bool *convert_children)
Preformatted text [9.3.4].
Definition: box_special.c:1647
static bool box_image(dom_node *n, html_content *content, struct box *box, bool *convert_children)
Embedded image [13.2].
Definition: box_special.c:1150
static bool box_body(dom_node *n, html_content *content, struct box *box, bool *convert_children)
Document body special element handler [7.5.1].
Definition: box_special.c:761
static const content_type image_types
Definition: box_special.c:57
static bool box_input(dom_node *n, html_content *content, struct box *box, bool *convert_children)
Form control [17.4].
Definition: box_special.c:1233
HTML Box tree construction special element conversion interface.
bool box_textarea_create_textarea(html_content *html, struct box *box, struct dom_node *node)
Create textarea widget for a form element.
Definition: box_textarea.c:257
Box tree treeview box replacement (interface).
@ BW_SCROLLING_AUTO
@ BW_SCROLLING_NO
@ BW_SCROLLING_YES
static uint32_t count(const http_directive *list, lwc_string *key)
static uint8_t ns_computed_display(const css_computed_style *style, bool root)
Temporary helper wrappers for for libcss computed style getter, while we don't support all values of ...
Definition: utils.h:33
bool html_fetch_object(html_content *c, nsurl *url, struct box *box, content_type permitted_types, bool background)
Start a fetch for an object required by a page.
Definition: object.c:710
HTML content object interface.
content_type content_factory_type_from_mime_type(lwc_string *mime_type)
Compute the generic content type for a MIME type.
content_type
The type of a content.
Definition: content_type.h:53
@ CONTENT_IMAGE
All images.
Definition: content_type.h:67
@ CONTENT_NONE
no type for content
Definition: content_type.h:55
@ CONTENT_ANY
Any content matches.
Definition: content_type.h:82
Useful interned string pointers (interface).
wimp_w parent
Definition: dialog.c:88
nserror
Enumeration of error codes.
Definition: errors.h:29
@ NSERROR_OK
No error.
Definition: errors.h:30
const char * type
Definition: filetype.cpp:44
bool form_add_option(struct form_control *control, char *value, char *text, bool selected, void *node)
Add an option to a form select control.
Definition: form.c:1529
void form_free_control(struct form_control *control)
Free a struct form_control.
Definition: form.c:1455
Interface to form handling functions internal to HTML content handler.
@ GADGET_SUBMIT
Definition: form_internal.h:56
@ GADGET_RESET
Definition: form_internal.h:57
@ GADGET_IMAGE
Definition: form_internal.h:54
struct form_control * html_forms_get_control_for_node(struct form *forms, dom_node *node)
Definition: forms.c:545
Interface to browser frames.
bool nscss_parse_colour(const char *data, css_color *result)
Parser for colours specified in attribute values.
Definition: hints.c:449
Interface to text/html content handler.
#define nscss_color_is_transparent(color)
Determine if a CSS color primitive is transparent.
Definition: css.h:62
#define nscss_color_to_ns(c)
Convert a CSS color to a NetSurf colour primitive.
Definition: css.h:35
#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).
NetSurf URL handling (interface).
bool nsurl_compare(const nsurl *url1, const nsurl *url2, nsurl_component parts)
Compare two URLs.
void nsurl_unref(nsurl *url)
Drop a reference to a NetSurf URL object.
nsurl * nsurl_ref(nsurl *url)
Increment the reference count to a NetSurf URL object.
@ NSURL_COMPLETE
Definition: nsurl.h:54
nserror nsurl_join(const nsurl *base, const char *rel, nsurl **joined)
Join a base url to a relative link part, creating a new NetSurf URL object.
struct nsurl nsurl
NetSurf URL object.
Definition: nsurl.h:31
plotter style interfaces, generic styles and style colour helpers.
#define NS_TRANSPARENT
Transparent colour value.
Definition: plot_style.h:39
Private data for text/html content.
Interface to utility string handling.
char * cnv_space2nbsp(const char *s)
Converts NUL terminated UTF-8 encoded string s containing zero or more spaces (char 32) or TABs (char...
Definition: utils.c:67
char * squash_whitespace(const char *s)
Replace consecutive whitespace with a single space.
Definition: utils.c:38
Node in box tree.
Definition: box.h:177
lwc_string * id
value of id attribute (or name for anchors)
Definition: box.h:210
const char * title
Title, or NULL.
Definition: box.h:386
char * usemap
(Image)map to use with this object, or NULL if none
Definition: box.h:429
const char * target
Link target, or NULL.
Definition: box.h:381
box_type type
Type of box.
Definition: box.h:181
struct nsurl * href
Link, or NULL.
Definition: box.h:376
css_computed_style * style
Style for this box.
Definition: box.h:205
size_t length
Length of text.
Definition: box.h:360
struct object_params * object_params
Parameters for the object, or NULL.
Definition: box.h:446
char * text
Text, or NULL if none.
Definition: box.h:355
box_flags flags
Box flags.
Definition: box.h:186
struct form_control * gadget
Form control data, or NULL if not a form control.
Definition: box.h:423
struct dom_node * node
DOM node that generated this box or NULL.
Definition: box.h:191
Frame tree (frameset or frame tag)
Definition: html.h:108
char * name
frame margin height
Definition: html.h:117
int rows
number of columns in frameset
Definition: html.h:110
struct content_html_frames * children
frame border colour
Definition: html.h:125
bool no_resize
frame url
Definition: html.h:120
int margin_width
frame width
Definition: html.h:114
struct nsurl * url
frame name (for targetting)
Definition: html.h:118
browser_scrolling scrolling
frame is not resizable
Definition: html.h:121
bool border
scrolling characteristics
Definition: html.h:122
colour border_colour
frame has a border
Definition: html.h:123
int margin_height
frame margin width
Definition: html.h:115
struct frame_dimension width
number of rows in frameset
Definition: html.h:112
struct frame_dimension height
frame width
Definition: html.h:113
Inline frame list (iframe tag)
Definition: html.h:131
struct content_html_iframe * next
frame border colour
Definition: html.h:144
struct box * box
Definition: html.h:132
int margin_height
frame margin width
Definition: html.h:135
browser_scrolling scrolling
frame url
Definition: html.h:140
struct nsurl * url
frame name (for targetting)
Definition: html.h:138
colour border_colour
frame has a border
Definition: html.h:142
bool border
scrolling characteristics
Definition: html.h:141
char * name
frame margin height
Definition: html.h:137
Content which corresponds to a single URL.
Form control.
Definition: form_internal.h:73
struct form_textarea_data data
form_control_type type
Type of control.
Definition: form_internal.h:79
void * node
Corresponding DOM node.
Definition: form_internal.h:74
char * name
Control name.
Definition: form_internal.h:83
struct form_control * next
Next control in this form.
struct html_content * html
HTML content containing control.
Definition: form_internal.h:77
char * value
Current value of control.
Definition: form_internal.h:84
struct box * box
Box for control.
Definition: form_internal.h:89
enum frame_dimension::@63 unit
@ FRAME_DIMENSION_RELATIVE
Definition: frame_types.h:32
Data specific to CONTENT_HTML.
Definition: private.h:93
int * bctx
A talloc context purely for the render box tree.
Definition: private.h:134
Linked list of object element parameters.
Definition: box.h:152
char * value
Definition: box.h:154
struct object_param * next
Definition: box.h:157
char * name
Definition: box.h:153
char * valuetype
Definition: box.h:156
char * type
Definition: box.h:155
Parameters for object element and similar elements.
Definition: box.h:164
struct nsurl * data
Definition: box.h:165
char * codetype
Definition: box.h:167
struct nsurl * classid
Definition: box.h:169
struct nsurl * codebase
Definition: box.h:168
char * type
Definition: box.h:166
struct object_param * params
Definition: box.h:170
char * talloc_strdup(const void *t, const char *p)
Definition: talloc.c:1118
#define talloc_array(ctx, type, count)
Definition: talloc.h:95
#define talloc_set_destructor(ptr, function)
Definition: talloc.h:75
#define talloc_zero(ctx, type)
Definition: talloc.h:91
#define talloc(ctx, type)
Definition: talloc.h:85
uint32_t colour
Colour type: XBGR.
Definition: types.h:35
Option reading and saving interface.
#define nsoption_bool(OPTION)
Get the value of a boolean option.
Definition: nsoption.h:308
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