Bug Summary

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