Bug Summary

File:content/handlers/html/box_construct.c
Warning:line 600, column 7
Access to field 'type' results in a dereference of a null pointer (loaded from field 'containing_block')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name box_construct.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/var/lib/jenkins/workspace/scan-build-netsurf -resource-dir /usr/lib/llvm-14/lib/clang/14.0.6 -I . -I include -I build/Linux-gtk2 -I frontends -I content/handlers -D WITH_JPEG -U WITH_PDF_EXPORT -D LIBICONV_PLUG -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -I /usr/include/x86_64-linux-gnu -D WITH_CURL -D WITH_OPENSSL -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D UTF8PROC_EXPORTS -D WITH_UTF8PROC -D WITH_WEBP -I /usr/include/libpng16 -D WITH_PNG -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include/ -D WITH_BMP -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D WITH_GIF -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D WITH_NS_SVG -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D WITH_NSSPRITE -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D WITH_NSPSL -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D WITH_NSLOG -D NETSURF_UA_FORMAT_STRING="Mozilla/5.0 (%s) NetSurf/%d.%d" -D NETSURF_HOMEPAGE="about:welcome" -D NETSURF_LOG_LEVEL=VERBOSE -D NETSURF_BUILTIN_LOG_FILTER="(level:WARNING || cat:jserrors)" -D NETSURF_BUILTIN_VERBOSE_FILTER="(level:VERBOSE || cat:jserrors)" -D STMTEXPR=1 -I /usr/include/librsvg-2.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/libpng16 -I /usr/include/x86_64-linux-gnu -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/freetype2 -D WITH_RSVG -I /usr/include/gtk-2.0 -I /usr/lib/x86_64-linux-gnu/gtk-2.0/include -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/atk-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -D gtk -D nsgtk -D G_DISABLE_SINGLE_INCLUDES -D G_DISABLE_DEPRECATED -D GTK_DISABLE_SINGLE_INCLUDES -D GTK_MULTIHEAD_SAFE -D PANGO_DISABLE_DEPRECATED -D GTK_DISABLE_DEPRECATED -D _XOPEN_SOURCE=700 -D _POSIX_C_SOURCE=200809L -D _BSD_SOURCE -D _DEFAULT_SOURCE -D _NETBSD_SOURCE -D GTK_RESPATH="/var/lib/jenkins/artifacts-x86_64-linux-gnu/share/netsurf/:./frontends/gtk/res/" -D WITH_GRESOURCE -D DUK_OPT_HAVE_CUSTOM_H -internal-isystem /usr/lib/llvm-14/lib/clang/14.0.6/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wwrite-strings -Wno-unused-parameter -Wno-unused-but-set-variable -std=c99 -fconst-strings -fdebug-compilation-dir=/var/lib/jenkins/workspace/scan-build-netsurf -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-display-progress -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /var/lib/jenkins/workspace/scan-build-netsurf/clangScanBuildReports/2024-12-27-084849-3370695-1 -x c content/handlers/html/box_construct.c
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 *
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 conversion from DOM tree to box tree.
26 */
27
28#include <string.h>
29#include <dom/dom.h>
30
31#include "utils/errors.h"
32#include "utils/nsoption.h"
33#include "utils/corestrings.h"
34#include "utils/talloc.h"
35#include "utils/string.h"
36#include "utils/ascii.h"
37#include "utils/nsurl.h"
38#include "utils/utils.h"
39#include "netsurf/misc.h"
40#include "css/select.h"
41#include "desktop/gui_internal.h"
42
43#include "html/private.h"
44#include "html/object.h"
45#include "html/box.h"
46#include "html/box_manipulate.h"
47#include "html/box_construct.h"
48#include "html/box_special.h"
49#include "html/box_normalise.h"
50#include "html/form_internal.h"
51
52/**
53 * Context for box tree construction
54 */
55struct box_construct_ctx {
56 html_content *content; /**< Content we're constructing for */
57
58 dom_node *n; /**< Current node to process */
59
60 struct box *root_box; /**< Root box in the tree */
61
62 box_construct_complete_cb cb; /**< Callback to invoke on completion */
63
64 int *bctx; /**< talloc context */
65};
66
67/**
68 * Transient properties for construction of current node
69 */
70struct box_construct_props {
71 /** Style from which to inherit, or NULL if none */
72 const css_computed_style *parent_style;
73 /** Current link target, or NULL if none */
74 struct nsurl *href;
75 /** Current frame target, or NULL if none */
76 const char *target;
77 /** Current title attribute, or NULL if none */
78 const char *title;
79 /** Identity of the current block-level container */
80 struct box *containing_block;
81 /** Current container for inlines, or NULL if none
82 * \note If non-NULL, will be the last child of containing_block */
83 struct box *inline_container;
84 /** Whether the current node is the root of the DOM tree */
85 bool_Bool node_is_root;
86};
87
88static const content_type image_types = CONTENT_IMAGE;
89
90/* mapping from CSS display to box type
91 * this table must be in sync with libcss' css_display enum */
92static const box_type box_map[] = {
93 BOX_BLOCK, /* CSS_DISPLAY_INHERIT */
94 BOX_INLINE, /* CSS_DISPLAY_INLINE */
95 BOX_BLOCK, /* CSS_DISPLAY_BLOCK */
96 BOX_BLOCK, /* CSS_DISPLAY_LIST_ITEM */
97 BOX_INLINE, /* CSS_DISPLAY_RUN_IN */
98 BOX_INLINE_BLOCK, /* CSS_DISPLAY_INLINE_BLOCK */
99 BOX_TABLE, /* CSS_DISPLAY_TABLE */
100 BOX_TABLE, /* CSS_DISPLAY_INLINE_TABLE */
101 BOX_TABLE_ROW_GROUP, /* CSS_DISPLAY_TABLE_ROW_GROUP */
102 BOX_TABLE_ROW_GROUP, /* CSS_DISPLAY_TABLE_HEADER_GROUP */
103 BOX_TABLE_ROW_GROUP, /* CSS_DISPLAY_TABLE_FOOTER_GROUP */
104 BOX_TABLE_ROW, /* CSS_DISPLAY_TABLE_ROW */
105 BOX_NONE, /* CSS_DISPLAY_TABLE_COLUMN_GROUP */
106 BOX_NONE, /* CSS_DISPLAY_TABLE_COLUMN */
107 BOX_TABLE_CELL, /* CSS_DISPLAY_TABLE_CELL */
108 BOX_INLINE, /* CSS_DISPLAY_TABLE_CAPTION */
109 BOX_NONE, /* CSS_DISPLAY_NONE */
110 BOX_FLEX, /* CSS_DISPLAY_FLEX */
111 BOX_INLINE_FLEX, /* CSS_DISPLAY_INLINE_FLEX */
112 BOX_BLOCK, /* CSS_DISPLAY_GRID */
113 BOX_INLINE_BLOCK, /* CSS_DISPLAY_INLINE_GRID */
114};
115
116
117/**
118 * determine if a box is the root node
119 *
120 * \param n node to check
121 * \return true if node is root else false.
122 */
123static inline bool_Bool box_is_root(dom_node *n)
124{
125 dom_node *parent;
126 dom_node_type type;
127 dom_exception err;
128
129 err = dom_node_get_parent_node(n, &parent)dom_node_get_parent_node( (dom_node *) (n), (dom_node **) (&
parent))
;
130 if (err != DOM_NO_ERR)
131 return false0;
132
133 if (parent != NULL((void*)0)) {
134 err = dom_node_get_node_type(parent, &type)dom_node_get_node_type( (dom_node *) (parent), (dom_node_type
*) (&type))
;
135
136 dom_node_unref(parent)dom_node_unref((dom_node *) (parent));
137
138 if (err != DOM_NO_ERR)
139 return false0;
140
141 if (type != DOM_DOCUMENT_NODE)
142 return false0;
143 }
144
145 return true1;
146}
147
148/**
149 * Extract transient construction properties
150 *
151 * \param n Current DOM node to convert
152 * \param props Property object to populate
153 */
154static void
155box_extract_properties(dom_node *n, struct box_construct_props *props)
156{
157 memset(props, 0, sizeof(*props));
158
159 props->node_is_root = box_is_root(n);
160
161 /* Extract properties from containing DOM node */
162 if (props->node_is_root == false0) {
163 dom_node *current_node = n;
164 dom_node *parent_node = NULL((void*)0);
165 struct box *parent_box;
166 dom_exception err;
167
168 /* Find ancestor node containing parent box */
169 while (true1) {
170 err = dom_node_get_parent_node(current_node,dom_node_get_parent_node( (dom_node *) (current_node), (dom_node
**) (&parent_node))
171 &parent_node)dom_node_get_parent_node( (dom_node *) (current_node), (dom_node
**) (&parent_node))
;
172 if (err != DOM_NO_ERR || parent_node == NULL((void*)0))
173 break;
174
175 parent_box = box_for_node(parent_node);
176
177 if (parent_box != NULL((void*)0)) {
178 props->parent_style = parent_box->style;
179 props->href = parent_box->href;
180 props->target = parent_box->target;
181 props->title = parent_box->title;
182
183 dom_node_unref(parent_node)dom_node_unref((dom_node *) (parent_node));
184 break;
185 } else {
186 if (current_node != n)
187 dom_node_unref(current_node)dom_node_unref((dom_node *) (current_node));
188 current_node = parent_node;
189 parent_node = NULL((void*)0);
190 }
191 }
192
193 /* Find containing block (may be parent) */
194 while (true1) {
195 struct box *b;
196
197 err = dom_node_get_parent_node(current_node,dom_node_get_parent_node( (dom_node *) (current_node), (dom_node
**) (&parent_node))
198 &parent_node)dom_node_get_parent_node( (dom_node *) (current_node), (dom_node
**) (&parent_node))
;
199 if (err != DOM_NO_ERR || parent_node == NULL((void*)0)) {
200 if (current_node != n)
201 dom_node_unref(current_node)dom_node_unref((dom_node *) (current_node));
202 break;
203 }
204
205 if (current_node != n)
206 dom_node_unref(current_node)dom_node_unref((dom_node *) (current_node));
207
208 b = box_for_node(parent_node);
209
210 /* Children of nodes that created an inline box
211 * will generate boxes which are attached as
212 * _siblings_ of the box generated for their
213 * parent node. Note, however, that we'll still
214 * use the parent node's styling as the parent
215 * style, above. */
216 if (b != NULL((void*)0) && b->type != BOX_INLINE &&
217 b->type != BOX_BR) {
218 props->containing_block = b;
219
220 dom_node_unref(parent_node)dom_node_unref((dom_node *) (parent_node));
221 break;
222 } else {
223 current_node = parent_node;
224 parent_node = NULL((void*)0);
225 }
226 }
227 }
228
229 /* Compute current inline container, if any */
230 if (props->containing_block != NULL((void*)0) &&
231 props->containing_block->last != NULL((void*)0) &&
232 props->containing_block->last->type ==
233 BOX_INLINE_CONTAINER)
234 props->inline_container = props->containing_block->last;
235}
236
237
238/**
239 * Get the style for an element.
240 *
241 * \param c content of type CONTENT_HTML that is being processed
242 * \param parent_style style at this point in xml tree, or NULL for root
243 * \param root_style root node's style, or NULL for root
244 * \param n node in xml tree
245 * \return the new style, or NULL on memory exhaustion
246 */
247static css_select_results *
248box_get_style(html_content *c,
249 const css_computed_style *parent_style,
250 const css_computed_style *root_style,
251 dom_node *n)
252{
253 dom_string *s = NULL((void*)0);
254 css_stylesheet *inline_style = NULL((void*)0);
255 css_select_results *styles;
256 nscss_select_ctx ctx;
257
258 /* Firstly, construct inline stylesheet, if any */
259 if (nsoption_bool(author_level_css)(nsoptions[NSOPTION_author_level_css].value.b)) {
260 dom_exception err;
261 err = dom_element_get_attribute(n, corestring_dom_style, &s)dom_element_get_attribute( (dom_element *) (n), (corestring_dom_style
), (&s))
;
262 if (err != DOM_NO_ERR) {
263 return NULL((void*)0);
264 }
265 }
266
267 if (s != NULL((void*)0)) {
268 inline_style = nscss_create_inline_style(
269 (const uint8_t *) dom_string_data(s),
270 dom_string_byte_length(s),
271 c->encoding,
272 nsurl_access(c->base_url),
273 c->quirks != DOM_DOCUMENT_QUIRKS_MODE_NONE);
274
275 dom_string_unref(s);
276
277 if (inline_style == NULL((void*)0))
278 return NULL((void*)0);
279 }
280
281 /* Populate selection context */
282 ctx.ctx = c->select_ctx;
283 ctx.quirks = (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL);
284 ctx.base_url = c->base_url;
285 ctx.universal = c->universal;
286 ctx.root_style = root_style;
287 ctx.parent_style = parent_style;
288
289 /* Select style for element */
290 styles = nscss_get_style(&ctx, n, &c->media, &c->unit_len_ctx,
291 inline_style);
292
293 /* No longer need inline style */
294 if (inline_style != NULL((void*)0))
295 css_stylesheet_destroy(inline_style);
296
297 return styles;
298}
299
300
301/**
302 * Construct the box required for a generated element.
303 *
304 * \param n XML node of type XML_ELEMENT_NODE
305 * \param content Content of type CONTENT_HTML that is being processed
306 * \param box Box which may have generated content
307 * \param style Complete computed style for pseudo element, or NULL
308 *
309 * \todo This is currently incomplete. It just does enough to support
310 * the clearfix hack. (http://www.positioniseverything.net/easyclearing.html )
311 */
312static void
313box_construct_generate(dom_node *n,
314 html_content *content,
315 struct box *box,
316 const css_computed_style *style)
317{
318 struct box *gen = NULL((void*)0);
319 enum css_display_e computed_display;
320 const css_computed_content_item *c_item;
321
322 /* Nothing to generate if the parent box is not a block */
323 if (box->type != BOX_BLOCK)
324 return;
325
326 /* To determine if an element has a pseudo element, we select
327 * for it and test to see if the returned style's content
328 * property is set to normal. */
329 if (style == NULL((void*)0) ||
330 css_computed_content(style, &c_item) ==
331 CSS_CONTENT_NORMAL) {
332 /* No pseudo element */
333 return;
334 }
335
336 /* create box for this element */
337 computed_display = ns_computed_display(style, box_is_root(n));
338 if (computed_display == CSS_DISPLAY_BLOCK ||
339 computed_display == CSS_DISPLAY_TABLE) {
340 /* currently only support block level boxes */
341
342 /** \todo Not wise to drop const from the computed style */
343 gen = box_create(NULL((void*)0), (css_computed_style *) style,
344 false0, NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), content->bctx);
345 if (gen == NULL((void*)0)) {
346 return;
347 }
348
349 /* set box type from computed display */
350 gen->type = box_map[ns_computed_display(
351 style, box_is_root(n))];
352
353 box_add_child(box, gen);
354 }
355}
356
357
358/**
359 * Construct a list marker box
360 *
361 * \param box Box to attach marker to
362 * \param title Current title attribute
363 * \param ctx Box construction context
364 * \param parent Current block-level container
365 * \return true on success, false on memory exhaustion
366 */
367static bool_Bool
368box_construct_marker(struct box *box,
369 const char *title,
370 struct box_construct_ctx *ctx,
371 struct box *parent)
372{
373 lwc_string *image_uri;
374 struct box *marker;
375 enum css_list_style_type_e list_style_type;
376
377 marker = box_create(NULL((void*)0), box->style, false0, NULL((void*)0), NULL((void*)0), title,
378 NULL((void*)0), ctx->bctx);
379 if (marker == false0)
380 return false0;
381
382 marker->type = BOX_BLOCK;
383
384 list_style_type = css_computed_list_style_type(box->style);
385
386 /** \todo marker content (list-style-type) */
387 switch (list_style_type) {
388 case CSS_LIST_STYLE_TYPE_DISC:
389 /* 2022 BULLET */
390 marker->text = (char *) "\342\200\242";
391 marker->length = 3;
392 break;
393
394 case CSS_LIST_STYLE_TYPE_CIRCLE:
395 /* 25CB WHITE CIRCLE */
396 marker->text = (char *) "\342\227\213";
397 marker->length = 3;
398 break;
399
400 case CSS_LIST_STYLE_TYPE_SQUARE:
401 /* 25AA BLACK SMALL SQUARE */
402 marker->text = (char *) "\342\226\252";
403 marker->length = 3;
404 break;
405
406 default:
407 /* Numerical list counters get handled in layout. */
408 /* Fall through. */
409 case CSS_LIST_STYLE_TYPE_NONE:
410 marker->text = NULL((void*)0);
411 marker->length = 0;
412 break;
413 }
414
415 if (css_computed_list_style_image(box->style, &image_uri) == CSS_LIST_STYLE_IMAGE_URI &&
416 (image_uri != NULL((void*)0)) &&
417 (nsoption_bool(foreground_images)(nsoptions[NSOPTION_foreground_images].value.b) == true1)) {
418 nsurl *url;
419 nserror error;
420
421 /* TODO: we get a url out of libcss as a lwc string, but
422 * earlier we already had it as a nsurl after we
423 * nsurl_joined it. Can this be improved?
424 * For now, just making another nsurl. */
425 error = nsurl_create(lwc_string_data(image_uri)({((image_uri != ((void*)0)) ? (void) (0) : __assert_fail ("image_uri != NULL"
, "content/handlers/html/box_construct.c", 425, __extension__
__PRETTY_FUNCTION__)); (const char *)((image_uri)+1);})
, &url);
426 if (error != NSERROR_OK)
427 return false0;
428
429 if (html_fetch_object(ctx->content,
430 url,
431 marker,
432 image_types,
433 false0) == false0) {
434 nsurl_unref(url);
435 return false0;
436 }
437 nsurl_unref(url);
438 }
439
440 box->list_marker = marker;
441 marker->parent = box;
442
443 return true1;
444}
445
446static inline bool_Bool box__style_is_float(const struct box *box)
447{
448 return css_computed_float(box->style) == CSS_FLOAT_LEFT ||
449 css_computed_float(box->style) == CSS_FLOAT_RIGHT;
450}
451
452static inline bool_Bool box__is_flex(const struct box *box)
453{
454 return box->type == BOX_FLEX || box->type == BOX_INLINE_FLEX;
455}
456
457static inline bool_Bool box__containing_block_is_flex(
458 const struct box_construct_props *props)
459{
460 return props->containing_block != NULL((void*)0) &&
461 box__is_flex(props->containing_block);
462}
463
464/**
465 * Construct the box tree for an XML element.
466 *
467 * \param ctx Tree construction context
468 * \param convert_children Whether to convert children
469 * \return true on success, false on memory exhaustion
470 */
471static bool_Bool
472box_construct_element(struct box_construct_ctx *ctx, bool_Bool *convert_children)
473{
474 dom_string *title0, *s;
475 lwc_string *id = NULL((void*)0);
476 enum css_display_e css_display;
477 struct box *box = NULL((void*)0), *old_box;
478 css_select_results *styles = NULL((void*)0);
479 lwc_string *bgimage_uri;
480 dom_exception err;
481 struct box_construct_props props;
482 const css_computed_style *root_style = NULL((void*)0);
483
484 assert(ctx->n != NULL)((ctx->n != ((void*)0)) ? (void) (0) : __assert_fail ("ctx->n != NULL"
, "content/handlers/html/box_construct.c", 484, __extension__
__PRETTY_FUNCTION__))
;
1
Assuming field 'n' is not equal to null
2
'?' condition is true
485
486 box_extract_properties(ctx->n, &props);
3
Value assigned to 'props.containing_block'
487
488 if (props.containing_block != NULL((void*)0)) {
4
Assuming field 'containing_block' is equal to NULL
5
Taking false branch
489 /* In case the containing block is a pre block, we clear
490 * the PRE_STRIP flag since it is not used if we follow
491 * the pre with a tag */
492 props.containing_block->flags &= ~PRE_STRIP;
493 }
494
495 if (props.node_is_root == false0) {
6
Assuming field 'node_is_root' is equal to false
7
Taking true branch
496 root_style = ctx->root_box->style;
497 }
498
499 styles = box_get_style(ctx->content, props.parent_style, root_style,
500 ctx->n);
501 if (styles == NULL((void*)0))
8
Assuming 'styles' is not equal to NULL
9
Taking false branch
502 return false0;
503
504 /* Extract title attribute, if present */
505 err = dom_element_get_attribute(ctx->n, corestring_dom_title, &title0)dom_element_get_attribute( (dom_element *) (ctx->n), (corestring_dom_title
), (&title0))
;
506 if (err != DOM_NO_ERR)
10
Assuming 'err' is equal to DOM_NO_ERR
11
Taking false branch
507 return false0;
508
509 if (title0 != NULL((void*)0)) {
12
Assuming 'title0' is equal to NULL
13
Taking false branch
510 char *t = squash_whitespace(dom_string_data(title0));
511
512 dom_string_unref(title0);
513
514 if (t == NULL((void*)0))
515 return false0;
516
517 props.title = talloc_strdup(ctx->bctx, t);
518
519 free(t);
520
521 if (props.title == NULL((void*)0))
522 return false0;
523 }
524
525 /* Extract id attribute, if present */
526 err = dom_element_get_attribute(ctx->n, corestring_dom_id, &s)dom_element_get_attribute( (dom_element *) (ctx->n), (corestring_dom_id
), (&s))
;
527 if (err != DOM_NO_ERR)
14
Assuming 'err' is equal to DOM_NO_ERR
15
Taking false branch
528 return false0;
529
530 if (s != NULL((void*)0)) {
16
Assuming 's' is equal to NULL
17
Taking false branch
531 err = dom_string_intern(s, &id);
532 if (err != DOM_NO_ERR)
533 id = NULL((void*)0);
534
535 dom_string_unref(s);
536 }
537
538 box = box_create(styles, styles->styles[CSS_PSEUDO_ELEMENT_NONE], false0,
539 props.href, props.target, props.title, id,
540 ctx->bctx);
541 if (box == NULL((void*)0))
18
Assuming 'box' is not equal to NULL
19
Taking false branch
542 return false0;
543
544 /* If this is the root box, add it to the context */
545 if (props.node_is_root
19.1
Field 'node_is_root' is false
)
20
Taking false branch
546 ctx->root_box = box;
547
548 /* Deal with colspan/rowspan */
549 err = dom_element_get_attribute(ctx->n, corestring_dom_colspan, &s)dom_element_get_attribute( (dom_element *) (ctx->n), (corestring_dom_colspan
), (&s))
;
550 if (err != DOM_NO_ERR)
21
Assuming 'err' is equal to DOM_NO_ERR
22
Taking false branch
551 return false0;
552
553 if (s != NULL((void*)0)) {
23
Assuming 's' is equal to NULL
24
Taking false branch
554 const char *val = dom_string_data(s);
555
556 /* Convert to a number, clamping to [1,1000] according to 4.9.11 */
557 if ('0' <= val[0] && val[0] <= '9')
558 box->columns = clamp(strtol(val, NULL, 10), 1, 1000)((((((((strtol(val, ((void*)0), 10)))>((1)))?((strtol(val,
((void*)0), 10))):((1))))<((1000)))?(((((strtol(val, ((void
*)0), 10)))>((1)))?((strtol(val, ((void*)0), 10))):((1))))
:((1000))))
;
559
560 dom_string_unref(s);
561 }
562
563 err = dom_element_get_attribute(ctx->n, corestring_dom_rowspan, &s)dom_element_get_attribute( (dom_element *) (ctx->n), (corestring_dom_rowspan
), (&s))
;
564 if (err != DOM_NO_ERR)
25
Assuming 'err' is equal to DOM_NO_ERR
26
Taking false branch
565 return false0;
566
567 if (s != NULL((void*)0)) {
27
Assuming 's' is equal to NULL
28
Taking false branch
568 const char *val = dom_string_data(s);
569
570 /* Convert to a number, clamping to [0,65534] according to 4.9.11 */
571 if ('0' <= val[0] && val[0] <= '9')
572 box->rows = clamp(strtol(val, NULL, 10), 0, 65534)((((((((strtol(val, ((void*)0), 10)))>((0)))?((strtol(val,
((void*)0), 10))):((0))))<((65534)))?(((((strtol(val, ((void
*)0), 10)))>((0)))?((strtol(val, ((void*)0), 10))):((0))))
:((65534))))
;
573
574 dom_string_unref(s);
575 }
576
577 css_display = ns_computed_display_static(box->style);
578
579 /* Set box type from computed display */
580 if ((css_computed_position(box->style) == CSS_POSITION_ABSOLUTE ||
29
Assuming the condition is false
581 css_computed_position(box->style) == CSS_POSITION_FIXED) &&
30
Assuming the condition is false
582 (css_display == CSS_DISPLAY_INLINE ||
583 css_display == CSS_DISPLAY_INLINE_BLOCK ||
584 css_display == CSS_DISPLAY_INLINE_TABLE ||
585 css_display == CSS_DISPLAY_INLINE_FLEX)) {
586 /* Special case for absolute positioning: make absolute inlines
587 * into inline block so that the boxes are constructed in an
588 * inline container as if they were not absolutely positioned.
589 * Layout expects and handles this. */
590 box->type = box_map[CSS_DISPLAY_INLINE_BLOCK];
591 } else if (props.node_is_root
30.1
Field 'node_is_root' is false
) {
31
Taking false branch
592 /* Special case for root element: force it to BLOCK, or the
593 * rest of the layout will break. */
594 box->type = BOX_BLOCK;
595 } else {
596 /* Normal mapping */
597 box->type = box_map[ns_computed_display(box->style,
598 props.node_is_root)];
599
600 if (props.containing_block->type == BOX_FLEX ||
32
Access to field 'type' results in a dereference of a null pointer (loaded from field 'containing_block')
601 props.containing_block->type == BOX_INLINE_FLEX) {
602 /* Blockification */
603 switch (box->type) {
604 case BOX_INLINE_FLEX:
605 box->type = BOX_FLEX;
606 break;
607 case BOX_INLINE_BLOCK:
608 box->type = BOX_BLOCK;
609 break;
610 default:
611 break;
612 }
613 }
614 }
615
616 if (convert_special_elements(ctx->n,
617 ctx->content,
618 box,
619 convert_children) == false0) {
620 return false0;
621 }
622
623 /* Handle the :before pseudo element */
624 if (!(box->flags & IS_REPLACED)) {
625 box_construct_generate(ctx->n, ctx->content, box,
626 box->styles->styles[CSS_PSEUDO_ELEMENT_BEFORE]);
627 }
628
629 if (box->type == BOX_NONE || (ns_computed_display(box->style,
630 props.node_is_root) == CSS_DISPLAY_NONE &&
631 props.node_is_root == false0)) {
632 css_select_results_destroy(styles);
633 box->styles = NULL((void*)0);
634 box->style = NULL((void*)0);
635
636 /* Invalidate associated gadget, if any */
637 if (box->gadget != NULL((void*)0)) {
638 box->gadget->box = NULL((void*)0);
639 box->gadget = NULL((void*)0);
640 }
641
642 /* Can't do this, because the lifetimes of boxes and gadgets
643 * are inextricably linked. Fortunately, talloc will save us
644 * (for now) */
645 /* box_free_box(box); */
646
647 *convert_children = false0;
648
649 return true1;
650 }
651
652 /* Attach DOM node to box */
653 err = dom_node_set_user_data(ctx->n,dom_node_set_user_data( (dom_node *) (ctx->n), (corestring_dom___ns_key_box_node_data
), (void *) (box), (dom_user_data_handler) ((void*)0), (void *
*) ((void *) &old_box))
654 corestring_dom___ns_key_box_node_data, box, NULL,dom_node_set_user_data( (dom_node *) (ctx->n), (corestring_dom___ns_key_box_node_data
), (void *) (box), (dom_user_data_handler) ((void*)0), (void *
*) ((void *) &old_box))
655 (void *) &old_box)dom_node_set_user_data( (dom_node *) (ctx->n), (corestring_dom___ns_key_box_node_data
), (void *) (box), (dom_user_data_handler) ((void*)0), (void *
*) ((void *) &old_box))
;
656 if (err != DOM_NO_ERR)
657 return false0;
658
659 /* Attach box to DOM node */
660 box->node = dom_node_ref(ctx->n)dom_node_ref((dom_node *) (ctx->n));
661
662 if (props.inline_container == NULL((void*)0) &&
663 (box->type == BOX_INLINE ||
664 box->type == BOX_BR ||
665 box->type == BOX_INLINE_BLOCK ||
666 box->type == BOX_INLINE_FLEX ||
667 (box__style_is_float(box) &&
668 !box__containing_block_is_flex(&props))) &&
669 props.node_is_root == false0) {
670 /* Found an inline child of a block without a current container
671 * (i.e. this box is the first child of its parent, or was
672 * preceded by block-level siblings) */
673 assert(props.containing_block != NULL &&((props.containing_block != ((void*)0) && "Box must have containing block."
) ? (void) (0) : __assert_fail ("props.containing_block != NULL && \"Box must have containing block.\""
, "content/handlers/html/box_construct.c", 674, __extension__
__PRETTY_FUNCTION__))
674 "Box must have containing block.")((props.containing_block != ((void*)0) && "Box must have containing block."
) ? (void) (0) : __assert_fail ("props.containing_block != NULL && \"Box must have containing block.\""
, "content/handlers/html/box_construct.c", 674, __extension__
__PRETTY_FUNCTION__))
;
675
676 props.inline_container = box_create(NULL((void*)0), NULL((void*)0), false0, NULL((void*)0),
677 NULL((void*)0), NULL((void*)0), NULL((void*)0), ctx->bctx);
678 if (props.inline_container == NULL((void*)0))
679 return false0;
680
681 props.inline_container->type = BOX_INLINE_CONTAINER;
682
683 box_add_child(props.containing_block, props.inline_container);
684 }
685
686 /* Kick off fetch for any background image */
687 if (css_computed_background_image(box->style, &bgimage_uri) ==
688 CSS_BACKGROUND_IMAGE_IMAGE && bgimage_uri != NULL((void*)0) &&
689 nsoption_bool(background_images)(nsoptions[NSOPTION_background_images].value.b) == true1) {
690 nsurl *url;
691 nserror error;
692
693 /* TODO: we get a url out of libcss as a lwc string, but
694 * earlier we already had it as a nsurl after we
695 * nsurl_joined it. Can this be improved?
696 * For now, just making another nsurl. */
697 error = nsurl_create(lwc_string_data(bgimage_uri)({((bgimage_uri != ((void*)0)) ? (void) (0) : __assert_fail (
"bgimage_uri != NULL", "content/handlers/html/box_construct.c"
, 697, __extension__ __PRETTY_FUNCTION__)); (const char *)((bgimage_uri
)+1);})
, &url);
698 if (error == NSERROR_OK) {
699 /* Fetch image if we got a valid URL */
700 if (html_fetch_object(ctx->content,
701 url,
702 box,
703 image_types,
704 true1) == false0) {
705 nsurl_unref(url);
706 return false0;
707 }
708 nsurl_unref(url);
709 }
710 }
711
712 if (*convert_children)
713 box->flags |= CONVERT_CHILDREN;
714
715 if (box->type == BOX_INLINE || box->type == BOX_BR ||
716 box->type == BOX_INLINE_FLEX ||
717 box->type == BOX_INLINE_BLOCK) {
718 /* Inline container must exist, as we'll have
719 * created it above if it didn't */
720 assert(props.inline_container != NULL)((props.inline_container != ((void*)0)) ? (void) (0) : __assert_fail
("props.inline_container != NULL", "content/handlers/html/box_construct.c"
, 720, __extension__ __PRETTY_FUNCTION__))
;
721
722 box_add_child(props.inline_container, box);
723 } else {
724 if (ns_computed_display(box->style, props.node_is_root) ==
725 CSS_DISPLAY_LIST_ITEM) {
726 /* List item: compute marker */
727 if (box_construct_marker(box, props.title, ctx,
728 props.containing_block) == false0)
729 return false0;
730 }
731
732 if (props.node_is_root == false0 &&
733 box__containing_block_is_flex(&props) == false0 &&
734 (css_computed_float(box->style) ==
735 CSS_FLOAT_LEFT ||
736 css_computed_float(box->style) ==
737 CSS_FLOAT_RIGHT)) {
738 /* Float: insert a float between the parent and box. */
739 struct box *flt = box_create(NULL((void*)0), NULL((void*)0), false0,
740 props.href, props.target, props.title,
741 NULL((void*)0), ctx->bctx);
742 if (flt == NULL((void*)0))
743 return false0;
744
745 if (css_computed_float(box->style) == CSS_FLOAT_LEFT)
746 flt->type = BOX_FLOAT_LEFT;
747 else
748 flt->type = BOX_FLOAT_RIGHT;
749
750 box_add_child(props.inline_container, flt);
751 box_add_child(flt, box);
752 } else {
753 /* Non-floated block-level box: add to containing block
754 * if there is one. If we're the root box, then there
755 * won't be. */
756 if (props.containing_block != NULL((void*)0))
757 box_add_child(props.containing_block, box);
758 }
759 }
760
761 return true1;
762}
763
764
765/**
766 * Complete construction of the box tree for an element.
767 *
768 * \param n DOM node to construct for
769 * \param content Containing document
770 *
771 * This will be called after all children of an element have been processed
772 */
773static void box_construct_element_after(dom_node *n, html_content *content)
774{
775 struct box_construct_props props;
776 struct box *box = box_for_node(n);
777
778 assert(box != NULL)((box != ((void*)0)) ? (void) (0) : __assert_fail ("box != NULL"
, "content/handlers/html/box_construct.c", 778, __extension__
__PRETTY_FUNCTION__))
;
779
780 box_extract_properties(n, &props);
781
782 if (box->type == BOX_INLINE || box->type == BOX_BR) {
783 /* Insert INLINE_END into containing block */
784 struct box *inline_end;
785 bool_Bool has_children;
786 dom_exception err;
787
788 err = dom_node_has_child_nodes(n, &has_children)dom_node_has_child_nodes( (dom_node *) (n), (_Bool *) (&has_children
))
;
789 if (err != DOM_NO_ERR)
790 return;
791
792 if (has_children == false0 ||
793 (box->flags & CONVERT_CHILDREN) == 0) {
794 /* No children, or didn't want children converted */
795 return;
796 }
797
798 if (props.inline_container == NULL((void*)0)) {
799 /* Create inline container if we don't have one */
800 props.inline_container = box_create(NULL((void*)0), NULL((void*)0), false0,
801 NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), content->bctx);
802 if (props.inline_container == NULL((void*)0))
803 return;
804
805 props.inline_container->type = BOX_INLINE_CONTAINER;
806
807 box_add_child(props.containing_block,
808 props.inline_container);
809 }
810
811 inline_end = box_create(NULL((void*)0), box->style, false0,
812 box->href, box->target, box->title,
813 box->id == NULL((void*)0) ? NULL((void*)0) :
814 lwc_string_ref(box->id)({lwc_string *__lwc_s = (box->id); ((__lwc_s != ((void*)0)
) ? (void) (0) : __assert_fail ("__lwc_s != NULL", "content/handlers/html/box_construct.c"
, 814, __extension__ __PRETTY_FUNCTION__)); __lwc_s->refcnt
++; __lwc_s;})
, content->bctx);
815 if (inline_end != NULL((void*)0)) {
816 inline_end->type = BOX_INLINE_END;
817
818 assert(props.inline_container != NULL)((props.inline_container != ((void*)0)) ? (void) (0) : __assert_fail
("props.inline_container != NULL", "content/handlers/html/box_construct.c"
, 818, __extension__ __PRETTY_FUNCTION__))
;
819
820 box_add_child(props.inline_container, inline_end);
821
822 box->inline_end = inline_end;
823 inline_end->inline_end = box;
824 }
825 } else if (!(box->flags & IS_REPLACED)) {
826 /* Handle the :after pseudo element */
827 box_construct_generate(n, content, box,
828 box->styles->styles[CSS_PSEUDO_ELEMENT_AFTER]);
829 }
830}
831
832
833/**
834 * Find the next node in the DOM tree, completing element construction
835 * where appropriate.
836 *
837 * \param n Current node
838 * \param content Containing content
839 * \param convert_children Whether to consider children of \a n
840 * \return Next node to process, or NULL if complete
841 *
842 * \note \a n will be unreferenced
843 */
844static dom_node *
845next_node(dom_node *n, html_content *content, bool_Bool convert_children)
846{
847 dom_node *next = NULL((void*)0);
848 bool_Bool has_children;
849 dom_exception err;
850
851 err = dom_node_has_child_nodes(n, &has_children)dom_node_has_child_nodes( (dom_node *) (n), (_Bool *) (&has_children
))
;
852 if (err != DOM_NO_ERR) {
853 dom_node_unref(n)dom_node_unref((dom_node *) (n));
854 return NULL((void*)0);
855 }
856
857 if (convert_children && has_children) {
858 err = dom_node_get_first_child(n, &next)dom_node_get_first_child( (dom_node *) (n), (dom_node **) (&
next))
;
859 if (err != DOM_NO_ERR) {
860 dom_node_unref(n)dom_node_unref((dom_node *) (n));
861 return NULL((void*)0);
862 }
863 dom_node_unref(n)dom_node_unref((dom_node *) (n));
864 } else {
865 err = dom_node_get_next_sibling(n, &next)dom_node_get_next_sibling( (dom_node *) (n), (dom_node **) (&
next))
;
866 if (err != DOM_NO_ERR) {
867 dom_node_unref(n)dom_node_unref((dom_node *) (n));
868 return NULL((void*)0);
869 }
870
871 if (next != NULL((void*)0)) {
872 if (box_for_node(n) != NULL((void*)0))
873 box_construct_element_after(n, content);
874 dom_node_unref(n)dom_node_unref((dom_node *) (n));
875 } else {
876 if (box_for_node(n) != NULL((void*)0))
877 box_construct_element_after(n, content);
878
879 while (box_is_root(n) == false0) {
880 dom_node *parent = NULL((void*)0);
881 dom_node *parent_next = NULL((void*)0);
882
883 err = dom_node_get_parent_node(n, &parent)dom_node_get_parent_node( (dom_node *) (n), (dom_node **) (&
parent))
;
884 if (err != DOM_NO_ERR) {
885 dom_node_unref(n)dom_node_unref((dom_node *) (n));
886 return NULL((void*)0);
887 }
888
889 assert(parent != NULL)((parent != ((void*)0)) ? (void) (0) : __assert_fail ("parent != NULL"
, "content/handlers/html/box_construct.c", 889, __extension__
__PRETTY_FUNCTION__))
;
890
891 err = dom_node_get_next_sibling(parent,dom_node_get_next_sibling( (dom_node *) (parent), (dom_node *
*) (&parent_next))
892 &parent_next)dom_node_get_next_sibling( (dom_node *) (parent), (dom_node *
*) (&parent_next))
;
893 if (err != DOM_NO_ERR) {
894 dom_node_unref(parent)dom_node_unref((dom_node *) (parent));
895 dom_node_unref(n)dom_node_unref((dom_node *) (n));
896 return NULL((void*)0);
897 }
898
899 if (parent_next != NULL((void*)0)) {
900 dom_node_unref(parent_next)dom_node_unref((dom_node *) (parent_next));
901 dom_node_unref(parent)dom_node_unref((dom_node *) (parent));
902 break;
903 }
904
905 dom_node_unref(n)dom_node_unref((dom_node *) (n));
906 n = parent;
907 parent = NULL((void*)0);
908
909 if (box_for_node(n) != NULL((void*)0)) {
910 box_construct_element_after(
911 n, content);
912 }
913 }
914
915 if (box_is_root(n) == false0) {
916 dom_node *parent = NULL((void*)0);
917
918 err = dom_node_get_parent_node(n, &parent)dom_node_get_parent_node( (dom_node *) (n), (dom_node **) (&
parent))
;
919 if (err != DOM_NO_ERR) {
920 dom_node_unref(n)dom_node_unref((dom_node *) (n));
921 return NULL((void*)0);
922 }
923
924 assert(parent != NULL)((parent != ((void*)0)) ? (void) (0) : __assert_fail ("parent != NULL"
, "content/handlers/html/box_construct.c", 924, __extension__
__PRETTY_FUNCTION__))
;
925
926 err = dom_node_get_next_sibling(parent, &next)dom_node_get_next_sibling( (dom_node *) (parent), (dom_node *
*) (&next))
;
927 if (err != DOM_NO_ERR) {
928 dom_node_unref(parent)dom_node_unref((dom_node *) (parent));
929 dom_node_unref(n)dom_node_unref((dom_node *) (n));
930 return NULL((void*)0);
931 }
932
933 if (box_for_node(parent) != NULL((void*)0)) {
934 box_construct_element_after(parent,
935 content);
936 }
937
938 dom_node_unref(parent)dom_node_unref((dom_node *) (parent));
939 }
940
941 dom_node_unref(n)dom_node_unref((dom_node *) (n));
942 }
943 }
944
945 return next;
946}
947
948
949/**
950 * Apply the CSS text-transform property to given text for its ASCII chars.
951 *
952 * \param s string to transform
953 * \param len length of s
954 * \param tt transform type
955 */
956static void
957box_text_transform(char *s, unsigned int len, enum css_text_transform_e tt)
958{
959 unsigned int i;
960 if (len == 0)
961 return;
962 switch (tt) {
963 case CSS_TEXT_TRANSFORM_UPPERCASE:
964 for (i = 0; i < len; ++i)
965 if ((unsigned char) s[i] < 0x80)
966 s[i] = ascii_to_upper(s[i]);
967 break;
968 case CSS_TEXT_TRANSFORM_LOWERCASE:
969 for (i = 0; i < len; ++i)
970 if ((unsigned char) s[i] < 0x80)
971 s[i] = ascii_to_lower(s[i]);
972 break;
973 case CSS_TEXT_TRANSFORM_CAPITALIZE:
974 if ((unsigned char) s[0] < 0x80)
975 s[0] = ascii_to_upper(s[0]);
976 for (i = 1; i < len; ++i)
977 if ((unsigned char) s[i] < 0x80 &&
978 ascii_is_space(s[i - 1]))
979 s[i] = ascii_to_upper(s[i]);
980 break;
981 default:
982 break;
983 }
984}
985
986
987/**
988 * Construct the box tree for an XML text node.
989 *
990 * \param ctx Tree construction context
991 * \return true on success, false on memory exhaustion
992 */
993static bool_Bool box_construct_text(struct box_construct_ctx *ctx)
994{
995 struct box_construct_props props;
996 struct box *box = NULL((void*)0);
997 dom_string *content;
998 dom_exception err;
999
1000 assert(ctx->n != NULL)((ctx->n != ((void*)0)) ? (void) (0) : __assert_fail ("ctx->n != NULL"
, "content/handlers/html/box_construct.c", 1000, __extension__
__PRETTY_FUNCTION__))
;
1001
1002 box_extract_properties(ctx->n, &props);
1003
1004 assert(props.containing_block != NULL)((props.containing_block != ((void*)0)) ? (void) (0) : __assert_fail
("props.containing_block != NULL", "content/handlers/html/box_construct.c"
, 1004, __extension__ __PRETTY_FUNCTION__))
;
1005
1006 err = dom_characterdata_get_data(ctx->n, &content)dom_characterdata_get_data( (struct dom_characterdata *) (ctx
->n), (&content))
;
1007 if (err != DOM_NO_ERR || content == NULL((void*)0))
1008 return false0;
1009
1010 if (css_computed_white_space(props.parent_style) ==
1011 CSS_WHITE_SPACE_NORMAL ||
1012 css_computed_white_space(props.parent_style) ==
1013 CSS_WHITE_SPACE_NOWRAP) {
1014 char *text;
1015
1016 text = squash_whitespace(dom_string_data(content));
1017
1018 dom_string_unref(content);
1019
1020 if (text == NULL((void*)0))
1021 return false0;
1022
1023 /* if the text is just a space, combine it with the preceding
1024 * text node, if any */
1025 if (text[0] == ' ' && text[1] == 0) {
1026 if (props.inline_container != NULL((void*)0)) {
1027 assert(props.inline_container->last != NULL)((props.inline_container->last != ((void*)0)) ? (void) (0)
: __assert_fail ("props.inline_container->last != NULL", "content/handlers/html/box_construct.c"
, 1027, __extension__ __PRETTY_FUNCTION__))
;
1028
1029 props.inline_container->last->space =
1030 UNKNOWN_WIDTH2147483647;
1031 }
1032
1033 free(text);
1034
1035 return true1;
1036 }
1037
1038 if (props.inline_container == NULL((void*)0)) {
1039 /* Child of a block without a current container
1040 * (i.e. this box is the first child of its parent, or
1041 * was preceded by block-level siblings) */
1042 props.inline_container = box_create(NULL((void*)0), NULL((void*)0), false0,
1043 NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), ctx->bctx);
1044 if (props.inline_container == NULL((void*)0)) {
1045 free(text);
1046 return false0;
1047 }
1048
1049 props.inline_container->type = BOX_INLINE_CONTAINER;
1050
1051 box_add_child(props.containing_block,
1052 props.inline_container);
1053 }
1054
1055 /** \todo Dropping const here is not clever */
1056 box = box_create(NULL((void*)0),
1057 (css_computed_style *) props.parent_style,
1058 false0, props.href, props.target, props.title,
1059 NULL((void*)0), ctx->bctx);
1060 if (box == NULL((void*)0)) {
1061 free(text);
1062 return false0;
1063 }
1064
1065 box->type = BOX_TEXT;
1066
1067 box->text = talloc_strdup(ctx->bctx, text);
1068 free(text);
1069 if (box->text == NULL((void*)0))
1070 return false0;
1071
1072 box->length = strlen(box->text);
1073
1074 /* strip ending space char off */
1075 if (box->length > 1 && box->text[box->length - 1] == ' ') {
1076 box->space = UNKNOWN_WIDTH2147483647;
1077 box->length--;
1078 }
1079
1080 if (css_computed_text_transform(props.parent_style) !=
1081 CSS_TEXT_TRANSFORM_NONE)
1082 box_text_transform(box->text, box->length,
1083 css_computed_text_transform(
1084 props.parent_style));
1085
1086 box_add_child(props.inline_container, box);
1087
1088 if (box->text[0] == ' ') {
1089 box->length--;
1090
1091 memmove(box->text, &box->text[1], box->length);
1092
1093 if (box->prev != NULL((void*)0))
1094 box->prev->space = UNKNOWN_WIDTH2147483647;
1095 }
1096 } else {
1097 /* white-space: pre */
1098 char *text;
1099 size_t text_len = dom_string_byte_length(content);
1100 size_t i;
1101 char *current;
1102 enum css_white_space_e white_space =
1103 css_computed_white_space(props.parent_style);
1104
1105 /* note: pre-wrap/pre-line are unimplemented */
1106 assert(white_space == CSS_WHITE_SPACE_PRE ||((white_space == CSS_WHITE_SPACE_PRE || white_space == CSS_WHITE_SPACE_PRE_LINE
|| white_space == CSS_WHITE_SPACE_PRE_WRAP) ? (void) (0) : __assert_fail
("white_space == CSS_WHITE_SPACE_PRE || white_space == CSS_WHITE_SPACE_PRE_LINE || white_space == CSS_WHITE_SPACE_PRE_WRAP"
, "content/handlers/html/box_construct.c", 1108, __extension__
__PRETTY_FUNCTION__))
1107 white_space == CSS_WHITE_SPACE_PRE_LINE ||((white_space == CSS_WHITE_SPACE_PRE || white_space == CSS_WHITE_SPACE_PRE_LINE
|| white_space == CSS_WHITE_SPACE_PRE_WRAP) ? (void) (0) : __assert_fail
("white_space == CSS_WHITE_SPACE_PRE || white_space == CSS_WHITE_SPACE_PRE_LINE || white_space == CSS_WHITE_SPACE_PRE_WRAP"
, "content/handlers/html/box_construct.c", 1108, __extension__
__PRETTY_FUNCTION__))
1108 white_space == CSS_WHITE_SPACE_PRE_WRAP)((white_space == CSS_WHITE_SPACE_PRE || white_space == CSS_WHITE_SPACE_PRE_LINE
|| white_space == CSS_WHITE_SPACE_PRE_WRAP) ? (void) (0) : __assert_fail
("white_space == CSS_WHITE_SPACE_PRE || white_space == CSS_WHITE_SPACE_PRE_LINE || white_space == CSS_WHITE_SPACE_PRE_WRAP"
, "content/handlers/html/box_construct.c", 1108, __extension__
__PRETTY_FUNCTION__))
;
1109
1110 text = malloc(text_len + 1);
1111 dom_string_unref(content);
1112
1113 if (text == NULL((void*)0))
1114 return false0;
1115
1116 memcpy(text, dom_string_data(content), text_len);
1117 text[text_len] = '\0';
1118
1119 /* TODO: Handle tabs properly */
1120 for (i = 0; i < text_len; i++)
1121 if (text[i] == '\t')
1122 text[i] = ' ';
1123
1124 if (css_computed_text_transform(props.parent_style) !=
1125 CSS_TEXT_TRANSFORM_NONE)
1126 box_text_transform(text, strlen(text),
1127 css_computed_text_transform(
1128 props.parent_style));
1129
1130 current = text;
1131
1132 /* swallow a single leading new line */
1133 if (props.containing_block->flags & PRE_STRIP) {
1134 switch (*current) {
1135 case '\n':
1136 current++;
1137 break;
1138 case '\r':
1139 current++;
1140 if (*current == '\n')
1141 current++;
1142 break;
1143 }
1144 props.containing_block->flags &= ~PRE_STRIP;
1145 }
1146
1147 do {
1148 size_t len = strcspn(current, "\r\n");
1149
1150 char old = current[len];
1151
1152 current[len] = 0;
1153
1154 if (props.inline_container == NULL((void*)0)) {
1155 /* Child of a block without a current container
1156 * (i.e. this box is the first child of its
1157 * parent, or was preceded by block-level
1158 * siblings) */
1159 props.inline_container = box_create(NULL((void*)0), NULL((void*)0),
1160 false0, NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0),
1161 ctx->bctx);
1162 if (props.inline_container == NULL((void*)0)) {
1163 free(text);
1164 return false0;
1165 }
1166
1167 props.inline_container->type =
1168 BOX_INLINE_CONTAINER;
1169
1170 box_add_child(props.containing_block,
1171 props.inline_container);
1172 }
1173
1174 /** \todo Dropping const isn't clever */
1175 box = box_create(NULL((void*)0),
1176 (css_computed_style *) props.parent_style,
1177 false0, props.href, props.target, props.title,
1178 NULL((void*)0), ctx->bctx);
1179 if (box == NULL((void*)0)) {
1180 free(text);
1181 return false0;
1182 }
1183
1184 box->type = BOX_TEXT;
1185
1186 box->text = talloc_strdup(ctx->bctx, current);
1187 if (box->text == NULL((void*)0)) {
1188 free(text);
1189 return false0;
1190 }
1191
1192 box->length = strlen(box->text);
1193
1194 box_add_child(props.inline_container, box);
1195
1196 current[len] = old;
1197
1198 current += len;
1199
1200 if (current[0] != '\0') {
1201 /* Linebreak: create new inline container */
1202 props.inline_container = box_create(NULL((void*)0), NULL((void*)0),
1203 false0, NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0),
1204 ctx->bctx);
1205 if (props.inline_container == NULL((void*)0)) {
1206 free(text);
1207 return false0;
1208 }
1209
1210 props.inline_container->type =
1211 BOX_INLINE_CONTAINER;
1212
1213 box_add_child(props.containing_block,
1214 props.inline_container);
1215
1216 if (current[0] == '\r' && current[1] == '\n')
1217 current += 2;
1218 else
1219 current++;
1220 }
1221 } while (*current);
1222
1223 free(text);
1224 }
1225
1226 return true1;
1227}
1228
1229
1230/**
1231 * Convert an ELEMENT node to a box tree fragment,
1232 * then schedule conversion of the next ELEMENT node
1233 */
1234static void convert_xml_to_box(struct box_construct_ctx *ctx)
1235{
1236 dom_node *next;
1237 bool_Bool convert_children;
1238 uint32_t num_processed = 0;
1239 const uint32_t max_processed_before_yield = 10;
1240
1241 do {
1242 convert_children = true1;
1243
1244 assert(ctx->n != NULL)((ctx->n != ((void*)0)) ? (void) (0) : __assert_fail ("ctx->n != NULL"
, "content/handlers/html/box_construct.c", 1244, __extension__
__PRETTY_FUNCTION__))
;
1245
1246 if (box_construct_element(ctx, &convert_children) == false0) {
1247 ctx->cb(ctx->content, false0);
1248 dom_node_unref(ctx->n)dom_node_unref((dom_node *) (ctx->n));
1249 free(ctx);
1250 return;
1251 }
1252
1253 /* Find next element to process, converting text nodes as we go */
1254 next = next_node(ctx->n, ctx->content, convert_children);
1255 while (next != NULL((void*)0)) {
1256 dom_node_type type;
1257 dom_exception err;
1258
1259 err = dom_node_get_node_type(next, &type)dom_node_get_node_type( (dom_node *) (next), (dom_node_type *
) (&type))
;
1260 if (err != DOM_NO_ERR) {
1261 ctx->cb(ctx->content, false0);
1262 dom_node_unref(next)dom_node_unref((dom_node *) (next));
1263 free(ctx);
1264 return;
1265 }
1266
1267 if (type == DOM_ELEMENT_NODE)
1268 break;
1269
1270 if (type == DOM_TEXT_NODE) {
1271 ctx->n = next;
1272 if (box_construct_text(ctx) == false0) {
1273 ctx->cb(ctx->content, false0);
1274 dom_node_unref(ctx->n)dom_node_unref((dom_node *) (ctx->n));
1275 free(ctx);
1276 return;
1277 }
1278 }
1279
1280 next = next_node(next, ctx->content, true1);
1281 }
1282
1283 ctx->n = next;
1284
1285 if (next == NULL((void*)0)) {
1286 /* Conversion complete */
1287 struct box root;
1288
1289 memset(&root, 0, sizeof(root));
1290
1291 root.type = BOX_BLOCK;
1292 root.children = root.last = ctx->root_box;
1293 root.children->parent = &root;
1294
1295 /** \todo Remove box_normalise_block */
1296 if (box_normalise_block(&root, ctx->root_box,
1297 ctx->content) == false0) {
1298 ctx->cb(ctx->content, false0);
1299 } else {
1300 ctx->content->layout = root.children;
1301 ctx->content->layout->parent = NULL((void*)0);
1302
1303 ctx->cb(ctx->content, true1);
1304 }
1305
1306 assert(ctx->n == NULL)((ctx->n == ((void*)0)) ? (void) (0) : __assert_fail ("ctx->n == NULL"
, "content/handlers/html/box_construct.c", 1306, __extension__
__PRETTY_FUNCTION__))
;
1307
1308 free(ctx);
1309 return;
1310 }
1311 } while (++num_processed < max_processed_before_yield);
1312
1313 /* More work to do: schedule a continuation */
1314 guit->misc->schedule(0, (void *)convert_xml_to_box, ctx);
1315}
1316
1317
1318/* exported function documented in html/box_construct.h */
1319nserror
1320dom_to_box(dom_node *n,
1321 html_content *c,
1322 box_construct_complete_cb cb,
1323 void **box_conversion_context)
1324{
1325 struct box_construct_ctx *ctx;
1326
1327 assert(box_conversion_context != NULL)((box_conversion_context != ((void*)0)) ? (void) (0) : __assert_fail
("box_conversion_context != NULL", "content/handlers/html/box_construct.c"
, 1327, __extension__ __PRETTY_FUNCTION__))
;
1328
1329 if (c->bctx == NULL((void*)0)) {
1330 /* create a context allocation for this box tree */
1331 c->bctx = talloc_zero(0, int)(int *)_talloc_zero(0, sizeof(int), "int");
1332 if (c->bctx == NULL((void*)0)) {
1333 return NSERROR_NOMEM;
1334 }
1335 }
1336
1337 ctx = malloc(sizeof(*ctx));
1338 if (ctx == NULL((void*)0)) {
1339 return NSERROR_NOMEM;
1340 }
1341
1342 ctx->content = c;
1343 ctx->n = dom_node_ref(n)dom_node_ref((dom_node *) (n));
1344 ctx->root_box = NULL((void*)0);
1345 ctx->cb = cb;
1346 ctx->bctx = c->bctx;
1347
1348 *box_conversion_context = ctx;
1349
1350 return guit->misc->schedule(0, (void *)convert_xml_to_box, ctx);
1351}
1352
1353
1354/* exported function documented in html/box_construct.h */
1355nserror cancel_dom_to_box(void *box_conversion_context)
1356{
1357 struct box_construct_ctx *ctx = box_conversion_context;
1358 nserror err;
1359
1360 err = guit->misc->schedule(-1, (void *)convert_xml_to_box, ctx);
1361 if (err != NSERROR_OK) {
1362 return err;
1363 }
1364
1365 dom_node_unref(ctx->n)dom_node_unref((dom_node *) (ctx->n));
1366 free(ctx);
1367
1368 return NSERROR_OK;
1369}
1370
1371
1372/* exported function documented in html/box_construct.h */
1373struct box *box_for_node(dom_node *n)
1374{
1375 struct box *box = NULL((void*)0);
1376 dom_exception err;
1377
1378 err = dom_node_get_user_data(n, corestring_dom___ns_key_box_node_data,dom_node_get_user_data( (dom_node *) (n), (corestring_dom___ns_key_box_node_data
), (void **) ((void *) &box))
1379 (void *) &box)dom_node_get_user_data( (dom_node *) (n), (corestring_dom___ns_key_box_node_data
), (void **) ((void *) &box))
;
1380 if (err != DOM_NO_ERR)
1381 return NULL((void*)0);
1382
1383 return box;
1384}
1385
1386/* exported function documented in html/box_construct.h */
1387bool_Bool
1388box_extract_link(const html_content *content,
1389 const dom_string *dsrel,
1390 nsurl *base,
1391 nsurl **result)
1392{
1393 char *s, *s1, *apos0 = 0, *apos1 = 0, *quot0 = 0, *quot1 = 0;
1394 unsigned int i, j, end;
1395 nserror error;
1396 const char *rel;
1397
1398 rel = dom_string_data(dsrel);
1399
1400 s1 = s = malloc(3 * strlen(rel) + 1);
1401 if (!s)
1402 return false0;
1403
1404 /* copy to s, removing white space and control characters */
1405 for (i = 0; rel[i] && ascii_is_space(rel[i]); i++)
1406 ;
1407 for (end = strlen(rel);
1408 (end != i) && ascii_is_space(rel[end - 1]);
1409 end--)
1410 ;
1411 for (j = 0; i != end; i++) {
1412 if ((unsigned char) rel[i] < 0x20) {
1413 ; /* skip control characters */
1414 } else if (rel[i] == ' ') {
1415 s[j++] = '%';
1416 s[j++] = '2';
1417 s[j++] = '0';
1418 } else {
1419 s[j++] = rel[i];
1420 }
1421 }
1422 s[j] = 0;
1423
1424 if (content->enable_scripting == false0) {
1425 /* extract first quoted string out of "javascript:" link */
1426 if (strncmp(s, "javascript:", 11) == 0) {
1427 apos0 = strchr(s, '\'');
1428 if (apos0)
1429 apos1 = strchr(apos0 + 1, '\'');
1430 quot0 = strchr(s, '"');
1431 if (quot0)
1432 quot1 = strchr(quot0 + 1, '"');
1433 if (apos0 && apos1 &&
1434 (!quot0 || !quot1 || apos0 < quot0)) {
1435 *apos1 = 0;
1436 s1 = apos0 + 1;
1437 } else if (quot0 && quot1) {
1438 *quot1 = 0;
1439 s1 = quot0 + 1;
1440 }
1441 }
1442 }
1443
1444 /* construct absolute URL */
1445 error = nsurl_join(base, s1, result);
1446 free(s);
1447 if (error != NSERROR_OK) {
1448 *result = NULL((void*)0);
1449 return false0;
1450 }
1451
1452 return true1;
1453}