You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							1936 lines
						
					
					
						
							44 KiB
						
					
					
				
			
		
		
	
	
							1936 lines
						
					
					
						
							44 KiB
						
					
					
				| /*
 | |
|  * Copyright 2005 James Bursa <bursa@users.sourceforge.net>
 | |
|  * Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
 | |
|  * Copyright 2005 John M Bell <jmb202@ecs.soton.ac.uk>
 | |
|  * Copyright 2006 Richard Wilson <info@tinct.net>
 | |
|  * Copyright 2008 Michael Drake <tlsa@netsurf-browser.org>
 | |
|  * Copyright 2020 Vincent Sanders <vince@netsurf-browser.org>
 | |
|  *
 | |
|  * This file is part of NetSurf, http://www.netsurf-browser.org/
 | |
|  *
 | |
|  * NetSurf is free software; you can redistribute it and/or modify
 | |
|  * it under the terms of the GNU General Public License as published by
 | |
|  * the Free Software Foundation; version 2 of the License.
 | |
|  *
 | |
|  * NetSurf is distributed in the hope that it will be useful,
 | |
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|  * GNU General Public License for more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU General Public License
 | |
|  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | |
|  */
 | |
| 
 | |
| /**
 | |
|  * \file
 | |
|  * Implementation of special element handling conversion.
 | |
|  */
 | |
| 
 | |
| #include <string.h>
 | |
| #include <stdbool.h>
 | |
| #include <dom/dom.h>
 | |
| 
 | |
| #include "utils/nsoption.h"
 | |
| #include "utils/corestrings.h"
 | |
| #include "utils/log.h"
 | |
| #include "utils/messages.h"
 | |
| #include "utils/talloc.h"
 | |
| #include "utils/string.h"
 | |
| #include "utils/ascii.h"
 | |
| #include "utils/nsurl.h"
 | |
| #include "netsurf/plot_style.h"
 | |
| #include "css/hints.h"
 | |
| #include "desktop/frame_types.h"
 | |
| #include "content/content_factory.h"
 | |
| 
 | |
| #include "html/html.h"
 | |
| #include "html/private.h"
 | |
| #include "html/object.h"
 | |
| #include "html/box.h"
 | |
| #include "html/box_manipulate.h"
 | |
| #include "html/box_construct.h"
 | |
| #include "html/box_special.h"
 | |
| #include "html/box_textarea.h"
 | |
| #include "html/form_internal.h"
 | |
| 
 | |
| 
 | |
| static const content_type image_types = CONTENT_IMAGE;
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * determine if a box is the root node
 | |
|  *
 | |
|  * \param n node to check
 | |
|  * \return true if node is root else false.
 | |
|  */
 | |
| static inline bool box_is_root(dom_node *n)
 | |
