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 if (box->id != NULL)
719 lwc_string_unref(box->id);
720
721 box->id = lwc_name;
722 }
723 }
724
725 /* target frame [16.3] */
726 err = dom_element_get_attribute(n, corestring_dom_target, &s);
727 if (err == DOM_NO_ERR && s != NULL) {
728 if (dom_string_caseless_lwc_isequal(s,
729 corestring_lwc__blank))
730 box->target = "_blank";
731 else if (dom_string_caseless_lwc_isequal(s,
732 corestring_lwc__top))
733 box->target = "_top";
734 else if (dom_string_caseless_lwc_isequal(s,
735 corestring_lwc__parent))
736 box->target = "_parent";
737 else if (dom_string_caseless_lwc_isequal(s,
738 corestring_lwc__self))
739 /* the default may have been overridden by a
740 * <base target=...>, so this is different to 0 */
741 box->target = "_self";
742 else {
743 /* 6.16 says that frame names must begin with [a-zA-Z]
744 * This doesn't match reality, so just take anything */
746 dom_string_data(s));
747 if (!box->target) {
748 dom_string_unref(s);
749 return false;
750 }
751 }
752 dom_string_unref(s);
753 }
754
755 return true;
756}
757
758
759/**
760 * Document body special element handler [7.5.1].
761 */
762static bool
763box_body(dom_node *n,
765 struct box *box,
766 bool *convert_children)
767{
768 css_color color;
769
770 css_computed_background_color(box->style, &color);
771 if (nscss_color_is_transparent(color)) {
772 content->background_colour = NS_TRANSPARENT;
773 } else {
774 content->background_colour = nscss_color_to_ns(color);
775 }
776
777 return true;
778}
779
780
781/**
782 * special element handler for forced line break [9.3.2].
783 */
784static bool
785box_br(dom_node *n,
787 struct box *box,
788 bool *convert_children)
789{
790 box->type = BOX_BR;
791 return true;
792}
793
794
795/**
796 * special element handler for Push button [17.5].
797 */
798static bool
799box_button(dom_node *n,
801 struct box *box,
802 bool *convert_children)
803{
804 struct form_control *gadget;
805
806 gadget = html_forms_get_control_for_node(content->forms, n);
807 if (!gadget)
808 return false;
809
810 gadget->html = content;
811 box->gadget = gadget;
813 gadget->box = box;
814
816
817 /* Just render the contents */
818
819 return true;
820}
821
822
823/**
824 * Canvas element
825 */
826static bool
827box_canvas(dom_node *n,
829 struct box *box,
830 bool *convert_children)
831{
832 /* If scripting is not enabled display the contents of canvas */
833 if (!content->enable_scripting) {
834 return true;
835 }
836 *convert_children = false;
837
839 box_is_root(n)) == CSS_DISPLAY_NONE)
840 return true;
841
842 /* This is replaced content */
844
845 return true;
846}
847
848
849/**
850 * Embedded object (not in any HTML specification:
851 * see http://wp.netscape.com/assist/net_sites/new_html3_prop.html )
852 */
853static bool
854box_embed(dom_node *n,
856 struct box *box,
857 bool *convert_children)
858{
859 struct object_params *params;
860 struct object_param *param;
861 dom_namednodemap *attrs;
862 unsigned long idx;
863 uint32_t num_attrs;
864 dom_string *src;
865 dom_exception err;
866
868 box_is_root(n)) == CSS_DISPLAY_NONE)
869 return true;
870
871 params = talloc(content->bctx, struct object_params);
872 if (params == NULL)
873 return false;
874
876
877 params->data = NULL;
878 params->type = NULL;
879 params->codetype = NULL;
880 params->codebase = NULL;
881 params->classid = NULL;
882 params->params = NULL;
883
884 /* src is a URL */
885 err = dom_element_get_attribute(n, corestring_dom_src, &src);
886 if (err != DOM_NO_ERR || src == NULL)
887 return true;
888 if (box_extract_link(content, src, content->base_url,
889 &params->data) == false) {
890 dom_string_unref(src);
891 return false;
892 }
893
894 dom_string_unref(src);
895
896 if (params->data == NULL)
897 return true;
898
899 /* Don't include ourself */
900 if (nsurl_compare(content->base_url, params->data, NSURL_COMPLETE))
901 return true;
902
903 /* add attributes as parameters to linked list */
904 err = dom_node_get_attributes(n, &attrs);
905 if (err != DOM_NO_ERR)
906 return false;
907
908 err = dom_namednodemap_get_length(attrs, &num_attrs);
909 if (err != DOM_NO_ERR) {
910 dom_namednodemap_unref(attrs);
911 return false;
912 }
913
914 for (idx = 0; idx < num_attrs; idx++) {
915 dom_attr *attr;
916 dom_string *name, *value;
917
918 err = dom_namednodemap_item(attrs, idx, (void *) &attr);
919 if (err != DOM_NO_ERR) {
920 dom_namednodemap_unref(attrs);
921 return false;
922 }
923
924 err = dom_attr_get_name(attr, &name);
925 if (err != DOM_NO_ERR) {
926 dom_node_unref(attr);
927 dom_namednodemap_unref(attrs);
928 return false;
929 }
930
931 if (dom_string_caseless_lwc_isequal(name, corestring_lwc_src)) {
932 dom_node_unref(attr);
933 dom_string_unref(name);
934 continue;
935 }
936
937 err = dom_attr_get_value(attr, &value);
938 if (err != DOM_NO_ERR) {
939 dom_node_unref(attr);
940 dom_string_unref(name);
941 dom_namednodemap_unref(attrs);
942 return false;
943 }
944
945 param = talloc(content->bctx, struct object_param);
946 if (param == NULL) {
947 dom_node_unref(attr);
948 dom_string_unref(value);
949 dom_string_unref(name);
950 dom_namednodemap_unref(attrs);
951 return false;
952 }
953
954 param->name = talloc_strdup(content->bctx, dom_string_data(name));
955 param->value = talloc_strdup(content->bctx, dom_string_data(value));
956 param->type = NULL;
957 param->valuetype = talloc_strdup(content->bctx, "data");
958 param->next = NULL;
959
960 dom_string_unref(value);
961 dom_string_unref(name);
962 dom_node_unref(attr);
963
964 if (param->name == NULL || param->value == NULL ||
965 param->valuetype == NULL) {
966 dom_namednodemap_unref(attrs);
967 return false;
968 }
969
970 param->next = params->params;
971 params->params = param;
972 }
973
974 dom_namednodemap_unref(attrs);
975
976 box->object_params = params;
977
978 /* start fetch */
980 return html_fetch_object(content, params->data, box, CONTENT_ANY, false);
981}
982
983
984/**
985 * Window subdivision [16.2.1].
986 */
987static bool
988box_frameset(dom_node *n,
990 struct box *box,
991 bool *convert_children)
992{
993 bool ok;
994
995 if (content->frameset) {
996 NSLOG(netsurf, INFO, "Error: multiple framesets in document.");
997 /* Don't convert children */
998 if (convert_children)
999 *convert_children = false;
1000 /* And ignore this spurious frameset */
1001 box->type = BOX_NONE;
1002 return true;
1003 }
1004
1005 content->frameset = talloc_zero(content->bctx,
1006 struct content_html_frames);
1007 if (!content->frameset) {
1008 return false;
1009 }
1010
1011 ok = box_create_frameset(content->frameset, n, content);
1012 if (ok) {
1013 box->type = BOX_NONE;
1014 }
1015
1016 if (convert_children) {
1017 *convert_children = false;
1018 }
1019 return ok;
1020}
1021
1022
1023/**
1024 * Inline subwindow [16.5].
1025 */
1026static bool
1027box_iframe(dom_node *n,
1029 struct box *box,
1030 bool *convert_children)
1031{
1032 nsurl *url;
1033 dom_string *s;
1034 dom_exception err;
1035 struct content_html_iframe *iframe;
1036 int i;
1037
1039 box_is_root(n)) == CSS_DISPLAY_NONE)
1040 return true;
1041
1042 if (box->style &&
1043 css_computed_visibility(box->style) == CSS_VISIBILITY_HIDDEN) {
1044 /* Don't create iframe discriptors for invisible iframes
1045 * TODO: handle hidden iframes at browser_window generation
1046 * time instead? */
1047 return true;
1048 }
1049
1050 /* get frame URL */
1051 err = dom_element_get_attribute(n, corestring_dom_src, &s);
1052 if (err != DOM_NO_ERR || s == NULL)
1053 return true;
1054 if (box_extract_link(content, s, content->base_url, &url) == false) {
1055 dom_string_unref(s);
1056 return false;
1057 }
1058 dom_string_unref(s);
1059 if (url == NULL)
1060 return true;
1061
1062 /* don't include ourself */
1063 if (nsurl_compare(content->base_url, url, NSURL_COMPLETE)) {
1065 return true;
1066 }
1067
1068 /* create a new iframe */
1069 iframe = talloc(content->bctx, struct content_html_iframe);
1070 if (iframe == NULL) {
1072 return false;
1073 }
1074
1076
1077 iframe->box = box;
1078 iframe->margin_width = 0;
1079 iframe->margin_height = 0;
1080 iframe->name = NULL;
1081 iframe->url = url;
1082 iframe->scrolling = BW_SCROLLING_AUTO;
1083 iframe->border = true;
1084
1085 /* Add this iframe to the linked list of iframes */
1086 iframe->next = content->iframe;
1087 content->iframe = iframe;
1088
1089 /* fill in specified values */
1090 err = dom_element_get_attribute(n, corestring_dom_name, &s);
1091 if (err == DOM_NO_ERR && s != NULL) {
1092 iframe->name = talloc_strdup(content->bctx, dom_string_data(s));
1093 dom_string_unref(s);
1094 }
1095
1096 err = dom_element_get_attribute(n, corestring_dom_frameborder, &s);
1097 if (err == DOM_NO_ERR && s != NULL) {
1098 i = atoi(dom_string_data(s));
1099 iframe->border = (i != 0);
1100 dom_string_unref(s);
1101 }
1102
1103 err = dom_element_get_attribute(n, corestring_dom_bordercolor, &s);
1104 if (err == DOM_NO_ERR && s != NULL) {
1105 css_color color;
1106
1107 if (nscss_parse_colour(dom_string_data(s), &color))
1108 iframe->border_colour = nscss_color_to_ns(color);
1109
1110 dom_string_unref(s);
1111 }
1112
1113 err = dom_element_get_attribute(n, corestring_dom_scrolling, &s);
1114 if (err == DOM_NO_ERR && s != NULL) {
1115 if (dom_string_caseless_lwc_isequal(s,
1116 corestring_lwc_yes))
1117 iframe->scrolling = BW_SCROLLING_YES;
1118 else if (dom_string_caseless_lwc_isequal(s,
1119 corestring_lwc_no))
1120 iframe->scrolling = BW_SCROLLING_NO;
1121 dom_string_unref(s);
1122 }
1123
1124 err = dom_element_get_attribute(n, corestring_dom_marginwidth, &s);
1125 if (err == DOM_NO_ERR && s != NULL) {
1126 iframe->margin_width = atoi(dom_string_data(s));
1127 dom_string_unref(s);
1128 }
1129
1130 err = dom_element_get_attribute(n, corestring_dom_marginheight, &s);
1131 if (err == DOM_NO_ERR && s != NULL) {
1132 iframe->margin_height = atoi(dom_string_data(s));
1133 dom_string_unref(s);
1134 }
1135
1136 /* box */
1137 assert(box->style);
1138 box->flags |= IFRAME;
1139 box->flags |= IS_REPLACED;
1140
1141 /* Showing iframe, so don't show alternate content */
1142 if (convert_children)
1143 *convert_children = false;
1144 return true;
1145}
1146
1147
1148/**
1149 * Embedded image [13.2].
1150 */
1151static bool
1152box_image(dom_node *n,
1154 struct box *box,
1155 bool *convert_children)
1156{
1157 bool ok;
1158 dom_string *s;
1159 dom_exception err;
1160 nsurl *url;
1161 enum css_width_e wtype;
1162 enum css_height_e htype;
1163 css_fixed value = 0;
1164 css_unit wunit = CSS_UNIT_PX;
1165 css_unit hunit = CSS_UNIT_PX;
1166
1168 box_is_root(n)) == CSS_DISPLAY_NONE)
1169 return true;
1170
1171 /* handle alt text */
1172 err = dom_element_get_attribute(n, corestring_dom_alt, &s);
1173 if (err == DOM_NO_ERR && s != NULL) {
1174 char *alt = squash_whitespace(dom_string_data(s));
1175 dom_string_unref(s);
1176 if (alt == NULL)
1177 return false;
1178 box->text = talloc_strdup(content->bctx, alt);
1179 free(alt);
1180 if (box->text == NULL)
1181 return false;
1182 box->length = strlen(box->text);
1183 }
1184
1185 if (nsoption_bool(foreground_images) == false) {
1186 return true;
1187 }
1188
1189 /* imagemap associated with this image */
1190 if (!box_get_attribute(n, "usemap", content->bctx, &box->usemap))
1191 return false;
1192 if (box->usemap && box->usemap[0] == '#')
1193 box->usemap++;
1194
1195 /* get image URL */
1196 err = dom_element_get_attribute(n, corestring_dom_src, &s);
1197 if (err != DOM_NO_ERR || s == NULL)
1198 return true;
1199
1200 if (box_extract_link(content, s, content->base_url, &url) == false) {
1201 dom_string_unref(s);
1202 return false;
1203 }
1204
1205 dom_string_unref(s);
1206
1207 if (url == NULL)
1208 return true;
1209
1210 /* start fetch */
1211 box->flags |= IS_REPLACED;
1214
1215 wtype = css_computed_width(box->style, &value, &wunit);
1216 htype = css_computed_height(box->style, &value, &hunit);
1217
1218 if (wtype == CSS_WIDTH_SET &&
1219 wunit != CSS_UNIT_PCT &&
1220 htype == CSS_HEIGHT_SET &&
1221 hunit != CSS_UNIT_PCT) {
1222 /* We know the dimensions the image will be shown at
1223 * before it's fetched. */
1224 box->flags |= REPLACE_DIM;
1225 }
1226
1227 return ok;
1228}
1229
1230
1231/**
1232 * Form control [17.4].
1233 */
1234static bool
1235box_input(dom_node *n,
1237 struct box *box,
1238 bool *convert_children)
1239{
1240 struct form_control *gadget;
1241 dom_string *type = NULL;
1242 dom_exception err;
1243 nsurl *url;
1244 nserror error;
1245
1246 gadget = html_forms_get_control_for_node(content->forms, n);
1247 if (gadget == NULL) {
1248 return false;
1249 }
1250
1251 box->gadget = gadget;
1252 box->flags |= IS_REPLACED;
1253 gadget->box = box;
1254 gadget->html = content;
1255
1256 /* get entry type */
1257 err = dom_element_get_attribute(n, corestring_dom_type, &type);
1258 if ((err != DOM_NO_ERR) || (type == NULL)) {
1259 /* no type so "text" is assumed */
1260 if (box_input_text(content, box, n) == false) {
1261 return false;
1262 }
1263 *convert_children = false;
1264 return true;
1265 }
1266
1267 if (dom_string_caseless_lwc_isequal(type, corestring_lwc_password)) {
1268 if (box_input_text(content, box, n) == false)
1269 goto no_memory;
1270
1271 } else if (dom_string_caseless_lwc_isequal(type, corestring_lwc_file)) {
1273
1274 } else if (dom_string_caseless_lwc_isequal(type,
1275 corestring_lwc_hidden)) {
1276 /* no box for hidden inputs */
1277 box->type = BOX_NONE;
1278
1279 } else if ((dom_string_caseless_lwc_isequal(type,
1280 corestring_lwc_checkbox) ||
1281 dom_string_caseless_lwc_isequal(type,
1282 corestring_lwc_radio))) {
1283
1284 } else if (dom_string_caseless_lwc_isequal(type,
1285 corestring_lwc_submit) ||
1286 dom_string_caseless_lwc_isequal(type,
1287 corestring_lwc_reset) ||
1288 dom_string_caseless_lwc_isequal(type,
1289 corestring_lwc_button)) {
1290 struct box *inline_container, *inline_box;
1291
1292 if (box_button(n, content, box, 0) == false)
1293 goto no_memory;
1294
1295 inline_container = box_create(NULL, 0, false, 0, 0, 0, 0,
1296 content->bctx);
1297 if (inline_container == NULL)
1298 goto no_memory;
1299
1300 inline_container->type = BOX_INLINE_CONTAINER;
1301
1302 inline_box = box_create(NULL, box->style, false, 0, 0,
1303 box->title, 0, content->bctx);
1304 if (inline_box == NULL)
1305 goto no_memory;
1306
1307 inline_box->type = BOX_TEXT;
1308
1309 if (box->gadget->value != NULL)
1310 inline_box->text = talloc_strdup(content->bctx,
1311 box->gadget->value);
1312 else if (box->gadget->type == GADGET_SUBMIT)
1313 inline_box->text = talloc_strdup(content->bctx,
1314 messages_get("Form_Submit"));
1315 else if (box->gadget->type == GADGET_RESET)
1316 inline_box->text = talloc_strdup(content->bctx,
1317 messages_get("Form_Reset"));
1318 else
1319 inline_box->text = talloc_strdup(content->bctx,
1320 "Button");
1321
1322 if (inline_box->text == NULL)
1323 goto no_memory;
1324
1325 inline_box->length = strlen(inline_box->text);
1326
1327 box_add_child(inline_container, inline_box);
1328
1329 box_add_child(box, inline_container);
1330
1331 } else if (dom_string_caseless_lwc_isequal(type,
1332 corestring_lwc_image)) {
1334
1336 box_is_root(n)) != CSS_DISPLAY_NONE &&
1337 nsoption_bool(foreground_images) == true) {
1338 dom_string *s;
1339
1340 err = dom_element_get_attribute(n, corestring_dom_src, &s);
1341 if (err == DOM_NO_ERR && s != NULL) {
1342 error = nsurl_join(content->base_url,
1343 dom_string_data(s), &url);
1344 dom_string_unref(s);
1345 if (error != NSERROR_OK)
1346 goto no_memory;
1347
1348 /* if url is equivalent to the parent's url,
1349 * we've got infinite inclusion. stop it here
1350 */
1351 if (nsurl_compare(url, content->base_url,
1352 NSURL_COMPLETE) == false) {
1354 url,
1355 box,
1357 false)) {
1358 nsurl_unref(url);
1359 goto no_memory;
1360 }
1361 }
1362 nsurl_unref(url);
1363 }
1364 }
1365 } else {
1366 /* unhandled type the default is "text" */
1367 if (box_input_text(content, box, n) == false)
1368 goto no_memory;
1369 }
1370
1371 dom_string_unref(type);
1372
1373 *convert_children = false;
1374
1375 return true;
1376
1377no_memory:
1378 dom_string_unref(type);
1379
1380 return false;
1381}
1382
1383
1384/**
1385 * Noscript element
1386 */
1387static bool
1388box_noscript(dom_node *n,
1390 struct box *box,
1391 bool *convert_children)
1392{
1393 /* If scripting is enabled, do not display the contents of noscript */
1394 if (content->enable_scripting) {
1395 *convert_children = false;
1396 }
1397
1398 return true;
1399}
1400
1401
1402/**
1403 * Generic embedded object [13.3].
1404 */
1405static bool
1406box_object(dom_node *n,
1408 struct box *box,
1409 bool *convert_children)
1410{
1411 struct object_params *params;
1412 struct object_param *param;
1413 dom_string *codebase, *classid, *data;
1414 dom_node *c;
1415 dom_exception err;
1416
1418 box_is_root(n)) == CSS_DISPLAY_NONE)
1419 return true;
1420
1421 if (box_get_attribute(n, "usemap", content->bctx, &box->usemap) ==
1422 false)
1423 return false;
1424 if (box->usemap && box->usemap[0] == '#')
1425 box->usemap++;
1426
1427 params = talloc(content->bctx, struct object_params);
1428 if (params == NULL)
1429 return false;
1430
1432
1433 params->data = NULL;
1434 params->type = NULL;
1435 params->codetype = NULL;
1436 params->codebase = NULL;
1437 params->classid = NULL;
1438 params->params = NULL;
1439
1440 /* codebase, classid, and data are URLs
1441 * (codebase is the base for the other two) */
1442 err = dom_element_get_attribute(n, corestring_dom_codebase, &codebase);
1443 if (err == DOM_NO_ERR && codebase != NULL) {
1444 if (box_extract_link(content, codebase, content->base_url,
1445 &params->codebase) == false) {
1446 dom_string_unref(codebase);
1447 return false;
1448 }
1449 dom_string_unref(codebase);
1450 }
1451 if (params->codebase == NULL)
1452 params->codebase = nsurl_ref(content->base_url);
1453
1454 err = dom_element_get_attribute(n, corestring_dom_classid, &classid);
1455 if (err == DOM_NO_ERR && classid != NULL) {
1456 if (box_extract_link(content, classid,
1457 params->codebase, &params->classid) == false) {
1458 dom_string_unref(classid);
1459 return false;
1460 }
1461 dom_string_unref(classid);
1462 }
1463
1464 err = dom_element_get_attribute(n, corestring_dom_data, &data);
1465 if (err == DOM_NO_ERR && data != NULL) {
1466 if (box_extract_link(content, data,
1467 params->codebase, &params->data) == false) {
1468 dom_string_unref(data);
1469 return false;
1470 }
1471 dom_string_unref(data);
1472 }
1473
1474 if (params->classid == NULL && params->data == NULL)
1475 /* nothing to embed; ignore */
1476 return true;
1477
1478 /* Don't include ourself */
1479 if (params->classid != NULL && nsurl_compare(content->base_url,
1480 params->classid, NSURL_COMPLETE))
1481 return true;
1482
1483 if (params->data != NULL && nsurl_compare(content->base_url,
1484 params->data, NSURL_COMPLETE))
1485 return true;
1486
1487 /* codetype and type are MIME types */
1488 if (box_get_attribute(n, "codetype", params,
1489 &params->codetype) == false)
1490 return false;
1491 if (box_get_attribute(n, "type", params, &params->type) == false)
1492 return false;
1493
1494 /* classid && !data => classid is used (consult codetype)
1495 * (classid || !classid) && data => data is used (consult type)
1496 * !classid && !data => invalid; ignored */
1497
1498 if (params->classid != NULL && params->data == NULL &&
1499 params->codetype != NULL) {
1500 lwc_string *icodetype;
1501 lwc_error lerror;
1502
1503 lerror = lwc_intern_string(params->codetype,
1504 strlen(params->codetype), &icodetype);
1505 if (lerror != lwc_error_ok)
1506 return false;
1507
1508 if (content_factory_type_from_mime_type(icodetype) ==
1509 CONTENT_NONE) {
1510 /* can't handle this MIME type */
1511 lwc_string_unref(icodetype);
1512 return true;
1513 }
1514
1515 lwc_string_unref(icodetype);
1516 }
1517
1518 if (params->data != NULL && params->type != NULL) {
1519 lwc_string *itype;
1520 lwc_error lerror;
1521
1522 lerror = lwc_intern_string(params->type, strlen(params->type),
1523 &itype);
1524 if (lerror != lwc_error_ok)
1525 return false;
1526
1528 CONTENT_NONE) {
1529 /* can't handle this MIME type */
1530 lwc_string_unref(itype);
1531 return true;
1532 }
1533
1534 lwc_string_unref(itype);
1535 }
1536
1537 /* add parameters to linked list */
1538 err = dom_node_get_first_child(n, &c);
1539 if (err != DOM_NO_ERR)
1540 return false;
1541
1542 while (c != NULL) {
1543 dom_node *next;
1544 dom_node_type type;
1545
1546 err = dom_node_get_node_type(c, &type);
1547 if (err != DOM_NO_ERR) {
1548 dom_node_unref(c);
1549 return false;
1550 }
1551
1552 if (type == DOM_ELEMENT_NODE) {
1553 dom_string *name;
1554
1555 err = dom_node_get_node_name(c, &name);
1556 if (err != DOM_NO_ERR) {
1557 dom_node_unref(c);
1558 return false;
1559 }
1560
1561 if (!dom_string_caseless_lwc_isequal(name,
1562 corestring_lwc_param)) {
1563 /* The first non-param child is the start of
1564 * the alt html. Therefore, we should break
1565 * out of this loop. */
1566 dom_string_unref(name);
1567 dom_node_unref(c);
1568 break;
1569 }
1570 dom_string_unref(name);
1571
1572 param = talloc(params, struct object_param);
1573 if (param == NULL) {
1574 dom_node_unref(c);
1575 return false;
1576 }
1577 param->name = NULL;
1578 param->value = NULL;
1579 param->type = NULL;
1580 param->valuetype = NULL;
1581 param->next = NULL;
1582
1583 if (box_get_attribute(c, "name", param,
1584 &param->name) == false) {
1585 dom_node_unref(c);
1586 return false;
1587 }
1588
1589 if (box_get_attribute(c, "value", param,
1590 &param->value) == false) {
1591 dom_node_unref(c);
1592 return false;
1593 }
1594
1595 if (box_get_attribute(c, "type", param,
1596 &param->type) == false) {
1597 dom_node_unref(c);
1598 return false;
1599 }
1600
1601 if (box_get_attribute(c, "valuetype", param,
1602 &param->valuetype) == false) {
1603 dom_node_unref(c);
1604 return false;
1605 }
1606
1607 if (param->valuetype == NULL) {
1608 param->valuetype = talloc_strdup(param, "data");
1609 if (param->valuetype == NULL) {
1610 dom_node_unref(c);
1611 return false;
1612 }
1613 }
1614
1615 param->next = params->params;
1616 params->params = param;
1617 }
1618
1619 err = dom_node_get_next_sibling(c, &next);
1620 if (err != DOM_NO_ERR) {
1621 dom_node_unref(c);
1622 return false;
1623 }
1624
1625 dom_node_unref(c);
1626 c = next;
1627 }
1628
1629 box->object_params = params;
1630
1631 /* start fetch (MIME type is ok or not specified) */
1632 box->flags |= IS_REPLACED;
1634 params->data ? params->data : params->classid,
1635 box,
1637 false))
1638 return false;
1639
1640 *convert_children = false;
1641 return true;
1642}
1643
1644
1645/**
1646 * Preformatted text [9.3.4].
1647 */
1648static bool
1649box_pre(dom_node *n,
1651 struct box *box,
1652 bool *convert_children)
1653{
1654 box->flags |= PRE_STRIP;
1655 return true;
1656}
1657
1658
1659/**
1660 * Option selector [17.6].
1661 */
1662static bool
1663box_select(dom_node *n,
1665 struct box *box,
1666 bool *convert_children)
1667{
1668 struct box *inline_container;
1669 struct box *inline_box;
1670 struct form_control *gadget;
1671 dom_node *c, *c2;
1672 dom_node *next, *next2;
1673 dom_exception err;
1674
1675 gadget = html_forms_get_control_for_node(content->forms, n);
1676 if (gadget == NULL)
1677 return false;
1678
1679 gadget->html = content;
1680 err = dom_node_get_first_child(n, &c);
1681 if (err != DOM_NO_ERR) {
1682 form_free_control(gadget);
1683 return false;
1684 }
1685
1686 while (c != NULL) {
1687 dom_string *name;
1688
1689 err = dom_node_get_node_name(c, &name);
1690 if (err != DOM_NO_ERR) {
1691 dom_node_unref(c);
1692 form_free_control(gadget);
1693 return false;
1694 }
1695
1696 if (dom_string_caseless_lwc_isequal(name,
1697 corestring_lwc_option)) {
1698 dom_string_unref(name);
1699
1700 if (box_select_add_option(gadget, c) == false) {
1701 dom_node_unref(c);
1702 form_free_control(gadget);
1703 return false;
1704 }
1705 } else if (dom_string_caseless_lwc_isequal(name,
1706 corestring_lwc_optgroup)) {
1707 dom_string_unref(name);
1708
1709 err = dom_node_get_first_child(c, &c2);
1710 if (err != DOM_NO_ERR) {
1711 dom_node_unref(c);
1712 form_free_control(gadget);
1713 return false;
1714 }
1715
1716 while (c2 != NULL) {
1717 dom_string *c2_name;
1718
1719 err = dom_node_get_node_name(c2, &c2_name);
1720 if (err != DOM_NO_ERR) {
1721 dom_node_unref(c2);
1722 dom_node_unref(c);
1723 form_free_control(gadget);
1724 return false;
1725 }
1726
1727 if (dom_string_caseless_lwc_isequal(c2_name,
1728 corestring_lwc_option)) {
1729 dom_string_unref(c2_name);
1730
1731 if (box_select_add_option(gadget,
1732 c2) == false) {
1733 dom_node_unref(c2);
1734 dom_node_unref(c);
1735 form_free_control(gadget);
1736 return false;
1737 }
1738 } else {
1739 dom_string_unref(c2_name);
1740 }
1741
1742 err = dom_node_get_next_sibling(c2, &next2);
1743 if (err != DOM_NO_ERR) {
1744 dom_node_unref(c2);
1745 dom_node_unref(c);
1746 form_free_control(gadget);
1747 return false;
1748 }
1749
1750 dom_node_unref(c2);
1751 c2 = next2;
1752 }
1753 } else {
1754 dom_string_unref(name);
1755 }
1756
1757 err = dom_node_get_next_sibling(c, &next);
1758 if (err != DOM_NO_ERR) {
1759 dom_node_unref(c);
1760 form_free_control(gadget);
1761 return false;
1762 }
1763
1764 dom_node_unref(c);
1765 c = next;
1766 }
1767
1768 if (gadget->data.select.num_items == 0) {
1769 /* no options: ignore entire select */
1770 form_free_control(gadget);
1771 return true;
1772 }
1773
1775 box->gadget = gadget;
1776 box->flags |= IS_REPLACED;
1777 gadget->box = box;
1778
1779 inline_container = box_create(NULL, 0, false, 0, 0, 0, 0, content->bctx);
1780 if (inline_container == NULL)
1781 goto no_memory;
1782 inline_container->type = BOX_INLINE_CONTAINER;
1783 inline_box = box_create(NULL, box->style, false, 0, 0, box->title, 0,
1784 content->bctx);
1785 if (inline_box == NULL)
1786 goto no_memory;
1787 inline_box->type = BOX_TEXT;
1788 box_add_child(inline_container, inline_box);
1789 box_add_child(box, inline_container);
1790
1791 if (gadget->data.select.multiple == false &&
1792 gadget->data.select.num_selected == 0) {
1793 gadget->data.select.current = gadget->data.select.items;
1794 gadget->data.select.current->initial_selected =
1795 gadget->data.select.current->selected = true;
1796 gadget->data.select.num_selected = 1;
1797 dom_html_option_element_set_selected(
1798 gadget->data.select.current->node, true);
1799 }
1800
1801 if (gadget->data.select.num_selected == 0)
1802 inline_box->text = talloc_strdup(content->bctx,
1803 messages_get("Form_None"));
1804 else if (gadget->data.select.num_selected == 1)
1805 inline_box->text = talloc_strdup(content->bctx,
1806 gadget->data.select.current->text);
1807 else
1808 inline_box->text = talloc_strdup(content->bctx,
1809 messages_get("Form_Many"));
1810 if (inline_box->text == NULL)
1811 goto no_memory;
1812
1813 inline_box->length = strlen(inline_box->text);
1814
1815 *convert_children = false;
1816 return true;
1817
1818no_memory:
1819 return false;
1820}
1821
1822
1823/**
1824 * Multi-line text field [17.7].
1825 */
1826static bool box_textarea(dom_node *n,
1828 struct box *box,
1829 bool *convert_children)
1830{
1831 /* Get the form_control for the DOM node */
1833 if (box->gadget == NULL)
1834 return false;
1835
1836 box->flags |= IS_REPLACED;
1837 box->gadget->html = content;
1838 box->gadget->box = box;
1839
1840 if (!box_input_text(content, box, n))
1841 return false;
1842
1843 *convert_children = false;
1844 return true;
1845}
1846
1847
1848/**
1849 * \}
1850 */
1851
1852
1853/* exported interface documented in html/box_special.h */
1854bool
1857 struct box *box,
1858 bool *convert_children)
1859{
1860 dom_exception exc;
1861 dom_html_element_type tag_type;
1862 bool res;
1863
1864 exc = dom_html_element_get_tag_type(node, &tag_type);
1865 if (exc != DOM_NO_ERR) {
1866 tag_type = DOM_HTML_ELEMENT_TYPE__UNKNOWN;
1867 }
1868
1869 switch (tag_type) {
1870 case DOM_HTML_ELEMENT_TYPE_A:
1871 res = box_a(node, content, box, convert_children);
1872 break;
1873
1874 case DOM_HTML_ELEMENT_TYPE_BODY:
1875 res = box_body(node, content, box, convert_children);
1876 break;
1877
1878 case DOM_HTML_ELEMENT_TYPE_BR:
1879 res = box_br(node, content, box, convert_children);
1880 break;
1881
1882 case DOM_HTML_ELEMENT_TYPE_BUTTON:
1883 res = box_button(node, content, box, convert_children);
1884 break;
1885
1886 case DOM_HTML_ELEMENT_TYPE_CANVAS:
1887 res = box_canvas(node, content, box, convert_children);
1888 break;
1889
1890 case DOM_HTML_ELEMENT_TYPE_EMBED:
1891 res = box_embed(node, content, box, convert_children);
1892 break;
1893
1894 case DOM_HTML_ELEMENT_TYPE_FRAMESET:
1895 res = box_frameset(node, content, box, convert_children);
1896 break;
1897
1898 case DOM_HTML_ELEMENT_TYPE_IFRAME:
1899 res = box_iframe(node, content, box, convert_children);
1900 break;
1901
1902 case DOM_HTML_ELEMENT_TYPE_IMG:
1903 res = box_image(node, content, box, convert_children);
1904 break;
1905
1906 case DOM_HTML_ELEMENT_TYPE_INPUT:
1907 res = box_input(node, content, box, convert_children);
1908 break;
1909
1910 case DOM_HTML_ELEMENT_TYPE_NOSCRIPT:
1911 res = box_noscript(node, content, box, convert_children);
1912 break;
1913
1914 case DOM_HTML_ELEMENT_TYPE_OBJECT:
1915 res = box_object(node, content, box, convert_children);
1916 break;
1917
1918 case DOM_HTML_ELEMENT_TYPE_PRE:
1919 res = box_pre(node, content, box, convert_children);
1920 break;
1921
1922 case DOM_HTML_ELEMENT_TYPE_SELECT:
1923 res = box_select(node, content, box, convert_children);
1924 break;
1925
1926 case DOM_HTML_ELEMENT_TYPE_TEXTAREA:
1927 res = box_textarea(node, content, box, convert_children);
1928 break;
1929
1930 default:
1931 res = true;
1932 }
1933
1934 return res;
1935}
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:854
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:1826
static bool box_canvas(dom_node *n, html_content *content, struct box *box, bool *convert_children)
Canvas element.
Definition: box_special.c:827
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:799
static bool box_noscript(dom_node *n, html_content *content, struct box *box, bool *convert_children)
Noscript element.
Definition: box_special.c:1388
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:1855
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:1027
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:785
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:1406
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:988
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:1663
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:1649
static bool box_image(dom_node *n, html_content *content, struct box *box, bool *convert_children)
Embedded image [13.2].
Definition: box_special.c:1152
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:763
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:1235
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:241
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:270
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