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