| {
 | |
| 	dom_node *parent;
 | |
| 	dom_node_type type;
 | |
| 	dom_exception err;
 | |
| 
 | |
| 	err = dom_node_get_parent_node(n, &parent);
 | |
| 	if (err != DOM_NO_ERR)
 | |
| 		return false;
 | |
| 
 | |
| 	if (parent != NULL) {
 | |
| 		err = dom_node_get_node_type(parent, &type);
 | |
| 
 | |
| 		dom_node_unref(parent);
 | |
| 
 | |
| 		if (err != DOM_NO_ERR)
 | |
| 			return false;
 | |
| 
 | |
| 		if (type != DOM_DOCUMENT_NODE)
 | |
| 			return false;
 | |
| 	}
 | |
| 
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Destructor for object_params, for <object> elements
 | |
|  *
 | |
|  * \param o  The object params being destroyed.
 | |
|  * \return 0 to allow talloc to continue destroying the tree.
 | |
|  */
 | |
| static int box_object_talloc_destructor(struct object_params *o)
 | |
| {
 | |
| 	if (o->codebase != NULL)
 | |
| 		nsurl_unref(o->codebase);
 | |
| 	if (o->classid != NULL)
 | |
| 		nsurl_unref(o->classid);
 | |
| 	if (o->data != NULL)
 | |
| 		nsurl_unref(o->data);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Parse a multi-length-list, as defined by HTML 4.01.
 | |
|  *
 | |
|  * \param ds dom string to parse
 | |
|  * \param count updated to number of entries
 | |
|  * \return array of struct box_multi_length, or 0 on memory exhaustion
 | |
|  */
 | |
| static struct frame_dimension *
 | |
| box_parse_multi_lengths(const dom_string *ds, unsigned int *count)
 | |
| {
 | |
| 	char *end;
 | |
| 	unsigned int i, n;
 | |
| 	struct frame_dimension *length;
 | |
| 	const char *s;
 | |
| 
 | |
| 	s = dom_string_data(ds);
 | |
| 
 | |
| 	for (i = 0, n = 1; s[i]; i++)
 | |
| 		if (s[i] == ',')
 | |
| 			n++;
 | |
| 
 | |
| 	length = calloc(n, sizeof(struct frame_dimension));
 | |
| 	if (!length)
 | |
| 		return NULL;
 | |
| 
 | |
| 	for (i = 0; i != n; i++) {
 | |
| 		while (ascii_is_space(*s)) {
 | |
| 			s++;
 | |
| 		}
 | |
| 		length[i].value = strtof(s, &end);
 | |
| 		if (length[i].value <= 0) {
 | |
| 			length[i].value = 1;
 | |
| 		}
 | |
| 		s = end;
 | |
| 		switch (*s) {
 | |
| 			case '%':
 | |
| 				length[i].unit = FRAME_DIMENSION_PERCENT;
 | |
| 				break;
 | |
| 			case '*':
 | |
| 				length[i].unit = FRAME_DIMENSION_RELATIVE;
 | |
| 				break;
 | |
| 			default:
 | |
| 				length[i].unit = FRAME_DIMENSION_PIXELS;
 | |
| 				break;
 | |
| 		}
 | |
| 		while (*s && *s != ',') {
 | |
| 			s++;
 | |
| 		}
 | |
| 		if (*s == ',') {
 | |
| 			s++;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	*count = n;
 | |
| 	return length;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Destructor for content_html_frames, for frame elements
 | |
|  *
 | |
|  * \param f  The frame params being destroyed.
 | |
|  * \return 0 to allow talloc to continue destroying the tree.
 | |
|  */
 | |
| static int box_frames_talloc_destructor(struct content_html_frames *f)
 | |
| {
 | |
| 	if (f->url != NULL) {
 | |
| 		nsurl_unref(f->url);
 | |
| 		f->url = NULL;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * create a frameset box tree
 | |
|  */
 | |
| static bool
 | |
| box_create_frameset(struct content_html_frames *f,
 | |
| 		    dom_node *n,
 | |
| 		    html_content *content)
 | |
| {
 | |
| 	unsigned int row, col, index, i;
 | |
| 	unsigned int rows = 1, cols = 1;
 | |
| 	dom_string *s;
 | |
| 	dom_exception err;
 | |
| 	nsurl *url;
 | |
| 	struct frame_dimension *row_height = 0, *col_width = 0;
 | |
| 	dom_node *c, *next;
 | |
| 	struct content_html_frames *frame;
 | |
| 	bool default_border = true;
 | |
| 	colour default_border_colour = 0x000000;
 | |
| 
 | |
| 	/* parse rows and columns */
 | |
| 	err = dom_element_get_attribute(n, corestring_dom_rows, &s);
 | |
| 	if (err == DOM_NO_ERR && s != NULL) {
 | |
| 		row_height = box_parse_multi_lengths(s, &rows);
 | |
| 		dom_string_unref(s);
 | |
| 		if (row_height == NULL)
 | |
| 			return false;
 | |
| 	} else {
 | |
| 		row_height = calloc(1, sizeof(struct frame_dimension));
 | |
| 		if (row_height == NULL)
 | |
| 			return false;
 | |
| 		row_height->value = 100;
 | |
| 		row_height->unit = FRAME_DIMENSION_PERCENT;
 | |
| 	}
 | |
| 
 | |
| 	err = dom_element_get_attribute(n, corestring_dom_cols, &s);
 | |
| 	if (err == DOM_NO_ERR && s != NULL) {
 | |
| 		col_width = box_parse_multi_lengths(s, &cols);
 | |
| 		dom_string_unref(s);
 | |
| 		if (col_width == NULL) {
 | |
| 			free(row_height);
 | |
| 			return false;
 | |
| 		}
 | |
| 	} else {
 | |
| 		col_width = calloc(1, sizeof(struct frame_dimension));
 | |
| 		if (col_width == NULL) {
 | |
| 			free(row_height);
 | |
| 			return false;
 | |
| 		}
 | |
| 		col_width->value = 100;
 | |
| 		col_width->unit = FRAME_DIMENSION_PERCENT;
 | |
| 	}
 | |
| 
 | |
| 	/* common extension: border="0|1" to control all children */
 | |
| 	err = dom_element_get_attribute(n, corestring_dom_border, &s);
 | |
| 	if (err == DOM_NO_ERR && s != NULL) {
 | |
| 		if ((dom_string_data(s)[0] == '0') &&
 | |
| 				(dom_string_data(s)[1] == '\0'))
 | |
| 			default_border = false;
 | |
| 		dom_string_unref(s);
 | |
| 	}
 | |
| 
 | |
| 	/* common extension: frameborder="yes|no" to control all children */
 | |
| 	err = dom_element_get_attribute(n, corestring_dom_frameborder, &s);
 | |
| 	if (err == DOM_NO_ERR && s != NULL) {
 | |
| 		if (dom_string_caseless_lwc_isequal(s,
 | |
| 				corestring_lwc_no) == 0)
 | |
| 			default_border = false;
 | |
| 		dom_string_unref(s);
 | |
| 	}
 | |
| 
 | |
| 	/* common extension: bordercolor="#RRGGBB|<named colour>" to control
 | |
| 	 *all children */
 | |
| 	err = dom_element_get_attribute(n, corestring_dom_bordercolor, &s);
 | |
| 	if (err == DOM_NO_ERR && s != NULL) {
 | |
| 		css_color color;
 | |
| 
 | |
| 		if (nscss_parse_colour(dom_string_data(s), &color))
 | |
| 			default_border_colour = nscss_color_to_ns(color);
 | |
| 
 | |
| 		dom_string_unref(s);
 | |
| 	}
 | |
| 
 | |
| 	/* update frameset and create default children */
 | |
| 	f->cols = cols;
 | |
| 	f->rows = rows;
 | |
| 	f->scrolling = BW_SCROLLING_NO;
 | |
| 	f->children = talloc_array(content->bctx, struct content_html_frames,
 | |
| 								(rows * cols));
 | |
| 
 | |
| 	talloc_set_destructor(f->children, box_frames_talloc_destructor);
 | |
| 
 | |
| 	for (row = 0; row < rows; row++) {
 | |
| 		for (col = 0; col < cols; col++) {
 | |
| 			index = (row * cols) + col;
 | |
| 			frame = &f->children[index];
 | |
| 			frame->cols = 0;
 | |
| 			frame->rows = 0;
 | |
| 			frame->width = col_width[col];
 | |
| 			frame->height = row_height[row];
 | |
| 			frame->margin_width = 0;
 | |
| 			frame->margin_height = 0;
 | |
| 			frame->name = NULL;
 | |
| 			frame->url = NULL;
 | |
| 			frame->no_resize = false;
 | |
| 			frame->scrolling = BW_SCROLLING_AUTO;
 | |
| 			frame->border = default_border;
 | |
| 			frame->border_colour = default_border_colour;
 | |
| 			frame->children = NULL;
 | |
| 		}
 | |
| 	}
 | |
| 	free(col_width);
 | |
| 	free(row_height);
 | |
| 
 | |
| 	/* create the frameset windows */
 | |
| 	err = dom_node_get_first_child(n, &c);
 | |
| 	if (err != DOM_NO_ERR)
 | |
| 		return false;
 | |
| 
 | |
| 	for (row = 0; c != NULL && row < rows; row++) {
 | |
| 		for (col = 0; c != NULL && col < cols; col++) {
 | |
| 			while (c != NULL) {
 | |
| 				dom_node_type type;
 | |
| 				dom_string *name;
 | |
| 
 | |
| 				err = dom_node_get_node_type(c, &type);
 | |
| 				if (err != DOM_NO_ERR) {
 | |
| 					dom_node_unref(c);
 | |
| 					return false;
 | |
| 				}
 | |
| 
 | |
| 				err = dom_node_get_node_name(c, &name);
 | |
| 				if (err != DOM_NO_ERR) {
 | |
| 					dom_node_unref(c);
 | |
| 					return false;
 | |
| 				}
 | |
| 
 | |
| 				if (type != DOM_ELEMENT_NODE ||
 | |
| 					(!dom_string_caseless_lwc_isequal(
 | |
| 							name,
 | |
| 							corestring_lwc_frame) &&
 | |
| 					!dom_string_caseless_lwc_isequal(
 | |
| 							name,
 | |
| 							corestring_lwc_frameset
 | |
| 							))) {
 | |
| 					err = dom_node_get_next_sibling(c,
 | |
| 							&next);
 | |
| 					if (err != DOM_NO_ERR) {
 | |
| 						dom_string_unref(name);
 | |
| 						dom_node_unref(c);
 | |
| 						return false;
 | |
| 					}
 | |
| 
 | |
| 					dom_string_unref(name);
 | |
| 					dom_node_unref(c);
 | |
| 					c = next;
 | |
| 				} else {
 | |
| 					/* Got a FRAME or FRAMESET element */
 | |
| 					dom_string_unref(name);
 | |
| 					break;
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			if (c == NULL)
 | |
| 				break;
 | |
| 
 | |
| 			/* get current frame */
 | |
| 			index = (row * cols) + col;
 | |
| 			frame = &f->children[index];
 | |
| 
 | |
| 			/* nest framesets */
 | |
| 			err = dom_node_get_node_name(c, &s);
 | |
| 			if (err != DOM_NO_ERR) {
 | |
| 				dom_node_unref(c);
 | |
| 				return false;
 | |
| 			}
 | |
| 
 | |
| 			if (dom_string_caseless_lwc_isequal(s,
 | |
| 					corestring_lwc_frameset)) {
 | |
| 				dom_string_unref(s);
 | |
| 				frame->border = 0;
 | |
| 				if (box_create_frameset(frame, c,
 | |
| 						content) == false) {
 | |
| 					dom_node_unref(c);
 | |
| 					return false;
 | |
| 				}
 | |
| 
 | |
| 				err = dom_node_get_next_sibling(c, &next);
 | |
| 				if (err != DOM_NO_ERR) {
 | |
| 					dom_node_unref(c);
 | |
| 					return false;
 | |
| 				}
 | |
| 
 | |
| 				dom_node_unref(c);
 | |
| 				c = next;
 | |
| 				continue;
 | |
| 			}
 | |
| 
 | |
| 			dom_string_unref(s);
 | |
| 
 | |
| 			/* get frame URL (not required) */
 | |
| 			url = NULL;
 | |
| 			err = dom_element_get_attribute(c, corestring_dom_src, &s);
 | |
| 			if (err == DOM_NO_ERR && s != NULL) {
 | |
| 				box_extract_link(content, s, content->base_url,
 | |
| 						 &url);
 | |
| 				dom_string_unref(s);
 | |
| 			}
 | |
| 
 | |
| 			/* copy url */
 | |
| 			if (url != NULL) {
 | |
| 				/* no self-references */
 | |
| 				if (nsurl_compare(content->base_url, url,
 | |
| 						NSURL_COMPLETE) == false)
 | |
| 					frame->url = url;
 | |
| 				url = NULL;
 | |
| 			}
 | |
| 
 | |
| 			/* fill in specified values */
 | |
| 			err = dom_element_get_attribute(c, corestring_dom_name, &s);
 | |
| 			if (err == DOM_NO_ERR && s != NULL) {
 | |
| 				frame->name = talloc_strdup(content->bctx,
 | |
| 						dom_string_data(s));
 | |
| 				dom_string_unref(s);
 | |
| 			}
 | |
| 
 | |
| 			if (dom_element_has_attribute(c, corestring_dom_noresize,
 | |
| 						      &frame->no_resize) != DOM_NO_ERR) {
 | |
| 				/* If we can't read the attribute for some reason,
 | |
| 				 * assume we didn't have it.
 | |
| 				 */
 | |
| 				frame->no_resize = false;
 | |
| 			}
 | |
| 
 | |
| 			err = dom_element_get_attribute(c, corestring_dom_frameborder,
 | |
| 					&s);
 | |
| 			if (err == DOM_NO_ERR && s != NULL) {
 | |
| 				i = atoi(dom_string_data(s));
 | |
| 				frame->border = (i != 0);
 | |
| 				dom_string_unref(s);
 | |
| 			}
 | |
| 
 | |
| 			err = dom_element_get_attribute(c, corestring_dom_scrolling, &s);
 | |
| 			if (err == DOM_NO_ERR && s != NULL) {
 | |
| 				if (dom_string_caseless_lwc_isequal(s,
 | |
| 						corestring_lwc_yes))
 | |
| 					frame->scrolling = BW_SCROLLING_YES;
 | |
| 				else if (dom_string_caseless_lwc_isequal(s,
 | |
| 						corestring_lwc_no))
 | |
| 					frame->scrolling = BW_SCROLLING_NO;
 | |
| 				dom_string_unref(s);
 | |
| 			}
 | |
| 
 | |
| 			err = dom_element_get_attribute(c, corestring_dom_marginwidth,
 | |
| 					&s);
 | |
| 			if (err == DOM_NO_ERR && s != NULL) {
 | |
| 				frame->margin_width = atoi(dom_string_data(s));
 | |
| 				dom_string_unref(s);
 | |
| 			}
 | |
| 
 | |
| 			err = dom_element_get_attribute(c, corestring_dom_marginheight,
 | |
| 					&s);
 | |
| 			if (err == DOM_NO_ERR && s != NULL) {
 | |
| 				frame->margin_height = atoi(dom_string_data(s));
 | |
| 				dom_string_unref(s);
 | |
| 			}
 | |
| 
 | |
| 			err = dom_element_get_attribute(c, corestring_dom_bordercolor,
 | |
| 					&s);
 | |
| 			if (err == DOM_NO_ERR && s != NULL) {
 | |
| 				css_color color;
 | |
| 
 | |
| 				if (nscss_parse_colour(dom_string_data(s),
 | |
| 						&color))
 | |
| 					frame->border_colour =
 | |
| 						nscss_color_to_ns(color);
 | |
| 
 | |
| 				dom_string_unref(s);
 | |
| 			}
 | |
| 
 | |
| 			/* advance */
 | |
| 			err = dom_node_get_next_sibling(c, &next);
 | |
| 			if (err != DOM_NO_ERR) {
 | |
| 				dom_node_unref(c);
 | |
| 				return false;
 | |
| 			}
 | |
| 
 | |
| 			dom_node_unref(c);
 | |
| 			c = next;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* If the last child wasn't a frame, we still need to unref it */
 | |
| 	if (c != NULL) {
 | |
| 		dom_node_unref(c);
 | |
| 	}
 | |
| 
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Destructor for content_html_iframe, for <iframe> elements
 | |
|  *
 | |
|  * \param f The iframe params being destroyed.
 | |
|  * \return 0 to allow talloc to continue destroying the tree.
 | |
|  */
 | |
| static int box_iframes_talloc_destructor(struct content_html_iframe *f)
 | |
| {
 | |
| 	if (f->url != NULL) {
 | |
| 		nsurl_unref(f->url);
 | |
| 		f->url = NULL;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Get the value of a dom node element's attribute.
 | |
|  *
 | |
|  * \param  n	      dom element node
 | |
|  * \param  attribute  name of attribute
 | |
|  * \param  context    talloc context for result buffer
 | |
|  * \param  value      updated to value, if the attribute is present
 | |
|  * \return  true on success, false if attribute present but memory exhausted
 | |
|  *
 | |
|  * \note returning true does not imply that the attribute was found. If the
 | |
|  * attribute was not found, *value will be unchanged.
 | |
|  */
 | |
| static bool
 | |
| box_get_attribute(dom_node *n,
 | |
| 		  const char *attribute,
 | |
| 		  void *context,
 | |
| 		  char **value)
 | |
| {
 | |
| 	char *result;
 | |
| 	dom_string *attr, *attr_name;
 | |
| 	dom_exception err;
 | |
| 
 | |
| 	err = dom_string_create_interned((const uint8_t *) attribute,
 | |
| 			strlen(attribute), &attr_name);
 | |
| 	if (err != DOM_NO_ERR)
 | |
| 		return false;
 | |
| 
 | |
| 	err = dom_element_get_attribute(n, attr_name, &attr);
 | |
| 	if (err != DOM_NO_ERR) {
 | |
| 		dom_string_unref(attr_name);
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	dom_string_unref(attr_name);
 | |
| 
 | |
| 	if (attr != NULL) {
 | |
| 		result = talloc_strdup(context, dom_string_data(attr));
 | |
| 
 | |
| 		dom_string_unref(attr);
 | |
| 
 | |
| 		if (result == NULL)
 | |
| 			return false;
 | |
| 
 | |
| 		*value = result;
 | |
| 	}
 | |
| 
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Helper function for adding textarea widget to box.
 | |
|  *
 | |
|  * This is a load of hacks to ensure boxes replaced with textareas
 | |
|  * can be handled by the layout code.
 | |
|  */
 | |
| static bool
 | |
| box_input_text(html_content *html, struct box *box, struct dom_node *node)
 | |
| {
 | |
| 	struct box *inline_container, *inline_box;
 | |
| 	uint8_t display = css_computed_display_static(box->style);
 | |
| 
 | |
| 	switch (display) {
 | |
| 	case CSS_DISPLAY_GRID:
 | |
| 	case CSS_DISPLAY_FLEX:
 | |
| 	case CSS_DISPLAY_BLOCK:
 | |
| 		box->type = BOX_BLOCK;
 | |
| 		break;
 | |
| 	default:
 | |
| 		box->type = BOX_INLINE_BLOCK;
 | |
| 		break;
 | |
| 	}
 | |
| 
 | |
| 	inline_container = box_create(NULL, 0, false, 0, 0, 0, 0, html->bctx);
 | |
| 	if (!inline_container)
 | |
| 		return false;
 | |
| 	inline_container->type = BOX_INLINE_CONTAINER;
 | |
| 	inline_box = box_create(NULL, box->style, false, 0, 0, box->title, 0,
 | |
| 			html->bctx);
 | |
| 	if (!inline_box)
 | |
| 		return false;
 | |
| 	inline_box->type = BOX_TEXT;
 | |
| 	inline_box->text = talloc_strdup(html->bctx, "");
 | |
| 
 | |
| 	box_add_child(inline_container, inline_box);
 | |
| 	box_add_child(box, inline_container);
 | |
| 
 | |
| 	return box_textarea_create_textarea(html, box, node);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Add an option to a form select control (helper function for box_select()).
 | |
|  *
 | |
|  * \param  control  select containing the <option>
 | |
|  * \param  n	    xml element node for <option>
 | |
|  * \return  true on success, false on memory exhaustion
 | |
|  */
 | |
| static bool box_select_add_option(struct form_control *control, dom_node *n)
 | |
| {
 | |
| 	char *value = NULL;
 | |
| 	char *text = NULL;
 | |
| 	char *text_nowrap = NULL;
 | |
| 	bool selected;
 | |
| 	dom_string *content, *s;
 | |
| 	dom_exception err;
 | |
| 
 | |
| 	err = dom_node_get_text_content(n, &content);
 | |
| 	if (err != DOM_NO_ERR)
 | |
| 		return false;
 | |
| 
 | |
| 	if (content != NULL) {
 | |
| 		text = squash_whitespace(dom_string_data(content));
 | |
| 		dom_string_unref(content);
 | |
| 	} else {
 | |
| 		text = strdup("");
 | |
| 	}
 | |
| 
 | |
| 	if (text == NULL)
 | |
| 		goto no_memory;
 | |
| 
 | |
| 	err = dom_element_get_attribute(n, corestring_dom_value, &s);
 | |
| 	if (err == DOM_NO_ERR && s != NULL) {
 | |
| 		value = strdup(dom_string_data(s));
 | |
| 		dom_string_unref(s);
 | |
| 	} else {
 | |
| 		value = strdup(text);
 | |
| 	}
 | |
| 
 | |
| 	if (value == NULL)
 | |
| 		goto no_memory;
 | |
| 
 | |
| 	if (dom_element_has_attribute(n, corestring_dom_selected, &selected) != DOM_NO_ERR) {
 | |
| 		/* Assume not selected if we can't read the attribute presence */
 | |
| 		selected = false;
 | |
| 	}
 | |
| 
 | |
| 	/* replace spaces/TABs with hard spaces to prevent line wrapping */
 | |
| 	text_nowrap = cnv_space2nbsp(text);
 | |
| 	if (text_nowrap == NULL)
 | |
| 		goto no_memory;
 | |
| 
 | |
| 	if (form_add_option(control, value, text_nowrap, selected, n) == false)
 | |
| 		goto no_memory;
 | |
| 
 | |
| 	free(text);
 | |
| 
 | |
| 	return true;
 | |
| 
 | |
| no_memory:
 | |
| 	free(value);
 | |
| 	free(text);
 | |
| 	free(text_nowrap);
 | |
| 	return false;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * \name  Special case element handlers
 | |
|  *
 | |
|  * These functions are called by box_construct_element() when an element is
 | |
|  * being converted, according to the entries in element_table.
 | |
|  *
 | |
|  * The parameters are the xmlNode, the content for the document, and a partly
 | |
|  * filled in box structure for the element.
 | |
|  *
 | |
|  * Return true on success, false on memory exhaustion. Set *convert_children
 | |
|  * to false if children of this element in the XML tree should be skipped (for
 | |
|  * example, if they have been processed in some special way already).
 | |
|  *
 | |
|  * Elements ordered as in the HTML 4.01 specification. Section numbers in
 | |
|  * brackets [] refer to the spec.
 | |
|  *
 | |
|  * \{
 | |
|  */
 | |
| 
 | |
| /**
 | |
|  * special element handler for Anchor [12.2].
 | |
|  */
 | |
| static bool
 | |
| box_a(dom_node *n,
 | |
|       html_content *content,
 | |
|       struct box *box,
 | |
|       bool *convert_children)
 | |
| {
 | |
| 	bool ok;
 | |
| 	nsurl *url;
 | |
| 	dom_string *s;
 | |
| 	dom_exception err;
 | |
| 
 | |
| 	err = dom_element_get_attribute(n, corestring_dom_href, &s);
 | |
| 	if (err == DOM_NO_ERR && s != NULL) {
 | |
| 		ok = box_extract_link(content, s, content->base_url, &url);
 | |
| 		dom_string_unref(s);
 | |
| 		if (!ok)
 | |
| 			return false;
 | |
| 		if (url) {
 | |
| 			if (box->href != NULL)
 | |
| 				nsurl_unref(box->href);
 | |
| 			box->href = url;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* name and id share the same namespace */
 | |
| 	err = dom_element_get_attribute(n, corestring_dom_name, &s);
 | |
| 	if (err == DOM_NO_ERR && s != NULL) {
 | |
| 		lwc_string *lwc_name;
 | |
| 
 | |
| 		err = dom_string_intern(s, &lwc_name);
 | |
| 
 | |
| 		dom_string_unref(s);
 | |
| 
 | |
| 		if (err == DOM_NO_ERR) {
 | |
| 			/* name replaces existing id
 | |
| 			 * TODO: really? */
 | |
| 			if (box->id != NULL)
 | |
| 				lwc_string_unref(box->id);
 | |
| 
 | |
| 			box->id = lwc_name;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/* target frame [16.3] */
 | |
| 	err = dom_element_get_attribute(n, corestring_dom_target, &s);
 | |
| 	if (err == DOM_NO_ERR && s != NULL) {
 | |
| 		if (dom_string_caseless_lwc_isequal(s,
 | |
| 				corestring_lwc__blank))
 | |
| 			box->target = "_blank";
 | |
| 		else if (dom_string_caseless_lwc_isequal(s,
 | |
| 				corestring_lwc__top))
 | |
| 			box->target = "_top";
 | |
| 		else if (dom_string_caseless_lwc_isequal(s,
 | |
| 				corestring_lwc__parent))
 | |
| 			box->target = "_parent";
 | |
| 		else if (dom_string_caseless_lwc_isequal(s,
 | |
| 				corestring_lwc__self))
 | |
| 			/* the default may have been overridden by a
 | |
| 			 * <base target=...>, so this is different to 0 */
 | |
| 			box->target = "_self";
 | |
| 		else {
 | |
| 			/* 6.16 says that frame names must begin with [a-zA-Z]
 | |
| 			 * This doesn't match reality, so just take anything */
 | |
| 			box->target = talloc_strdup(content->bctx,
 | |
| 					dom_string_data(s));
 | |
| 			if (!box->target) {
 | |
| 				dom_string_unref(s);
 | |
| 				return false;
 | |
| 			}
 | |
| 		}
 | |
| 		dom_string_unref(s);
 | |
| 	}
 | |
| 
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Document body special element handler [7.5.1].
 | |
|  */
 | |
| static bool
 | |
| box_body(dom_node *n,
 | |
| 	 html_content *content,
 | |
| 	 struct box *box,
 | |
| 	 bool *convert_children)
 | |
| {
 | |
| 	css_color color;
 | |
| 
 | |
| 	css_computed_background_color(box->style, &color);
 | |
| 	if (nscss_color_is_transparent(color)) {
 | |
| 		content->background_colour = NS_TRANSPARENT;
 | |
| 	} else {
 | |
| 		content->background_colour = nscss_color_to_ns(color);
 | |
| 	}
 | |
| 
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * special element handler for forced line break [9.3.2].
 | |
|  */
 | |
| static bool
 | |
| box_br(dom_node *n,
 | |
|        html_content *content,
 | |
|        struct box *box,
 | |
|        bool *convert_children)
 | |
| {
 | |
| 	box->type = BOX_BR;
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * special element handler for Push button [17.5].
 | |
|  */
 | |
| static bool
 | |
| box_button(dom_node *n,
 | |
| 	   html_content *content,
 | |
| 	   struct box *box,
 | |
| 	   bool *convert_children)
 | |
| {
 | |
| 	struct form_control *gadget;
 | |
| 
 | |
| 	gadget = html_forms_get_control_for_node(content->forms, n);
 | |
| 	if (!gadget)
 | |
| 		return false;
 | |
| 
 | |
| 	gadget->html = content;
 | |
| 	box->gadget = gadget;
 | |
| 	box->flags |= IS_REPLACED;
 | |
| 	gadget->box = box;
 | |
| 
 | |
| 	box->type = BOX_INLINE_BLOCK;
 | |
| 
 | |
| 	/* Just render the contents */
 | |
| 
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Canvas element
 | |
|  */
 | |
| static bool
 | |
| box_canvas(dom_node *n,
 | |
| 	     html_content *content,
 | |
| 	     struct box *box,
 | |
| 	     bool *convert_children)
 | |
| {
 | |
| 	/* If scripting is not enabled display the contents of canvas */
 | |
| 	if (!content->enable_scripting) {
 | |
| 		return true;
 | |
| 	}
 | |
| 	*convert_children = false;
 | |
| 
 | |
| 	if (box->style && ns_computed_display(box->style,
 | |
| 			box_is_root(n)) == CSS_DISPLAY_NONE)
 | |
| 		return true;
 | |
| 
 | |
| 	/* This is replaced content */
 | |
| 	box->flags |= IS_REPLACED | REPLACE_DIM;
 | |
| 
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Embedded object (not in any HTML specification:
 | |
|  * see http://wp.netscape.com/assist/net_sites/new_html3_prop.html )
 | |
|  */
 | |
| static bool
 | |
| box_embed(dom_node *n,
 | |
| 	  html_content *content,
 | |
| 	  struct box *box,
 | |
| 	  bool *convert_children)
 | |
| {
 | |
| 	struct object_params *params;
 | |
| 	struct object_param *param;
 | |
| 	dom_namednodemap *attrs;
 | |
| 	unsigned long idx;
 | |
| 	uint32_t num_attrs;
 | |
| 	dom_string *src;
 | |
| 	dom_exception err;
 | |
| 
 | |
| 	if (box->style && ns_computed_display(box->style,
 | |
| 			box_is_root(n)) == CSS_DISPLAY_NONE)
 | |
| 		return true;
 | |
| 
 | |
| 	params = talloc(content->bctx, struct object_params);
 | |
| 	if (params == NULL)
 | |
| 		return false;
 | |
| 
 | |
| 	talloc_set_destructor(params, box_object_talloc_destructor);
 | |
| 
 | |
| 	params->data = NULL;
 | |
| 	params->type = NULL;
 | |
| 	params->codetype = NULL;
 | |
| 	params->codebase = NULL;
 | |
| 	params->classid = NULL;
 | |
| 	params->params = NULL;
 | |
| 
 | |
| 	/* src is a URL */
 | |
| 	err = dom_element_get_attribute(n, corestring_dom_src, &src);
 | |
| 	if (err != DOM_NO_ERR || src == NULL)
 | |
| 		return true;
 | |
| 	if (box_extract_link(content, src, content->base_url,
 | |
| 			     ¶ms->data) == false) {
 | |
| 		dom_string_unref(src);
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	dom_string_unref(src);
 | |
| 
 | |
| 	if (params->data == NULL)
 | |
| 		return true;
 | |
| 
 | |
| 	/* Don't include ourself */
 | |
| 	if (nsurl_compare(content->base_url, params->data, NSURL_COMPLETE))
 | |
| 		return true;
 | |
| 
 | |
| 	/* add attributes as parameters to linked list */
 | |
| 	err = dom_node_get_attributes(n, &attrs);
 | |
| 	if (err != DOM_NO_ERR)
 | |
| 		return false;
 | |
| 
 | |
| 	err = dom_namednodemap_get_length(attrs, &num_attrs);
 | |
| 	if (err != DOM_NO_ERR) {
 | |
| 		dom_namednodemap_unref(attrs);
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	for (idx = 0; idx < num_attrs; idx++) {
 | |
| 		dom_attr *attr;
 | |
| 		dom_string *name, *value;
 | |
| 
 | |
| 		err = dom_namednodemap_item(attrs, idx, (void *) &attr);
 | |
| 		if (err != DOM_NO_ERR) {
 | |
| 			dom_namednodemap_unref(attrs);
 | |
| 			return false;
 | |
| 		}
 | |
| 
 | |
| 		err = dom_attr_get_name(attr, &name);
 | |
| 		if (err != DOM_NO_ERR) {
 | |
| 			dom_node_unref(attr);
 | |
| 			dom_namednodemap_unref(attrs);
 | |
| 			return false;
 | |
| 		}
 | |
| 
 | |
| 		if (dom_string_caseless_lwc_isequal(name, corestring_lwc_src)) {
 | |
| 			dom_node_unref(attr);
 | |
| 			dom_string_unref(name);
 | |
| 			continue;
 | |
| 		}
 | |
| 
 | |
| 		err = dom_attr_get_value(attr, &value);
 | |
| 		if (err != DOM_NO_ERR) {
 | |
| 			dom_node_unref(attr);
 | |
| 			dom_string_unref(name);
 | |
| 			dom_namednodemap_unref(attrs);
 | |
| 			return false;
 | |
| 		}
 | |
| 
 | |
| 		param = talloc(content->bctx, struct object_param);
 | |
| 		if (param == NULL) {
 | |
| 			dom_node_unref(attr);
 | |
| 			dom_string_unref(value);
 | |
| 			dom_string_unref(name);
 | |
| 			dom_namednodemap_unref(attrs);
 | |
| 			return false;
 | |
| 		}
 | |
| 
 | |
| 		param->name = talloc_strdup(content->bctx, dom_string_data(name));
 | |
| 		param->value = talloc_strdup(content->bctx, dom_string_data(value));
 | |
| 		param->type = NULL;
 | |
| 		param->valuetype = talloc_strdup(content->bctx, "data");
 | |
| 		param->next = NULL;
 | |
| 
 | |
| 		dom_string_unref(value);
 | |
| 		dom_string_unref(name);
 | |
| 		dom_node_unref(attr);
 | |
| 
 | |
| 		if (param->name == NULL || param->value == NULL ||
 | |
| 				param->valuetype == NULL) {
 | |
| 			dom_namednodemap_unref(attrs);
 | |
| 			return false;
 | |
| 		}
 | |
| 
 | |
| 		param->next = params->params;
 | |
| 		params->params = param;
 | |
| 	}
 | |
| 
 | |
| 	dom_namednodemap_unref(attrs);
 | |
| 
 | |
| 	box->object_params = params;
 | |
| 
 | |
| 	/* start fetch */
 | |
| 	box->flags |= IS_REPLACED;
 | |
| 	return html_fetch_object(content, params->data, box, CONTENT_ANY, false);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Window subdivision [16.2.1].
 | |
|  */
 | |
| static bool
 | |
| box_frameset(dom_node *n,
 | |
| 	     html_content *content,
 | |
| 	     struct box *box,
 | |
| 	     bool *convert_children)
 | |
| {
 | |
| 	bool ok;
 | |
| 
 | |
| 	if (content->frameset) {
 | |
| 		NSLOG(netsurf, INFO, "Error: multiple framesets in document.");
 | |
| 		/* Don't convert children */
 | |
| 		if (convert_children)
 | |
| 			*convert_children = false;
 | |
| 		/* And ignore this spurious frameset */
 | |
| 		box->type = BOX_NONE;
 | |
| 		return true;
 | |
| 	}
 | |
| 
 | |
| 	content->frameset = talloc_zero(content->bctx,
 | |
| 					struct content_html_frames);
 | |
| 	if (!content->frameset) {
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	ok = box_create_frameset(content->frameset, n, content);
 | |
| 	if (ok) {
 | |
| 		box->type = BOX_NONE;
 | |
| 	}
 | |
| 
 | |
| 	if (convert_children) {
 | |
| 		*convert_children = false;
 | |
| 	}
 | |
| 	return ok;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Inline subwindow [16.5].
 | |
|  */
 | |
| static bool
 | |
| box_iframe(dom_node *n,
 | |
| 	   html_content *content,
 | |
| 	   struct box *box,
 | |
| 	   bool *convert_children)
 | |
| {
 | |
| 	nsurl *url;
 | |
| 	dom_string *s;
 | |
| 	dom_exception err;
 | |
| 	struct content_html_iframe *iframe;
 | |
| 	int i;
 | |
| 
 | |
| 	if (box->style && ns_computed_display(box->style,
 | |
| 			box_is_root(n)) == CSS_DISPLAY_NONE)
 | |
| 		return true;
 | |
| 
 | |
| 	if (box->style &&
 | |
| 	    css_computed_visibility(box->style) == CSS_VISIBILITY_HIDDEN) {
 | |
| 		/* Don't create iframe discriptors for invisible iframes
 | |
| 		 * TODO: handle hidden iframes at browser_window generation
 | |
| 		 * time instead? */
 | |
| 		return true;
 | |
| 	}
 | |
| 
 | |
| 	/* get frame URL */
 | |
| 	err = dom_element_get_attribute(n, corestring_dom_src, &s);
 | |
| 	if (err != DOM_NO_ERR || s == NULL)
 | |
| 		return true;
 | |
| 	if (box_extract_link(content, s, content->base_url, &url) == false) {
 | |
| 		dom_string_unref(s);
 | |
| 		return false;
 | |
| 	}
 | |
| 	dom_string_unref(s);
 | |
| 	if (url == NULL)
 | |
| 		return true;
 | |
| 
 | |
| 	/* don't include ourself */
 | |
| 	if (nsurl_compare(content->base_url, url, NSURL_COMPLETE)) {
 | |
| 		nsurl_unref(url);
 | |
| 		return true;
 | |
| 	}
 | |
| 
 | |
| 	/* create a new iframe */
 | |
| 	iframe = talloc(content->bctx, struct content_html_iframe);
 | |
| 	if (iframe == NULL) {
 | |
| 		nsurl_unref(url);
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	talloc_set_destructor(iframe, box_iframes_talloc_destructor);
 | |
| 
 | |
| 	iframe->box = box;
 | |
| 	iframe->margin_width = 0;
 | |
| 	iframe->margin_height = 0;
 | |
| 	iframe->name = NULL;
 | |
| 	iframe->url = url;
 | |
| 	iframe->scrolling = BW_SCROLLING_AUTO;
 | |
| 	iframe->border = true;
 | |
| 
 | |
| 	/* Add this iframe to the linked list of iframes */
 | |
| 	iframe->next = content->iframe;
 | |
| 	content->iframe = iframe;
 | |
| 
 | |
| 	/* fill in specified values */
 | |
| 	err = dom_element_get_attribute(n, corestring_dom_name, &s);
 | |
| 	if (err == DOM_NO_ERR && s != NULL) {
 | |
| 		iframe->name = talloc_strdup(content->bctx, dom_string_data(s));
 | |
| 		dom_string_unref(s);
 | |
| 	}
 | |
| 
 | |
| 	err = dom_element_get_attribute(n, corestring_dom_frameborder, &s);
 | |
| 	if (err == DOM_NO_ERR && s != NULL) {
 | |
| 		i = atoi(dom_string_data(s));
 | |
| 		iframe->border = (i != 0);
 | |
| 		dom_string_unref(s);
 | |
| 	}
 | |
| 
 | |
| 	err = dom_element_get_attribute(n, corestring_dom_bordercolor, &s);
 | |
| 	if (err == DOM_NO_ERR && s != NULL) {
 | |
| 		css_color color;
 | |
| 
 | |
| 		if (nscss_parse_colour(dom_string_data(s), &color))
 | |
| 			iframe->border_colour = nscss_color_to_ns(color);
 | |
| 
 | |
| 		dom_string_unref(s);
 | |
| 	}
 | |
| 
 | |
| 	err = dom_element_get_attribute(n, corestring_dom_scrolling, &s);
 | |
| 	if (err == DOM_NO_ERR && s != NULL) {
 | |
| 		if (dom_string_caseless_lwc_isequal(s,
 | |
| 				corestring_lwc_yes))
 | |
| 			iframe->scrolling = BW_SCROLLING_YES;
 | |
| 		else if (dom_string_caseless_lwc_isequal(s,
 | |
| 				corestring_lwc_no))
 | |
| 			iframe->scrolling = BW_SCROLLING_NO;
 | |
| 		dom_string_unref(s);
 | |
| 	}
 | |
| 
 | |
| 	err = dom_element_get_attribute(n, corestring_dom_marginwidth, &s);
 | |
| 	if (err == DOM_NO_ERR && s != NULL) {
 | |
| 		iframe->margin_width = atoi(dom_string_data(s));
 | |
| 		dom_string_unref(s);
 | |
| 	}
 | |
| 
 | |
| 	err = dom_element_get_attribute(n, corestring_dom_marginheight, &s);
 | |
| 	if (err == DOM_NO_ERR && s != NULL) {
 | |
| 		iframe->margin_height = atoi(dom_string_data(s));
 | |
| 		dom_string_unref(s);
 | |
| 	}
 | |
| 
 | |
| 	/* box */
 | |
| 	assert(box->style);
 | |
| 	box->flags |= IFRAME;
 | |
| 	box->flags |= IS_REPLACED;
 | |
| 
 | |
| 	/* Showing iframe, so don't show alternate content */
 | |
| 	if (convert_children)
 | |
| 		*convert_children = false;
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Embedded image [13.2].
 | |
|  */
 | |
| static bool
 | |
| box_image(dom_node *n,
 | |
| 	  html_content *content,
 | |
| 	  struct box *box,
 | |
| 	  bool *convert_children)
 | |
| {
 | |
| 	bool ok;
 | |
| 	dom_string *s;
 | |
| 	dom_exception err;
 | |
| 	nsurl *url;
 | |
| 	enum css_width_e wtype;
 | |
| 	enum css_height_e htype;
 | |
| 	css_fixed value = 0;
 | |
| 	css_unit wunit = CSS_UNIT_PX;
 | |
| 	css_unit hunit = CSS_UNIT_PX;
 | |
| 
 | |
| 	if (box->style && ns_computed_display(box->style,
 | |
| 			box_is_root(n)) == CSS_DISPLAY_NONE)
 | |
| 		return true;
 | |
| 
 | |
| 	/* handle alt text */
 | |
| 	err = dom_element_get_attribute(n, corestring_dom_alt, &s);
 | |
| 	if (err == DOM_NO_ERR && s != NULL) {
 | |
| 		char *alt = squash_whitespace(dom_string_data(s));
 | |
| 		dom_string_unref(s);
 | |
| 		if (alt == NULL)
 | |
| 			return false;
 | |
| 		box->text = talloc_strdup(content->bctx, alt);
 | |
| 		free(alt);
 | |
| 		if (box->text == NULL)
 | |
| 			return false;
 | |
| 		box->length = strlen(box->text);
 | |
| 	}
 | |
| 
 | |
| 	if (nsoption_bool(foreground_images) == false) {
 | |
| 		return true;
 | |
| 	}
 | |
| 
 | |
| 	/* imagemap associated with this image */
 | |
| 	if (!box_get_attribute(n, "usemap", content->bctx, &box->usemap))
 | |
| 		return false;
 | |
| 	if (box->usemap && box->usemap[0] == '#')
 | |
| 		box->usemap++;
 | |
| 
 | |
| 	/* get image URL */
 | |
| 	err = dom_element_get_attribute(n, corestring_dom_src, &s);
 | |
| 	if (err != DOM_NO_ERR || s == NULL)
 | |
| 		return true;
 | |
| 
 | |
| 	if (box_extract_link(content, s, content->base_url, &url) == false) {
 | |
| 		dom_string_unref(s);
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	dom_string_unref(s);
 | |
| 
 | |
| 	if (url == NULL)
 | |
| 		return true;
 | |
| 
 | |
| 	/* start fetch */
 | |
| 	box->flags |= IS_REPLACED;
 | |
| 	ok = html_fetch_object(content, url, box, image_types, false);
 | |
| 	nsurl_unref(url);
 | |
| 
 | |
| 	wtype = css_computed_width(box->style, &value, &wunit);
 | |
| 	htype = css_computed_height(box->style, &value, &hunit);
 | |
| 
 | |
| 	if (wtype == CSS_WIDTH_SET &&
 | |
| 	    wunit != CSS_UNIT_PCT &&
 | |
| 	    htype == CSS_HEIGHT_SET &&
 | |
| 	    hunit != CSS_UNIT_PCT) {
 | |
| 		/* We know the dimensions the image will be shown at
 | |
| 		 * before it's fetched. */
 | |
| 		box->flags |= REPLACE_DIM;
 | |
| 	}
 | |
| 
 | |
| 	return ok;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Form control [17.4].
 | |
|  */
 | |
| static bool
 | |
| box_input(dom_node *n,
 | |
| 	  html_content *content,
 | |
| 	  struct box *box,
 | |
| 	  bool *convert_children)
 | |
| {
 | |
| 	struct form_control *gadget;
 | |
| 	dom_string *type = NULL;
 | |
| 	dom_exception err;
 | |
| 	nsurl *url;
 | |
| 	nserror error;
 | |
| 
 | |
| 	gadget = html_forms_get_control_for_node(content->forms, n);
 | |
| 	if (gadget == NULL) {
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	box->gadget = gadget;
 | |
| 	box->flags |= IS_REPLACED;
 | |
| 	gadget->box = box;
 | |
| 	gadget->html = content;
 | |
| 
 | |
| 	/* get entry type */
 | |
| 	err = dom_element_get_attribute(n, corestring_dom_type, &type);
 | |
| 	if ((err != DOM_NO_ERR) || (type == NULL)) {
 | |
| 		/* no type so "text" is assumed */
 | |
| 		if (box_input_text(content, box, n) == false) {
 | |
| 			return false;
 | |
| 		}
 | |
| 		*convert_children = false;
 | |
| 		return true;
 | |
| 	}
 | |
| 
 | |
| 	if (dom_string_caseless_lwc_isequal(type, corestring_lwc_password)) {
 | |
| 		if (box_input_text(content, box, n) == false)
 | |
| 			goto no_memory;
 | |
| 
 | |
| 	} else if (dom_string_caseless_lwc_isequal(type, corestring_lwc_file)) {
 | |
| 		box->type = BOX_INLINE_BLOCK;
 | |
| 
 | |
| 	} else if (dom_string_caseless_lwc_isequal(type,
 | |
| 			corestring_lwc_hidden)) {
 | |
| 		/* no box for hidden inputs */
 | |
| 		box->type = BOX_NONE;
 | |
| 
 | |
| 	} else if ((dom_string_caseless_lwc_isequal(type,
 | |
| 				corestring_lwc_checkbox) ||
 | |
| 			dom_string_caseless_lwc_isequal(type,
 | |
| 				corestring_lwc_radio))) {
 | |
| 
 | |
| 	} else if (dom_string_caseless_lwc_isequal(type,
 | |
| 				corestring_lwc_submit) ||
 | |
| 			dom_string_caseless_lwc_isequal(type,
 | |
| 				corestring_lwc_reset) ||
 | |
| 			dom_string_caseless_lwc_isequal(type,
 | |
| 				corestring_lwc_button)) {
 | |
| 		struct box *inline_container, *inline_box;
 | |
| 
 | |
| 		if (box_button(n, content, box, 0) == false)
 | |
| 			goto no_memory;
 | |
| 
 | |
| 		inline_container = box_create(NULL, 0, false, 0, 0, 0, 0,
 | |
| 				content->bctx);
 | |
| 		if (inline_container == NULL)
 | |
| 			goto no_memory;
 | |
| 
 | |
| 		inline_container->type = BOX_INLINE_CONTAINER;
 | |
| 
 | |
| 		inline_box = box_create(NULL, box->style, false, 0, 0,
 | |
| 				box->title, 0, content->bctx);
 | |
| 		if (inline_box == NULL)
 | |
| 			goto no_memory;
 | |
| 
 | |
| 		inline_box->type = BOX_TEXT;
 | |
| 
 | |
| 		if (box->gadget->value != NULL)
 | |
| 			inline_box->text = talloc_strdup(content->bctx,
 | |
| 					box->gadget->value);
 | |
| 		else if (box->gadget->type == GADGET_SUBMIT)
 | |
| 			inline_box->text = talloc_strdup(content->bctx,
 | |
| 					messages_get("Form_Submit"));
 | |
| 		else if (box->gadget->type == GADGET_RESET)
 | |
| 			inline_box->text = talloc_strdup(content->bctx,
 | |
| 					messages_get("Form_Reset"));
 | |
| 		else
 | |
| 			inline_box->text = talloc_strdup(content->bctx,
 | |
| 							 "Button");
 | |
| 
 | |
| 		if (inline_box->text == NULL)
 | |
| 			goto no_memory;
 | |
| 
 | |
| 		inline_box->length = strlen(inline_box->text);
 | |
| 
 | |
| 		box_add_child(inline_container, inline_box);
 | |
| 
 | |
| 		box_add_child(box, inline_container);
 | |
| 
 | |
| 	} else if (dom_string_caseless_lwc_isequal(type,
 | |
| 						   corestring_lwc_image)) {
 | |
| 		gadget->type = GADGET_IMAGE;
 | |
| 
 | |
| 		if (box->style && ns_computed_display(box->style,
 | |
| 				box_is_root(n)) != CSS_DISPLAY_NONE &&
 | |
| 				nsoption_bool(foreground_images) == true) {
 | |
| 			dom_string *s;
 | |
| 
 | |
| 			err = dom_element_get_attribute(n, corestring_dom_src, &s);
 | |
| 			if (err == DOM_NO_ERR && s != NULL) {
 | |
| 				error = nsurl_join(content->base_url,
 | |
| 						dom_string_data(s), &url);
 | |
| 				dom_string_unref(s);
 | |
| 				if (error != NSERROR_OK)
 | |
| 					goto no_memory;
 | |
| 
 | |
| 				/* if url is equivalent to the parent's url,
 | |
| 				 * we've got infinite inclusion. stop it here
 | |
| 				 */
 | |
| 				if (nsurl_compare(url, content->base_url,
 | |
| 						NSURL_COMPLETE) == false) {
 | |
| 					if (!html_fetch_object(content,
 | |
| 							       url,
 | |
| 							       box,
 | |
| 							       image_types,
 | |
| 							       false)) {
 | |
| 						nsurl_unref(url);
 | |
| 						goto no_memory;
 | |
| 					}
 | |
| 				}
 | |
| 				nsurl_unref(url);
 | |
| 			}
 | |
| 		}
 | |
| 	} else {
 | |
| 		/* unhandled type the default is "text" */
 | |
| 		if (box_input_text(content, box, n) == false)
 | |
| 			goto no_memory;
 | |
| 	}
 | |
| 
 | |
| 	dom_string_unref(type);
 | |
| 
 | |
| 	*convert_children = false;
 | |
| 
 | |
| 	return true;
 | |
| 
 | |
| no_memory:
 | |
| 	dom_string_unref(type);
 | |
| 
 | |
| 	return false;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Noscript element
 | |
|  */
 | |
| static bool
 | |
| box_noscript(dom_node *n,
 | |
| 	     html_content *content,
 | |
| 	     struct box *box,
 | |
| 	     bool *convert_children)
 | |
| {
 | |
| 	/* If scripting is enabled, do not display the contents of noscript */
 | |
| 	if (content->enable_scripting) {
 | |
| 		*convert_children = false;
 | |
| 	}
 | |
| 
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Generic embedded object [13.3].
 | |
|  */
 | |
| static bool
 | |
| box_object(dom_node *n,
 | |
| 	   html_content *content,
 | |
| 	   struct box *box,
 | |
| 	   bool *convert_children)
 | |
| {
 | |
| 	struct object_params *params;
 | |
| 	struct object_param *param;
 | |
| 	dom_string *codebase, *classid, *data;
 | |
| 	dom_node *c;
 | |
| 	dom_exception err;
 | |
| 
 | |
| 	if (box->style && ns_computed_display(box->style,
 | |
| 			box_is_root(n)) == CSS_DISPLAY_NONE)
 | |
| 		return true;
 | |
| 
 | |
| 	if (box_get_attribute(n, "usemap", content->bctx, &box->usemap) ==
 | |
| 			false)
 | |
| 		return false;
 | |
| 	if (box->usemap && box->usemap[0] == '#')
 | |
| 		box->usemap++;
 | |
| 
 | |
| 	params = talloc(content->bctx, struct object_params);
 | |
| 	if (params == NULL)
 | |
| 		return false;
 | |
| 
 | |
| 	talloc_set_destructor(params, box_object_talloc_destructor);
 | |
| 
 | |
| 	params->data = NULL;
 | |
| 	params->type = NULL;
 | |
| 	params->codetype = NULL;
 | |
| 	params->codebase = NULL;
 | |
| 	params->classid = NULL;
 | |
| 	params->params = NULL;
 | |
| 
 | |
| 	/* codebase, classid, and data are URLs
 | |
| 	 * (codebase is the base for the other two) */
 | |
| 	err = dom_element_get_attribute(n, corestring_dom_codebase, &codebase);
 | |
| 	if (err == DOM_NO_ERR && codebase != NULL) {
 | |
| 		if (box_extract_link(content, codebase,	content->base_url,
 | |
| 				¶ms->codebase) == false) {
 | |
| 			dom_string_unref(codebase);
 | |
| 			return false;
 | |
| 		}
 | |
| 		dom_string_unref(codebase);
 | |
| 	}
 | |
| 	if (params->codebase == NULL)
 | |
| 		params->codebase = nsurl_ref(content->base_url);
 | |
| 
 | |
| 	err = dom_element_get_attribute(n, corestring_dom_classid, &classid);
 | |
| 	if (err == DOM_NO_ERR && classid != NULL) {
 | |
| 		if (box_extract_link(content, classid,
 | |
| 				params->codebase, ¶ms->classid) == false) {
 | |
| 			dom_string_unref(classid);
 | |
| 			return false;
 | |
| 		}
 | |
| 		dom_string_unref(classid);
 | |
| 	}
 | |
| 
 | |
| 	err = dom_element_get_attribute(n, corestring_dom_data, &data);
 | |
| 	if (err == DOM_NO_ERR && data != NULL) {
 | |
| 		if (box_extract_link(content, data,
 | |
| 				params->codebase, ¶ms->data) == false) {
 | |
| 			dom_string_unref(data);
 | |
| 			return false;
 | |
| 		}
 | |
| 		dom_string_unref(data);
 | |
| 	}
 | |
| 
 | |
| 	if (params->classid == NULL && params->data == NULL)
 | |
| 		/* nothing to embed; ignore */
 | |
| 		return true;
 | |
| 
 | |
| 	/* Don't include ourself */
 | |
| 	if (params->classid != NULL && nsurl_compare(content->base_url,
 | |
| 			params->classid, NSURL_COMPLETE))
 | |
| 		return true;
 | |
| 
 | |
| 	if (params->data != NULL && nsurl_compare(content->base_url,
 | |
| 			params->data, NSURL_COMPLETE))
 | |
| 		return true;
 | |
| 
 | |
| 	/* codetype and type are MIME types */
 | |
| 	if (box_get_attribute(n, "codetype", params,
 | |
| 			¶ms->codetype) == false)
 | |
| 		return false;
 | |
| 	if (box_get_attribute(n, "type", params, ¶ms->type) == false)
 | |
| 		return false;
 | |
| 
 | |
| 	/* classid && !data => classid is used (consult codetype)
 | |
| 	 * (classid || !classid) && data => data is used (consult type)
 | |
| 	 * !classid && !data => invalid; ignored */
 | |
| 
 | |
| 	if (params->classid != NULL && params->data == NULL &&
 | |
| 			params->codetype != NULL) {
 | |
| 		lwc_string *icodetype;
 | |
| 		lwc_error lerror;
 | |
| 
 | |
| 		lerror = lwc_intern_string(params->codetype,
 | |
| 				strlen(params->codetype), &icodetype);
 | |
| 		if (lerror != lwc_error_ok)
 | |
| 			return false;
 | |
| 
 | |
| 		if (content_factory_type_from_mime_type(icodetype) ==
 | |
| 				CONTENT_NONE) {
 | |
| 			/* can't handle this MIME type */
 | |
| 			lwc_string_unref(icodetype);
 | |
| 			return true;
 | |
| 		}
 | |
| 
 | |
| 		lwc_string_unref(icodetype);
 | |
| 	}
 | |
| 
 | |
| 	if (params->data != NULL && params->type != NULL) {
 | |
| 		lwc_string *itype;
 | |
| 		lwc_error lerror;
 | |
| 
 | |
| 		lerror = lwc_intern_string(params->type, strlen(params->type),
 | |
| 				&itype);
 | |
| 		if (lerror != lwc_error_ok)
 | |
| 			return false;
 | |
| 
 | |
| 		if (content_factory_type_from_mime_type(itype) ==
 | |
| 				CONTENT_NONE) {
 | |
| 			/* can't handle this MIME type */
 | |
| 			lwc_string_unref(itype);
 | |
| 			return true;
 | |
| 		}
 | |
| 
 | |
| 		lwc_string_unref(itype);
 | |
| 	}
 | |
| 
 | |
| 	/* add parameters to linked list */
 | |
| 	err = dom_node_get_first_child(n, &c);
 | |
| 	if (err != DOM_NO_ERR)
 | |
| 		return false;
 | |
| 
 | |
| 	while (c != NULL) {
 | |
| 		dom_node *next;
 | |
| 		dom_node_type type;
 | |
| 
 | |
| 		err = dom_node_get_node_type(c, &type);
 | |
| 		if (err != DOM_NO_ERR) {
 | |
| 			dom_node_unref(c);
 | |
| 			return false;
 | |
| 		}
 | |
| 
 | |
| 		if (type == DOM_ELEMENT_NODE) {
 | |
| 			dom_string *name;
 | |
| 
 | |
| 			err = dom_node_get_node_name(c, &name);
 | |
| 			if (err != DOM_NO_ERR) {
 | |
| 				dom_node_unref(c);
 | |
| 				return false;
 | |
| 			}
 | |
| 
 | |
| 			if (!dom_string_caseless_lwc_isequal(name,
 | |
| 					corestring_lwc_param)) {
 | |
| 				/* The first non-param child is the start of
 | |
| 				 * the alt html. Therefore, we should break
 | |
| 				 * out of this loop. */
 | |
| 				dom_string_unref(name);
 | |
| 				dom_node_unref(c);
 | |
| 				break;
 | |
| 			}
 | |
| 			dom_string_unref(name);
 | |
| 
 | |
| 			param = talloc(params, struct object_param);
 | |
| 			if (param == NULL) {
 | |
| 				dom_node_unref(c);
 | |
| 				return false;
 | |
| 			}
 | |
| 			param->name = NULL;
 | |
| 			param->value = NULL;
 | |
| 			param->type = NULL;
 | |
| 			param->valuetype = NULL;
 | |
| 			param->next = NULL;
 | |
| 
 | |
| 			if (box_get_attribute(c, "name", param,
 | |
| 					¶m->name) == false) {
 | |
| 				dom_node_unref(c);
 | |
| 				return false;
 | |
| 			}
 | |
| 
 | |
| 			if (box_get_attribute(c, "value", param,
 | |
| 					¶m->value) == false) {
 | |
| 				dom_node_unref(c);
 | |
| 				return false;
 | |
| 			}
 | |
| 
 | |
| 			if (box_get_attribute(c, "type", param,
 | |
| 					¶m->type) == false) {
 | |
| 				dom_node_unref(c);
 | |
| 				return false;
 | |
| 			}
 | |
| 
 | |
| 			if (box_get_attribute(c, "valuetype", param,
 | |
| 					¶m->valuetype) == false) {
 | |
| 				dom_node_unref(c);
 | |
| 				return false;
 | |
| 			}
 | |
| 
 | |
| 			if (param->valuetype == NULL) {
 | |
| 				param->valuetype = talloc_strdup(param, "data");
 | |
| 				if (param->valuetype == NULL) {
 | |
| 					dom_node_unref(c);
 | |
| 					return false;
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			param->next = params->params;
 | |
| 			params->params = param;
 | |
| 		}
 | |
| 
 | |
| 		err = dom_node_get_next_sibling(c, &next);
 | |
| 		if (err != DOM_NO_ERR) {
 | |
| 			dom_node_unref(c);
 | |
| 			return false;
 | |
| 		}
 | |
| 
 | |
| 		dom_node_unref(c);
 | |
| 		c = next;
 | |
| 	}
 | |
| 
 | |
| 	box->object_params = params;
 | |
| 
 | |
| 	/* start fetch (MIME type is ok or not specified) */
 | |
| 	box->flags |= IS_REPLACED;
 | |
| 	if (!html_fetch_object(content,
 | |
| 			       params->data ? params->data : params->classid,
 | |
| 			       box,
 | |
| 			       CONTENT_ANY,
 | |
| 			       false))
 | |
| 		return false;
 | |
| 
 | |
| 	*convert_children = false;
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Preformatted text [9.3.4].
 | |
|  */
 | |
| static bool
 | |
| box_pre(dom_node *n,
 | |
| 	html_content *content,
 | |
| 	struct box *box,
 | |
| 	bool *convert_children)
 | |
| {
 | |
| 	box->flags |= PRE_STRIP;
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Option selector [17.6].
 | |
|  */
 | |
| static bool
 | |
| box_select(dom_node *n,
 | |
| 	   html_content *content,
 | |
| 	   struct box *box,
 | |
| 	   bool *convert_children)
 | |
| {
 | |
| 	struct box *inline_container;
 | |
| 	struct box *inline_box;
 | |
| 	struct form_control *gadget;
 | |
| 	dom_node *c, *c2;
 | |
| 	dom_node *next, *next2;
 | |
| 	dom_exception err;
 | |
| 
 | |
| 	gadget = html_forms_get_control_for_node(content->forms, n);
 | |
| 	if (gadget == NULL)
 | |
| 		return false;
 | |
| 
 | |
| 	gadget->html = content;
 | |
| 	err = dom_node_get_first_child(n, &c);
 | |
| 	if (err != DOM_NO_ERR) {
 | |
| 		form_free_control(gadget);
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	while (c != NULL) {
 | |
| 		dom_string *name;
 | |
| 
 | |
| 		err = dom_node_get_node_name(c, &name);
 | |
| 		if (err != DOM_NO_ERR) {
 | |
| 			dom_node_unref(c);
 | |
| 			form_free_control(gadget);
 | |
| 			return false;
 | |
| 		}
 | |
| 
 | |
| 		if (dom_string_caseless_lwc_isequal(name,
 | |
| 				corestring_lwc_option)) {
 | |
| 			dom_string_unref(name);
 | |
| 
 | |
| 			if (box_select_add_option(gadget, c) == false) {
 | |
| 				dom_node_unref(c);
 | |
| 				form_free_control(gadget);
 | |
| 				return false;
 | |
| 			}
 | |
| 		} else if (dom_string_caseless_lwc_isequal(name,
 | |
| 				corestring_lwc_optgroup)) {
 | |
| 			dom_string_unref(name);
 | |
| 
 | |
| 			err = dom_node_get_first_child(c, &c2);
 | |
| 			if (err != DOM_NO_ERR) {
 | |
| 				dom_node_unref(c);
 | |
| 				form_free_control(gadget);
 | |
| 				return false;
 | |
| 			}
 | |
| 
 | |
| 			while (c2 != NULL) {
 | |
| 				dom_string *c2_name;
 | |
| 
 | |
| 				err = dom_node_get_node_name(c2, &c2_name);
 | |
| 				if (err != DOM_NO_ERR) {
 | |
| 					dom_node_unref(c2);
 | |
| 					dom_node_unref(c);
 | |
| 					form_free_control(gadget);
 | |
| 					return false;
 | |
| 				}
 | |
| 
 | |
| 				if (dom_string_caseless_lwc_isequal(c2_name,
 | |
| 						corestring_lwc_option)) {
 | |
| 					dom_string_unref(c2_name);
 | |
| 
 | |
| 					if (box_select_add_option(gadget,
 | |
| 							c2) == false) {
 | |
| 						dom_node_unref(c2);
 | |
| 						dom_node_unref(c);
 | |
| 						form_free_control(gadget);
 | |
| 						return false;
 | |
| 					}
 | |
| 				} else {
 | |
| 					dom_string_unref(c2_name);
 | |
| 				}
 | |
| 
 | |
| 				err = dom_node_get_next_sibling(c2, &next2);
 | |
| 				if (err != DOM_NO_ERR) {
 | |
| 					dom_node_unref(c2);
 | |
| 					dom_node_unref(c);
 | |
| 					form_free_control(gadget);
 | |
| 					return false;
 | |
| 				}
 | |
| 
 | |
| 				dom_node_unref(c2);
 | |
| 				c2 = next2;
 | |
| 			}
 | |
| 		} else {
 | |
| 			dom_string_unref(name);
 | |
| 		}
 | |
| 
 | |
| 		err = dom_node_get_next_sibling(c, &next);
 | |
| 		if (err != DOM_NO_ERR) {
 | |
| 			dom_node_unref(c);
 | |
| 			form_free_control(gadget);
 | |
| 			return false;
 | |
| 		}
 | |
| 
 | |
| 		dom_node_unref(c);
 | |
| 		c = next;
 | |
| 	}
 | |
| 
 | |
| 	if (gadget->data.select.num_items == 0) {
 | |
| 		/* no options: ignore entire select */
 | |
| 		form_free_control(gadget);
 | |
| 		return true;
 | |
| 	}
 | |
| 
 | |
| 	box->type = BOX_INLINE_BLOCK;
 | |
| 	box->gadget = gadget;
 | |
| 	box->flags |= IS_REPLACED;
 | |
| 	gadget->box = box;
 | |
| 
 | |
| 	inline_container = box_create(NULL, 0, false, 0, 0, 0, 0, content->bctx);
 | |
| 	if (inline_container == NULL)
 | |
| 		goto no_memory;
 | |
| 	inline_container->type = BOX_INLINE_CONTAINER;
 | |
| 	inline_box = box_create(NULL, box->style, false, 0, 0, box->title, 0,
 | |
| 			content->bctx);
 | |
| 	if (inline_box == NULL)
 | |
| 		goto no_memory;
 | |
| 	inline_box->type = BOX_TEXT;
 | |
| 	box_add_child(inline_container, inline_box);
 | |
| 	box_add_child(box, inline_container);
 | |
| 
 | |
| 	if (gadget->data.select.multiple == false &&
 | |
| 			gadget->data.select.num_selected == 0) {
 | |
| 		gadget->data.select.current = gadget->data.select.items;
 | |
| 		gadget->data.select.current->initial_selected =
 | |
| 			gadget->data.select.current->selected = true;
 | |
| 		gadget->data.select.num_selected = 1;
 | |
| 		dom_html_option_element_set_selected(
 | |
| 				gadget->data.select.current->node, true);
 | |
| 	}
 | |
| 
 | |
| 	if (gadget->data.select.num_selected == 0)
 | |
| 		inline_box->text = talloc_strdup(content->bctx,
 | |
| 				messages_get("Form_None"));
 | |
| 	else if (gadget->data.select.num_selected == 1)
 | |
| 		inline_box->text = talloc_strdup(content->bctx,
 | |
| 				gadget->data.select.current->text);
 | |
| 	else
 | |
| 		inline_box->text = talloc_strdup(content->bctx,
 | |
| 				messages_get("Form_Many"));
 | |
| 	if (inline_box->text == NULL)
 | |
| 		goto no_memory;
 | |
| 
 | |
| 	inline_box->length = strlen(inline_box->text);
 | |
| 
 | |
| 	*convert_children = false;
 | |
| 	return true;
 | |
| 
 | |
| no_memory:
 | |
| 	return false;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Multi-line text field [17.7].
 | |
|  */
 | |
| static bool box_textarea(dom_node *n,
 | |
| 			html_content *content,
 | |
| 			struct box *box,
 | |
| 			bool *convert_children)
 | |
| {
 | |
| 	/* Get the form_control for the DOM node */
 | |
| 	box->gadget = html_forms_get_control_for_node(content->forms, n);
 | |
| 	if (box->gadget == NULL)
 | |
| 		return false;
 | |
| 
 | |
| 	box->flags |= IS_REPLACED;
 | |
| 	box->gadget->html = content;
 | |
| 	box->gadget->box = box;
 | |
| 
 | |
| 	if (!box_input_text(content, box, n))
 | |
| 		return false;
 | |
| 
 | |
| 	*convert_children = false;
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * \}
 | |
|  */
 | |
| 
 | |
| 
 | |
| /* exported interface documented in html/box_special.h */
 | |
| bool
 | |
| convert_special_elements(dom_node *node,
 | |
| 			 html_content *content,
 | |
| 			 struct box *box,
 | |
| 			 bool *convert_children)
 | |
| {
 | |
| 	dom_exception exc;
 | |
| 	dom_html_element_type tag_type;
 | |
| 	bool res;
 | |
| 
 | |
| 	exc = dom_html_element_get_tag_type(node, &tag_type);
 | |
| 	if (exc != DOM_NO_ERR) {
 | |
| 		tag_type = DOM_HTML_ELEMENT_TYPE__UNKNOWN;
 | |
| 	}
 | |
| 
 | |
| 	switch (tag_type) {
 | |
| 	case DOM_HTML_ELEMENT_TYPE_A:
 | |
| 		res =  box_a(node, content, box, convert_children);
 | |
| 		break;
 | |
| 
 | |
| 	case DOM_HTML_ELEMENT_TYPE_BODY:
 | |
| 		res = box_body(node, content, box, convert_children);
 | |
| 		break;
 | |
| 
 | |
| 	case DOM_HTML_ELEMENT_TYPE_BR:
 | |
| 		res = box_br(node, content, box, convert_children);
 | |
| 		break;
 | |
| 
 | |
| 	case DOM_HTML_ELEMENT_TYPE_BUTTON:
 | |
| 		res = box_button(node, content, box, convert_children);
 | |
| 		break;
 | |
| 
 | |
| 	case DOM_HTML_ELEMENT_TYPE_CANVAS:
 | |
| 		res = box_canvas(node, content, box, convert_children);
 | |
| 		break;
 | |
| 
 | |
| 	case DOM_HTML_ELEMENT_TYPE_EMBED:
 | |
| 		res = box_embed(node, content, box, convert_children);
 | |
| 		break;
 | |
| 
 | |
| 	case DOM_HTML_ELEMENT_TYPE_FRAMESET:
 | |
| 		res = box_frameset(node, content, box, convert_children);
 | |
| 		break;
 | |
| 
 | |
| 	case DOM_HTML_ELEMENT_TYPE_IFRAME:
 | |
| 		res = box_iframe(node, content, box, convert_children);
 | |
| 		break;
 | |
| 
 | |
| 	case DOM_HTML_ELEMENT_TYPE_IMG:
 | |
| 		res = box_image(node, content, box, convert_children);
 | |
| 		break;
 | |
| 
 | |
| 	case DOM_HTML_ELEMENT_TYPE_INPUT:
 | |
| 		res = box_input(node, content, box, convert_children);
 | |
| 		break;
 | |
| 
 | |
| 	case DOM_HTML_ELEMENT_TYPE_NOSCRIPT:
 | |
| 		res = box_noscript(node, content, box, convert_children);
 | |
| 		break;
 | |
| 
 | |
| 	case DOM_HTML_ELEMENT_TYPE_OBJECT:
 | |
| 		res = box_object(node, content, box, convert_children);
 | |
| 		break;
 | |
| 
 | |
| 	case DOM_HTML_ELEMENT_TYPE_PRE:
 | |
| 		res = box_pre(node, content, box, convert_children);
 | |
| 		break;
 | |
| 
 | |
| 	case DOM_HTML_ELEMENT_TYPE_SELECT:
 | |
| 		res = box_select(node, content, box, convert_children);
 | |
| 		break;
 | |
| 
 | |
| 	case DOM_HTML_ELEMENT_TYPE_TEXTAREA:
 | |
| 		res = box_textarea(node, content, box, convert_children);
 | |
| 		break;
 | |
| 
 | |
| 	default:
 | |
| 		res = true;
 | |
| 	}
 | |
| 
 | |
| 	return res;
 | |
| }
 |