NetSurf
box_construct.c
Go to the documentation of this file.
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"
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 */
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 */
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 */
80 /** Current container for inlines, or NULL if none
81 * \note If non-NULL, will be the last child of containing_block */
83 /** Whether the current node is the root of the DOM tree */
85};
86
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 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);
129 if (err != DOM_NO_ERR)
130 return false;
131
132 if (parent != NULL) {
133 err = dom_node_get_node_type(parent, &type);
134
135 dom_node_unref(parent);
136
137 if (err != DOM_NO_ERR)
138 return false;
139
140 if (type != DOM_DOCUMENT_NODE)
141 return false;
142 }
143
144 return true;
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
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 == false) {
162 dom_node *current_node = n;
163 dom_node *parent_node = NULL;
164 struct box *parent_box;
165 dom_exception err;
166
167 /* Find ancestor node containing parent box */
168 while (true) {
169 err = dom_node_get_parent_node(current_node,
170 &parent_node);
171 if (err != DOM_NO_ERR || parent_node == NULL)
172 break;
173
174 parent_box = box_for_node(parent_node);
175
176 if (parent_box != NULL) {
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);
183 break;
184 } else {
185 if (current_node != n)
186 dom_node_unref(current_node);
187 current_node = parent_node;
188 parent_node = NULL;
189 }
190 }
191
192 /* Find containing block (may be parent) */
193 while (true) {
194 struct box *b;
195
196 err = dom_node_get_parent_node(current_node,
197 &parent_node);
198 if (err != DOM_NO_ERR || parent_node == NULL) {
199 if (current_node != n)
200 dom_node_unref(current_node);
201 break;
202 }
203
204 if (current_node != n)
205 dom_node_unref(current_node);
206
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 && b->type != BOX_INLINE &&
216 b->type != BOX_BR) {
217 props->containing_block = b;
218
219 dom_node_unref(parent_node);
220 break;
221 } else {
222 current_node = parent_node;
223 parent_node = NULL;
224 }
225 }
226 }
227
228 /* Compute current inline container, if any */
229 if (props->containing_block != NULL &&
230 props->containing_block->last != NULL &&
231 props->containing_block->last->type ==
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 *
248 const css_computed_style *parent_style,
249 const css_computed_style *root_style,
250 dom_node *n)
251{
252 dom_string *s = NULL;
253 css_stylesheet *inline_style = NULL;
254 css_select_results *styles;
256
257 /* Firstly, construct inline stylesheet, if any */
258 if (nsoption_bool(author_level_css)) {
259 dom_exception err;
260 err = dom_element_get_attribute(n, corestring_dom_style, &s);
261 if (err != DOM_NO_ERR) {
262 return NULL;
263 }
264 }
265
266 if (s != NULL) {
267 inline_style = nscss_create_inline_style(
268 (const uint8_t *) dom_string_data(s),
269 dom_string_byte_length(s),
270 c->encoding,
272 c->quirks != DOM_DOCUMENT_QUIRKS_MODE_NONE);
273
274 dom_string_unref(s);
275
276 if (inline_style == NULL)
277 return NULL;
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)
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
314 struct box *box,
315 const css_computed_style *style)
316{
317 struct box *gen = NULL;
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 ||
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, (css_computed_style *) style,
343 false, NULL, NULL, NULL, NULL, content->bctx);
344 if (gen == NULL) {
345 return;
346 }
347
348 /* set box type from 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
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, box->style, false, NULL, NULL, title,
377 NULL, ctx->bctx);
378 if (marker == false)
379 return false;
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;
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) &&
416 (nsoption_bool(foreground_images) == true)) {
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), &url);
425 if (error != NSERROR_OK)
426 return false;
427
428 if (html_fetch_object(ctx->content,
429 url,
430 marker,
432 false) == false) {
433 nsurl_unref(url);
434 return false;
435 }
436 nsurl_unref(url);
437 }
438
439 box->list_marker = marker;
440 marker->parent = box;
441
442 return true;
443}
444
445static inline 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 box__is_flex(const struct box *box)
452{
453 return box->type == BOX_FLEX || box->type == BOX_INLINE_FLEX;
454}
455
457 const struct box_construct_props *props)
458{
459 return props->containing_block != NULL &&
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
471box_construct_element(struct box_construct_ctx *ctx, bool *convert_children)
472{
473 dom_string *title0, *s;
474 lwc_string *id = NULL;
475 enum css_display_e css_display;
476 struct box *box = NULL, *old_box;
477 css_select_results *styles = NULL;
478 lwc_string *bgimage_uri;
479 dom_exception err;
480 struct box_construct_props props;
481 const css_computed_style *root_style = NULL;
482
483 assert(ctx->n != NULL);
484
485 box_extract_properties(ctx->n, &props);
486
487 if (props.containing_block != NULL) {
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 == false) {
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)
501 return false;
502
503 /* Extract title attribute, if present */
504 err = dom_element_get_attribute(ctx->n, corestring_dom_title, &title0);
505 if (err != DOM_NO_ERR)
506 return false;
507
508 if (title0 != NULL) {
509 char *t = squash_whitespace(dom_string_data(title0));
510
511 dom_string_unref(title0);
512
513 if (t == NULL)
514 return false;
515
516 props.title = talloc_strdup(ctx->bctx, t);
517
518 free(t);
519
520 if (props.title == NULL)
521 return false;
522 }
523
524 /* Extract id attribute, if present */
525 err = dom_element_get_attribute(ctx->n, corestring_dom_id, &s);
526 if (err != DOM_NO_ERR)
527 return false;
528
529 if (s != NULL) {
530 err = dom_string_intern(s, &id);
531 if (err != DOM_NO_ERR)
532 id = NULL;
533
534 dom_string_unref(s);
535 }
536
537 box = box_create(styles, styles->styles[CSS_PSEUDO_ELEMENT_NONE], false,
538 props.href, props.target, props.title, id,
539 ctx->bctx);
540 if (box == NULL)
541 return false;
542
543 /* If this is the root box, add it to the context */
544 if (props.node_is_root)
545 ctx->root_box = box;
546
547 /* Deal with colspan/rowspan */
548 err = dom_element_get_attribute(ctx->n, corestring_dom_colspan, &s);
549 if (err != DOM_NO_ERR)
550 return false;
551
552 if (s != NULL) {
553 const char *val = dom_string_data(s);
554
555 if ('0' <= val[0] && val[0] <= '9')
556 box->columns = strtol(val, NULL, 10);
557
558 dom_string_unref(s);
559 }
560
561 err = dom_element_get_attribute(ctx->n, corestring_dom_rowspan, &s);
562 if (err != DOM_NO_ERR)
563 return false;
564
565 if (s != NULL) {
566 const char *val = dom_string_data(s);
567
568 if ('0' <= val[0] && val[0] <= '9')
569 box->rows = strtol(val, NULL, 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 ||
578 css_computed_position(box->style) == CSS_POSITION_FIXED) &&
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) {
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 */
595 props.node_is_root)];
596
597 if (props.containing_block->type == BOX_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
614 ctx->content,
615 box,
616 convert_children) == false) {
617 return false;
618 }
619
620 /* Handle the :before pseudo element */
621 if (!(box->flags & IS_REPLACED)) {
623 box->styles->styles[CSS_PSEUDO_ELEMENT_BEFORE]);
624 }
625
627 props.node_is_root) == CSS_DISPLAY_NONE &&
628 props.node_is_root == false)) {
629 css_select_results_destroy(styles);
630 box->styles = NULL;
631 box->style = NULL;
632
633 /* Invalidate associated gadget, if any */
634 if (box->gadget != NULL) {
635 box->gadget->box = NULL;
636 box->gadget = NULL;
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 = false;
645
646 return true;
647 }
648
649 /* Attach DOM node to box */
650 err = dom_node_set_user_data(ctx->n,
651 corestring_dom___ns_key_box_node_data, box, NULL,
652 (void *) &old_box);
653 if (err != DOM_NO_ERR)
654 return false;
655
656 /* Attach box to DOM node */
657 box->node = dom_node_ref(ctx->n);
658
659 if (props.inline_container == NULL &&
660 (box->type == BOX_INLINE ||
661 box->type == BOX_BR ||
666 props.node_is_root == false) {
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 &&
671 "Box must have containing block.");
672
673 props.inline_container = box_create(NULL, NULL, false, NULL,
674 NULL, NULL, NULL, ctx->bctx);
675 if (props.inline_container == NULL)
676 return false;
677
679
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 &&
686 nsoption_bool(background_images) == true) {
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), &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,
701 true) == false) {
702 nsurl_unref(url);
703 return false;
704 }
705 nsurl_unref(url);
706 }
707 }
708
709 if (*convert_children)
711
712 if (box->type == BOX_INLINE || box->type == BOX_BR ||
715 /* Inline container must exist, as we'll have
716 * created it above if it didn't */
717 assert(props.inline_container != NULL);
718
720 } else {
722 CSS_DISPLAY_LIST_ITEM) {
723 /* List item: compute marker */
724 if (box_construct_marker(box, props.title, ctx,
725 props.containing_block) == false)
726 return false;
727 }
728
729 if (props.node_is_root == false &&
730 box__containing_block_is_flex(&props) == false &&
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, NULL, false,
737 props.href, props.target, props.title,
738 NULL, ctx->bctx);
739 if (flt == NULL)
740 return false;
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
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)
755 }
756 }
757
758 return true;
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 */
771{
772 struct box_construct_props props;
773 struct box *box = box_for_node(n);
774
775 assert(box != NULL);
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 has_children;
783 dom_exception err;
784
785 err = dom_node_has_child_nodes(n, &has_children);
786 if (err != DOM_NO_ERR)
787 return;
788
789 if (has_children == false ||
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) {
796 /* Create inline container if we don't have one */
797 props.inline_container = box_create(NULL, NULL, false,
798 NULL, NULL, NULL, NULL, content->bctx);
799 if (props.inline_container == NULL)
800 return;
801
803
805 props.inline_container);
806 }
807
808 inline_end = box_create(NULL, box->style, false,
809 box->href, box->target, box->title,
810 box->id == NULL ? NULL :
811 lwc_string_ref(box->id), content->bctx);
812 if (inline_end != NULL) {
814
815 assert(props.inline_container != NULL);
816
818
821 }
822 } else if (!(box->flags & IS_REPLACED)) {
823 /* Handle the :after pseudo element */
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 convert_children)
843{
844 dom_node *next = NULL;
845 bool has_children;
846 dom_exception err;
847
848 err = dom_node_has_child_nodes(n, &has_children);
849 if (err != DOM_NO_ERR) {
850 dom_node_unref(n);
851 return NULL;
852 }
853
854 if (convert_children && has_children) {
855 err = dom_node_get_first_child(n, &next);
856 if (err != DOM_NO_ERR) {
857 dom_node_unref(n);
858 return NULL;
859 }
860 dom_node_unref(n);
861 } else {
862 err = dom_node_get_next_sibling(n, &next);
863 if (err != DOM_NO_ERR) {
864 dom_node_unref(n);
865 return NULL;
866 }
867
868 if (next != NULL) {
869 if (box_for_node(n) != NULL)
871 dom_node_unref(n);
872 } else {
873 if (box_for_node(n) != NULL)
875
876 while (box_is_root(n) == false) {
877 dom_node *parent = NULL;
878 dom_node *parent_next = NULL;
879
880 err = dom_node_get_parent_node(n, &parent);
881 if (err != DOM_NO_ERR) {
882 dom_node_unref(n);
883 return NULL;
884 }
885
886 assert(parent != NULL);
887
888 err = dom_node_get_next_sibling(parent,
889 &parent_next);
890 if (err != DOM_NO_ERR) {
891 dom_node_unref(parent);
892 dom_node_unref(n);
893 return NULL;
894 }
895
896 if (parent_next != NULL) {
897 dom_node_unref(parent_next);
898 dom_node_unref(parent);
899 break;
900 }
901
902 dom_node_unref(n);
903 n = parent;
904 parent = NULL;
905
906 if (box_for_node(n) != NULL) {
908 n, content);
909 }
910 }
911
912 if (box_is_root(n) == false) {
913 dom_node *parent = NULL;
914
915 err = dom_node_get_parent_node(n, &parent);
916 if (err != DOM_NO_ERR) {
917 dom_node_unref(n);
918 return NULL;
919 }
920
921 assert(parent != NULL);
922
923 err = dom_node_get_next_sibling(parent, &next);
924 if (err != DOM_NO_ERR) {
925 dom_node_unref(parent);
926 dom_node_unref(n);
927 return NULL;
928 }
929
930 if (box_for_node(parent) != NULL) {
932 content);
933 }
934
935 dom_node_unref(parent);
936 }
937
938 dom_node_unref(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 box_construct_text(struct box_construct_ctx *ctx)
991{
992 struct box_construct_props props;
993 struct box *box = NULL;
994 dom_string *content;
995 dom_exception err;
996
997 assert(ctx->n != NULL);
998
999 box_extract_properties(ctx->n, &props);
1000
1001 assert(props.containing_block != NULL);
1002
1003 err = dom_characterdata_get_data(ctx->n, &content);
1004 if (err != DOM_NO_ERR || content == NULL)
1005 return false;
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)
1018 return false;
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) {
1024 assert(props.inline_container->last != NULL);
1025
1026 props.inline_container->last->space =
1028 }
1029
1030 free(text);
1031
1032 return true;
1033 }
1034
1035 if (props.inline_container == NULL) {
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, NULL, false,
1040 NULL, NULL, NULL, NULL, ctx->bctx);
1041 if (props.inline_container == NULL) {
1042 free(text);
1043 return false;
1044 }
1045
1047
1049 props.inline_container);
1050 }
1051
1052 /** \todo Dropping const here is not clever */
1053 box = box_create(NULL,
1054 (css_computed_style *) props.parent_style,
1055 false, props.href, props.target, props.title,
1056 NULL, ctx->bctx);
1057 if (box == NULL) {
1058 free(text);
1059 return false;
1060 }
1061
1062 box->type = BOX_TEXT;
1063
1064 box->text = talloc_strdup(ctx->bctx, text);
1065 free(text);
1066 if (box->text == NULL)
1067 return false;
1068
1069 box->length = strlen(box->text);
1070
1071 /* strip ending space char off */
1072 if (box->length > 1 && box->text[box->length - 1] == ' ') {
1074 box->length--;
1075 }
1076
1077 if (css_computed_text_transform(props.parent_style) !=
1078 CSS_TEXT_TRANSFORM_NONE)
1080 css_computed_text_transform(
1081 props.parent_style));
1082
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)
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 ||
1104 white_space == CSS_WHITE_SPACE_PRE_LINE ||
1105 white_space == CSS_WHITE_SPACE_PRE_WRAP);
1106
1107 text = malloc(text_len + 1);
1108 dom_string_unref(content);
1109
1110 if (text == NULL)
1111 return false;
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) {
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, NULL,
1157 false, NULL, NULL, NULL, NULL,
1158 ctx->bctx);
1159 if (props.inline_container == NULL) {
1160 free(text);
1161 return false;
1162 }
1163
1164 props.inline_container->type =
1166
1168 props.inline_container);
1169 }
1170
1171 /** \todo Dropping const isn't clever */
1172 box = box_create(NULL,
1173 (css_computed_style *) props.parent_style,
1174 false, props.href, props.target, props.title,
1175 NULL, ctx->bctx);
1176 if (box == NULL) {
1177 free(text);
1178 return false;
1179 }
1180
1181 box->type = BOX_TEXT;
1182
1183 box->text = talloc_strdup(ctx->bctx, current);
1184 if (box->text == NULL) {
1185 free(text);
1186 return false;
1187 }
1188
1189 box->length = strlen(box->text);
1190
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, NULL,
1200 false, NULL, NULL, NULL, NULL,
1201 ctx->bctx);
1202 if (props.inline_container == NULL) {
1203 free(text);
1204 return false;
1205 }
1206
1207 props.inline_container->type =
1209
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 true;
1224}
1225
1226
1227/**
1228 * Convert an ELEMENT node to a box tree fragment,
1229 * then schedule conversion of the next ELEMENT node
1230 */
1232{
1233 dom_node *next;
1234 bool convert_children;
1235 uint32_t num_processed = 0;
1236 const uint32_t max_processed_before_yield = 10;
1237
1238 do {
1239 convert_children = true;
1240
1241 assert(ctx->n != NULL);
1242
1243 if (box_construct_element(ctx, &convert_children) == false) {
1244 ctx->cb(ctx->content, false);
1245 dom_node_unref(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) {
1253 dom_node_type type;
1254 dom_exception err;
1255
1256 err = dom_node_get_node_type(next, &type);
1257 if (err != DOM_NO_ERR) {
1258 ctx->cb(ctx->content, false);
1259 dom_node_unref(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) == false) {
1270 ctx->cb(ctx->content, false);
1271 dom_node_unref(ctx->n);
1272 free(ctx);
1273 return;
1274 }
1275 }
1276
1277 next = next_node(next, ctx->content, true);
1278 }
1279
1280 ctx->n = next;
1281
1282 if (next == NULL) {
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 */
1294 ctx->content) == false) {
1295 ctx->cb(ctx->content, false);
1296 } else {
1297 ctx->content->layout = root.children;
1298 ctx->content->layout->parent = NULL;
1299
1300 ctx->cb(ctx->content, true);
1301 }
1302
1303 assert(ctx->n == NULL);
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,
1320 void **box_conversion_context)
1321{
1322 struct box_construct_ctx *ctx;
1323
1324 assert(box_conversion_context != NULL);
1325
1326 if (c->bctx == NULL) {
1327 /* create a context allocation for this box tree */
1328 c->bctx = talloc_zero(0, int);
1329 if (c->bctx == NULL) {
1330 return NSERROR_NOMEM;
1331 }
1332 }
1333
1334 ctx = malloc(sizeof(*ctx));
1335 if (ctx == NULL) {
1336 return NSERROR_NOMEM;
1337 }
1338
1339 ctx->content = c;
1340 ctx->n = dom_node_ref(n);
1341 ctx->root_box = NULL;
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);
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;
1373 dom_exception err;
1374
1375 err = dom_node_get_user_data(n, corestring_dom___ns_key_box_node_data,
1376 (void *) &box);
1377 if (err != DOM_NO_ERR)
1378 return NULL;
1379
1380 return box;
1381}
1382
1383/* exported function documented in html/box_construct.h */
1384bool
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 false;
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 == false) {
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;
1446 return false;
1447 }
1448
1449 return true;
1450}
STATIC char result[100]
Definition: arexx.c:77
Helpers for ASCII string handling.
static char ascii_to_lower(char c)
Convert an upper case character to lower case.
Definition: ascii.h:212
static char ascii_to_upper(char c)
Convert a lower case character to upper case.
Definition: ascii.h:226
static bool ascii_is_space(char c)
Test whether a character is a whitespace character.
Definition: ascii.h:40
Box interface.
void(* box_construct_complete_cb)(struct html_content *c, bool success)
Definition: box.h:49
#define UNKNOWN_WIDTH
Definition: box.h:45
box_type
Type of a struct box.
Definition: box.h:55
@ BOX_BLOCK
Definition: box.h:56
@ BOX_FLOAT_LEFT
Definition: box.h:63
@ BOX_INLINE_BLOCK
Definition: box.h:65
@ BOX_FLOAT_RIGHT
Definition: box.h:64
@ BOX_INLINE_CONTAINER
Definition: box.h:57
@ BOX_TABLE_CELL
Definition: box.h:61
@ BOX_TABLE_ROW_GROUP
Definition: box.h:62
@ BOX_INLINE_END
Definition: box.h:68
@ BOX_TABLE
Definition: box.h:59
@ BOX_INLINE
Definition: box.h:58
@ BOX_TABLE_ROW
Definition: box.h:60
@ BOX_TEXT
Definition: box.h:67
@ BOX_INLINE_FLEX
Definition: box.h:71
@ BOX_BR
Definition: box.h:66
@ BOX_FLEX
Definition: box.h:70
@ BOX_NONE
Definition: box.h:69
@ CONVERT_CHILDREN
Definition: box.h:90
@ IS_REPLACED
Definition: box.h:91
@ PRE_STRIP
Definition: box.h:82
static void box_construct_element_after(dom_node *n, html_content *content)
Complete construction of the box tree for an element.
static bool box__is_flex(const struct box *box)
static const box_type box_map[]
Definition: box_construct.c:91
static bool box_construct_text(struct box_construct_ctx *ctx)
Construct the box tree for an XML text node.
static bool box__style_is_float(const struct box *box)
nserror dom_to_box(dom_node *n, html_content *c, box_construct_complete_cb cb, void **box_conversion_context)
Construct a box tree from a dom and html content.
static void box_extract_properties(dom_node *n, struct box_construct_props *props)
Extract transient construction properties.
static dom_node * next_node(dom_node *n, html_content *content, bool convert_children)
Find the next node in the DOM tree, completing element construction where appropriate.
struct box * box_for_node(dom_node *n)
Retrieve the box for a dom node, if there is one.
static css_select_results * box_get_style(html_content *c, const css_computed_style *parent_style, const css_computed_style *root_style, dom_node *n)
Get the style for an element.
static bool box_is_root(dom_node *n)
determine if a box is the root node
static void box_text_transform(char *s, unsigned int len, enum css_text_transform_e tt)
Apply the CSS text-transform property to given text for its ASCII chars.
bool box_extract_link(const html_content *content, const dom_string *dsrel, nsurl *base, nsurl **result)
static bool box__containing_block_is_flex(const struct box_construct_props *props)
static bool box_construct_marker(struct box *box, const char *title, struct box_construct_ctx *ctx, struct box *parent)
Construct a list marker box.
nserror cancel_dom_to_box(void *box_conversion_context)
aborts any ongoing box construction
static void convert_xml_to_box(struct box_construct_ctx *ctx)
Convert an ELEMENT node to a box tree fragment, then schedule conversion of the next ELEMENT node.
static void box_construct_generate(dom_node *n, html_content *content, struct box *box, const css_computed_style *style)
Construct the box required for a generated element.
static bool box_construct_element(struct box_construct_ctx *ctx, bool *convert_children)
Construct the box tree for an XML element.
static const content_type image_types
Definition: box_construct.c:87
HTML Box tree construction interface.
struct box * box_create(css_select_results *styles, css_computed_style *style, bool style_owned, nsurl *href, const char *target, const char *title, lwc_string *id, void *context)
Create a box tree node.
void box_add_child(struct box *parent, struct box *child)
Add a child to a box tree node.
Box tree manipulation interface.
bool box_normalise_block(struct box *block, const struct box *root, html_content *c)
Ensure the box tree is correctly nested by adding and removing nodes.
HTML Box tree normalise interface.
bool convert_special_elements(dom_node *node, html_content *content, struct box *box, bool *convert_children)
call an elements special conversion handler
Definition: box_special.c:1855
HTML Box tree construction special element conversion interface.
static uint8_t ns_computed_display(const css_computed_style *style, bool root)
Temporary helper wrappers for for libcss computed style getter, while we don't support all values of ...
Definition: utils.h:33
static uint8_t ns_computed_display_static(const css_computed_style *style)
Temporary helper wrappers for for libcss computed style getter, while we don't support all values of ...
Definition: utils.h:56
bool html_fetch_object(html_content *c, nsurl *url, struct box *box, content_type permitted_types, bool background)
Start a fetch for an object required by a page.
Definition: object.c:710
HTML content object interface.
content_type
The type of a content.
Definition: content_type.h:53
@ CONTENT_IMAGE
All images.
Definition: content_type.h:67
Useful interned string pointers (interface).
wimp_w parent
Definition: dialog.c:88
Error codes.
nserror
Enumeration of error codes.
Definition: errors.h:29
@ NSERROR_NOMEM
Memory exhaustion.
Definition: errors.h:32
@ NSERROR_OK
No error.
Definition: errors.h:30
static struct directory * root
Definition: filename.c:55
const char * type
Definition: filetype.cpp:44
Interface to form handling functions internal to HTML content handler.
struct netsurf_table * guit
The global interface table.
Definition: gui_factory.c:49
Interface to core interface table.
Interface to platform-specific miscellaneous browser operation table.
NetSurf URL handling (interface).
nserror nsurl_create(const char *const url_s, nsurl **url)
Create a NetSurf URL object from a URL string.
void nsurl_unref(nsurl *url)
Drop a reference to a NetSurf URL object.
const char * nsurl_access(const nsurl *url)
Access a NetSurf URL object as a string.
nserror nsurl_join(const nsurl *base, const char *rel, nsurl **joined)
Join a base url to a relative link part, creating a new NetSurf URL object.
struct nsurl nsurl
NetSurf URL object.
Definition: nsurl.h:31
Private data for text/html content.
@ base
Definition: punycode.c:19
css_select_results * nscss_get_style(nscss_select_ctx *ctx, dom_node *n, const css_media *media, const css_unit_ctx *unit_len_ctx, const css_stylesheet *inline_style)
Get style selection results for an element.
Definition: select.c:253
css_stylesheet * nscss_create_inline_style(const uint8_t *data, size_t len, const char *charset, const char *url, bool allow_quirks)
Create an inline style.
Definition: select.c:148
static css_error parent_node(void *pw, void *node, void **parent)
Callback to retrieve the parent of a node.
Definition: select.c:644
Interface to utility string handling.
char * squash_whitespace(const char *s)
Replace consecutive whitespace with a single space.
Definition: utils.c:38
Context for box tree construction.
Definition: box_construct.c:54
box_construct_complete_cb cb
Callback to invoke on completion.
Definition: box_construct.c:61
struct box * root_box
Root box in the tree.
Definition: box_construct.c:59
int * bctx
talloc context
Definition: box_construct.c:63
dom_node * n
Current node to process.
Definition: box_construct.c:57
html_content * content
Content we're constructing for.
Definition: box_construct.c:55
Transient properties for construction of current node.
Definition: box_construct.c:69
struct nsurl * href
Current link target, or NULL if none.
Definition: box_construct.c:73
bool node_is_root
Whether the current node is the root of the DOM tree.
Definition: box_construct.c:84
struct box * containing_block
Identity of the current block-level container.
Definition: box_construct.c:79
const char * target
Current frame target, or NULL if none.
Definition: box_construct.c:75
struct box * inline_container
Current container for inlines, or NULL if none.
Definition: box_construct.c:82
const css_computed_style * parent_style
Style from which to inherit, or NULL if none.
Definition: box_construct.c:71
const char * title
Current title attribute, or NULL if none.
Definition: box_construct.c:77
Node in box tree.
Definition: box.h:177
struct box * parent
Parent box, or NULL.
Definition: box.h:236
lwc_string * id
value of id attribute (or name for anchors)
Definition: box.h:210
const char * title
Title, or NULL.
Definition: box.h:386
struct box * inline_end
INLINE_END box corresponding to this INLINE box, or INLINE box corresponding to this INLINE_END box.
Definition: box.h:242
struct box * prev
Previous sibling box, or NULL.
Definition: box.h:221
struct box * list_marker
List marker box if this is a list-item, or NULL.
Definition: box.h:417
const char * target
Link target, or NULL.
Definition: box.h:381
css_select_results * styles
Computed styles for elements and their pseudo elements.
Definition: box.h:197
struct box * last
Last child box, or NULL.
Definition: box.h:231
struct box * next
Next sibling box, or NULL.
Definition: box.h:216
box_type type
Type of box.
Definition: box.h:181
struct nsurl * href
Link, or NULL.
Definition: box.h:376
css_computed_style * style
Style for this box.
Definition: box.h:205
size_t length
Length of text.
Definition: box.h:360
char * text
Text, or NULL if none.
Definition: box.h:355
box_flags flags
Box flags.
Definition: box.h:186
int space
Width of space after current text (depends on font and size).
Definition: box.h:365
struct form_control * gadget
Form control data, or NULL if not a form control.
Definition: box.h:423
unsigned int rows
Number of rows for TABLE only.
Definition: box.h:397
struct dom_node * node
DOM node that generated this box or NULL.
Definition: box.h:191
unsigned int columns
Number of columns for TABLE / TABLE_CELL.
Definition: box.h:392
Content which corresponds to a single URL.
struct box * box
Box for control.
Definition: form_internal.h:89
nserror(* schedule)(int t, void(*callback)(void *p), void *p)
Schedule a callback.
Definition: misc.h:58
Data specific to CONTENT_HTML.
Definition: private.h:93
dom_document_quirks_mode quirks
Quirkyness of document.
Definition: private.h:103
int * bctx
A talloc context purely for the render box tree.
Definition: private.h:134
char * encoding
Encoding of source, NULL if unknown.
Definition: private.h:106
struct nsurl * base_url
Base URL (may be a copy of content->url).
Definition: private.h:111
css_select_ctx * select_ctx
Style selection media specification.
Definition: private.h:159
css_media media
Definition: private.h:161
css_unit_ctx unit_len_ctx
CSS length conversion context for document.
Definition: private.h:163
struct box * layout
Box tree, or NULL.
Definition: private.h:140
lwc_string * universal
Definition: private.h:165
struct gui_misc_table * misc
Browser table.
Definition: gui_table.h:57
Selection context.
Definition: select.h:35
struct nsurl * base_url
Definition: select.h:38
css_select_ctx * ctx
Definition: select.h:36
lwc_string * universal
Definition: select.h:39
const css_computed_style * parent_style
Definition: select.h:41
const css_computed_style * root_style
Definition: select.h:40
char * talloc_strdup(const void *t, const char *p)
Definition: talloc.c:1118
#define talloc_zero(ctx, type)
Definition: talloc.h:91
Option reading and saving interface.
#define nsoption_bool(OPTION)
Get the value of a boolean option.
Definition: nsoption.h:270
static nserror text(const struct redraw_context *ctx, const struct plot_font_style *fstyle, int x, int y, const char *text, size_t length)
Text plotting.
Definition: plot.c:978