summaryrefslogtreecommitdiff
path: root/content/handlers
diff options
context:
space:
mode:
authorVincent Sanders <vince@kyllikki.org>2020-04-28 23:30:20 +0100
committerVincent Sanders <vince@kyllikki.org>2020-04-28 23:30:20 +0100
commitc0ef8ce645d6077831877b5a8499b89c18df7bf9 (patch)
tree28cb9813cdfaac57218ebf24264c124af92e6584 /content/handlers
parentf6883d6761975c6512455f0c854b683240c7cd48 (diff)
downloadnetsurf-c0ef8ce645d6077831877b5a8499b89c18df7bf9.tar.gz
netsurf-c0ef8ce645d6077831877b5a8499b89c18df7bf9.tar.bz2
clean up html box, no functionality change just cosmetic
split up the html box headers tidy up the documentation comments avoid forward declarations in normalisation implementation
Diffstat (limited to 'content/handlers')
-rw-r--r--content/handlers/html/box.c199
-rw-r--r--content/handlers/html/box.h613
-rw-r--r--content/handlers/html/box_construct.c62
-rw-r--r--content/handlers/html/box_construct.h65
-rw-r--r--content/handlers/html/box_normalise.c874
-rw-r--r--content/handlers/html/box_normalise.h50
-rw-r--r--content/handlers/html/html.c3
-rw-r--r--content/handlers/html/imagemap.c1
8 files changed, 1040 insertions, 827 deletions
diff --git a/content/handlers/html/box.c b/content/handlers/html/box.c
index 94c74877f..0ad10619b 100644
--- a/content/handlers/html/box.c
+++ b/content/handlers/html/box.c
@@ -97,26 +97,17 @@ static int box_talloc_destructor(struct box *b)
return 0;
}
-/**
- * Create a box tree node.
- *
- * \param styles selection results for the box, or NULL
- * \param style computed style for the box (not copied), or 0
- * \param style_owned whether style is owned by this box
- * \param href href for the box (copied), or 0
- * \param target target for the box (not copied), or 0
- * \param title title for the box (not copied), or 0
- * \param id id for the box (not copied), or 0
- * \param context context for allocations
- * \return allocated and initialised box, or 0 on memory exhaustion
- *
- * styles is always owned by the box, if it is set.
- * style is only owned by the box in the case of implied boxes.
- */
-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)
+/* Exported function documented in html/box.h */
+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)
{
unsigned int i;
struct box *box;
@@ -177,13 +168,8 @@ struct box * box_create(css_select_results *styles, css_computed_style *style,
return box;
}
-/**
- * Add a child to a box tree node.
- *
- * \param parent box giving birth
- * \param child box to link as last child of parent
- */
+/* Exported function documented in html/box.h */
void box_add_child(struct box *parent, struct box *child)
{
assert(parent);
@@ -202,13 +188,7 @@ void box_add_child(struct box *parent, struct box *child)
}
-/**
- * Insert a new box as a sibling to a box in a tree.
- *
- * \param box box already in tree
- * \param new_box box to link into tree as next sibling
- */
-
+/* Exported function documented in html/box.h */
void box_insert_sibling(struct box *box, struct box *new_box)
{
new_box->parent = box->parent;
@@ -222,12 +202,7 @@ void box_insert_sibling(struct box *box, struct box *new_box)
}
-/**
- * Unlink a box from the box tree and then free it recursively.
- *
- * \param box box to unlink and free recursively.
- */
-
+/* Exported function documented in html/box.h */
void box_unlink_and_free(struct box *box)
{
struct box *parent = box->parent;
@@ -250,14 +225,7 @@ void box_unlink_and_free(struct box *box)
}
-/**
- * Free a box tree recursively.
- *
- * \param box box to free recursively
- *
- * The box and all its children is freed.
- */
-
+/* Exported function documented in html/box.h */
void box_free(struct box *box)
{
struct box *child, *next;
@@ -273,12 +241,7 @@ void box_free(struct box *box)
}
-/**
- * Free the data in a single box structure.
- *
- * \param box box to free
- */
-
+/* Exported function documented in html/box.h */
void box_free_box(struct box *box)
{
if (!(box->flags & CLONE)) {
@@ -296,14 +259,7 @@ void box_free_box(struct box *box)
}
-/**
- * Find the absolute coordinates of a box.
- *
- * \param box the box to calculate coordinates of
- * \param x updated to x coordinate
- * \param y updated to y coordinate
- */
-
+/* Exported function documented in html/box.h */
void box_coords(struct box *box, int *x, int *y)
{
*x = box->x;
@@ -321,13 +277,7 @@ void box_coords(struct box *box, int *x, int *y)
}
-/**
- * Find the bounds of a box.
- *
- * \param box the box to calculate bounds of
- * \param r receives bounds
- */
-
+/* Exported function documented in html/box.h */
void box_bounds(struct box *box, struct rect *r)
{
int width, height;
@@ -359,7 +309,6 @@ void box_bounds(struct box *box, struct rect *r)
*
* This is a helper function for box_at_point().
*/
-
static bool box_contains_point(
const nscss_len_ctx *len_ctx,
const struct box *box,
@@ -471,7 +420,9 @@ static bool box_contains_point(
}
-/** Direction to move in a box-tree walk */
+/**
+ * Direction to move in a box-tree walk
+ */
enum box_walk_dir {
BOX_WALK_CHILDREN,
BOX_WALK_PARENT,
@@ -492,8 +443,8 @@ enum box_walk_dir {
*
* If no box can be found in given direction, NULL is returned.
*/
-static inline struct box *box_move_xy(struct box *b, enum box_walk_dir dir,
- int *x, int *y)
+static inline struct box *
+box_move_xy(struct box *b, enum box_walk_dir dir, int *x, int *y)
{
struct box *rb = NULL;
@@ -665,35 +616,12 @@ skip_children:
}
-
-/**
- * Find the boxes at a point.
- *
- * \param len_ctx CSS length conversion context for document.
- * \param box box to search children of
- * \param x point to find, in global document coordinates
- * \param y point to find, in global document coordinates
- * \param box_x position of box, in global document coordinates, updated
- * to position of returned box, if any
- * \param box_y position of box, in global document coordinates, updated
- * to position of returned box, if any
- * \return box at given point, or 0 if none found
- *
- * To find all the boxes in the hierarchy at a certain point, use code like
- * this:
- * \code
- * struct box *box = top_of_document_to_search;
- * int box_x = 0, box_y = 0;
- *
- * while ((box = box_at_point(len_ctx, box, x, y, &box_x, &box_y))) {
- * // process box
- * }
- * \endcode
- */
-
-struct box *box_at_point(const nscss_len_ctx *len_ctx,
- struct box *box, const int x, const int y,
- int *box_x, int *box_y)
+/* Exported function documented in html/box.h */
+struct box *
+box_at_point(const nscss_len_ctx *len_ctx,
+ struct box *box,
+ const int x, const int y,
+ int *box_x, int *box_y)
{
bool skip_children;
bool physically;
@@ -742,10 +670,14 @@ struct box *box_at_point(const nscss_len_ctx *len_ctx,
* updated if box is nearer than existing nearest
* \return true if mouse point is inside box
*/
-
-static bool box_nearer_text_box(struct box *box, int bx, int by,
- int x, int y, int dir, struct box **nearest, int *tx, int *ty,
- int *nr_xd, int *nr_yd)
+static bool
+box_nearer_text_box(struct box *box,
+ int bx, int by,
+ int x, int y,
+ int dir,
+ struct box **nearest,
+ int *tx, int *ty,
+ int *nr_xd, int *nr_yd)
{
int w = box->padding[LEFT] + box->width + box->padding[RIGHT];
int h = box->padding[TOP] + box->height + box->padding[BOTTOM];
@@ -814,7 +746,6 @@ static bool box_nearer_text_box(struct box *box, int bx, int by,
* updated if a descendant of box is nearer than old nearest
* \return true if mouse point is inside text_box
*/
-
static bool box_nearest_text_box(struct box *box, int bx, int by,
int fx, int fy, int x, int y, int dir, struct box **nearest,
int *tx, int *ty, int *nr_xd, int *nr_yd)
@@ -885,21 +816,12 @@ static bool box_nearest_text_box(struct box *box, int bx, int by,
}
-/**
- * Peform pick text on browser window contents to locate the box under
- * the mouse pointer, or nearest in the given direction if the pointer is
- * not over a text box.
- *
- * \param html an HTML content
- * \param x coordinate of mouse
- * \param y coordinate of mouse
- * \param dir direction to search (-1 = above-left, +1 = below-right)
- * \param dx receives x ordinate of mouse relative to text box
- * \param dy receives y ordinate of mouse relative to text box
- */
-
-struct box *box_pick_text_box(struct html_content *html,
- int x, int y, int dir, int *dx, int *dy)
+/* Exported function documented in html/box.h */
+struct box *
+box_pick_text_box(struct html_content *html,
+ int x, int y,
+ int dir,
+ int *dx, int *dy)
{
struct box *text_box = NULL;
struct box *box;
@@ -947,14 +869,7 @@ struct box *box_pick_text_box(struct html_content *html,
}
-/**
- * Find a box based upon its id attribute.
- *
- * \param box box tree to search
- * \param id id to look for
- * \return the box or 0 if not found
- */
-
+/* Exported function documented in html/box.h */
struct box *box_find_by_id(struct box *box, lwc_string *id)
{
struct box *a, *b;
@@ -974,13 +889,7 @@ struct box *box_find_by_id(struct box *box, lwc_string *id)
}
-/**
- * Determine if a box is visible when the tree is rendered.
- *
- * \param box box to check
- * \return true iff the box is rendered
- */
-
+/* Exported function documented in html/box.h */
bool box_visible(struct box *box)
{
/* visibility: hidden */
@@ -992,10 +901,7 @@ bool box_visible(struct box *box)
}
-/**
- * Print a box tree to a file.
- */
-
+/* Exported function documented in html/box.h */
void box_dump(FILE *stream, struct box *box, unsigned int depth, bool style)
{
unsigned int i;
@@ -1218,13 +1124,8 @@ box_handle_scrollbars(struct content *c,
return NSERROR_OK;
}
-/**
- * Determine if a box has a vertical scrollbar.
- *
- * \param box scrolling box
- * \return the box has a vertical scrollbar
- */
+/* exported interface documented in html/box.h */
bool box_vscrollbar_present(const struct box * const box)
{
return box->padding[TOP] + box->height + box->padding[BOTTOM] +
@@ -1232,13 +1133,7 @@ bool box_vscrollbar_present(const struct box * const box)
}
-/**
- * Determine if a box has a horizontal scrollbar.
- *
- * \param box scrolling box
- * \return the box has a horizontal scrollbar
- */
-
+/* exported interface documented in html/box.h */
bool box_hscrollbar_present(const struct box * const box)
{
return box->padding[LEFT] + box->width + box->padding[RIGHT] +
diff --git a/content/handlers/html/box.h b/content/handlers/html/box.h
index efad90fe4..1781d1332 100644
--- a/content/handlers/html/box.h
+++ b/content/handlers/html/box.h
@@ -19,7 +19,7 @@
/**
* \file
- * Box tree construction and manipulation (interface).
+ * Box tree construction and manipulation interface.
*
* This stage of rendering converts a tree of dom_nodes (produced by libdom)
* to a tree of struct box. The box tree represents the structure of the
@@ -97,9 +97,6 @@
struct content;
struct box;
struct browser_window;
-struct column;
-struct object_params;
-struct object_param;
struct html_content;
struct nsurl;
struct dom_node;
@@ -109,20 +106,34 @@ struct rect;
#define UNKNOWN_WIDTH INT_MAX
#define UNKNOWN_MAX_WIDTH INT_MAX
+
typedef void (*box_construct_complete_cb)(struct html_content *c, bool success);
-/** Type of a struct box. */
+
+/**
+ * Type of a struct box.
+ */
typedef enum {
- BOX_BLOCK, BOX_INLINE_CONTAINER, BOX_INLINE,
- BOX_TABLE, BOX_TABLE_ROW, BOX_TABLE_CELL,
+ BOX_BLOCK,
+ BOX_INLINE_CONTAINER,
+ BOX_INLINE,
+ BOX_TABLE,
+ BOX_TABLE_ROW,
+ BOX_TABLE_CELL,
BOX_TABLE_ROW_GROUP,
- BOX_FLOAT_LEFT, BOX_FLOAT_RIGHT,
- BOX_INLINE_BLOCK, BOX_BR, BOX_TEXT,
- BOX_INLINE_END, BOX_NONE
+ BOX_FLOAT_LEFT,
+ BOX_FLOAT_RIGHT,
+ BOX_INLINE_BLOCK,
+ BOX_BR,
+ BOX_TEXT,
+ BOX_INLINE_END,
+ BOX_NONE
} box_type;
-/** Flags for a struct box. */
+/**
+ * Flags for a struct box.
+ */
typedef enum {
NEW_LINE = 1 << 0, /* first inline on a new line */
STYLE_OWNED = 1 << 1, /* style is owned by this box */
@@ -139,9 +150,13 @@ typedef enum {
IS_REPLACED = 1 << 12 /* box is a replaced element */
} box_flags;
-/* Sides of a box */
+
+/**
+ * Sides of a box
+ */
enum box_side { TOP, RIGHT, BOTTOM, LEFT };
+
/**
* Container for box border details
*/
@@ -151,31 +166,190 @@ struct box_border {
int width; /**< border-width (pixels) */
};
-/** Node in box tree. All dimensions are in pixels. */
+
+/**
+ * Table column data.
+ */
+struct column {
+ /**
+ * Type of column.
+ */
+ enum {
+ COLUMN_WIDTH_UNKNOWN,
+ COLUMN_WIDTH_FIXED,
+ COLUMN_WIDTH_AUTO,
+ COLUMN_WIDTH_PERCENT,
+ COLUMN_WIDTH_RELATIVE
+ } type;
+
+ /**
+ * Preferred width of column. Pixels for FIXED, percentage for
+ * PERCENT, relative units for RELATIVE, unused for AUTO.
+ */
+ int width;
+
+ /**
+ * Minimum width of content.
+ */
+ int min;
+
+ /**
+ * Maximum width of content.
+ */
+ int max;
+
+ /**
+ * Whether all of column's cells are css positioned.
+ */
+ bool positioned;
+};
+
+
+/**
+ * Linked list of object element parameters.
+ */
+struct object_param {
+ char *name;
+ char *value;
+ char *type;
+ char *valuetype;
+ struct object_param *next;
+};
+
+
+/**
+ * Parameters for object element and similar elements.
+ */
+struct object_params {
+ struct nsurl *data;
+ char *type;
+ char *codetype;
+ struct nsurl *codebase;
+ struct nsurl *classid;
+ struct object_param *params;
+};
+
+
+/**
+ * Node in box tree. All dimensions are in pixels.
+ */
struct box {
- /** Type of box. */
+ /**
+ * Type of box.
+ */
box_type type;
- /** Box flags */
+ /**
+ * Box flags
+ */
box_flags flags;
- /** Computed styles for elements and their pseudo elements. NULL on
- * non-element boxes. */
+ /**
+ * DOM node that generated this box or NULL
+ */
+ struct dom_node *node;
+
+ /**
+ * Computed styles for elements and their pseudo elements.
+ * NULL on non-element boxes.
+ */
css_select_results *styles;
- /** Style for this box. 0 for INLINE_CONTAINER and FLOAT_*. Pointer into
- * a box's 'styles' select results, except for implied boxes, where it
- * is a pointer to an owned computed style. */
+ /**
+ * Style for this box. 0 for INLINE_CONTAINER and
+ * FLOAT_*. Pointer into a box's 'styles' select results,
+ * except for implied boxes, where it is a pointer to an
+ * owned computed style.
+ */
css_computed_style *style;
- /** Coordinate of left padding edge relative to parent box, or relative
- * to ancestor that contains this box in float_children for FLOAT_. */
+ /**
+ * value of id attribute (or name for anchors)
+ */
+ lwc_string *id;
+
+
+ /**
+ * Next sibling box, or NULL.
+ */
+ struct box *next;
+
+ /**
+ * Previous sibling box, or NULL.
+ */
+ struct box *prev;
+
+ /**
+ * First child box, or NULL.
+ */
+ struct box *children;
+
+ /**
+ * Last child box, or NULL.
+ */
+ struct box *last;
+
+ /**
+ * Parent box, or NULL.
+ */
+ struct box *parent;
+
+ /**
+ * INLINE_END box corresponding to this INLINE box, or INLINE
+ * box corresponding to this INLINE_END box.
+ */
+ struct box *inline_end;
+
+
+ /**
+ * First float child box, or NULL. Float boxes are in the tree
+ * twice, in this list for the block box which defines the
+ * area for floats, and also in the standard tree given by
+ * children, next, prev, etc.
+ */
+ struct box *float_children;
+
+ /**
+ * Next sibling float box.
+ */
+ struct box *next_float;
+
+ /**
+ * If box is a float, points to box's containing block
+ */
+ struct box *float_container;
+
+ /**
+ * Level below which subsequent floats must be cleared. This
+ * is used only for boxes with float_children
+ */
+ int clear_level;
+
+ /**
+ * Level below which floats have been placed.
+ */
+ int cached_place_below_level;
+
+
+ /**
+ * Coordinate of left padding edge relative to parent box, or
+ * relative to ancestor that contains this box in
+ * float_children for FLOAT_.
+ */
int x;
- /** Coordinate of top padding edge, relative as for x. */
+ /**
+ * Coordinate of top padding edge, relative as for x.
+ */
int y;
- int width; /**< Width of content box (excluding padding etc.). */
- int height; /**< Height of content box (excluding padding etc.). */
+ /**
+ * Width of content box (excluding padding etc.).
+ */
+ int width;
+ /**
+ * Height of content box (excluding padding etc.).
+ */
+ int height;
/* These four variables determine the maximum extent of a box's
* descendants. They are relative to the x,y coordinates of the box.
@@ -196,123 +370,146 @@ struct box {
int descendant_x1; /**< right edge of descendants */
int descendant_y1; /**< bottom edge of descendants */
- int margin[4]; /**< Margin: TOP, RIGHT, BOTTOM, LEFT. */
- int padding[4]; /**< Padding: TOP, RIGHT, BOTTOM, LEFT. */
- struct box_border border[4]; /**< Border: TOP, RIGHT, BOTTOM, LEFT. */
+ /**
+ * Margin: TOP, RIGHT, BOTTOM, LEFT.
+ */
+ int margin[4];
+
+ /**
+ * Padding: TOP, RIGHT, BOTTOM, LEFT.
+ */
+ int padding[4];
+
+ /**
+ * Border: TOP, RIGHT, BOTTOM, LEFT.
+ */
+ struct box_border border[4];
+
+ /**
+ * Horizontal scroll.
+ */
+ struct scrollbar *scroll_x;
- struct scrollbar *scroll_x; /**< Horizontal scroll. */
- struct scrollbar *scroll_y; /**< Vertical scroll. */
+ /**
+ * Vertical scroll.
+ */
+ struct scrollbar *scroll_y;
- /** Width of box taking all line breaks (including margins etc). Must
- * be non-negative. */
+ /**
+ * Width of box taking all line breaks (including margins
+ * etc). Must be non-negative.
+ */
int min_width;
- /** Width that would be taken with no line breaks. Must be
- * non-negative. */
+
+ /**
+ * Width that would be taken with no line breaks. Must be
+ * non-negative.
+ */
int max_width;
- /**< Byte offset within a textual representation of this content. */
- size_t byte_offset;
- char *text; /**< Text, or 0 if none. Unterminated. */
- size_t length; /**< Length of text. */
+ /**
+ * Text, or NULL if none. Unterminated.
+ */
+ char *text;
+
+ /**
+ * Length of text.
+ */
+ size_t length;
- /** Width of space after current text (depends on font and size). */
+ /**
+ * Width of space after current text (depends on font and size).
+ */
int space;
- struct nsurl *href; /**< Link, or 0. */
- const char *target; /**< Link target, or 0. */
- const char *title; /**< Title, or 0. */
-
- unsigned int columns; /**< Number of columns for TABLE / TABLE_CELL. */
- unsigned int rows; /**< Number of rows for TABLE only. */
- unsigned int start_column; /**< Start column for TABLE_CELL only. */
-
- struct box *next; /**< Next sibling box, or 0. */
- struct box *prev; /**< Previous sibling box, or 0. */
- struct box *children; /**< First child box, or 0. */
- struct box *last; /**< Last child box, or 0. */
- struct box *parent; /**< Parent box, or 0. */
- /** INLINE_END box corresponding to this INLINE box, or INLINE box
- * corresponding to this INLINE_END box. */
- struct box *inline_end;
+ /**
+ * Byte offset within a textual representation of this content.
+ */
+ size_t byte_offset;
- /** First float child box, or 0. Float boxes are in the tree twice, in
- * this list for the block box which defines the area for floats, and
- * also in the standard tree given by children, next, prev, etc. */
- struct box *float_children;
- /** Next sibling float box. */
- struct box *next_float;
- /** If box is a float, points to box's containing block */
- struct box *float_container;
- /** Level below which subsequent floats must be cleared.
- * This is used only for boxes with float_children */
- int clear_level;
- /* Level below which floats have been placed. */
- int cached_place_below_level;
+ /**
+ * Link, or NULL.
+ */
+ struct nsurl *href;
+
+ /**
+ * Link target, or NULL.
+ */
+ const char *target;
- /** List marker box if this is a list-item, or 0. */
+ /**
+ * Title, or NULL.
+ */
+ const char *title;
+
+
+ /**
+ * Number of columns for TABLE / TABLE_CELL.
+ */
+ unsigned int columns;
+
+ /**
+ * Number of rows for TABLE only.
+ */
+ unsigned int rows;
+
+ /**
+ * Start column for TABLE_CELL only.
+ */
+ unsigned int start_column;
+
+ /**
+ * Array of table column data for TABLE only.
+ */
+ struct column *col;
+
+
+ /**
+ * List marker box if this is a list-item, or NULL.
+ */
struct box *list_marker;
- struct column *col; /**< Array of table column data for TABLE only. */
- /** Form control data, or 0 if not a form control. */
+ /**
+ * Form control data, or NULL if not a form control.
+ */
struct form_control* gadget;
- char *usemap; /** (Image)map to use with this object, or 0 if none */
- lwc_string *id; /**< value of id attribute (or name for anchors) */
- /** Background image for this box, or 0 if none */
+ /**
+ * (Image)map to use with this object, or NULL if none
+ */
+ char *usemap;
+
+
+ /**
+ * Background image for this box, or NULL if none
+ */
struct hlcache_handle *background;
- /** Object in this box (usually an image), or 0 if none. */
+
+ /**
+ * Object in this box (usually an image), or NULL if none.
+ */
struct hlcache_handle* object;
- /** Parameters for the object, or 0. */
- struct object_params *object_params;
- /** Iframe's browser_window, or NULL if none */
- struct browser_window *iframe;
+ /**
+ * Parameters for the object, or NULL.
+ */
+ struct object_params *object_params;
- struct dom_node *node; /**< DOM node that generated this box or NULL */
-};
-/** Table column data. */
-struct column {
- /** Type of column. */
- enum { COLUMN_WIDTH_UNKNOWN, COLUMN_WIDTH_FIXED,
- COLUMN_WIDTH_AUTO, COLUMN_WIDTH_PERCENT,
- COLUMN_WIDTH_RELATIVE } type;
- /** Preferred width of column. Pixels for FIXED, percentage for PERCENT,
- * relative units for RELATIVE, unused for AUTO. */
- int width;
- /** Minimum width of content. */
- int min;
- /** Maximum width of content. */
- int max;
- /** Whether all of column's cells are css positioned. */
- bool positioned;
-};
+ /**
+ * Iframe's browser_window, or NULL if none
+ */
+ struct browser_window *iframe;
-/** Parameters for object element and similar elements. */
-struct object_params {
- struct nsurl *data;
- char *type;
- char *codetype;
- struct nsurl *codebase;
- struct nsurl *classid;
- struct object_param *params;
};
-/** Linked list of object element parameters. */
-struct object_param {
- char *name;
- char *value;
- char *type;
- char *valuetype;
- struct object_param *next;
-};
-/** Frame target names (constant pointers to save duplicating the strings many
+/* Frame target names (constant pointers to save duplicating the strings many
* times). We convert _blank to _top for user-friendliness. */
extern const char *TARGET_SELF;
extern const char *TARGET_PARENT;
@@ -320,38 +517,154 @@ extern const char *TARGET_TOP;
extern const char *TARGET_BLANK;
+/**
+ * Create a box tree node.
+ *
+ * \param styles selection results for the box, or NULL
+ * \param style computed style for the box (not copied), or 0
+ * \param style_owned whether style is owned by this box
+ * \param href href for the box (copied), or 0
+ * \param target target for the box (not copied), or 0
+ * \param title title for the box (not copied), or 0
+ * \param id id for the box (not copied), or 0
+ * \param context context for allocations
+ * \return allocated and initialised box, or 0 on memory exhaustion
+ *
+ * styles is always owned by the box, if it is set.
+ * style is only owned by the box in the case of implied boxes.
+ */
+struct box * box_create(css_select_results *styles, css_computed_style *style, bool style_owned, struct nsurl *href, const char *target, const char *title, lwc_string *id, void *context);
+
-struct box * box_create(css_select_results *styles, css_computed_style *style,
- bool style_owned, struct nsurl *href, const char *target,
- const char *title, lwc_string *id, void *context);
+/**
+ * Add a child to a box tree node.
+ *
+ * \param parent box giving birth
+ * \param child box to link as last child of parent
+ */
void box_add_child(struct box *parent, struct box *child);
+
+
+/**
+ * Insert a new box as a sibling to a box in a tree.
+ *
+ * \param box box already in tree
+ * \param new_box box to link into tree as next sibling
+ */
void box_insert_sibling(struct box *box, struct box *new_box);
+
+
+/**
+ * Unlink a box from the box tree and then free it recursively.
+ *
+ * \param box box to unlink and free recursively.
+ */
void box_unlink_and_free(struct box *box);
+
+
+/**
+ * Free a box tree recursively.
+ *
+ * \param box box to free recursively
+ *
+ * The box and all its children is freed.
+ */
void box_free(struct box *box);
+
+
+/**
+ * Free the data in a single box structure.
+ *
+ * \param box box to free
+ */
void box_free_box(struct box *box);
-void box_bounds(struct box *box, struct rect *r);
+
+
+/**
+ * Find the absolute coordinates of a box.
+ *
+ * \param box the box to calculate coordinates of
+ * \param x updated to x coordinate
+ * \param y updated to y coordinate
+ */
void box_coords(struct box *box, int *x, int *y);
-struct box *box_at_point(
- const nscss_len_ctx *len_ctx,
- struct box *box, const int x, const int y,
- int *box_x, int *box_y);
-struct box *box_pick_text_box(struct html_content *html,
- int x, int y, int dir, int *dx, int *dy);
+
+
+/**
+ * Find the bounds of a box.
+ *
+ * \param box the box to calculate bounds of
+ * \param r receives bounds
+ */
+void box_bounds(struct box *box, struct rect *r);
+
+
+/**
+ * Find the boxes at a point.
+ *
+ * \param len_ctx CSS length conversion context for document.
+ * \param box box to search children of
+ * \param x point to find, in global document coordinates
+ * \param y point to find, in global document coordinates
+ * \param box_x position of box, in global document coordinates, updated
+ * to position of returned box, if any
+ * \param box_y position of box, in global document coordinates, updated
+ * to position of returned box, if any
+ * \return box at given point, or 0 if none found
+ *
+ * To find all the boxes in the hierarchy at a certain point, use code like
+ * this:
+ * \code
+ * struct box *box = top_of_document_to_search;
+ * int box_x = 0, box_y = 0;
+ *
+ * while ((box = box_at_point(len_ctx, box, x, y, &box_x, &box_y))) {
+ * // process box
+ * }
+ * \endcode
+ */
+struct box *box_at_point(const nscss_len_ctx *len_ctx, struct box *box, const int x, const int y, int *box_x, int *box_y);
+
+
+/**
+ * Peform pick text on browser window contents to locate the box under
+ * the mouse pointer, or nearest in the given direction if the pointer is
+ * not over a text box.
+ *
+ * \param html an HTML content
+ * \param x coordinate of mouse
+ * \param y coordinate of mouse
+ * \param dir direction to search (-1 = above-left, +1 = below-right)
+ * \param dx receives x ordinate of mouse relative to text box
+ * \param dy receives y ordinate of mouse relative to text box
+ */
+struct box *box_pick_text_box(struct html_content *html, int x, int y, int dir, int *dx, int *dy);
+
+
+/**
+ * Find a box based upon its id attribute.
+ *
+ * \param box box tree to search
+ * \param id id to look for
+ * \return the box or 0 if not found
+ */
struct box *box_find_by_id(struct box *box, lwc_string *id);
+
+
+/**
+ * Determine if a box is visible when the tree is rendered.
+ *
+ * \param box box to check
+ * \return true iff the box is rendered
+ */
bool box_visible(struct box *box);
-void box_dump(FILE *stream, struct box *box, unsigned int depth, bool style);
+
/**
- * Extract a URL from a relative link, handling junk like whitespace and
- * attempting to read a real URL from "javascript:" links.
- *
- * \param content html content
- * \param dsrel relative URL text taken from page
- * \param base base for relative URLs
- * \param result updated to target URL on heap, unchanged if extract failed
- * \return true on success, false on memory exhaustion
+ * Print a box tree to a file.
*/
-bool box_extract_link(const struct html_content *content, const struct dom_string *dsrel, struct nsurl *base, struct nsurl **result);
+void box_dump(FILE *stream, struct box *box, unsigned int depth, bool style);
+
/**
* Applies the given scroll setup to a box. This includes scroll
@@ -366,29 +679,24 @@ bool box_extract_link(const struct html_content *content, const struct dom_strin
nserror box_handle_scrollbars(struct content *c, struct box *box,
bool bottom, bool right);
-bool box_vscrollbar_present(const struct box *box);
-bool box_hscrollbar_present(const struct box *box);
/**
- * Construct a box tree from an xml tree and stylesheets.
+ * Determine if a box has a vertical scrollbar.
*
- * \param n xml tree
- * \param c content of type CONTENT_HTML to construct box tree in
- * \param cb callback to report conversion completion
- * \return netsurf error code indicating status of call
+ * \param box scrolling box
+ * \return the box has a vertical scrollbar
*/
-nserror dom_to_box(struct dom_node *n, struct html_content *c,
- box_construct_complete_cb cb, void **box_conversion_context);
+bool box_vscrollbar_present(const struct box *box);
+
/**
- * aborts any ongoing box construction
+ * Determine if a box has a horizontal scrollbar.
+ *
+ * \param box scrolling box
+ * \return the box has a horizontal scrollbar
*/
-nserror cancel_dom_to_box(void *box_conversion_context);
+bool box_hscrollbar_present(const struct box *box);
-bool box_normalise_block(
- struct box *block,
- const struct box *root,
- struct html_content *c);
/**
* Check if layout box is a first child.
@@ -401,12 +709,5 @@ static inline bool box_is_first_child(struct box *b)
return (b->parent == NULL || b == b->parent->children);
}
-/**
- * Retrieve the box for a dom node, if there is one
- *
- * \param node The DOM node
- * \return The box if there is one
- */
-struct box *box_for_node(struct dom_node *node);
#endif
diff --git a/content/handlers/html/box_construct.c b/content/handlers/html/box_construct.c
index 16154cbd4..039da7478 100644
--- a/content/handlers/html/box_construct.c
+++ b/content/handlers/html/box_construct.c
@@ -51,6 +51,8 @@
#include "html/html.h"
#include "html/box.h"
+#include "html/box_construct.h"
+#include "html/box_normalise.h"
#include "html/box_textarea.h"
#include "html/form_internal.h"
#include "html/html_internal.h"
@@ -3139,7 +3141,7 @@ static void convert_xml_to_box(struct box_construct_ctx *ctx)
}
-/* Exported function, documented in box.h */
+/* exported function documented in html/box_construct.h */
nserror
dom_to_box(dom_node *n,
html_content *c,
@@ -3175,7 +3177,7 @@ dom_to_box(dom_node *n,
}
-/* Exported function, see box.h */
+/* exported function documented in html/box_construct.h */
nserror cancel_dom_to_box(void *box_conversion_context)
{
struct box_construct_ctx *ctx = box_conversion_context;
@@ -3193,7 +3195,7 @@ nserror cancel_dom_to_box(void *box_conversion_context)
}
-/* Exported function, see box.h */
+/* exported function documented in html/box_construct.h */
struct box *box_for_node(dom_node *n)
{
struct box *box = NULL;
@@ -3208,59 +3210,7 @@ struct box *box_for_node(dom_node *n)
}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-/* exported function documented in html/box.h */
+/* exported function documented in html/box_construct.h */
bool
box_extract_link(const html_content *content,
const dom_string *dsrel,
diff --git a/content/handlers/html/box_construct.h b/content/handlers/html/box_construct.h
new file mode 100644
index 000000000..e93f515e4
--- /dev/null
+++ b/content/handlers/html/box_construct.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * HTML Box tree construction interface.
+ */
+
+#ifndef NETSURF_HTML_BOX_CONSTRUCT_H
+#define NETSURF_HTML_BOX_CONSTRUCT_H
+
+/**
+ * Construct a box tree from a dom and html content
+ *
+ * \param n dom document
+ * \param c content of type CONTENT_HTML to construct box tree in
+ * \param cb callback to report conversion completion
+ * \param box_conversion_context pointer that recives the conversion context
+ * \return netsurf error code indicating status of call
+ */
+nserror dom_to_box(struct dom_node *n, struct html_content *c, box_construct_complete_cb cb, void **box_conversion_context);
+
+
+/**
+ * aborts any ongoing box construction
+ */
+nserror cancel_dom_to_box(void *box_conversion_context);
+
+
+/**
+ * Retrieve the box for a dom node, if there is one
+ *
+ * \param node The DOM node
+ * \return The box if there is one
+ */
+struct box *box_for_node(struct dom_node *node);
+
+/**
+ * Extract a URL from a relative link, handling junk like whitespace and
+ * attempting to read a real URL from "javascript:" links.
+ *
+ * \param content html content
+ * \param dsrel relative URL text taken from page
+ * \param base base for relative URLs
+ * \param result updated to target URL on heap, unchanged if extract failed
+ * \return true on success, false on memory exhaustion
+ */
+bool box_extract_link(const struct html_content *content, const struct dom_string *dsrel, struct nsurl *base, struct nsurl **result);
+
+#endif
diff --git a/content/handlers/html/box_normalise.c b/content/handlers/html/box_normalise.c
index 7155cb722..03fe731b2 100644
--- a/content/handlers/html/box_normalise.c
+++ b/content/handlers/html/box_normalise.c
@@ -21,7 +21,7 @@
/**
* \file
- * Box tree normalisation (implementation).
+ * Box tree normalisation implementation.
*/
#include <assert.h>
@@ -33,6 +33,7 @@
#include "css/select.h"
#include "html/box.h"
+#include "html/box_normalise.h"
#include "html/html_internal.h"
#include "html/table.h"
@@ -66,279 +67,310 @@ struct columns {
};
-static bool box_normalise_table(
- struct box *table,
- const struct box *root,
- html_content *c);
-static bool box_normalise_table_spans(
- struct box *table,
- const struct box *root,
- struct span_info *spans,
- html_content *c);
-static bool box_normalise_table_row_group(
- struct box *row_group,
- const struct box *root,
- struct columns *col_info,
- html_content *c);
-static bool box_normalise_table_row(
- struct box *row,
- const struct box *root,
- struct columns *col_info,
- html_content *c);
-static bool calculate_table_row(struct columns *col_info,
- unsigned int col_span, unsigned int row_span,
- unsigned int *start_column, struct box *cell);
-static bool box_normalise_inline_container(
- struct box *cont,
- const struct box *root,
- html_content *c);
-
/**
- * Ensure the box tree is correctly nested by adding and removing nodes.
- *
- * \param block box of type BLOCK, INLINE_BLOCK, or TABLE_CELL
- * \param root root box of document
- * \param c content of boxes
- * \return true on success, false on memory exhaustion
+ * Compute the column index at which the current cell begins.
+ * Additionally, update the column record to reflect row spanning.
*
- * The tree is modified to satisfy the following:
- * \code
- * parent permitted child nodes
- * BLOCK, INLINE_BLOCK BLOCK, INLINE_CONTAINER, TABLE
- * INLINE_CONTAINER INLINE, INLINE_BLOCK, FLOAT_LEFT, FLOAT_RIGHT, BR, TEXT
- * INLINE, TEXT none
- * TABLE at least 1 TABLE_ROW_GROUP
- * TABLE_ROW_GROUP at least 1 TABLE_ROW
- * TABLE_ROW at least 1 TABLE_CELL
- * TABLE_CELL BLOCK, INLINE_CONTAINER, TABLE (same as BLOCK)
- * FLOAT_(LEFT|RIGHT) exactly 1 BLOCK or TABLE
- * \endcode
+ * \param col_info Column record
+ * \param col_span Number of columns that current cell spans
+ * \param row_span Number of rows that current cell spans
+ * \param start_column Pointer to location to receive column index
+ * \param cell Box for current table cell
+ * \return true on success, false on memory exhaustion
*/
+static bool
+calculate_table_row(struct columns *col_info,
+ unsigned int col_span,
+ unsigned int row_span,
+ unsigned int *start_column,
+ struct box *cell)
+{
+ unsigned int cell_start_col = col_info->current_column;
+ unsigned int cell_end_col;
+ unsigned int i;
+ struct span_info *spans;
+ struct box *rg = cell->parent->parent; /* Cell's row group */
+
+ /* Skip columns with cells spanning from above */
+ /* TODO: Need to ignore cells spanning from above that belong to
+ * different row group. We don't have that info here. */
+ while (col_info->spans[cell_start_col].row_span != 0 &&
+ col_info->spans[cell_start_col].rg == rg) {
+ cell_start_col++;
+ }
-bool box_normalise_block(
- struct box *block,
- const struct box *root,
- html_content *c)
+ /* Update current column with calculated start */
+ col_info->current_column = cell_start_col;
+
+ /* If this cell has a colspan of 0, then assume 1.
+ * No other browser supports colspan=0, anyway. */
+ if (col_span == 0)
+ col_span = 1;
+
+ cell_end_col = cell_start_col + col_span;
+
+ if (col_info->num_columns < cell_end_col) {
+ /* It appears that this row has more columns than
+ * the maximum recorded for the table so far.
+ * Allocate more span records. */
+ spans = realloc(col_info->spans,
+ sizeof *spans * (cell_end_col + 1));
+ if (spans == NULL)
+ return false;
+
+ col_info->spans = spans;
+ col_info->num_columns = cell_end_col;
+
+ /* Mark new final column as sentinel */
+ col_info->spans[cell_end_col].row_span = 0;
+ col_info->spans[cell_end_col].auto_row = false;
+ }
+
+ /* This cell may span multiple columns. If it also wants to span
+ * multiple rows, temporarily assume it spans 1 row only. This will
+ * be fixed up in box_normalise_table_spans() */
+ for (i = cell_start_col; i < cell_end_col; i++) {
+ col_info->spans[i].row_span = (row_span == 0) ? 1 : row_span;
+ col_info->spans[i].auto_row = (row_span == 0);
+ col_info->spans[i].rg = rg;
+ }
+
+ /* Update current column with calculated end. */
+ col_info->current_column = cell_end_col;
+
+ *start_column = cell_start_col;
+
+ return true;
+}
+
+
+static bool
+box_normalise_table_row(struct box *row,
+ const struct box *root,
+ struct columns *col_info,
+ html_content * c)
{
struct box *child;
struct box *next_child;
- struct box *table;
+ struct box *cell = NULL;
css_computed_style *style;
+ unsigned int i;
nscss_select_ctx ctx;
- assert(block != NULL);
- assert(root != NULL);
+ assert(row != NULL);
+ assert(row->type == BOX_TABLE_ROW);
ctx.root_style = root->style;
#ifdef BOX_NORMALISE_DEBUG
- NSLOG(netsurf, INFO, "block %p, block->type %u", block, block->type);
-#endif
-
- assert(block->type == BOX_BLOCK || block->type == BOX_INLINE_BLOCK ||
- block->type == BOX_TABLE_CELL);
-
- for (child = block->children; child != NULL; child = next_child) {
-#ifdef BOX_NORMALISE_DEBUG
- NSLOG(netsurf, INFO, "child %p, child->type = %d", child,
- child->type);
+ NSLOG(netsurf, INFO, "row %p", row);
#endif
- next_child = child->next; /* child may be destroyed */
+ for (child = row->children; child != NULL; child = next_child) {
+ next_child = child->next;
switch (child->type) {
- case BOX_BLOCK:
+ case BOX_TABLE_CELL:
/* ok */
if (box_normalise_block(child, root, c) == false)
return false;
+ cell = child;
break;
+ case BOX_BLOCK:
case BOX_INLINE_CONTAINER:
- if (box_normalise_inline_container(child, root, c) == false)
- return false;
- break;
case BOX_TABLE:
- if (box_normalise_table(child, root, c) == false)
- return false;
- break;
- case BOX_INLINE:
- case BOX_INLINE_END:
- case BOX_INLINE_BLOCK:
- case BOX_FLOAT_LEFT:
- case BOX_FLOAT_RIGHT:
- case BOX_BR:
- case BOX_TEXT:
- /* should have been wrapped in inline
- container by convert_xml_to_box() */
- assert(0);
- break;
case BOX_TABLE_ROW_GROUP:
case BOX_TABLE_ROW:
- case BOX_TABLE_CELL:
- /* insert implied table */
- assert(block->style != NULL);
+ /* insert implied table cell */
+ assert(row->style != NULL);
ctx.ctx = c->select_ctx;
ctx.quirks = (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL);
ctx.base_url = c->base_url;
ctx.universal = c->universal;
- style = nscss_get_blank_style(&ctx, block->style);
+ style = nscss_get_blank_style(&ctx, row->style);
if (style == NULL)
return false;
- table = box_create(NULL, style, true, block->href,
- block->target, NULL, NULL, c->bctx);
- if (table == NULL) {
+ cell = box_create(NULL, style, true, row->href,
+ row->target, NULL, NULL, c->bctx);
+ if (cell == NULL) {
css_computed_style_destroy(style);
return false;
}
- table->type = BOX_TABLE;
+ cell->type = BOX_TABLE_CELL;
if (child->prev == NULL)
- block->children = table;
+ row->children = cell;
else
- child->prev->next = table;
+ child->prev->next = cell;
- table->prev = child->prev;
+ cell->prev = child->prev;
while (child != NULL && (
+ child->type == BOX_BLOCK ||
+ child->type == BOX_INLINE_CONTAINER ||
+ child->type == BOX_TABLE ||
child->type == BOX_TABLE_ROW_GROUP ||
- child->type == BOX_TABLE_ROW ||
- child->type == BOX_TABLE_CELL)) {
- box_add_child(table, child);
+ child->type == BOX_TABLE_ROW)) {
+ box_add_child(cell, child);
next_child = child->next;
child->next = NULL;
child = next_child;
}
- table->last->next = NULL;
- table->next = next_child = child;
- if (table->next != NULL)
- table->next->prev = table;
+ assert(cell->last != NULL);
+
+ cell->last->next = NULL;
+ cell->next = next_child = child;
+ if (cell->next != NULL)
+ cell->next->prev = cell;
else
- block->last = table;
- table->parent = block;
+ row->last = cell;
+ cell->parent = row;
- if (box_normalise_table(table, root, c) == false)
+ if (box_normalise_block(cell, root, c) == false)
return false;
break;
+ case BOX_INLINE:
+ case BOX_INLINE_END:
+ case BOX_INLINE_BLOCK:
+ case BOX_FLOAT_LEFT:
+ case BOX_FLOAT_RIGHT:
+ case BOX_BR:
+ case BOX_TEXT:
+ /* should have been wrapped in inline
+ container by convert_xml_to_box() */
+ assert(0);
+ break;
default:
assert(0);
}
+
+ if (calculate_table_row(col_info, cell->columns, cell->rows,
+ &cell->start_column, cell) == false)
+ return false;
+ }
+
+
+ /* Update row spanning details for all columns */
+ for (i = 0; i < col_info->num_columns; i++) {
+ if (col_info->spans[i].row_span != 0 &&
+ col_info->spans[i].auto_row == false) {
+ /* This cell spans rows, and is not an auto row.
+ * Reduce number of rows left to span */
+ col_info->spans[i].row_span--;
+ }
}
+ /* Reset current column for next row */
+ col_info->current_column = 0;
+
+ /* Increment row counter */
+ col_info->num_rows++;
+
+#ifdef BOX_NORMALISE_DEBUG
+ NSLOG(netsurf, INFO, "row %p done", row);
+#endif
+
return true;
}
-bool box_normalise_table(
- struct box *table,
- const struct box *root,
- html_content * c)
+static bool
+box_normalise_table_row_group(struct box *row_group,
+ const struct box *root,
+ struct columns *col_info,
+ html_content * c)
{
struct box *child;
struct box *next_child;
- struct box *row_group;
+ struct box *row;
css_computed_style *style;
- struct columns col_info;
nscss_select_ctx ctx;
+ unsigned int group_row_count = 0;
- assert(table != NULL);
- assert(table->type == BOX_TABLE);
+ assert(row_group != 0);
+ assert(row_group->type == BOX_TABLE_ROW_GROUP);
ctx.root_style = root->style;
#ifdef BOX_NORMALISE_DEBUG
- NSLOG(netsurf, INFO, "table %p", table);
+ NSLOG(netsurf, INFO, "row_group %p", row_group);
#endif
- col_info.num_columns = 1;
- col_info.current_column = 0;
- col_info.spans = malloc(2 * sizeof *col_info.spans);
- if (col_info.spans == NULL)
- return false;
-
- col_info.spans[0].row_span = col_info.spans[1].row_span = 0;
- col_info.spans[0].auto_row = false;
- col_info.spans[1].auto_row = false;
- col_info.num_rows = 0;
-
- for (child = table->children; child != NULL; child = next_child) {
+ for (child = row_group->children; child != NULL; child = next_child) {
next_child = child->next;
+
switch (child->type) {
- case BOX_TABLE_ROW_GROUP:
+ case BOX_TABLE_ROW:
/* ok */
- if (box_normalise_table_row_group(child, root,
- &col_info, c) == false) {
- free(col_info.spans);
+ group_row_count++;
+ if (box_normalise_table_row(child, root, col_info,
+ c) == false)
return false;
- }
break;
case BOX_BLOCK:
case BOX_INLINE_CONTAINER:
case BOX_TABLE:
- case BOX_TABLE_ROW:
+ case BOX_TABLE_ROW_GROUP:
case BOX_TABLE_CELL:
- /* insert implied table row group */
- assert(table->style != NULL);
+ /* insert implied table row */
+ assert(row_group->style != NULL);
ctx.ctx = c->select_ctx;
ctx.quirks = (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL);
ctx.base_url = c->base_url;
ctx.universal = c->universal;
- style = nscss_get_blank_style(&ctx, table->style);
- if (style == NULL) {
- free(col_info.spans);
+ style = nscss_get_blank_style(&ctx, row_group->style);
+ if (style == NULL)
return false;
- }
- row_group = box_create(NULL, style, true, table->href,
- table->target, NULL, NULL, c->bctx);
- if (row_group == NULL) {
+ row = box_create(NULL, style, true, row_group->href,
+ row_group->target, NULL, NULL, c->bctx);
+ if (row == NULL) {
css_computed_style_destroy(style);
- free(col_info.spans);
return false;
}
-
- row_group->type = BOX_TABLE_ROW_GROUP;
+ row->type = BOX_TABLE_ROW;
if (child->prev == NULL)
- table->children = row_group;
+ row_group->children = row;
else
- child->prev->next = row_group;
+ child->prev->next = row;
- row_group->prev = child->prev;
+ row->prev = child->prev;
while (child != NULL && (
child->type == BOX_BLOCK ||
child->type == BOX_INLINE_CONTAINER ||
child->type == BOX_TABLE ||
- child->type == BOX_TABLE_ROW ||
+ child->type == BOX_TABLE_ROW_GROUP ||
child->type == BOX_TABLE_CELL)) {
- box_add_child(row_group, child);
+ box_add_child(row, child);
next_child = child->next;
child->next = NULL;
child = next_child;
}
- assert(row_group->last != NULL);
+ assert(row->last != NULL);
- row_group->last->next = NULL;
- row_group->next = next_child = child;
- if (row_group->next != NULL)
- row_group->next->prev = row_group;
+ row->last->next = NULL;
+ row->next = next_child = child;
+ if (row->next != NULL)
+ row->next->prev = row;
else
- table->last = row_group;
- row_group->parent = table;
+ row_group->last = row;
+ row->parent = row_group;
- if (box_normalise_table_row_group(row_group, root,
- &col_info, c) == false) {
- free(col_info.spans);
+ group_row_count++;
+ if (box_normalise_table_row(row, root, col_info,
+ c) == false)
return false;
- }
break;
case BOX_INLINE:
case BOX_INLINE_END:
@@ -352,48 +384,25 @@ bool box_normalise_table(
assert(0);
break;
default:
- fprintf(stderr, "%i\n", child->type);
assert(0);
}
}
- table->columns = col_info.num_columns;
- table->rows = col_info.num_rows;
-
- if (table->children == NULL) {
- struct box *row;
-
+ if (row_group->children == NULL) {
#ifdef BOX_NORMALISE_DEBUG
NSLOG(netsurf, INFO,
- "table->children == 0, creating implied row");
+ "row_group->children == 0, inserting implied row");
#endif
- assert(table->style != NULL);
+ assert(row_group->style != NULL);
ctx.ctx = c->select_ctx;
ctx.quirks = (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL);
ctx.base_url = c->base_url;
ctx.universal = c->universal;
- style = nscss_get_blank_style(&ctx, table->style);
- if (style == NULL) {
- free(col_info.spans);
- return false;
- }
-
- row_group = box_create(NULL, style, true, table->href,
- table->target, NULL, NULL, c->bctx);
- if (row_group == NULL) {
- css_computed_style_destroy(style);
- free(col_info.spans);
- return false;
- }
- row_group->type = BOX_TABLE_ROW_GROUP;
-
style = nscss_get_blank_style(&ctx, row_group->style);
if (style == NULL) {
- box_free(row_group);
- free(col_info.spans);
return false;
}
@@ -401,8 +410,6 @@ bool box_normalise_table(
row_group->target, NULL, NULL, c->bctx);
if (row == NULL) {
css_computed_style_destroy(style);
- box_free(row_group);
- free(col_info.spans);
return false;
}
row->type = BOX_TABLE_ROW;
@@ -410,21 +417,16 @@ bool box_normalise_table(
row->parent = row_group;
row_group->children = row_group->last = row;
- row_group->parent = table;
- table->children = table->last = row_group;
-
- table->rows = 1;
- }
+ group_row_count = 1;
- if (box_normalise_table_spans(table, root, col_info.spans, c) == false) {
- free(col_info.spans);
- return false;
+ /* Keep table's row count in sync */
+ col_info->num_rows++;
}
- free(col_info.spans);
+ row_group->rows = group_row_count;
#ifdef BOX_NORMALISE_DEBUG
- NSLOG(netsurf, INFO, "table %p done", table);
+ NSLOG(netsurf, INFO, "row_group %p done", row_group);
#endif
return true;
@@ -441,12 +443,11 @@ bool box_normalise_table(
* \param c Content containing table
* \return True on success, false on memory exhaustion.
*/
-
-bool box_normalise_table_spans(
- struct box *table,
- const struct box *root,
- struct span_info *spans,
- html_content *c)
+static bool
+box_normalise_table_spans(struct box *table,
+ const struct box *root,
+ struct span_info *spans,
+ html_content *c)
{
struct box *table_row_group;
struct box *table_row;
@@ -601,98 +602,111 @@ bool box_normalise_table_spans(
}
-bool box_normalise_table_row_group(
- struct box *row_group,
- const struct box *root,
- struct columns *col_info,
- html_content * c)
+static bool
+box_normalise_table(struct box *table, const struct box *root, html_content * c)
{
struct box *child;
struct box *next_child;
- struct box *row;
+ struct box *row_group;
css_computed_style *style;
+ struct columns col_info;
nscss_select_ctx ctx;
- unsigned int group_row_count = 0;
- assert(row_group != 0);
- assert(row_group->type == BOX_TABLE_ROW_GROUP);
+ assert(table != NULL);
+ assert(table->type == BOX_TABLE);
ctx.root_style = root->style;
#ifdef BOX_NORMALISE_DEBUG
- NSLOG(netsurf, INFO, "row_group %p", row_group);
+ NSLOG(netsurf, INFO, "table %p", table);
#endif
- for (child = row_group->children; child != NULL; child = next_child) {
- next_child = child->next;
+ col_info.num_columns = 1;
+ col_info.current_column = 0;
+ col_info.spans = malloc(2 * sizeof *col_info.spans);
+ if (col_info.spans == NULL)
+ return false;
+ col_info.spans[0].row_span = col_info.spans[1].row_span = 0;
+ col_info.spans[0].auto_row = false;
+ col_info.spans[1].auto_row = false;
+ col_info.num_rows = 0;
+
+ for (child = table->children; child != NULL; child = next_child) {
+ next_child = child->next;
switch (child->type) {
- case BOX_TABLE_ROW:
+ case BOX_TABLE_ROW_GROUP:
/* ok */
- group_row_count++;
- if (box_normalise_table_row(child, root, col_info,
- c) == false)
+ if (box_normalise_table_row_group(child, root,
+ &col_info, c) == false) {
+ free(col_info.spans);
return false;
+ }
break;
case BOX_BLOCK:
case BOX_INLINE_CONTAINER:
case BOX_TABLE:
- case BOX_TABLE_ROW_GROUP:
+ case BOX_TABLE_ROW:
case BOX_TABLE_CELL:
- /* insert implied table row */
- assert(row_group->style != NULL);
+ /* insert implied table row group */
+ assert(table->style != NULL);
ctx.ctx = c->select_ctx;
ctx.quirks = (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL);
ctx.base_url = c->base_url;
ctx.universal = c->universal;
- style = nscss_get_blank_style(&ctx, row_group->style);
- if (style == NULL)
+ style = nscss_get_blank_style(&ctx, table->style);
+ if (style == NULL) {
+ free(col_info.spans);
return false;
+ }
- row = box_create(NULL, style, true, row_group->href,
- row_group->target, NULL, NULL, c->bctx);
- if (row == NULL) {
+ row_group = box_create(NULL, style, true, table->href,
+ table->target, NULL, NULL, c->bctx);
+ if (row_group == NULL) {
css_computed_style_destroy(style);
+ free(col_info.spans);
return false;
}
- row->type = BOX_TABLE_ROW;
+
+ row_group->type = BOX_TABLE_ROW_GROUP;
if (child->prev == NULL)
- row_group->children = row;
+ table->children = row_group;
else
- child->prev->next = row;
+ child->prev->next = row_group;
- row->prev = child->prev;
+ row_group->prev = child->prev;
while (child != NULL && (
child->type == BOX_BLOCK ||
child->type == BOX_INLINE_CONTAINER ||
child->type == BOX_TABLE ||
- child->type == BOX_TABLE_ROW_GROUP ||
+ child->type == BOX_TABLE_ROW ||
child->type == BOX_TABLE_CELL)) {
- box_add_child(row, child);
+ box_add_child(row_group, child);
next_child = child->next;
child->next = NULL;
child = next_child;
}
- assert(row->last != NULL);
+ assert(row_group->last != NULL);
- row->last->next = NULL;
- row->next = next_child = child;
- if (row->next != NULL)
- row->next->prev = row;
+ row_group->last->next = NULL;
+ row_group->next = next_child = child;
+ if (row_group->next != NULL)
+ row_group->next->prev = row_group;
else
- row_group->last = row;
- row->parent = row_group;
+ table->last = row_group;
+ row_group->parent = table;
- group_row_count++;
- if (box_normalise_table_row(row, root, col_info,
- c) == false)
+ if (box_normalise_table_row_group(row_group, root,
+ &col_info, c) == false) {
+ free(col_info.spans);
return false;
+ }
break;
case BOX_INLINE:
case BOX_INLINE_END:
@@ -706,25 +720,48 @@ bool box_normalise_table_row_group(
assert(0);
break;
default:
+ fprintf(stderr, "%i\n", child->type);
assert(0);
}
}
- if (row_group->children == NULL) {
+ table->columns = col_info.num_columns;
+ table->rows = col_info.num_rows;
+
+ if (table->children == NULL) {
+ struct box *row;
+
#ifdef BOX_NORMALISE_DEBUG
NSLOG(netsurf, INFO,
- "row_group->children == 0, inserting implied row");
+ "table->children == 0, creating implied row");
#endif
- assert(row_group->style != NULL);
+ assert(table->style != NULL);
ctx.ctx = c->select_ctx;
ctx.quirks = (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL);
ctx.base_url = c->base_url;
ctx.universal = c->universal;
+ style = nscss_get_blank_style(&ctx, table->style);
+ if (style == NULL) {
+ free(col_info.spans);
+ return false;
+ }
+
+ row_group = box_create(NULL, style, true, table->href,
+ table->target, NULL, NULL, c->bctx);
+ if (row_group == NULL) {
+ css_computed_style_destroy(style);
+ free(col_info.spans);
+ return false;
+ }
+ row_group->type = BOX_TABLE_ROW_GROUP;
+
style = nscss_get_blank_style(&ctx, row_group->style);
if (style == NULL) {
+ box_free(row_group);
+ free(col_info.spans);
return false;
}
@@ -732,6 +769,8 @@ bool box_normalise_table_row_group(
row_group->target, NULL, NULL, c->bctx);
if (row == NULL) {
css_computed_style_destroy(style);
+ box_free(row_group);
+ free(col_info.spans);
return false;
}
row->type = BOX_TABLE_ROW;
@@ -739,236 +778,31 @@ bool box_normalise_table_row_group(
row->parent = row_group;
row_group->children = row_group->last = row;
- group_row_count = 1;
-
- /* Keep table's row count in sync */
- col_info->num_rows++;
- }
-
- row_group->rows = group_row_count;
-
-#ifdef BOX_NORMALISE_DEBUG
- NSLOG(netsurf, INFO, "row_group %p done", row_group);
-#endif
-
- return true;
-}
-
-
-bool box_normalise_table_row(
- struct box *row,
- const struct box *root,
- struct columns *col_info,
- html_content * c)
-{
- struct box *child;
- struct box *next_child;
- struct box *cell = NULL;
- css_computed_style *style;
- unsigned int i;
- nscss_select_ctx ctx;
-
- assert(row != NULL);
- assert(row->type == BOX_TABLE_ROW);
-
- ctx.root_style = root->style;
-
-#ifdef BOX_NORMALISE_DEBUG
- NSLOG(netsurf, INFO, "row %p", row);
-#endif
-
- for (child = row->children; child != NULL; child = next_child) {
- next_child = child->next;
-
- switch (child->type) {
- case BOX_TABLE_CELL:
- /* ok */
- if (box_normalise_block(child, root, c) == false)
- return false;
- cell = child;
- break;
- case BOX_BLOCK:
- case BOX_INLINE_CONTAINER:
- case BOX_TABLE:
- case BOX_TABLE_ROW_GROUP:
- case BOX_TABLE_ROW:
- /* insert implied table cell */
- assert(row->style != NULL);
-
- ctx.ctx = c->select_ctx;
- ctx.quirks = (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL);
- ctx.base_url = c->base_url;
- ctx.universal = c->universal;
-
- style = nscss_get_blank_style(&ctx, row->style);
- if (style == NULL)
- return false;
-
- cell = box_create(NULL, style, true, row->href,
- row->target, NULL, NULL, c->bctx);
- if (cell == NULL) {
- css_computed_style_destroy(style);
- return false;
- }
- cell->type = BOX_TABLE_CELL;
-
- if (child->prev == NULL)
- row->children = cell;
- else
- child->prev->next = cell;
-
- cell->prev = child->prev;
-
- while (child != NULL && (
- child->type == BOX_BLOCK ||
- child->type == BOX_INLINE_CONTAINER ||
- child->type == BOX_TABLE ||
- child->type == BOX_TABLE_ROW_GROUP ||
- child->type == BOX_TABLE_ROW)) {
- box_add_child(cell, child);
-
- next_child = child->next;
- child->next = NULL;
- child = next_child;
- }
-
- assert(cell->last != NULL);
-
- cell->last->next = NULL;
- cell->next = next_child = child;
- if (cell->next != NULL)
- cell->next->prev = cell;
- else
- row->last = cell;
- cell->parent = row;
-
- if (box_normalise_block(cell, root, c) == false)
- return false;
- break;
- case BOX_INLINE:
- case BOX_INLINE_END:
- case BOX_INLINE_BLOCK:
- case BOX_FLOAT_LEFT:
- case BOX_FLOAT_RIGHT:
- case BOX_BR:
- case BOX_TEXT:
- /* should have been wrapped in inline
- container by convert_xml_to_box() */
- assert(0);
- break;
- default:
- assert(0);
- }
+ row_group->parent = table;
+ table->children = table->last = row_group;
- if (calculate_table_row(col_info, cell->columns, cell->rows,
- &cell->start_column, cell) == false)
- return false;
+ table->rows = 1;
}
-
- /* Update row spanning details for all columns */
- for (i = 0; i < col_info->num_columns; i++) {
- if (col_info->spans[i].row_span != 0 &&
- col_info->spans[i].auto_row == false) {
- /* This cell spans rows, and is not an auto row.
- * Reduce number of rows left to span */
- col_info->spans[i].row_span--;
- }
+ if (box_normalise_table_spans(table, root, col_info.spans, c) == false) {
+ free(col_info.spans);
+ return false;
}
- /* Reset current column for next row */
- col_info->current_column = 0;
-
- /* Increment row counter */
- col_info->num_rows++;
+ free(col_info.spans);
#ifdef BOX_NORMALISE_DEBUG
- NSLOG(netsurf, INFO, "row %p done", row);
+ NSLOG(netsurf, INFO, "table %p done", table);
#endif
return true;
}
-/**
- * Compute the column index at which the current cell begins.
- * Additionally, update the column record to reflect row spanning.
- *
- * \param col_info Column record
- * \param col_span Number of columns that current cell spans
- * \param row_span Number of rows that current cell spans
- * \param start_column Pointer to location to receive column index
- * \param cell Box for current table cell
- * \return true on success, false on memory exhaustion
- */
-
-bool calculate_table_row(struct columns *col_info,
- unsigned int col_span, unsigned int row_span,
- unsigned int *start_column, struct box *cell)
-{
- unsigned int cell_start_col = col_info->current_column;
- unsigned int cell_end_col;
- unsigned int i;
- struct span_info *spans;
- struct box *rg = cell->parent->parent; /* Cell's row group */
-
- /* Skip columns with cells spanning from above */
- /* TODO: Need to ignore cells spanning from above that belong to
- * different row group. We don't have that info here. */
- while (col_info->spans[cell_start_col].row_span != 0 &&
- col_info->spans[cell_start_col].rg == rg) {
- cell_start_col++;
- }
-
- /* Update current column with calculated start */
- col_info->current_column = cell_start_col;
-
- /* If this cell has a colspan of 0, then assume 1.
- * No other browser supports colspan=0, anyway. */
- if (col_span == 0)
- col_span = 1;
-
- cell_end_col = cell_start_col + col_span;
-
- if (col_info->num_columns < cell_end_col) {
- /* It appears that this row has more columns than
- * the maximum recorded for the table so far.
- * Allocate more span records. */
- spans = realloc(col_info->spans,
- sizeof *spans * (cell_end_col + 1));
- if (spans == NULL)
- return false;
-
- col_info->spans = spans;
- col_info->num_columns = cell_end_col;
-
- /* Mark new final column as sentinel */
- col_info->spans[cell_end_col].row_span = 0;
- col_info->spans[cell_end_col].auto_row = false;
- }
-
- /* This cell may span multiple columns. If it also wants to span
- * multiple rows, temporarily assume it spans 1 row only. This will
- * be fixed up in box_normalise_table_spans() */
- for (i = cell_start_col; i < cell_end_col; i++) {
- col_info->spans[i].row_span = (row_span == 0) ? 1 : row_span;
- col_info->spans[i].auto_row = (row_span == 0);
- col_info->spans[i].rg = rg;
- }
-
- /* Update current column with calculated end. */
- col_info->current_column = cell_end_col;
-
- *start_column = cell_start_col;
-
- return true;
-}
-
-
-bool box_normalise_inline_container(
- struct box *cont,
- const struct box *root,
- html_content * c)
+static bool
+box_normalise_inline_container(struct box *cont,
+ const struct box *root,
+ html_content * c)
{
struct box *child;
struct box *next_child;
@@ -1045,3 +879,119 @@ bool box_normalise_inline_container(
return true;
}
+
+
+/* Exported function documented in html/box_normalise.h */
+bool
+box_normalise_block(struct box *block, const struct box *root, html_content *c)
+{
+ struct box *child;
+ struct box *next_child;
+ struct box *table;
+ css_computed_style *style;
+ nscss_select_ctx ctx;
+
+ assert(block != NULL);
+ assert(root != NULL);
+
+ ctx.root_style = root->style;
+
+#ifdef BOX_NORMALISE_DEBUG
+ NSLOG(netsurf, INFO, "block %p, block->type %u", block, block->type);
+#endif
+
+ assert(block->type == BOX_BLOCK || block->type == BOX_INLINE_BLOCK ||
+ block->type == BOX_TABLE_CELL);
+
+ for (child = block->children; child != NULL; child = next_child) {
+#ifdef BOX_NORMALISE_DEBUG
+ NSLOG(netsurf, INFO, "child %p, child->type = %d", child,
+ child->type);
+#endif
+
+ next_child = child->next; /* child may be destroyed */
+
+ switch (child->type) {
+ case BOX_BLOCK:
+ /* ok */
+ if (box_normalise_block(child, root, c) == false)
+ return false;
+ break;
+ case BOX_INLINE_CONTAINER:
+ if (box_normalise_inline_container(child, root, c) == false)
+ return false;
+ break;
+ case BOX_TABLE:
+ if (box_normalise_table(child, root, c) == false)
+ return false;
+ break;
+ case BOX_INLINE:
+ case BOX_INLINE_END:
+ case BOX_INLINE_BLOCK:
+ case BOX_FLOAT_LEFT:
+ case BOX_FLOAT_RIGHT:
+ case BOX_BR:
+ case BOX_TEXT:
+ /* should have been wrapped in inline
+ container by convert_xml_to_box() */
+ assert(0);
+ break;
+ case BOX_TABLE_ROW_GROUP:
+ case BOX_TABLE_ROW:
+ case BOX_TABLE_CELL:
+ /* insert implied table */
+ assert(block->style != NULL);
+
+ ctx.ctx = c->select_ctx;
+ ctx.quirks = (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL);
+ ctx.base_url = c->base_url;
+ ctx.universal = c->universal;
+
+ style = nscss_get_blank_style(&ctx, block->style);
+ if (style == NULL)
+ return false;
+
+ table = box_create(NULL, style, true, block->href,
+ block->target, NULL, NULL, c->bctx);
+ if (table == NULL) {
+ css_computed_style_destroy(style);
+ return false;
+ }
+ table->type = BOX_TABLE;
+
+ if (child->prev == NULL)
+ block->children = table;
+ else
+ child->prev->next = table;
+
+ table->prev = child->prev;
+
+ while (child != NULL && (
+ child->type == BOX_TABLE_ROW_GROUP ||
+ child->type == BOX_TABLE_ROW ||
+ child->type == BOX_TABLE_CELL)) {
+ box_add_child(table, child);
+
+ next_child = child->next;
+ child->next = NULL;
+ child = next_child;
+ }
+
+ table->last->next = NULL;
+ table->next = next_child = child;
+ if (table->next != NULL)
+ table->next->prev = table;
+ else
+ block->last = table;
+ table->parent = block;
+
+ if (box_normalise_table(table, root, c) == false)
+ return false;
+ break;
+ default:
+ assert(0);
+ }
+ }
+
+ return true;
+}
diff --git a/content/handlers/html/box_normalise.h b/content/handlers/html/box_normalise.h
new file mode 100644
index 000000000..60f259189
--- /dev/null
+++ b/content/handlers/html/box_normalise.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2020 Vincent Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * HTML Box tree normalise interface.
+ */
+
+#ifndef NETSURF_HTML_BOX_NORMALISE_H
+#define NETSURF_HTML_BOX_NORMALISE_H
+
+/**
+ * Ensure the box tree is correctly nested by adding and removing nodes.
+ *
+ * \param block box of type BLOCK, INLINE_BLOCK, or TABLE_CELL
+ * \param root root box of document
+ * \param c content of boxes
+ * \return true on success, false on memory exhaustion
+ *
+ * The tree is modified to satisfy the following:
+ * \code
+ * parent permitted child nodes
+ * BLOCK, INLINE_BLOCK BLOCK, INLINE_CONTAINER, TABLE
+ * INLINE_CONTAINER INLINE, INLINE_BLOCK, FLOAT_LEFT, FLOAT_RIGHT, BR, TEXT
+ * INLINE, TEXT none
+ * TABLE at least 1 TABLE_ROW_GROUP
+ * TABLE_ROW_GROUP at least 1 TABLE_ROW
+ * TABLE_ROW at least 1 TABLE_CELL
+ * TABLE_CELL BLOCK, INLINE_CONTAINER, TABLE (same as BLOCK)
+ * FLOAT_(LEFT|RIGHT) exactly 1 BLOCK or TABLE
+ * \endcode
+ */
+bool box_normalise_block(struct box *block, const struct box *root, struct html_content *c);
+
+#endif
diff --git a/content/handlers/html/html.c b/content/handlers/html/html.c
index e445457ca..9b4785839 100644
--- a/content/handlers/html/html.c
+++ b/content/handlers/html/html.c
@@ -60,6 +60,7 @@
#include "html/html_internal.h"
#include "html/interaction.h"
#include "html/box.h"
+#include "html/box_construct.h"
#include "html/form_internal.h"
#include "html/imagemap.h"
#include "html/layout.h"
@@ -212,7 +213,7 @@ static void html_box_convert_done(html_content *c, bool success)
dom_exception exc; /* returned by libdom functions */
dom_node *html;
- NSLOG(netsurf, INFO, "Done XML to box (%p)", c);
+ NSLOG(netsurf, INFO, "DOM to box conversion complete (content %p)", c);
c->box_conversion_context = NULL;
diff --git a/content/handlers/html/imagemap.c b/content/handlers/html/imagemap.c
index 0c3576842..37095e21d 100644
--- a/content/handlers/html/imagemap.c
+++ b/content/handlers/html/imagemap.c
@@ -36,6 +36,7 @@
#include "content/hlcache.h"
#include "html/box.h"
+#include "html/box_construct.h"
#include "html/html_internal.h"
#include "html/imagemap.h"