1 /*
2  * Copyright 2005-2007 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 2008 Michael Drake <tlsa@netsurf-browser.org>
6  * Copyright 2020 Vincent Sanders <vince@netsurf-browser.org>
7  *
8  * This file is part of NetSurf, http://www.netsurf-browser.org/
9  *
10  * NetSurf is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; version 2 of the License.
13  *
14  * NetSurf is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 /**
24  * \file
25  * implementation of box tree manipulation.
26  */
27 
28 
29 #include "utils/errors.h"
30 #include "utils/talloc.h"
31 #include "utils/nsurl.h"
32 #include "netsurf/types.h"
33 #include "netsurf/mouse.h"
34 #include "desktop/scrollbar.h"
35 
36 #include "html/private.h"
37 #include "html/form_internal.h"
38 #include "html/interaction.h"
39 #include "html/box.h"
40 #include "html/box_manipulate.h"
41 
42 
43 /**
44  * Destructor for box nodes which own styles
45  *
46  * \param b The box being destroyed.
47  * \return 0 to allow talloc to continue destroying the tree.
48  */
box_talloc_destructor(struct box * b)49 static int box_talloc_destructor(struct box *b)
50 {
51 	struct html_scrollbar_data *data;
52 
53 	if ((b->flags & STYLE_OWNED) && b->style != NULL) {
54 		css_computed_style_destroy(b->style);
55 		b->style = NULL;
56 	}
57 
58 	if (b->styles != NULL) {
59 		css_select_results_destroy(b->styles);
60 		b->styles = NULL;
61 	}
62 
63 	if (b->href != NULL)
64 		nsurl_unref(b->href);
65 
66 	if (b->id != NULL) {
67 		lwc_string_unref(b->id);
68 	}
69 
70 	if (b->node != NULL) {
71 		dom_node_unref(b->node);
72 	}
73 
74 	if (b->scroll_x != NULL) {
75 		data = scrollbar_get_data(b->scroll_x);
76 		scrollbar_destroy(b->scroll_x);
77 		free(data);
78 	}
79 
80 	if (b->scroll_y != NULL) {
81 		data = scrollbar_get_data(b->scroll_y);
82 		scrollbar_destroy(b->scroll_y);
83 		free(data);
84 	}
85 
86 	return 0;
87 }
88 
89 
90 /* Exported function documented in html/box.h */
91 struct box *
box_create(css_select_results * styles,css_computed_style * style,bool style_owned,nsurl * href,const char * target,const char * title,lwc_string * id,void * context)92 box_create(css_select_results *styles,
93 	   css_computed_style *style,
94 	   bool style_owned,
95 	   nsurl *href,
96 	   const char *target,
97 	   const char *title,
98 	   lwc_string *id,
99 	   void *context)
100 {
101 	unsigned int i;
102 	struct box *box;
103 
104 	box = talloc(context, struct box);
105 	if (!box) {
106 		return 0;
107 	}
108 
109 	talloc_set_destructor(box, box_talloc_destructor);
110 
111 	box->type = BOX_INLINE;
112 	box->flags = 0;
113 	box->flags = style_owned ? (box->flags | STYLE_OWNED) : box->flags;
114 	box->styles = styles;
115 	box->style = style;
116 	box->x = box->y = 0;
117 	box->width = UNKNOWN_WIDTH;
118 	box->height = 0;
119 	box->descendant_x0 = box->descendant_y0 = 0;
120 	box->descendant_x1 = box->descendant_y1 = 0;
121 	for (i = 0; i != 4; i++)
122 		box->margin[i] = box->padding[i] = box->border[i].width = 0;
123 	box->scroll_x = box->scroll_y = NULL;
124 	box->min_width = 0;
125 	box->max_width = UNKNOWN_MAX_WIDTH;
126 	box->byte_offset = 0;
127 	box->text = NULL;
128 	box->length = 0;
129 	box->space = 0;
130 	box->href = (href == NULL) ? NULL : nsurl_ref(href);
131 	box->target = target;
132 	box->title = title;
133 	box->columns = 1;
134 	box->rows = 1;
135 	box->start_column = 0;
136 	box->next = NULL;
137 	box->prev = NULL;
138 	box->children = NULL;
139 	box->last = NULL;
140 	box->parent = NULL;
141 	box->inline_end = NULL;
142 	box->float_children = NULL;
143 	box->float_container = NULL;
144 	box->next_float = NULL;
145 	box->cached_place_below_level = 0;
146 	box->list_marker = NULL;
147 	box->col = NULL;
148 	box->gadget = NULL;
149 	box->usemap = NULL;
150 	box->id = id;
151 	box->background = NULL;
152 	box->object = NULL;
153 	box->object_params = NULL;
154 	box->iframe = NULL;
155 	box->node = NULL;
156 
157 	return box;
158 }
159 
160 
161 /* Exported function documented in html/box.h */
box_add_child(struct box * parent,struct box * child)162 void box_add_child(struct box *parent, struct box *child)
163 {
164 	assert(parent);
165 	assert(child);
166 
167 	if (parent->children != 0) {	/* has children already */
168 		parent->last->next = child;
169 		child->prev = parent->last;
170 	} else {			/* this is the first child */
171 		parent->children = child;
172 		child->prev = 0;
173 	}
174 
175 	parent->last = child;
176 	child->parent = parent;
177 }
178 
179 
180 /* Exported function documented in html/box.h */
box_insert_sibling(struct box * box,struct box * new_box)181 void box_insert_sibling(struct box *box, struct box *new_box)
182 {
183 	new_box->parent = box->parent;
184 	new_box->prev = box;
185 	new_box->next = box->next;
186 	box->next = new_box;
187 	if (new_box->next)
188 		new_box->next->prev = new_box;
189 	else if (new_box->parent)
190 		new_box->parent->last = new_box;
191 }
192 
193 
194 /* Exported function documented in html/box.h */
box_unlink_and_free(struct box * box)195 void box_unlink_and_free(struct box *box)
196 {
197 	struct box *parent = box->parent;
198 	struct box *next = box->next;
199 	struct box *prev = box->prev;
200 
201 	if (parent) {
202 		if (parent->children == box)
203 			parent->children = next;
204 		if (parent->last == box)
205 			parent->last = next ? next : prev;
206 	}
207 
208 	if (prev)
209 		prev->next = next;
210 	if (next)
211 		next->prev = prev;
212 
213 	box_free(box);
214 }
215 
216 
217 /* Exported function documented in html/box.h */
box_free(struct box * box)218 void box_free(struct box *box)
219 {
220 	struct box *child, *next;
221 
222 	/* free children first */
223 	for (child = box->children; child; child = next) {
224 		next = child->next;
225 		box_free(child);
226 	}
227 
228 	/* last this box */
229 	box_free_box(box);
230 }
231 
232 
233 /* Exported function documented in html/box.h */
box_free_box(struct box * box)234 void box_free_box(struct box *box)
235 {
236 	if (!(box->flags & CLONE)) {
237 		if (box->gadget)
238 			form_free_control(box->gadget);
239 		if (box->scroll_x != NULL)
240 			scrollbar_destroy(box->scroll_x);
241 		if (box->scroll_y != NULL)
242 			scrollbar_destroy(box->scroll_y);
243 		if (box->styles != NULL)
244 			css_select_results_destroy(box->styles);
245 	}
246 
247 	talloc_free(box);
248 }
249 
250 
251 /* exported interface documented in html/box.h */
252 nserror
box_handle_scrollbars(struct content * c,struct box * box,bool bottom,bool right)253 box_handle_scrollbars(struct content *c,
254 		      struct box *box,
255 		      bool bottom,
256 		      bool right)
257 {
258 	struct html_scrollbar_data *data;
259 	int visible_width, visible_height;
260 	int full_width, full_height;
261 	nserror res;
262 
263 	if (!bottom && box->scroll_x != NULL) {
264 		data = scrollbar_get_data(box->scroll_x);
265 		scrollbar_destroy(box->scroll_x);
266 		free(data);
267 		box->scroll_x = NULL;
268 	}
269 
270 	if (!right && box->scroll_y != NULL) {
271 		data = scrollbar_get_data(box->scroll_y);
272 		scrollbar_destroy(box->scroll_y);
273 		free(data);
274 		box->scroll_y = NULL;
275 	}
276 
277 	if (!bottom && !right) {
278 		return NSERROR_OK;
279 	}
280 
281 	visible_width = box->width + box->padding[RIGHT] + box->padding[LEFT];
282 	visible_height = box->height + box->padding[TOP] + box->padding[BOTTOM];
283 
284 	full_width = ((box->descendant_x1 - box->border[RIGHT].width) >
285 			visible_width) ?
286 			box->descendant_x1 + box->padding[RIGHT] :
287 			visible_width;
288 	full_height = ((box->descendant_y1 - box->border[BOTTOM].width) >
289 			visible_height) ?
290 			box->descendant_y1 + box->padding[BOTTOM] :
291 			visible_height;
292 
293 	if (right) {
294 		if (box->scroll_y == NULL) {
295 			data = malloc(sizeof(struct html_scrollbar_data));
296 			if (data == NULL) {
297 				return NSERROR_NOMEM;
298 			}
299 			data->c = c;
300 			data->box = box;
301 			res = scrollbar_create(false,
302 					       visible_height,
303 					       full_height,
304 					       visible_height,
305 					       data,
306 					       html_overflow_scroll_callback,
307 					       &(box->scroll_y));
308 			if (res != NSERROR_OK) {
309 				return res;
310 			}
311 		} else  {
312 			scrollbar_set_extents(box->scroll_y,
313 					      visible_height,
314 					      visible_height,
315 					      full_height);
316 		}
317 	}
318 	if (bottom) {
319 		if (box->scroll_x == NULL) {
320 			data = malloc(sizeof(struct html_scrollbar_data));
321 			if (data == NULL) {
322 				return NSERROR_OK;
323 			}
324 			data->c = c;
325 			data->box = box;
326 			res = scrollbar_create(true,
327 					       visible_width - (right ? SCROLLBAR_WIDTH : 0),
328 					       full_width,
329 					       visible_width,
330 					       data,
331 					       html_overflow_scroll_callback,
332 					       &box->scroll_x);
333 			if (res != NSERROR_OK) {
334 				return res;
335 			}
336 		} else {
337 			scrollbar_set_extents(box->scroll_x,
338 					visible_width -
339 					(right ? SCROLLBAR_WIDTH : 0),
340 					visible_width, full_width);
341 		}
342 	}
343 
344 	if (right && bottom) {
345 		scrollbar_make_pair(box->scroll_x, box->scroll_y);
346 	}
347 
348 	return NSERROR_OK;
349 }
350 
351 
352