summaryrefslogtreecommitdiff
path: root/render
diff options
context:
space:
mode:
Diffstat (limited to 'render')
-rw-r--r--render/box.c39
-rw-r--r--render/box.h22
-rw-r--r--render/box_construct.c997
-rw-r--r--render/box_normalise.c637
-rw-r--r--render/directory.c5
-rw-r--r--render/directory.h3
-rw-r--r--render/font.c48
-rw-r--r--render/font.h2
-rw-r--r--render/html.c191
-rw-r--r--render/html.h18
-rw-r--r--render/html_redraw.c349
-rw-r--r--render/hubbub_binding.c21
-rw-r--r--render/layout.c1558
-rw-r--r--render/list.c49
-rw-r--r--render/list.h10
-rw-r--r--render/loosen.c501
-rw-r--r--render/loosen.h35
-rw-r--r--render/parser_binding.h8
-rw-r--r--render/table.c892
-rw-r--r--render/table.h2
-rw-r--r--render/textplain.c9
-rw-r--r--render/textplain.h3
22 files changed, 2804 insertions, 2595 deletions
diff --git a/render/box.c b/render/box.c
index 7dde0b759..b1ebfcbad 100644
--- a/render/box.c
+++ b/render/box.c
@@ -28,6 +28,7 @@
#include <string.h>
#include "content/content.h"
#include "css/css.h"
+#include "css/dump.h"
#include "desktop/options.h"
#include "render/box.h"
#include "render/form.h"
@@ -58,7 +59,7 @@ static struct box_duplicate_llist *box_duplicate_last = NULL;
* \return allocated and initialised box, or 0 on memory exhaustion
*/
-struct box * box_create(struct css_style *style,
+struct box * box_create(css_computed_style *style,
char *href, const char *target, char *title, char *id,
void *context)
{
@@ -78,10 +79,11 @@ struct box * box_create(struct css_style *style,
box->descendant_x0 = box->descendant_y0 = 0;
box->descendant_x1 = box->descendant_y1 = 0;
for (i = 0; i != 4; i++)
- box->margin[i] = box->padding[i] = box->border[i] = 0;
+ box->margin[i] = box->padding[i] = box->border[i].width = 0;
box->scroll_x = box->scroll_y = 0;
box->min_width = 0;
box->max_width = UNKNOWN_MAX_WIDTH;
+ box->byte_offset = 0;
box->text = NULL;
box->length = 0;
box->space = 0;
@@ -444,34 +446,34 @@ siblings:
bool box_contains_point(struct box *box, int x, int y, bool *physically)
{
- if (box->x <= x + box->border[LEFT] &&
+ if (box->x <= x + box->border[LEFT].width &&
x < box->x + box->padding[LEFT] + box->width +
- box->border[RIGHT] + box->padding[RIGHT] &&
- box->y <= y + box->border[TOP] &&
+ box->border[RIGHT].width + box->padding[RIGHT] &&
+ box->y <= y + box->border[TOP].width &&
y < box->y + box->padding[TOP] + box->height +
- box->border[BOTTOM] + box->padding[BOTTOM]) {
+ box->border[BOTTOM].width + box->padding[BOTTOM]) {
*physically = true;
return true;
}
if (box->list_marker && box->list_marker->x <= x +
- box->list_marker->border[LEFT] &&
+ box->list_marker->border[LEFT].width &&
x < box->list_marker->x +
box->list_marker->padding[LEFT] +
box->list_marker->width +
- box->list_marker->border[RIGHT] +
+ box->list_marker->border[RIGHT].width +
box->list_marker->padding[RIGHT] &&
box->list_marker->y <= y +
- box->list_marker->border[TOP] &&
+ box->list_marker->border[TOP].width &&
y < box->list_marker->y +
box->list_marker->padding[TOP] +
box->list_marker->height +
- box->list_marker->border[BOTTOM] +
+ box->list_marker->border[BOTTOM].width +
box->list_marker->padding[BOTTOM]) {
*physically = true;
return true;
}
- if ((box->style && box->style->overflow == CSS_OVERFLOW_VISIBLE) ||
- !box->style) {
+ if ((box->style && css_computed_overflow(box->style) ==
+ CSS_OVERFLOW_VISIBLE) || !box->style) {
if (box->x + box->descendant_x0 <= x &&
x < box->x + box->descendant_x1 &&
box->y + box->descendant_y0 <= y &&
@@ -502,8 +504,8 @@ struct box *box_object_at_point(struct content *c, int x, int y)
assert(c->type == CONTENT_HTML);
while ((box = box_at_point(box, x, y, &box_x, &box_y, &content))) {
- if (box->style &&
- box->style->visibility == CSS_VISIBILITY_HIDDEN)
+ if (box->style && css_computed_visibility(box->style) ==
+ CSS_VISIBILITY_HIDDEN)
continue;
if (box->object)
@@ -532,8 +534,8 @@ struct box *box_href_at_point(struct content *c, int x, int y)
assert(c->type == CONTENT_HTML);
while ((box = box_at_point(box, x, y, &box_x, &box_y, &content))) {
- if (box->style &&
- box->style->visibility == CSS_VISIBILITY_HIDDEN)
+ if (box->style && css_computed_visibility(box->style) ==
+ CSS_VISIBILITY_HIDDEN)
continue;
if (box->href)
@@ -580,7 +582,8 @@ bool box_visible(struct box *box)
struct box *fallback;
/* visibility: hidden */
- if (box->style && box->style->visibility == CSS_VISIBILITY_HIDDEN)
+ if (box->style && css_computed_visibility(box->style) ==
+ CSS_VISIBILITY_HIDDEN)
return false;
/* check if a fallback */
@@ -651,7 +654,7 @@ void box_dump(FILE *stream, struct box *box, unsigned int depth)
if (box->gadget)
fprintf(stream, "(gadget) ");
if (box->style)
- css_dump_style(stream, box->style);
+ nscss_dump_computed_style(stream, box->style);
if (box->href)
fprintf(stream, " -> '%s'", box->href);
if (box->target)
diff --git a/render/box.h b/render/box.h
index 9a90c21a4..3134ea1a2 100644
--- a/render/box.h
+++ b/render/box.h
@@ -91,10 +91,10 @@
#include <stdio.h>
#include <libxml/HTMLparser.h>
+#include "css/css.h"
struct box;
struct column;
-struct css_style;
struct object_params;
struct object_param;
@@ -106,7 +106,7 @@ typedef enum {
BOX_TABLE_ROW_GROUP,
BOX_FLOAT_LEFT, BOX_FLOAT_RIGHT,
BOX_INLINE_BLOCK, BOX_BR, BOX_TEXT,
- BOX_INLINE_END
+ BOX_INLINE_END, BOX_NONE
} box_type;
struct rect {
@@ -114,6 +114,18 @@ struct rect {
int x1, y1;
};
+/* Sides of a box */
+enum box_side { TOP, RIGHT, BOTTOM, LEFT };
+
+/**
+ * Container for box border details
+ */
+struct box_border {
+ enum css_border_style style; /**< border-style */
+ enum css_border_color color; /**< border-color type */
+ css_color c; /**< border-color value */
+ int width; /**< border-width (pixels) */
+};
/** Node in box tree. All dimensions are in pixels. */
struct box {
@@ -121,7 +133,7 @@ struct box {
box_type type;
/** Style for this box. 0 for INLINE_CONTAINER and FLOAT_*. */
- struct css_style * 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_. */
@@ -153,7 +165,7 @@ struct box {
int margin[4]; /**< Margin: TOP, RIGHT, BOTTOM, LEFT. */
int padding[4]; /**< Padding: TOP, RIGHT, BOTTOM, LEFT. */
- int border[4]; /**< Border width: TOP, RIGHT, BOTTOM, LEFT. */
+ struct box_border border[4]; /**< Border: TOP, RIGHT, BOTTOM, LEFT. */
int scroll_x; /**< Horizontal scroll of descendants. */
int scroll_y; /**< Vertical scroll of descendants. */
@@ -282,7 +294,7 @@ extern const char *TARGET_BLANK;
#define UNKNOWN_MAX_WIDTH INT_MAX
-struct box * box_create(struct css_style *style,
+struct box * box_create(css_computed_style *style,
char *href, const char *target, char *title,
char *id, void *context);
void box_add_child(struct box *parent, struct box *child);
diff --git a/render/box_construct.c b/render/box_construct.c
index b8aa5e600..564a443c3 100644
--- a/render/box_construct.c
+++ b/render/box_construct.c
@@ -37,6 +37,8 @@
#include "utils/config.h"
#include "content/content.h"
#include "css/css.h"
+#include "css/utils.h"
+#include "css/select.h"
#include "desktop/browser.h"
#include "desktop/options.h"
#include "render/box.h"
@@ -82,59 +84,30 @@ static const content_type image_types[] = {
#endif
CONTENT_UNKNOWN };
-#define MAX_SPAN (100)
-
-
/* the strings are not important, since we just compare the pointers */
const char *TARGET_SELF = "_self";
const char *TARGET_PARENT = "_parent";
const char *TARGET_TOP = "_top";
const char *TARGET_BLANK = "_blank";
-/* keeps track of markup presentation */
-struct markup_track {
- enum {
- ALIGN_NONE,
- ALIGN_LEFT,
- ALIGN_CENTER,
- ALIGN_RIGHT
- } align;
- bool cell_border;
- colour border_color;
-
- bool cell_padding;
- long padding_width;
-
- bool table;
-};
-
static bool convert_xml_to_box(xmlNode *n, struct content *content,
- struct css_style *parent_style,
+ const css_computed_style *parent_style,
struct box *parent, struct box **inline_container,
- char *href, const char *target, char *title,
- struct markup_track markup_track,
- struct css_importance *author);
+ char *href, const char *target, char *title);
bool box_construct_element(xmlNode *n, struct content *content,
- struct css_style *parent_style,
+ const css_computed_style *parent_style,
struct box *parent, struct box **inline_container,
- char *href, const char *target, char *title,
- struct markup_track markup_track,
- struct css_importance *author);
+ char *href, const char *target, char *title);
bool box_construct_text(xmlNode *n, struct content *content,
- struct css_style *parent_style,
+ const css_computed_style *parent_style,
struct box *parent, struct box **inline_container,
char *href, const char *target, char *title);
-static struct css_style * box_get_style(struct content *c,
- struct css_style *parent_style,
- xmlNode *n, struct markup_track *markup_track,
- struct css_importance *author);
-static void box_solve_display(struct css_style *style, bool root);
+static css_computed_style * box_get_style(struct content *c,
+ const css_computed_style *parent_style, xmlNode *n);
static void box_text_transform(char *s, unsigned int len,
- css_text_transform tt);
+ enum css_text_transform tt);
#define BOX_SPECIAL_PARAMS xmlNode *n, struct content *content, \
- struct box *box, bool *convert_children, \
- struct markup_track markup_track, \
- struct css_importance *author
+ struct box *box, bool *convert_children
static bool box_a(BOX_SPECIAL_PARAMS);
static bool box_body(BOX_SPECIAL_PARAMS);
static bool box_br(BOX_SPECIAL_PARAMS);
@@ -157,8 +130,10 @@ static bool box_get_attribute(xmlNode *n, const char *attribute,
void *context, char **value);
static struct frame_dimension *box_parse_multi_lengths(const char *s,
unsigned int *count);
-static void parse_inline_colour(char *text, colour *variable);
-
+static bool fetch_object_interned_url(struct content *c, lwc_string *url,
+ struct box *box, const content_type *permitted_types,
+ int available_width, int available_height,
+ bool background);
/* element_table must be sorted by name */
struct element_entry {
@@ -195,12 +170,7 @@ static const struct element_entry element_table[] = {
bool xml_to_box(xmlNode *n, struct content *c)
{
struct box root;
- struct box *inline_container = 0;
- struct css_importance author;
- struct markup_track markup_track;
- markup_track.cell_border = false;
- markup_track.cell_padding = false;
- markup_track.align = ALIGN_NONE;
+ struct box *inline_container = NULL;
assert(c->type == CONTENT_HTML);
@@ -214,20 +184,12 @@ bool xml_to_box(xmlNode *n, struct content *c)
root.float_children = NULL;
root.next_float = NULL;
- c->data.html.style = talloc_memdup(c, &css_base_style,
- sizeof css_base_style);
- if (!c->data.html.style)
- return false;
- c->data.html.style->font_size.value.length.value =
- option_font_size * 0.1;
- /* and get the default font family from the options */
- c->data.html.style->font_family = option_font_default;
-
c->data.html.object_count = 0;
c->data.html.object = 0;
- if (!convert_xml_to_box(n, c, c->data.html.style, &root,
- &inline_container, 0, 0, 0, markup_track, &author))
+ /* The root box's style */
+ if (!convert_xml_to_box(n, c, NULL, &root,
+ &inline_container, 0, 0, 0))
return false;
if (!box_normalise_block(&root, c))
@@ -241,7 +203,7 @@ bool xml_to_box(xmlNode *n, struct content *c)
/* mapping from CSS display to box type
- * this table must be in sync with css/css_enums */
+ * this table must be in sync with libcss' css_display enum */
static const box_type box_map[] = {
0, /*CSS_DISPLAY_INHERIT,*/
BOX_INLINE, /*CSS_DISPLAY_INLINE,*/
@@ -255,10 +217,11 @@ static const box_type box_map[] = {
BOX_TABLE_ROW_GROUP, /*CSS_DISPLAY_TABLE_HEADER_GROUP,*/
BOX_TABLE_ROW_GROUP, /*CSS_DISPLAY_TABLE_FOOTER_GROUP,*/
BOX_TABLE_ROW, /*CSS_DISPLAY_TABLE_ROW,*/
- BOX_INLINE, /*CSS_DISPLAY_TABLE_COLUMN_GROUP,*/
- BOX_INLINE, /*CSS_DISPLAY_TABLE_COLUMN,*/
+ BOX_NONE, /*CSS_DISPLAY_TABLE_COLUMN_GROUP,*/
+ BOX_NONE, /*CSS_DISPLAY_TABLE_COLUMN,*/
BOX_TABLE_CELL, /*CSS_DISPLAY_TABLE_CELL,*/
- BOX_INLINE /*CSS_DISPLAY_TABLE_CAPTION,*/
+ BOX_INLINE, /*CSS_DISPLAY_TABLE_CAPTION,*/
+ BOX_NONE /*CSS_DISPLAY_NONE*/
};
@@ -267,31 +230,25 @@ static const box_type box_map[] = {
*
* \param n fragment of xml tree
* \param content content of type CONTENT_HTML that is being processed
- * \param parent_style style at this point in xml tree
+ * \param parent_style style at this point in xml tree, or NULL for root box
* \param parent parent in box tree
* \param inline_container current inline container box, or 0, updated to
* new current inline container on exit
* \param href current link URL, or 0 if not in a link
* \param target current link target, or 0 if none
* \param title current title, or 0 if none
- * \param markup_track track presentation markup that affects descendents
- * \param author denotes whether current style has author level
- * importance for certain properties
* \return true on success, false on memory exhaustion
*/
bool convert_xml_to_box(xmlNode *n, struct content *content,
- struct css_style *parent_style,
+ const css_computed_style *parent_style,
struct box *parent, struct box **inline_container,
- char *href, const char *target, char *title,
- struct markup_track markup_track,
- struct css_importance *author)
+ char *href, const char *target, char *title)
{
switch (n->type) {
case XML_ELEMENT_NODE:
return box_construct_element(n, content, parent_style, parent,
- inline_container,
- href, target, title, markup_track, author);
+ inline_container, href, target, title);
case XML_TEXT_NODE:
return box_construct_text(n, content, parent_style, parent,
inline_container, href, target, title);
@@ -307,25 +264,20 @@ bool convert_xml_to_box(xmlNode *n, struct content *content,
*
* \param n XML node of type XML_ELEMENT_NODE
* \param content content of type CONTENT_HTML that is being processed
- * \param parent_style style at this point in xml tree
+ * \param parent_style style at this point in xml tree, or NULL for root node
* \param parent parent in box tree
* \param inline_container current inline container box, or 0, updated to
* new current inline container on exit
* \param href current link URL, or 0 if not in a link
* \param target current link target, or 0 if none
* \param title current title, or 0 if none
- * \param markup_track track presentation markup that affects descendents
- * \param author denotes whether current style has author level
- * importance for certain properties
* \return true on success, false on memory exhaustion
*/
bool box_construct_element(xmlNode *n, struct content *content,
- struct css_style *parent_style,
+ const css_computed_style *parent_style,
struct box *parent, struct box **inline_container,
- char *href, const char *target, char *title,
- struct markup_track markup_track,
- struct css_importance *author)
+ char *href, const char *target, char *title)
{
bool convert_children = true;
char *id = 0;
@@ -333,14 +285,14 @@ bool box_construct_element(xmlNode *n, struct content *content,
struct box *box = 0;
struct box *inline_container_c;
struct box *inline_end;
- struct css_style *style = 0;
+ css_computed_style *style = 0;
struct element_entry *element;
xmlChar *title0;
xmlNode *c;
+ lwc_string *bgimage_uri;
assert(n);
assert(n->type == XML_ELEMENT_NODE);
- assert(parent_style);
assert(parent);
assert(inline_container);
@@ -352,18 +304,23 @@ bool box_construct_element(xmlNode *n, struct content *content,
*/
parent->strip_leading_newline = 0;
- style = box_get_style(content, parent_style, n, &markup_track, author);
+ style = box_get_style(content, parent_style, n);
if (!style)
return false;
/* extract title attribute, if present */
if ((title0 = xmlGetProp(n, (const xmlChar *) "title"))) {
char *title1 = squash_whitespace((char *) title0);
+
xmlFree(title0);
+
if (!title1)
return false;
+
title = talloc_strdup(content, title1);
+
free(title1);
+
if (!title)
return false;
}
@@ -376,8 +333,25 @@ bool box_construct_element(xmlNode *n, struct content *content,
box = box_create(style, href, target, title, id, content);
if (!box)
return false;
- /* set box type from style */
- box->type = box_map[style->display];
+ /* set box type from computed display */
+ if ((css_computed_position(style) == CSS_POSITION_ABSOLUTE ||
+ css_computed_position(style) == CSS_POSITION_FIXED) &&
+ (css_computed_display_static(style) ==
+ CSS_DISPLAY_INLINE ||
+ css_computed_display_static(style) ==
+ CSS_DISPLAY_INLINE_BLOCK ||
+ css_computed_display_static(style) ==
+ CSS_DISPLAY_INLINE_TABLE)) {
+ /* Special case for absolute positioning: make absolute inlines
+ * into inline block so that the boxes are constructed in an
+ * inline container as if they were not absolutely positioned.
+ * Layout expects and handles this. */
+ box->type = box_map[CSS_DISPLAY_INLINE_BLOCK];
+ } else {
+ /* Normal mapping */
+ box->type = box_map[css_computed_display(style,
+ n->parent == NULL)];
+ }
/* special elements */
element = bsearch((const char *) n->name, element_table,
@@ -385,16 +359,17 @@ bool box_construct_element(xmlNode *n, struct content *content,
(int (*)(const void *, const void *)) strcmp);
if (element) {
/* a special convert function exists for this element */
- if (!element->convert(n, content, box, &convert_children,
- markup_track, author))
+ if (!element->convert(n, content, box, &convert_children))
return false;
+
href = box->href;
target = box->target;
}
- if (style->display == CSS_DISPLAY_NONE) {
+ if (box->type == BOX_NONE || css_computed_display(box->style,
+ n->parent == NULL) == CSS_DISPLAY_NONE) {
/* Free style and invalidate box's style pointer */
- talloc_free(style);
+ css_computed_style_destroy(style);
box->style = NULL;
/* If this box has an associated gadget, invalidate the
@@ -416,60 +391,71 @@ bool box_construct_element(xmlNode *n, struct content *content,
(box->type == BOX_INLINE ||
box->type == BOX_BR ||
box->type == BOX_INLINE_BLOCK ||
- style->float_ == CSS_FLOAT_LEFT ||
- style->float_ == CSS_FLOAT_RIGHT)) {
+ css_computed_float(style) == CSS_FLOAT_LEFT ||
+ css_computed_float(style) == CSS_FLOAT_RIGHT)) {
/* this is the first inline in a block: make a container */
*inline_container = box_create(0, 0, 0, 0, 0, content);
if (!*inline_container)
return false;
+
(*inline_container)->type = BOX_INLINE_CONTAINER;
+
box_add_child(parent, *inline_container);
}
if (box->type == BOX_INLINE || box->type == BOX_BR) {
/* inline box: add to tree and recurse */
box_add_child(*inline_container, box);
+
if (convert_children && n->children) {
for (c = n->children; c; c = c->next)
if (!convert_xml_to_box(c, content, style,
parent, inline_container,
- href, target, title,
- markup_track, author))
+ href, target, title))
return false;
+
inline_end = box_create(style, href, target, title, id,
content);
if (!inline_end)
return false;
+
inline_end->type = BOX_INLINE_END;
+
if (*inline_container)
box_add_child(*inline_container, inline_end);
else
box_add_child(box->parent, inline_end);
+
box->inline_end = inline_end;
inline_end->inline_end = box;
}
} else if (box->type == BOX_INLINE_BLOCK) {
/* inline block box: add to tree and recurse */
box_add_child(*inline_container, box);
+
inline_container_c = 0;
+
for (c = n->children; convert_children && c; c = c->next)
if (!convert_xml_to_box(c, content, style, box,
&inline_container_c,
- href, target, title, markup_track,
- author))
+ href, target, title))
return false;
} else {
/* list item: compute marker, then treat as non-inline box */
- if (style->display == CSS_DISPLAY_LIST_ITEM) {
+ if (css_computed_display(style, n->parent == NULL) ==
+ CSS_DISPLAY_LIST_ITEM) {
+ lwc_string *image_uri;
struct box *marker;
+
marker = box_create(style, 0, 0, title, 0, content);
if (!marker)
return false;
+
marker->type = BOX_BLOCK;
+
/** \todo marker content (list-style-type) */
- switch (style->list_style_type) {
+ switch (css_computed_list_style_type(style)) {
case CSS_LIST_STYLE_TYPE_DISC:
- default:
/* 2022 BULLET */
marker->text = (char *) "\342\200\242";
marker->length = 3;
@@ -489,6 +475,7 @@ bool box_construct_element(xmlNode *n, struct content *content,
case CSS_LIST_STYLE_TYPE_LOWER_ROMAN:
case CSS_LIST_STYLE_TYPE_UPPER_ALPHA:
case CSS_LIST_STYLE_TYPE_UPPER_ROMAN:
+ default:
if (parent->last) {
struct box *last = parent->last;
@@ -515,9 +502,11 @@ bool box_construct_element(xmlNode *n, struct content *content,
list_marker->rows + 1;
}
}
+
marker->text = talloc_array(content, char, 20);
if (!marker->text)
return false;
+
snprintf(marker->text, 20, "%u.", marker->rows);
marker->length = strlen(marker->text);
break;
@@ -526,43 +515,50 @@ bool box_construct_element(xmlNode *n, struct content *content,
marker->length = 0;
break;
}
- if (style->list_style_image.type ==
- CSS_LIST_STYLE_IMAGE_URI) {
- if (!html_fetch_object(content,
- style->list_style_image.uri,
+
+ if (css_computed_list_style_image(style, &image_uri) ==
+ CSS_LIST_STYLE_IMAGE_URI &&
+ image_uri != NULL) {
+ if (!fetch_object_interned_url(content,
+ image_uri,
marker,
0, content->available_width,
1000, false))
return false;
}
+
box->list_marker = marker;
marker->parent = box;
}
/* float: insert a float box between the parent and
* current node. Note: new parent will be the float */
- if (style->float_ == CSS_FLOAT_LEFT ||
- style->float_ == CSS_FLOAT_RIGHT) {
+ if (css_computed_float(style) == CSS_FLOAT_LEFT ||
+ css_computed_float(style) == CSS_FLOAT_RIGHT) {
parent = box_create(0, href, target, title, 0, content);
if (!parent)
return false;
- if (style->float_ == CSS_FLOAT_LEFT)
+
+ if (css_computed_float(style) == CSS_FLOAT_LEFT)
parent->type = BOX_FLOAT_LEFT;
else
parent->type = BOX_FLOAT_RIGHT;
+
box_add_child(*inline_container, parent);
}
/* non-inline box: add to tree and recurse */
box_add_child(parent, box);
+
inline_container_c = 0;
+
for (c = n->children; convert_children && c; c = c->next)
if (!convert_xml_to_box(c, content, style, box,
&inline_container_c,
- href, target, title, markup_track,
- author))
+ href, target, title))
return false;
- if (style->float_ == CSS_FLOAT_NONE)
+
+ if (css_computed_float(style) == CSS_FLOAT_NONE)
/* new inline container unless this is a float */
*inline_container = 0;
}
@@ -571,23 +567,23 @@ bool box_construct_element(xmlNode *n, struct content *content,
if ((s = (char *) xmlGetProp(n, (const xmlChar *) "colspan"))) {
if (isdigit(s[0])) {
box->columns = strtol(s, NULL, 10);
- if ((MAX_SPAN < box->columns) || (box->columns < 1))
- box->columns = 1;
}
xmlFree(s);
}
+
if ((s = (char *) xmlGetProp(n, (const xmlChar *) "rowspan"))) {
if (isdigit(s[0])) {
box->rows = strtol(s, NULL, 10);
- if ((MAX_SPAN < box->rows) || (box->rows < 1))
- box->rows = 1;
}
xmlFree(s);
}
/* fetch any background image for this box */
- if (style->background_image.type == CSS_BACKGROUND_IMAGE_URI) {
- if (!html_fetch_object(content, style->background_image.uri,
+ if (css_computed_background_image(style, &bgimage_uri) ==
+ CSS_BACKGROUND_IMAGE_IMAGE &&
+ bgimage_uri != NULL) {
+ if (!fetch_object_interned_url(content,
+ bgimage_uri,
box, image_types, content->available_width,
1000, true))
return false;
@@ -613,7 +609,7 @@ bool box_construct_element(xmlNode *n, struct content *content,
*/
bool box_construct_text(xmlNode *n, struct content *content,
- struct css_style *parent_style,
+ const css_computed_style *parent_style,
struct box *parent, struct box **inline_container,
char *href, const char *target, char *title)
{
@@ -625,8 +621,9 @@ bool box_construct_text(xmlNode *n, struct content *content,
assert(parent);
assert(inline_container);
- if (parent_style->white_space == CSS_WHITE_SPACE_NORMAL ||
- parent_style->white_space == CSS_WHITE_SPACE_NOWRAP) {
+ if (css_computed_white_space(parent_style) == CSS_WHITE_SPACE_NORMAL ||
+ css_computed_white_space(parent_style) ==
+ CSS_WHITE_SPACE_NOWRAP) {
char *text = squash_whitespace((char *) n->content);
if (!text)
return false;
@@ -643,10 +640,14 @@ bool box_construct_text(xmlNode *n, struct content *content,
parent = parent->parent;
box_dump(stderr, parent, 0);
}
+
assert((*inline_container)->last != 0);
+
(*inline_container)->last->space = 1;
}
+
free(text);
+
return true;
}
@@ -657,34 +658,48 @@ bool box_construct_text(xmlNode *n, struct content *content,
free(text);
return false;
}
+
(*inline_container)->type = BOX_INLINE_CONTAINER;
+
box_add_child(parent, *inline_container);
}
- box = box_create(parent_style, href, target, title, 0, content);
+ /** \todo Dropping const here is not clever */
+ box = box_create((css_computed_style *) parent_style,
+ href, target, title, 0, content);
if (!box) {
free(text);
return false;
}
+
box->type = BOX_TEXT;
+
box->text = talloc_strdup(content, text);
free(text);
if (!box->text)
return false;
+
box->length = strlen(box->text);
+
/* strip ending space char off */
if (box->length > 1 && box->text[box->length - 1] == ' ') {
box->space = 1;
box->length--;
}
- if (parent_style->text_transform != CSS_TEXT_TRANSFORM_NONE)
+
+ if (css_computed_text_transform(parent_style) !=
+ CSS_TEXT_TRANSFORM_NONE)
box_text_transform(box->text, box->length,
- parent_style->text_transform);
- if (parent_style->white_space == CSS_WHITE_SPACE_NOWRAP) {
+ css_computed_text_transform(parent_style));
+
+ if (css_computed_white_space(parent_style) ==
+ CSS_WHITE_SPACE_NOWRAP) {
unsigned int i;
+
for (i = 0; i != box->length &&
box->text[i] != ' '; ++i)
; /* no body */
+
if (i != box->length) {
/* there is a space in text block and we
* want all spaces to be converted to NBSP
@@ -699,9 +714,12 @@ bool box_construct_text(xmlNode *n, struct content *content,
}
box_add_child(*inline_container, box);
+
if (box->text[0] == ' ') {
box->length--;
+
memmove(box->text, &box->text[1], box->length);
+
if (box->prev != NULL)
box->prev->space = 1;
}
@@ -710,17 +728,22 @@ bool box_construct_text(xmlNode *n, struct content *content,
/* white-space: pre */
char *text = cnv_space2nbsp((char *) n->content);
char *current;
+ enum css_white_space white_space =
+ css_computed_white_space(parent_style);
+
/* note: pre-wrap/pre-line are unimplemented */
- assert(parent_style->white_space == CSS_WHITE_SPACE_PRE ||
- parent_style->white_space ==
- CSS_WHITE_SPACE_PRE_LINE ||
- parent_style->white_space ==
- CSS_WHITE_SPACE_PRE_WRAP);
+ assert(white_space == CSS_WHITE_SPACE_PRE ||
+ white_space == CSS_WHITE_SPACE_PRE_LINE ||
+ white_space == CSS_WHITE_SPACE_PRE_WRAP);
+
if (!text)
return false;
- if (parent_style->text_transform != CSS_TEXT_TRANSFORM_NONE)
+
+ if (css_computed_text_transform(parent_style) !=
+ CSS_TEXT_TRANSFORM_NONE)
box_text_transform(text, strlen(text),
- parent_style->text_transform);
+ css_computed_text_transform(parent_style));
+
current = text;
/* swallow a single leading new line */
@@ -739,7 +762,9 @@ bool box_construct_text(xmlNode *n, struct content *content,
do {
size_t len = strcspn(current, "\r\n");
char old = current[len];
+
current[len] = 0;
+
if (!*inline_container) {
*inline_container = box_create(0, 0, 0, 0, 0,
content);
@@ -747,26 +772,37 @@ bool box_construct_text(xmlNode *n, struct content *content,
free(text);
return false;
}
+
(*inline_container)->type =
BOX_INLINE_CONTAINER;
+
box_add_child(parent, *inline_container);
}
- box = box_create(parent_style, href, target, title, 0,
- content);
+
+ /** \todo Dropping const isn't clever */
+ box = box_create((css_computed_style *) parent_style,
+ href, target, title, 0, content);
if (!box) {
free(text);
return false;
}
+
box->type = BOX_TEXT;
+
box->text = talloc_strdup(content, current);
if (!box->text) {
free(text);
return false;
}
+
box->length = strlen(box->text);
+
box_add_child(*inline_container, box);
+
current[len] = old;
+
current += len;
+
if (current[0] == '\r' && current[1] == '\n') {
current += 2;
*inline_container = 0;
@@ -775,6 +811,7 @@ bool box_construct_text(xmlNode *n, struct content *content,
*inline_container = 0;
}
} while (*current);
+
free(text);
}
@@ -782,524 +819,69 @@ bool box_construct_text(xmlNode *n, struct content *content,
}
+static void *myrealloc(void *ptr, size_t len, void *pw)
+{
+ return talloc_realloc_size(pw, ptr, len);
+}
+
/**
* Get the style for an element.
*
* \param c content of type CONTENT_HTML that is being processed
- * \param parent_style style at this point in xml tree
+ * \param parent_style style at this point in xml tree, or NULL for root
* \param n node in xml tree
- * \param markup_track track presentation markup that affects descendents
- * \param author denotes whether current style has author level
- * importance for certain properties
- * \return the new style, or 0 on memory exhaustion
- *
- * The style is collected from three sources:
- * 1. any styles for this element in the document stylesheet(s)
- * 2. the 'style' attribute
- * 3. non-CSS HTML attributes (subject to importance of CSS style properties)
+ * \return the new style, or NULL on memory exhaustion
*/
-
-struct css_style * box_get_style(struct content *c,
- struct css_style *parent_style,
- xmlNode *n, struct markup_track *markup_track,
- struct css_importance *author)
+css_computed_style *box_get_style(struct content *c,
+ const css_computed_style *parent_style,
+ xmlNode *n)
{
char *s;
- struct css_style *style;
- struct css_style *style_new;
- char *url;
- url_func_result res;
- colour border_color = 0x888888; /* mid-grey default for tables */
-
- /* if not in a table, switch off cellpadding and cell borders
- * and record that we're not in a table */
- if (strcmp((const char *) n->name, "thead") != 0 &&
- strcmp((const char *) n->name, "tbody") != 0 &&
- strcmp((const char *) n->name, "tfoot") != 0 &&
- strcmp((const char *) n->name, "tr") != 0 &&
- strcmp((const char *) n->name, "td") != 0 &&
- strcmp((const char *) n->name, "th") != 0 &&
- strcmp((const char *) n->name, "col") != 0 &&
- strcmp((const char *) n->name, "colgroup") != 0) {
- markup_track->cell_border = false;
- markup_track->cell_padding = false;
- markup_track->table = false;
- }
-
- style = talloc_memdup(c, parent_style, sizeof *style);
- if (!style)
- return 0;
-
- style_new = talloc_memdup(c, &css_blank_style, sizeof *style_new);
- if (!style_new)
- return 0;
- css_get_style(c->data.html.working_stylesheet, n, style_new, author);
- css_cascade(style, style_new, NULL);
+ css_stylesheet *inline_style = NULL;
+ css_computed_style *partial;
+ css_computed_style *style;
- /* style_new isn't needed past this point */
- talloc_free(style_new);
-
- /* Handle style attribute. (style attribute values have high enough
- * specificity to override existing style data.) */
+ /* Firstly, construct inline stylesheet, if any */
if ((s = (char *) xmlGetProp(n, (const xmlChar *) "style"))) {
- struct css_style *astyle;
- astyle = css_duplicate_style(&css_empty_style);
- if (!astyle) {
- xmlFree(s);
- return 0;
- }
- css_parse_property_list(c, astyle, s);
- css_cascade(style, astyle, author);
- css_free_style(astyle);
- xmlFree(s);
- }
-
- /* Apply presentational HTML attributes to style
- * (Only apply if style property does not have "author" level
- * importance or higher.)
- */
-
- /* This property only applies to the body element, if you believe
- * the spec. Many browsers seem to allow it on other elements too,
- * so let's be generic ;) */
- if (!author->background_image && (s = (char *) xmlGetProp(n,
- (const xmlChar *) "background"))) {
- res = url_join(s, c->data.html.base_url, &url);
- xmlFree(s);
- if (res == URL_FUNC_NOMEM) {
- return 0;
- } else if (res == URL_FUNC_OK) {
- /* if url is equivalent to the parent's url,
- * we've got infinite inclusion: ignore */
- if (strcmp(url, c->data.html.base_url) == 0)
- free(url);
- else {
- style->background_image.type =
- CSS_BACKGROUND_IMAGE_URI;
- style->background_image.uri = talloc_strdup(
- c, url);
- free(url);
- if (!style->background_image.uri)
- return 0;
- }
- }
- }
-
- if (!author->background_color && (s = (char *) xmlGetProp(n,
- (const xmlChar *) "bgcolor"))) {
- parse_inline_colour(s, &style->background_color);
- xmlFree(s);
- }
-
- if (!author->color && (s = (char *) xmlGetProp(n,
- (const xmlChar *) "color"))) {
- parse_inline_colour(s, &style->color);
- xmlFree(s);
- }
-
- if (!author->height && (s = (char *) xmlGetProp(n,
- (const xmlChar *) "height")) &&
- ((strcmp((const char *) n->name, "iframe") == 0) ||
- (strcmp((const char *) n->name, "td") == 0) ||
- (strcmp((const char *) n->name, "th") == 0) ||
- (strcmp((const char *) n->name, "tr") == 0) ||
- (strcmp((const char *) n->name, "img") == 0) ||
- (strcmp((const char *) n->name, "object") == 0) ||
- (strcmp((const char *) n->name, "applet") == 0))) {
- float value = isdigit(s[0]) ? atof(s) : -1;
- if (value <= 0 || strlen(s) == 0) {
- /* ignore negative values and height="" */
- } else if (strrchr(s, '%')) {
- style->height.height = CSS_HEIGHT_PERCENT;
- style->height.value.percent = value;
- } else {
- style->height.height = CSS_HEIGHT_LENGTH;
- style->height.value.length.unit = CSS_UNIT_PX;
- style->height.value.length.value = value;
- }
- xmlFree(s);
- }
-
- if (!author->width && strcmp((const char *) n->name, "input") == 0) {
- int size = -1;
- if ((s = (char *) xmlGetProp(n, (const xmlChar *) "size"))) {
- size = isdigit(s[0]) ? atoi(s): -1;
- if (0 < size) {
- char *type = (char *) xmlGetProp(n,
- (const xmlChar *) "type");
- style->width.width = CSS_WIDTH_LENGTH;
- if (!type || strcasecmp(type, "text") == 0 ||
- strcasecmp(type, "password") == 0)
- /* in characters for text, password */
- style->width.value.length.unit =
- CSS_UNIT_EX;
- else if (strcasecmp(type, "file") != 0)
- /* in pixels otherwise; ignore width
- * on file, because we do them
- * differently to most browsers */
- style->width.value.length.unit =
- CSS_UNIT_PX;
- style->width.value.length.value = size;
- if (type)
- xmlFree(type);
- }
- xmlFree(s);
- }
- /* If valid maxlength value is provided, the size attribute is
- * unset and maxlength is small, use it to reduce input width
- * to sensible size */
- if ((s = (char *) xmlGetProp(n, (const xmlChar *)
- "maxlength"))) {
- int maxlength = isdigit(s[0]) ? atoi(s): -1;
- if (0 < maxlength && size == -1 && maxlength < 10) {
- char *type;
- /* Bump up really small widths */
- maxlength = maxlength < 5 ? maxlength + 1 :
- maxlength;
- type = (char *) xmlGetProp(n,
- (const xmlChar *) "type");
- style->width.width = CSS_WIDTH_LENGTH;
- if (!type || strcasecmp(type, "text") == 0 ||
- strcasecmp(type, "password") == 0)
- /* in characters for text, password */
- style->width.value.length.unit =
- CSS_UNIT_EX;
- style->width.value.length.value = maxlength;
- if (type)
- xmlFree(type);
- }
- xmlFree(s);
- }
- }
+ inline_style = nscss_create_inline_style(
+ (uint8_t *) s, strlen(s),
+ c->data.html.encoding, c->url, false,
+ c->data.html.dict, myrealloc, c);
- if (!author->color && strcmp((const char *) n->name, "body") == 0) {
- if ((s = (char *) xmlGetProp(n, (const xmlChar *) "text"))) {
- parse_inline_colour(s, &style->color);
- xmlFree(s);
- }
- }
-
- if (!author->width && (s = (char *) xmlGetProp(n,
- (const xmlChar *) "width")) &&
- ((strcmp((const char *) n->name, "hr") == 0) ||
- (strcmp((const char *) n->name, "iframe") == 0) ||
- (strcmp((const char *) n->name, "img") == 0) ||
- (strcmp((const char *) n->name, "object") == 0) ||
- (strcmp((const char *) n->name, "table") == 0) ||
- (strcmp((const char *) n->name, "td") == 0) ||
- (strcmp((const char *) n->name, "th") == 0) ||
- (strcmp((const char *) n->name, "applet") == 0))) {
- float value = isdigit(s[0]) ? atof(s) : -1;
- if (value < 0 || strlen(s) == 0) {
- /* ignore negative values and width="" */
- } else if (strrchr(s, '%')) {
- style->width.width = CSS_WIDTH_PERCENT;
- style->width.value.percent = value;
- } else {
- style->width.width = CSS_WIDTH_LENGTH;
- style->width.value.length.unit = CSS_UNIT_PX;
- style->width.value.length.value = value;
- }
xmlFree(s);
- }
-
- if (strcmp((const char *) n->name, "textarea") == 0) {
- if (!author->height && (s = (char *) xmlGetProp(n,
- (const xmlChar *) "rows"))) {
- int value = isdigit(s[0]) ? atoi(s): -1;
- if (0 < value) {
- style->height.height = CSS_HEIGHT_LENGTH;
- style->height.value.length.unit = CSS_UNIT_EM;
- style->height.value.length.value = value;
- }
- xmlFree(s);
- }
- if (!author->width && (s = (char *) xmlGetProp(n,
- (const xmlChar *) "cols"))) {
- int value = isdigit(s[0]) ? atoi(s): -1;
- if (0 < value) {
- style->width.width = CSS_WIDTH_LENGTH;
- style->width.value.length.unit = CSS_UNIT_EX;
- style->width.value.length.value = value;
- }
- xmlFree(s);
- }
- }
-
- if (strcmp((const char *) n->name, "table") == 0) {
- if (!author->border_spacing && (s = (char *) xmlGetProp(n,
- (const xmlChar *) "cellspacing"))) {
- /* percentage cellspacing not implemented */
- if (!strrchr(s, '%')) {
- int value = isdigit(s[0]) ? atoi(s): -1;
- if (0 <= value) {
- style->border_spacing.border_spacing =
- CSS_BORDER_SPACING_LENGTH;
- style->border_spacing.horz.unit =
- style->border_spacing.vert.unit =
- CSS_UNIT_PX;
- style->border_spacing.horz.value =
- style->border_spacing.vert.value =
- value;
- }
- }
- xmlFree(s);
- }
-
- if ((s = (char *) xmlGetProp(n,
- (const xmlChar *) "bordercolor"))) {
- parse_inline_colour(s, &border_color);
- xmlFree(s);
- }
- if ((s = (char *) xmlGetProp(n,
- (const xmlChar *) "border"))) {
- int border_width = atoi(s);
- /* precentage border width not implemented */
- if (!strrchr(s, '%') && 0 < border_width) {
- unsigned int i;
- for (i = 0; i != 4; i++) {
- if (!author->border_color[i])
- style->border[i].color =
- border_color;
- if (!author->border_width[i]) {
- style->border[i].width.width =
- CSS_BORDER_WIDTH_LENGTH;
- style->border[i].width.value.
- value = border_width;
- style->border[i].width.value.
- unit = CSS_UNIT_PX;
- }
- if (!author->border_style[i])
- style->border[i].style =
- CSS_BORDER_STYLE_OUTSET;
- }
- }
- xmlFree(s);
- }
- }
- if (strcmp((const char *) n->name, "td") == 0 ||
- strcmp((const char *) n->name, "th") == 0) {
- /* set any cellborders stipulated by associated table */
- if (markup_track->cell_border) {
- unsigned int i;
- for (i = 0; i != 4; i++) {
- if (!author->border_color[i])
- style->border[i].color = markup_track->
- border_color;
- if (!author->border_width[i]) {
- style->border[i].width.width =
- CSS_BORDER_WIDTH_LENGTH;
- style->border[i].width.value.value = 1;
- style->border[i].width.value.unit =
- CSS_UNIT_PX;
- }
- if (!author->border_style[i])
- style->border[i].style =
- CSS_BORDER_STYLE_INSET;
- }
- }
- /* set any cellpadding stipulated by associated table */
- if (markup_track->cell_padding) {
- unsigned int i;
- for (i = 0; i != 4; i++) {
- if (!author->padding[i]) {
- style->padding[i].padding =
- CSS_PADDING_LENGTH;
- style->padding[i].value.length.value =
- markup_track->padding_width;
- style->padding[i].value.length.unit =
- CSS_UNIT_PX;
- }
- }
- }
+ if (inline_style == NULL)
+ return NULL;
}
- if ((strcmp((const char *) n->name, "img") == 0) ||
- (strcmp((const char *) n->name, "image") == 0) ||
- (strcmp((const char *) n->name, "applet") == 0)) {
- if ((s = (char *) xmlGetProp(n,
- (const xmlChar *) "hspace"))) {
- /* percentage hspace not implemented */
- if (!strrchr(s, '%')) {
- int value = isdigit(s[0]) ? atoi(s): -1;
- if (0 <= value && !author->margin[LEFT]) {
- style->margin[LEFT].margin =
- CSS_MARGIN_LENGTH;
- style->margin[LEFT].value.length.value =
- value;
- style->margin[LEFT].value.length.unit =
- CSS_UNIT_PX;
- }
- if (0 <= value && !author->margin[RIGHT]) {
- style->margin[RIGHT].margin =
- CSS_MARGIN_LENGTH;
- style->margin[RIGHT].value.length.
- value = value;
- style->margin[RIGHT].value.length.unit =
- CSS_UNIT_PX;
- }
- }
- xmlFree(s);
- }
- if ((s = (char *) xmlGetProp(n,
- (const xmlChar *) "vspace"))) {
- /* percentage vspace not implemented */
- if (!strrchr(s, '%')) {
- int value = isdigit(s[0]) ? atoi(s): -1;
- if (0 <= value && !author->margin[TOP]) {
- style->margin[TOP].margin =
- CSS_MARGIN_LENGTH;
- style->margin[TOP].value.length.value =
- value;
- style->margin[TOP].value.length.unit =
- CSS_UNIT_PX;
- }
- if (0 <= value && !author->margin[BOTTOM]) {
- style->margin[BOTTOM].margin =
- CSS_MARGIN_LENGTH;
- style->margin[BOTTOM].value.length.
- value = value;
- style->margin[BOTTOM].value.length.
- unit = CSS_UNIT_PX;
- }
- }
- xmlFree(s);
- }
- }
+ /* Select partial style for element */
+ partial = nscss_get_style(c, n, CSS_PSEUDO_ELEMENT_NONE,
+ CSS_MEDIA_SCREEN, inline_style, myrealloc, c);
- /* Handle markup-originating alignment of block level elements.
- * Adjust left and right margins. text-align property is handled in
- * the default CSS file.
- */
- if (markup_track->align != ALIGN_NONE &&
- (style->display == CSS_DISPLAY_BLOCK ||
- style->display == CSS_DISPLAY_TABLE) &&
- (strcmp((const char *) n->name, "blockquote") != 0)) {
- if (!author->margin[LEFT]) {
- if (markup_track->align == ALIGN_LEFT) {
- /* left */
- style->margin[LEFT].margin = CSS_MARGIN_LENGTH;
- style->margin[LEFT].value.length.value = 0;
- style->margin[LEFT].value.length.unit =
- CSS_UNIT_PX;
- } else
- /* center or right */
- style->margin[LEFT].margin = CSS_MARGIN_AUTO;
- }
-
- if (!author->margin[RIGHT]) {
- if (markup_track->align == ALIGN_RIGHT) {
- /* right */
- style->margin[RIGHT].margin = CSS_MARGIN_LENGTH;
- style->margin[RIGHT].value.length.value= 0;
- style->margin[RIGHT].value.length.unit =
- CSS_UNIT_PX;
- } else
- /* left or center */
- style->margin[RIGHT].margin = CSS_MARGIN_AUTO;
- }
- if (author->margin[LEFT] || author->margin[RIGHT]) {
- /* author stylesheet sets a margin so stop markup
- * alignment model propagation */
- markup_track->align = ALIGN_NONE;
- }
- }
- /* Centered tables are a special case. The align attribute only
- * affects the current element (table) and overrides any existing
- * HTML alignment rule. Tables aligned to left or right are floated
- * by the default CSS file. */
- if (!author->margin[LEFT] && !author->margin[RIGHT] &&
- strcmp((const char *) n->name, "table") == 0) {
- if ((s = (char *) xmlGetProp(n,
- (const xmlChar *) "align"))) {
- if (strcasecmp(s, "center") == 0) {
- style->margin[LEFT].margin = CSS_MARGIN_AUTO;
- style->margin[RIGHT].margin = CSS_MARGIN_AUTO;
- }
- xmlFree(s);
- }
- }
+ /* No longer need inline style */
+ if (inline_style != NULL)
+ css_stylesheet_destroy(inline_style);
- box_solve_display(style, !n->parent);
+ /* Failed selecting partial style -- bail out */
+ if (partial == NULL)
+ return NULL;
- /* Update markup_track with attributes which affect children of
- * current box. */
+ /* If there's a parent style, compose with partial to obtain
+ * complete computed style for element */
+ if (parent_style != NULL) {
+ css_error error;
- /* Handle html block level element alignment model.
- * Note that only margins of block level children are considered,
- * text-align for the current block can be handled in the default
- * CSS file.
- */
- if (strcmp((const char *) n->name, "center") == 0)
- markup_track->align = ALIGN_CENTER;
- else if (strcmp((const char *) n->name, "div") == 0 ||
- strcmp((const char *) n->name, "col") == 0 ||
- strcmp((const char *) n->name, "colgroup") == 0 ||
- strcmp((const char *) n->name, "tbody") == 0 ||
- strcmp((const char *) n->name, "td") == 0 ||
- strcmp((const char *) n->name, "tfoot") == 0 ||
- strcmp((const char *) n->name, "th") == 0 ||
- strcmp((const char *) n->name, "thead") == 0 ||
- strcmp((const char *) n->name, "tr") == 0) {
-
- if ((s = (char *) xmlGetProp(n, (const xmlChar *) "align"))) {
- if (strcasecmp(s, "center") == 0)
- markup_track->align = ALIGN_CENTER;
- else if (strcasecmp(s, "right") == 0)
- markup_track->align = ALIGN_RIGHT;
- else if (strcasecmp(s, "left") == 0)
- markup_track->align = ALIGN_LEFT;
- xmlFree(s);
- /* Need to remember if we're in a table, so that any
- * alignment rules set on the table's elements won't
- * get overridden by the default alignment of a cell
- * with no align attribute. At this point, we're in a
- * table if the element isn't a div */
- if (strcmp((const char *) n->name, "div") != 0)
- markup_track->table = true;
+ error = css_computed_style_compose(parent_style, partial,
+ nscss_compute_font_size, NULL, partial);
+ if (error != CSS_OK) {
+ css_computed_style_destroy(partial);
+ return NULL;
}
- }
- /* Table cells without an align value have a default implied
- * alignment. */
- if (strcmp((const char *) n->name, "td") == 0 && !markup_track->table) {
- if (!(s = (char *) xmlGetProp(n, (const xmlChar *) "align")))
- markup_track->align = ALIGN_LEFT;
- else
- xmlFree(s);
- }
- if (strcmp((const char *) n->name, "th") == 0 && !markup_track->table) {
- if (!(s = (char *) xmlGetProp(n, (const xmlChar *) "align")))
- markup_track->align = ALIGN_CENTER;
- else
- xmlFree(s);
- }
- /* Some of TABLE's attributes apply to the table cells contained
- * within the table. Those details are stored so they may be applied
- * to the cells when we get to them. */
- if (strcmp((const char *) n->name, "table") == 0) {
- if ((s = (char *) xmlGetProp(n,
- (const xmlChar *) "cellpadding"))) {
- char *endp;
- long value = strtol(s, &endp, 10);
- /* precentage padding width not implemented */
- if (*endp == 0 && 0 <= value && value < 1000) {
- markup_track->padding_width = value;
- markup_track->cell_padding = true;
- }
- xmlFree(s);
- }
- if ((s = (char *) xmlGetProp(n,
- (const xmlChar *) "border"))) {
- int border_width = atoi(s);
- markup_track->border_color = border_color;
- /* percentage border width not implemented */
- if (!strrchr(s, '%') && 0 < border_width) {
- markup_track->cell_border = true;
- }
- xmlFree(s);
- }
+ style = partial;
+ } else {
+ /* No parent style, so partial must be fully computed */
+ style = partial;
}
return style;
@@ -1307,52 +889,6 @@ struct css_style * box_get_style(struct content *c,
/**
- * Calculate 'display' based on 'display', 'position', and 'float', as given
- * by CSS 2.1 9.7.
- *
- * \param style style to update
- * \param root this is the root element
- */
-
-void box_solve_display(struct css_style *style, bool root)
-{
- if (style->display == CSS_DISPLAY_NONE) /* 1. */
- return;
- else if (style->position == CSS_POSITION_ABSOLUTE ||
- style->position == CSS_POSITION_FIXED) /* 2. */
- style->float_ = CSS_FLOAT_NONE;
- else if (style->float_ != CSS_FLOAT_NONE) /* 3. */
- ;
- else if (root) /* 4. */
- ;
- else /* 5. */
- return;
-
- /* Special case for absolute positioning: make absolute inlines into
- * inline block so that the boxes are constructed in an inline container
- * as if they were not absolutely positioned. Layout expects and
- * handles this. */
- if ((style->position == CSS_POSITION_ABSOLUTE ||
- style->position == CSS_POSITION_FIXED) &&
- (style->display == CSS_DISPLAY_INLINE ||
- style->display == CSS_DISPLAY_INLINE_BLOCK ||
- style->display == CSS_DISPLAY_INLINE_TABLE)) {
- style->display = CSS_DISPLAY_INLINE_BLOCK;
- return;
- }
-
- /* map specified value to computed value using table given in 9.7 */
- if (style->display == CSS_DISPLAY_INLINE_TABLE)
- style->display = CSS_DISPLAY_TABLE;
- else if (style->display == CSS_DISPLAY_LIST_ITEM ||
- style->display == CSS_DISPLAY_TABLE)
- ; /* same as specified */
- else
- style->display = CSS_DISPLAY_BLOCK;
-}
-
-
-/**
* Apply the CSS text-transform property to given text for its ASCII chars.
*
* \param s string to transform
@@ -1360,8 +896,7 @@ void box_solve_display(struct css_style *style, bool root)
* \param tt transform type
*/
-void box_text_transform(char *s, unsigned int len,
- css_text_transform tt)
+void box_text_transform(char *s, unsigned int len, enum css_text_transform tt)
{
unsigned int i;
if (len == 0)
@@ -1416,7 +951,15 @@ void box_text_transform(char *s, unsigned int len,
bool box_body(BOX_SPECIAL_PARAMS)
{
- content->data.html.background_colour = box->style->background_color;
+ enum css_background_color type;
+ css_color color;
+
+ type = css_computed_background_color(box->style, &color);
+ if (type == CSS_BACKGROUND_COLOR_TRANSPARENT)
+ content->data.html.background_colour = NS_TRANSPARENT;
+ else
+ content->data.html.background_colour = nscss_color_to_ns(color);
+
return true;
}
@@ -1507,7 +1050,8 @@ bool box_image(BOX_SPECIAL_PARAMS)
char *s, *url;
xmlChar *alt, *src;
- if (box->style && box->style->display == CSS_DISPLAY_NONE)
+ if (box->style && css_computed_display(box->style,
+ n->parent == NULL) == CSS_DISPLAY_NONE)
return true;
/* handle alt text */
@@ -1558,7 +1102,8 @@ bool box_object(BOX_SPECIAL_PARAMS)
xmlNode *c;
struct box *inline_container = 0;
- if (box->style && box->style->display == CSS_DISPLAY_NONE)
+ if (box->style && css_computed_display(box->style,
+ n->parent == NULL) == CSS_DISPLAY_NONE)
return true;
if (!box_get_attribute(n, "usemap", content, &box->usemap))
@@ -1685,8 +1230,7 @@ bool box_object(BOX_SPECIAL_PARAMS)
/* convert children and place into fallback */
for (c = n->children; c; c = c->next) {
if (!convert_xml_to_box(c, content, box->style, box,
- &inline_container, 0, 0, 0, markup_track,
- author))
+ &inline_container, 0, 0, 0))
return false;
}
box->fallback = box->children;
@@ -1849,7 +1393,7 @@ bool box_frameset(BOX_SPECIAL_PARAMS)
if (convert_children)
*convert_children = false;
/* And ignore this spurious frameset */
- box->style->display = CSS_DISPLAY_NONE;
+ box->type = BOX_NONE;
return true;
}
@@ -1860,7 +1404,7 @@ bool box_frameset(BOX_SPECIAL_PARAMS)
ok = box_create_frameset(content->data.html.frameset, n, content);
if (ok)
- box->style->display = CSS_DISPLAY_NONE;
+ box->type = BOX_NONE;
if (convert_children)
*convert_children = false;
@@ -1920,7 +1464,11 @@ bool box_create_frameset(struct content_html_frames *f, xmlNode *n,
/* common extension: bordercolor="#RRGGBB|<named colour>" to control
*all children */
if ((s = (char *) xmlGetProp(n, (const xmlChar *) "bordercolor"))) {
- parse_inline_colour(s, &default_border_colour);
+ css_color color;
+
+ if (nscss_parse_colour((const char *) s, &color))
+ default_border_colour = nscss_color_to_ns(color);
+
xmlFree(s);
}
@@ -2030,7 +1578,13 @@ bool box_create_frameset(struct content_html_frames *f, xmlNode *n,
}
if ((s = (char *) xmlGetProp(c, (const xmlChar *)
"bordercolor"))) {
- parse_inline_colour(s, &frame->border_colour);
+ css_color color;
+
+ if (nscss_parse_colour((const char *) s,
+ &color))
+ frame->border_colour =
+ nscss_color_to_ns(color);
+
xmlFree(s);
}
@@ -2100,7 +1654,11 @@ bool box_iframe(BOX_SPECIAL_PARAMS)
xmlFree(s);
}
if ((s = (char *) xmlGetProp(n, (const xmlChar *) "bordercolor"))) {
- parse_inline_colour(s, &iframe->border_colour);
+ css_color color;
+
+ if (nscss_parse_colour(s, &color))
+ iframe->border_colour = nscss_color_to_ns(color);
+
xmlFree(s);
}
if ((s = (char *) xmlGetProp(n,
@@ -2155,31 +1713,36 @@ bool box_input(BOX_SPECIAL_PARAMS)
gadget->box = box;
if (type && strcasecmp(type, "password") == 0) {
- if (!box_input_text(n, content, box, 0, markup_track, author,
- true))
+ if (!box_input_text(n, content, box, 0, true))
goto no_memory;
} else if (type && strcasecmp(type, "file") == 0) {
box->type = BOX_INLINE_BLOCK;
} else if (type && strcasecmp(type, "hidden") == 0) {
/* no box for hidden inputs */
- box->style->display = CSS_DISPLAY_NONE;
+ box->type = BOX_NONE;
} else if (type && (strcasecmp(type, "checkbox") == 0 ||
strcasecmp(type, "radio") == 0)) {
} else if (type && (strcasecmp(type, "submit") == 0 ||
strcasecmp(type, "reset") == 0 ||
strcasecmp(type, "button") == 0)) {
struct box *inline_container, *inline_box;
- if (!box_button(n, content, box, 0, markup_track, author))
+
+ if (!box_button(n, content, box, 0))
goto no_memory;
+
inline_container = box_create(0, 0, 0, 0, 0, content);
if (!inline_container)
goto no_memory;
+
inline_container->type = BOX_INLINE_CONTAINER;
+
inline_box = box_create(box->style, 0, 0, box->title, 0,
content);
if (!inline_box)
goto no_memory;
+
inline_box->type = BOX_TEXT;
+
if (box->gadget->value != NULL)
inline_box->text = talloc_strdup(content,
box->gadget->value);
@@ -2191,15 +1754,20 @@ bool box_input(BOX_SPECIAL_PARAMS)
messages_get("Form_Reset"));
else
inline_box->text = talloc_strdup(content, "Button");
+
if (!inline_box->text)
goto no_memory;
+
inline_box->length = strlen(inline_box->text);
+
box_add_child(inline_container, inline_box);
+
box_add_child(box, inline_container);
} else if (type && strcasecmp(type, "image") == 0) {
gadget->type = GADGET_IMAGE;
- if (box->style && box->style->display != CSS_DISPLAY_NONE) {
+ if (box->style && css_computed_display(box->style,
+ n->parent == NULL) != CSS_DISPLAY_NONE) {
if ((s = (char *) xmlGetProp(n,
(const xmlChar*) "src"))) {
res = url_join(s,
@@ -2227,8 +1795,7 @@ bool box_input(BOX_SPECIAL_PARAMS)
}
} else {
/* the default type is "text" */
- if (!box_input_text(n, content, box, 0, markup_track, author,
- false))
+ if (!box_input_text(n, content, box, 0, false))
goto no_memory;
}
@@ -2582,7 +2149,8 @@ bool box_embed(BOX_SPECIAL_PARAMS)
xmlChar *src;
xmlAttr *a;
- if (box->style && box->style->display == CSS_DISPLAY_NONE)
+ if (box->style && css_computed_display(box->style,
+ n->parent == NULL) == CSS_DISPLAY_NONE)
return true;
params = talloc(content, struct object_params);
@@ -2790,18 +2358,39 @@ struct frame_dimension *box_parse_multi_lengths(const char *s,
return length;
}
-
/**
- * Parse an inline colour string
+ * Fetch an object from an interned URL
+ *
+ * \param c Current content
+ * \param url URL to fetch
+ * \param box Box containing object
+ * \param permitted_types Array of permitted types terminated by
+ * CONTENT_UNKNOWN, or NULL for all types
+ * \param available_width Estimate of width of object
+ * \param available_height Estimate of height of object
+ * \param background This object forms the box background
+ * \return true on success, false on memory exhaustion
*/
-static void parse_inline_colour(char *s, colour *variable) {
- colour new_colour = CSS_COLOR_NONE;
- if (s[0] == '#') {
- if (strlen(s) == 7)
- new_colour = hex_colour(s + 1, 6);
- } else {
- new_colour = named_colour(s);
- }
- if (new_colour != CSS_COLOR_NONE)
- *variable = new_colour;
+bool fetch_object_interned_url(struct content *c, lwc_string *url,
+ struct box *box, const content_type *permitted_types,
+ int available_width, int available_height,
+ bool background)
+{
+ char *url_buf;
+ bool ret = true;
+
+ url_buf = malloc(lwc_string_length(url) + 1);
+ if (url_buf == NULL)
+ return false;
+
+ memcpy(url_buf, lwc_string_data(url), lwc_string_length(url));
+ url_buf[lwc_string_length(url)] = '\0';
+
+ ret = html_fetch_object(c, url_buf, box, permitted_types,
+ available_width, available_height, background);
+
+ free(url_buf);
+
+ return ret;
}
+
diff --git a/render/box_normalise.c b/render/box_normalise.c
index 865433e26..fc563e743 100644
--- a/render/box_normalise.c
+++ b/render/box_normalise.c
@@ -26,6 +26,7 @@
#include <assert.h>
#include <stdbool.h>
#include "css/css.h"
+#include "css/select.h"
#include "render/box.h"
#include "render/table.h"
#include "desktop/gui.h"
@@ -35,29 +36,34 @@
#include "utils/talloc.h"
+/**
+ * Row spanning information for a cell
+ */
struct span_info {
+ /** Number of rows this cell spans */
unsigned int row_span;
+ /** The cell in this column spans all rows until the end of the table */
bool auto_row;
- bool auto_column;
};
+/**
+ * Column record for a table
+ */
struct columns {
+ /** Current column index */
unsigned int current_column;
- bool extra;
- /* Number of columns in main part of table 1..max columns */
+ /** Number of columns in main part of table 1..max columns */
unsigned int num_columns;
- /* Information about columns in main table,
- array 0 to num_columns - 1 */
+ /** Information about columns in main table, array [0, num_columns) */
struct span_info *spans;
- /* Number of columns that have cells after a colspan 0 */
- unsigned int extra_columns;
- /* Number of rows in table */
+ /** Number of rows in table */
unsigned int num_rows;
};
static bool box_normalise_table(struct box *table, struct content *c);
-static void box_normalise_table_spans(struct box *table);
+static bool box_normalise_table_spans(struct box *table,
+ struct span_info *spans, struct content *c);
static bool box_normalise_table_row_group(struct box *row_group,
struct columns *col_info,
struct content *c);
@@ -69,6 +75,18 @@ static bool calculate_table_row(struct columns *col_info,
unsigned int *start_column);
static bool box_normalise_inline_container(struct box *cont, struct content *c);
+/**
+ * Allocator
+ *
+ * \param ptr Pointer to reallocate, or NULL for new allocation
+ * \param size Number of bytes requires
+ * \param pw Allocation context
+ * \return Pointer to allocated block, or NULL on failure
+ */
+static void *myrealloc(void *ptr, size_t len, void *pw)
+{
+ return talloc_realloc_size(pw, ptr, len);
+}
/**
* Ensure the box tree is correctly nested by adding and removing nodes.
@@ -96,30 +114,34 @@ bool box_normalise_block(struct box *block, struct content *c)
struct box *child;
struct box *next_child;
struct box *table;
- struct css_style *style;
+ css_computed_style *style;
+
+ assert(block != NULL);
- assert(block != 0);
LOG(("block %p, block->type %u", block, block->type));
+
assert(block->type == BOX_BLOCK || block->type == BOX_INLINE_BLOCK ||
block->type == BOX_TABLE_CELL);
+
gui_multitask();
- for (child = block->children; child != 0; child = next_child) {
+ for (child = block->children; child != NULL; child = next_child) {
LOG(("child %p, child->type = %d", child, child->type));
+
next_child = child->next; /* child may be destroyed */
+
switch (child->type) {
case BOX_BLOCK:
/* ok */
- if (!box_normalise_block(child, c))
+ if (box_normalise_block(child, c) == false)
return false;
break;
case BOX_INLINE_CONTAINER:
- if (!box_normalise_inline_container(child,
- c))
+ if (box_normalise_inline_container(child, c) == false)
return false;
break;
case BOX_TABLE:
- if (!box_normalise_table(child, c))
+ if (box_normalise_table(child, c) == false)
return false;
break;
case BOX_INLINE:
@@ -137,37 +159,48 @@ bool box_normalise_block(struct box *block, struct content *c)
case BOX_TABLE_ROW:
case BOX_TABLE_CELL:
/* insert implied table */
- style = talloc_memdup(c, block->style, sizeof *style);
- if (!style)
+ assert(block->style != NULL);
+
+ style = nscss_get_blank_style(c, block->style,
+ myrealloc, c);
+ if (style == NULL)
return false;
- css_cascade(style, &css_blank_style, NULL);
+
table = box_create(style, block->href, block->target,
- 0, 0, c);
- if (!table) {
- talloc_free(style);
+ NULL, NULL, c);
+ if (table == NULL) {
+ css_computed_style_destroy(style);
return false;
}
table->type = BOX_TABLE;
- if (child->prev == 0)
+
+ if (child->prev == NULL)
block->children = table;
else
child->prev->next = table;
+
table->prev = child->prev;
- while (child != 0 && (
+
+ 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 = 0;
+ child->next = NULL;
child = next_child;
}
- table->last->next = 0;
+
+ table->last->next = NULL;
table->next = next_child = child;
- if (table->next)
+ if (table->next != NULL)
table->next->prev = table;
+ else
+ block->last = table;
table->parent = block;
- if (!box_normalise_table(table, c))
+
+ if (box_normalise_table(table, c) == false)
return false;
break;
default:
@@ -184,30 +217,32 @@ bool box_normalise_table(struct box *table, struct content * c)
struct box *child;
struct box *next_child;
struct box *row_group;
- struct css_style *style;
+ css_computed_style *style;
struct columns col_info;
- assert(table != 0);
+ assert(table != NULL);
assert(table->type == BOX_TABLE);
+
LOG(("table %p", table));
+
col_info.num_columns = 1;
col_info.current_column = 0;
col_info.spans = malloc(2 * sizeof *col_info.spans);
- if (!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 = col_info.spans[0].auto_column =
- col_info.spans[1].auto_row = col_info.spans[1].auto_column = false;
- col_info.num_rows = col_info.extra_columns = 0;
- col_info.extra = false;
+ col_info.spans[0].auto_row = false;
+ col_info.spans[1].auto_row = false;
+ col_info.num_rows = 0;
- for (child = table->children; child != 0; child = next_child) {
+ for (child = table->children; child != NULL; child = next_child) {
next_child = child->next;
switch (child->type) {
case BOX_TABLE_ROW_GROUP:
/* ok */
- if (!box_normalise_table_row_group(child,
- &col_info, c)) {
+ if (box_normalise_table_row_group(child,
+ &col_info, c) == false) {
free(col_info.spans);
return false;
}
@@ -219,46 +254,56 @@ bool box_normalise_table(struct box *table, struct content * c)
case BOX_TABLE_CELL:
/* insert implied table row group */
assert(table->style != NULL);
- style = talloc_memdup(c, table->style, sizeof *style);
- if (!style) {
+
+ style = nscss_get_blank_style(c, table->style,
+ myrealloc, c);
+ if (style == NULL) {
free(col_info.spans);
return false;
}
- css_cascade(style, &css_blank_style, NULL);
+
row_group = box_create(style, table->href,
- table->target, 0, 0, c);
- if (!row_group) {
+ table->target, NULL, NULL, c);
+ if (row_group == NULL) {
+ css_computed_style_destroy(style);
free(col_info.spans);
- talloc_free(style);
return false;
}
+
row_group->type = BOX_TABLE_ROW_GROUP;
- if (child->prev == 0)
+
+ if (child->prev == NULL)
table->children = row_group;
else
child->prev->next = row_group;
+
row_group->prev = child->prev;
- while (child != 0 && (
+
+ 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_CELL)) {
box_add_child(row_group, child);
+
next_child = child->next;
- child->next = 0;
+ child->next = NULL;
child = next_child;
}
+
assert(row_group->last != NULL);
- row_group->last->next = 0;
+
+ row_group->last->next = NULL;
row_group->next = next_child = child;
- if (row_group->next)
+ if (row_group->next != NULL)
row_group->next->prev = row_group;
else
table->last = row_group;
row_group->parent = table;
- if (!box_normalise_table_row_group(row_group,
- &col_info, c)) {
+
+ if (box_normalise_table_row_group(row_group,
+ &col_info, c) == false) {
free(col_info.spans);
return false;
}
@@ -282,38 +327,43 @@ bool box_normalise_table(struct box *table, struct content * c)
table->columns = col_info.num_columns;
table->rows = col_info.num_rows;
- free(col_info.spans);
- if (table->children == 0) {
+ if (table->children == NULL) {
struct box *row;
LOG(("table->children == 0, creating implied row"));
assert(table->style != NULL);
- style = talloc_memdup(c, table->style, sizeof *style);
- if (!style) {
+
+ style = nscss_get_blank_style(c, table->style, myrealloc, c);
+ if (style == NULL) {
+ free(col_info.spans);
return false;
}
- css_cascade(style, &css_blank_style, NULL);
+
row_group = box_create(style, table->href,
- table->target, 0, 0, c);
- if (!row_group) {
- talloc_free(style);
+ table->target, NULL, NULL, c);
+ if (row_group == NULL) {
+ css_computed_style_destroy(style);
+ free(col_info.spans);
return false;
}
row_group->type = BOX_TABLE_ROW_GROUP;
- style = talloc_memdup(c, row_group->style, sizeof *style);
- if (!style) {
+ style = nscss_get_blank_style(c, row_group->style,
+ myrealloc, c);
+ if (style == NULL) {
box_free(row_group);
+ free(col_info.spans);
return false;
}
- css_cascade(style, &css_blank_style, NULL);
+
row = box_create(style, row_group->href,
- row_group->target, 0, 0, c);
- if (!row) {
- talloc_free(style);
+ row_group->target, NULL, NULL, c);
+ if (row == NULL) {
+ css_computed_style_destroy(style);
box_free(row_group);
+ free(col_info.spans);
return false;
}
row->type = BOX_TABLE_ROW;
@@ -327,11 +377,15 @@ bool box_normalise_table(struct box *table, struct content * c)
table->rows = 1;
}
- box_normalise_table_spans(table);
- if (!table_calculate_column_types(table))
+ if (box_normalise_table_spans(table, col_info.spans, c) == false) {
+ free(col_info.spans);
+ return false;
+ }
+
+ free(col_info.spans);
+
+ if (table_calculate_column_types(table) == false)
return false;
- if (table->style->border_collapse == CSS_BORDER_COLLAPSE_COLLAPSE)
- table_collapse_borders(table);
LOG(("table %p done", table));
@@ -339,62 +393,141 @@ bool box_normalise_table(struct box *table, struct content * c)
}
-void box_normalise_table_spans(struct box *table)
+/**
+ * Normalise table cell column/row counts for colspan/rowspan = 0.
+ * Additionally, generate empty cells.
+ *
+ * \param table Table to process
+ * \param spans Array of length table->columns for use in empty cell detection
+ * \param c Content containing table
+ * \return True on success, false on memory exhaustion.
+ */
+
+bool box_normalise_table_spans(struct box *table, struct span_info *spans,
+ struct content *c)
{
struct box *table_row_group;
struct box *table_row;
struct box *table_cell;
- unsigned int last_column;
- unsigned int max_extra = 0;
- bool extra;
- bool force = false;
unsigned int rows_left = table->rows;
+ unsigned int col;
+
+ /* Clear span data */
+ memset(spans, 0, table->columns * sizeof(struct span_info));
- /* Scan table filling in table the width and height of table cells for
- cells with colspan = 0 or rowspan = 0. Ignore the colspan and
- rowspan of any cells that that follow an colspan = 0 */
+ /* Scan table, filling in width and height of table cells with
+ * colspan = 0 and rowspan = 0. Also generate empty cells */
for (table_row_group = table->children; table_row_group != NULL;
- table_row_group = table_row_group->next) {
- for (table_row = table_row_group->children; NULL != table_row;
+ table_row_group = table_row_group->next) {
+ for (table_row = table_row_group->children; table_row != NULL;
table_row = table_row->next){
- last_column = 0;
- extra = false;
- for (table_cell = table_row->children; NULL != table_cell;
+ for (table_cell = table_row->children;
+ table_cell != NULL;
table_cell = table_cell->next) {
- /* We hae reached the end of the row, and have passed
- a cell with colspan = 0 so ignore col and row spans */
- if (force || extra || (table_cell->start_column + 1 <=
- last_column)) {
- extra = true;
+ /* colspan = 0 -> colspan = 1 */
+ if (table_cell->columns == 0)
table_cell->columns = 1;
- table_cell->rows = 1;
- if (table_cell->start_column <= max_extra) {
- max_extra = table_cell->start_column + 1;
+
+ /* rowspan = 0 -> rowspan = rows_left */
+ if (table_cell->rows == 0)
+ table_cell->rows = rows_left;
+
+ /* Record span information */
+ for (col = table_cell->start_column;
+ col < table_cell->start_column +
+ table_cell->columns; col++) {
+ spans[col].row_span = table_cell->rows;
+ }
+ }
+
+ /* Reduce span count of each column */
+ for (col = 0; col < table->columns; col++) {
+ if (spans[col].row_span == 0) {
+ unsigned int start = col;
+ css_computed_style *style;
+ struct box *cell, *prev;
+
+ /* If it's already zero, then we need
+ * to generate an empty cell for the
+ * gap in the row that spans as many
+ * columns as remain blank.
+ */
+ assert(table_row->style != NULL);
+
+ /* Find width of gap */
+ while (col < table->columns &&
+ spans[col].row_span ==
+ 0) {
+ col++;
}
- table_cell->start_column += table->columns;
- } else {
- /* Fill out the number of columns or the number of rows
- if necessary */
- if (0 == table_cell->columns) {
- table_cell->columns = table->columns -
- table_cell->start_column;
- if ((0 == table_cell->start_column) &&
- (0 == table_cell->rows)) {
- force = true;
- }
+
+ style = nscss_get_blank_style(c,
+ table_row->style,
+ myrealloc, c);
+ if (style == NULL)
+ return false;
+
+ cell = box_create(style,
+ table_row->href,
+ table_row->target,
+ NULL, NULL, c);
+ if (cell == NULL) {
+ css_computed_style_destroy(
+ style);
+ return false;
}
- assert(0 != table_cell->columns);
- if (0 == table_cell->rows) {
- table_cell->rows = rows_left;
+ cell->type = BOX_TABLE_CELL;
+
+ cell->rows = 1;
+ cell->columns = col - start;
+ cell->start_column = start;
+
+ /* Find place to insert cell */
+ for (prev = table_row->children;
+ prev != NULL;
+ prev = prev->next) {
+ if (prev->start_column +
+ prev->columns ==
+ start)
+ break;
+ if (prev->next == NULL)
+ break;
}
- assert(0 != table_cell->rows);
- last_column = table_cell->start_column + 1;
+
+ /* Insert it */
+ if (prev == NULL) {
+ if (table_row->children != NULL)
+ table_row->children->
+ prev = cell;
+ else
+ table_row->last = cell;
+
+ cell->next =
+ table_row->children;
+ table_row->children = cell;
+ } else {
+ if (prev->next != NULL)
+ prev->next->prev = cell;
+ else
+ table_row->last = cell;
+
+ cell->next = prev->next;
+ prev->next = cell;
+ cell->prev = prev;
+ }
+ cell->parent = table_row;
+ } else {
+ spans[col].row_span--;
}
}
+
+ assert(rows_left > 0);
+
rows_left--;
}
}
- table->columns += max_extra;
+
+ return true;
}
@@ -405,19 +538,21 @@ bool box_normalise_table_row_group(struct box *row_group,
struct box *child;
struct box *next_child;
struct box *row;
- struct css_style *style;
+ css_computed_style *style;
assert(row_group != 0);
assert(row_group->type == BOX_TABLE_ROW_GROUP);
+
LOG(("row_group %p", row_group));
- for (child = row_group->children; child != 0; child = next_child) {
+ for (child = row_group->children; child != NULL; child = next_child) {
next_child = child->next;
+
switch (child->type) {
case BOX_TABLE_ROW:
/* ok */
- if (!box_normalise_table_row(child, col_info,
- c))
+ if (box_normalise_table_row(child, col_info,
+ c) == false)
return false;
break;
case BOX_BLOCK:
@@ -427,44 +562,52 @@ bool box_normalise_table_row_group(struct box *row_group,
case BOX_TABLE_CELL:
/* insert implied table row */
assert(row_group->style != NULL);
- style = talloc_memdup(c, row_group->style,
- sizeof *style);
- if (!style)
+
+ style = nscss_get_blank_style(c, row_group->style,
+ myrealloc, c);
+ if (style == NULL)
return false;
- css_cascade(style, &css_blank_style, NULL);
+
row = box_create(style, row_group->href,
- row_group->target, 0, 0, c);
- if (!row) {
- talloc_free(style);
+ row_group->target, NULL, NULL, c);
+ if (row == NULL) {
+ css_computed_style_destroy(style);
return false;
}
row->type = BOX_TABLE_ROW;
- if (child->prev == 0)
+
+ if (child->prev == NULL)
row_group->children = row;
else
child->prev->next = row;
+
row->prev = child->prev;
- while (child != 0 && (
+
+ 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_CELL)) {
box_add_child(row, child);
+
next_child = child->next;
- child->next = 0;
+ child->next = NULL;
child = next_child;
}
+
assert(row->last != NULL);
- row->last->next = 0;
+
+ row->last->next = NULL;
row->next = next_child = child;
- if (row->next)
+ if (row->next != NULL)
row->next->prev = row;
else
row_group->last = row;
row->parent = row_group;
- if (!box_normalise_table_row(row, col_info,
- c))
+
+ if (box_normalise_table_row(row, col_info,
+ c) == false)
return false;
break;
case BOX_INLINE:
@@ -483,24 +626,30 @@ bool box_normalise_table_row_group(struct box *row_group,
}
}
- if (row_group->children == 0) {
+ if (row_group->children == NULL) {
LOG(("row_group->children == 0, inserting implied row"));
+
assert(row_group->style != NULL);
- style = talloc_memdup(c, row_group->style, sizeof *style);
- if (!style) {
+
+ style = nscss_get_blank_style(c, row_group->style,
+ myrealloc, c);
+ if (style == NULL) {
return false;
}
- css_cascade(style, &css_blank_style, NULL);
+
row = box_create(style, row_group->href,
- row_group->target, 0, 0, c);
- if (!row) {
- talloc_free(style);
+ row_group->target, NULL, NULL, c);
+ if (row == NULL) {
+ css_computed_style_destroy(style);
return false;
}
row->type = BOX_TABLE_ROW;
row->parent = row_group;
row_group->children = row_group->last = row;
+
+ /* Keep table's row count in sync */
+ col_info->num_rows++;
}
LOG(("row_group %p done", row_group));
@@ -516,19 +665,20 @@ bool box_normalise_table_row(struct box *row,
struct box *child;
struct box *next_child;
struct box *cell = NULL;
- struct css_style *style;
+ css_computed_style *style;
unsigned int i;
- assert(row != 0);
+ assert(row != NULL);
assert(row->type == BOX_TABLE_ROW);
LOG(("row %p", row));
- for (child = row->children; child != 0; child = next_child) {
+ 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, c))
+ if (box_normalise_block(child, c) == false)
return false;
cell = child;
break;
@@ -539,46 +689,51 @@ bool box_normalise_table_row(struct box *row,
case BOX_TABLE_ROW:
/* insert implied table cell */
assert(row->style != NULL);
- style = talloc_memdup(c, row->style, sizeof *style);
- if (!style)
+
+ style = nscss_get_blank_style(c, row->style,
+ myrealloc, c);
+ if (style == NULL)
return false;
- css_cascade(style, &css_blank_style, NULL);
- if (child->style && (child->style->position ==
- CSS_POSITION_ABSOLUTE ||
- child->style->position ==
- CSS_POSITION_FIXED)) {
- style->position = child->style->position;
- }
- cell = box_create(style, row->href, row->target, 0, 0,
- c);
- if (!cell) {
- talloc_free(style);
+
+ cell = box_create(style, row->href, row->target,
+ NULL, NULL, c);
+ if (cell == NULL) {
+ css_computed_style_destroy(style);
return false;
}
cell->type = BOX_TABLE_CELL;
- if (child->prev == 0)
+
+ if (child->prev == NULL)
row->children = cell;
else
child->prev->next = cell;
+
cell->prev = child->prev;
- while (child != 0 && (
+
+ 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 = 0;
+ child->next = NULL;
child = next_child;
}
+
assert(cell->last != NULL);
- cell->last->next = 0;
+
+ cell->last->next = NULL;
cell->next = next_child = child;
- if (cell->next)
+ if (cell->next != NULL)
cell->next->prev = cell;
+ else
+ row->last = cell;
cell->parent = row;
- if (!box_normalise_block(cell, c))
+
+ if (box_normalise_block(cell, c) == false)
return false;
break;
case BOX_INLINE:
@@ -596,42 +751,27 @@ bool box_normalise_table_row(struct box *row,
assert(0);
}
- if (!calculate_table_row(col_info, cell->columns, cell->rows,
- &cell->start_column))
+ if (calculate_table_row(col_info, cell->columns, cell->rows,
+ &cell->start_column) == 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)) {
+ 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 ((col_info->spans[i].auto_column) && (0 == col_info->spans[i].row_span)) {
- col_info->spans[i].auto_column = false;
- }
}
}
+
+ /* Reset current column for next row */
col_info->current_column = 0;
- col_info->extra = false;
-
- /* Removing empty rows causes ill effects for HTML such as:
- *
- * <tr><td colspan="2">1</td></tr><tr></tr><tr><td>2</td></tr>
- *
- * as it breaks the colspan value. Additionally, both MSIE and FF
- * render in the same manner as NetSurf does with the empty row
- * culling commented out.
- */
-// if (row->children == 0) {
-// LOG(("row->children == 0, removing"));
-// if (row->prev == 0)
-// row->parent->children = row->next;
-// else
-// row->prev->next = row->next;
-// if (row->next != 0)
-// row->next->prev = row->prev;
-// box_free(row);
-// } else {
- col_info->num_rows++;
-// }
+
+ /* Increment row counter */
+ col_info->num_rows++;
LOG(("row %p done", row));
@@ -640,6 +780,13 @@ bool box_normalise_table_row(struct box *row,
/**
+ * 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
* \return true on success, false on memory exhaustion
*/
@@ -647,70 +794,55 @@ bool calculate_table_row(struct columns *col_info,
unsigned int col_span, unsigned int row_span,
unsigned int *start_column)
{
- unsigned int cell_start_col;
+ unsigned int cell_start_col = col_info->current_column;
unsigned int cell_end_col;
unsigned int i;
struct span_info *spans;
- if (!col_info->extra) {
- /* skip columns with cells spanning from above */
- while ((col_info->spans[col_info->current_column].row_span != 0) &&
- (!col_info->spans[col_info->current_column].auto_column)) {
- col_info->current_column++;
- }
- if (col_info->spans[col_info->current_column].auto_column) {
- col_info->extra = true;
- col_info->current_column = 0;
- }
- }
+ /* Skip columns with cells spanning from above */
+ while (col_info->spans[cell_start_col].row_span != 0)
+ 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;
- cell_start_col = col_info->current_column;
-
- /* If the current table cell follows a cell with colspan=0,
- ignore both colspan and rowspan just assume it is a standard
- size cell */
- if (col_info->extra) {
- col_info->current_column++;
- col_info->extra_columns = col_info->current_column;
- } else {
- /* If span to end of table, assume spaning single column
- at the moment */
- cell_end_col = cell_start_col + ((0 == col_span) ? 1 : col_span);
-
- if (col_info->num_columns < cell_end_col) {
- spans = realloc(col_info->spans,
- sizeof *spans * (cell_end_col + 1));
- if (!spans)
- return false;
- col_info->spans = spans;
- col_info->num_columns = cell_end_col;
-
- /* Mark new final column as sentinal */
- col_info->spans[cell_end_col].row_span = 0;
- col_info->spans[cell_end_col].auto_row =
- col_info->spans[cell_end_col].auto_column =
- false;
- }
+ col_info->spans = spans;
+ col_info->num_columns = cell_end_col;
- if (0 == col_span) {
- col_info->spans[cell_start_col].auto_column = true;
- col_info->spans[cell_start_col].row_span = row_span;
- col_info->spans[cell_start_col].auto_row = (0 == row_span);
- } else {
- for (i = cell_start_col; i < cell_end_col; i++) {
- col_info->spans[i].row_span = (0 == row_span) ?
- 1 : row_span;
- col_info->spans[i].auto_row = (0 == row_span);
- col_info->spans[i].auto_column = false;
- }
- }
- if (0 == col_span) {
- col_info->spans[cell_end_col].auto_column = true;
- }
- col_info->current_column = 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);
}
+ /* Update current column with calculated end. */
+ col_info->current_column = cell_end_col;
+
*start_column = cell_start_col;
+
return true;
}
@@ -720,11 +852,11 @@ bool box_normalise_inline_container(struct box *cont, struct content * c)
struct box *child;
struct box *next_child;
- assert(cont != 0);
+ assert(cont != NULL);
assert(cont->type == BOX_INLINE_CONTAINER);
LOG(("cont %p", cont));
- for (child = cont->children; child != 0; child = next_child) {
+ for (child = cont->children; child != NULL; child = next_child) {
next_child = child->next;
switch (child->type) {
case BOX_INLINE:
@@ -735,37 +867,40 @@ bool box_normalise_inline_container(struct box *cont, struct content * c)
break;
case BOX_INLINE_BLOCK:
/* ok */
- if (!box_normalise_block(child, c))
+ if (box_normalise_block(child, c) == false)
return false;
break;
case BOX_FLOAT_LEFT:
case BOX_FLOAT_RIGHT:
/* ok */
- assert(child->children != 0);
+ assert(child->children != NULL);
+
switch (child->children->type) {
case BOX_BLOCK:
- if (!box_normalise_block(
- child->children,
- c))
+ if (box_normalise_block(child->children,
+ c) == false)
return false;
break;
case BOX_TABLE:
- if (!box_normalise_table(
- child->children,
- c))
+ if (box_normalise_table(child->children,
+ c) == false)
return false;
break;
default:
assert(0);
}
- if (child->children == 0) {
+
+ if (child->children == NULL) {
/* the child has destroyed itself: remove float */
- if (child->prev == 0)
+ if (child->prev == NULL)
child->parent->children = child->next;
else
child->prev->next = child->next;
- if (child->next != 0)
+ if (child->next != NULL)
child->next->prev = child->prev;
+ else
+ child->parent->last = child->prev;
+
box_free(child);
}
break;
diff --git a/render/directory.c b/render/directory.c
index 2c4a70dbd..82f24efa2 100644
--- a/render/directory.c
+++ b/render/directory.c
@@ -40,8 +40,9 @@ static const char header[] = "<html>\n<head>\n<title>\n";
static const char footer[] = "</pre>\n</body>\n</html>\n";
-bool directory_create(struct content *c, const char *params[]) {
- if (!html_create(c, params))
+bool directory_create(struct content *c, struct content *parent,
+ const char *params[]) {
+ if (!html_create(c, parent, params))
/* html_create() must have broadcast MSG_ERROR already, so we
* don't need to. */
return false;
diff --git a/render/directory.h b/render/directory.h
index 259f51b88..a54d516fb 100644
--- a/render/directory.h
+++ b/render/directory.h
@@ -29,7 +29,8 @@
#include "content/content_type.h"
-bool directory_create(struct content *c, const char *params[]);
+bool directory_create(struct content *c, struct content *parent,
+ const char *params[]);
bool directory_convert(struct content *c, int width, int height);
void directory_destroy(struct content *c);
diff --git a/render/font.c b/render/font.c
index 11135d959..4577ff373 100644
--- a/render/font.c
+++ b/render/font.c
@@ -17,13 +17,15 @@
*/
#include "css/css.h"
+#include "css/utils.h"
+#include "desktop/options.h"
#include "render/font.h"
static plot_font_generic_family_t plot_font_generic_family(
- css_font_family css);
-static int plot_font_weight(css_font_weight css);
-static plot_font_flags_t plot_font_flags(css_font_style style,
- css_font_variant variant);
+ enum css_font_family css);
+static int plot_font_weight(enum css_font_weight css);
+static plot_font_flags_t plot_font_flags(enum css_font_style style,
+ enum css_font_variant variant);
/**
* Populate a font style using data from a computed CSS style
@@ -31,15 +33,31 @@ static plot_font_flags_t plot_font_flags(css_font_style style,
* \param css Computed style to consider
* \param fstyle Font style to populate
*/
-void font_plot_style_from_css(const struct css_style *css,
+void font_plot_style_from_css(const css_computed_style *css,
plot_font_style_t *fstyle)
{
- fstyle->family = plot_font_generic_family(css->font_family);
- fstyle->size =
- css_len2pt(&css->font_size.value.length, css) * FONT_SIZE_SCALE;
- fstyle->weight = plot_font_weight(css->font_weight);
- fstyle->flags = plot_font_flags(css->font_style, css->font_variant);
- fstyle->foreground = css->color;
+ lwc_string **families;
+ css_fixed length = 0;
+ css_unit unit = CSS_UNIT_PX;
+ css_color col;
+
+ fstyle->family = plot_font_generic_family(
+ css_computed_font_family(css, &families));
+
+ css_computed_font_size(css, &length, &unit);
+ fstyle->size = FIXTOINT(FMULI(nscss_len2pt(length, unit),
+ FONT_SIZE_SCALE));
+
+ /* Clamp font size to configured minimum */
+ if (fstyle->size < (option_font_min_size * FONT_SIZE_SCALE) / 10)
+ fstyle->size = (option_font_min_size * FONT_SIZE_SCALE) / 10;
+
+ fstyle->weight = plot_font_weight(css_computed_font_weight(css));
+ fstyle->flags = plot_font_flags(css_computed_font_style(css),
+ css_computed_font_variant(css));
+
+ css_computed_color(css, &col);
+ fstyle->foreground = nscss_color_to_ns(col);
fstyle->background = 0;
}
@@ -54,7 +72,7 @@ void font_plot_style_from_css(const struct css_style *css,
* \return Plot font family
*/
plot_font_generic_family_t plot_font_generic_family(
- css_font_family css)
+ enum css_font_family css)
{
plot_font_generic_family_t plot;
@@ -86,7 +104,7 @@ plot_font_generic_family_t plot_font_generic_family(
* \param css CSS font weight
* \return Plot weight
*/
-int plot_font_weight(css_font_weight css)
+int plot_font_weight(enum css_font_weight css)
{
int weight;
@@ -133,8 +151,8 @@ int plot_font_weight(css_font_weight css)
* \param variant CSS font variant
* \return Computed plot flags
*/
-plot_font_flags_t plot_font_flags(css_font_style style,
- css_font_variant variant)
+plot_font_flags_t plot_font_flags(enum css_font_style style,
+ enum css_font_variant variant)
{
plot_font_flags_t flags = FONTF_NONE;
diff --git a/render/font.h b/render/font.h
index 9a80af329..3012abce0 100644
--- a/render/font.h
+++ b/render/font.h
@@ -53,7 +53,7 @@ struct font_functions
extern const struct font_functions nsfont;
-void font_plot_style_from_css(const struct css_style *css,
+void font_plot_style_from_css(const css_computed_style *css,
plot_font_style_t *fstyle);
#endif
diff --git a/render/html.c b/render/html.c
index 1905e8bc3..bad7ff2e2 100644
--- a/render/html.c
+++ b/render/html.c
@@ -61,7 +61,8 @@ static void html_convert_css_callback(content_msg msg, struct content *css,
static bool html_meta_refresh(struct content *c, xmlNode *head);
static bool html_head(struct content *c, xmlNode *head);
static bool html_find_stylesheets(struct content *c, xmlNode *html);
-static bool html_process_style_element(struct content *c, xmlNode *style);
+static bool html_process_style_element(struct content *c, unsigned int index,
+ xmlNode *style);
static void html_object_callback(content_msg msg, struct content *object,
intptr_t p1, intptr_t p2, union content_msg_data data);
static void html_object_done(struct box *box, struct content *object,
@@ -92,6 +93,18 @@ static const char empty_document[] =
"</body>"
"</html>";
+/**
+ * Allocator
+ *
+ * \param ptr Pointer to reallocate, or NULL for new allocation
+ * \param size Number of bytes requires
+ * \param pw Allocation context
+ * \return Pointer to allocated block, or NULL on failure
+ */
+static void *myrealloc(void *ptr, size_t len, void *pw)
+{
+ return realloc(ptr, len);
+}
/**
* Create a CONTENT_HTML.
@@ -100,15 +113,19 @@ static const char empty_document[] =
* created.
*/
-bool html_create(struct content *c, const char *params[])
+bool html_create(struct content *c, struct content *parent,
+ const char *params[])
{
unsigned int i;
struct content_html_data *html = &c->data.html;
union content_msg_data msg_data;
binding_error error;
+ lwc_context *dict;
+ lwc_error lerror;
html->parser_binding = NULL;
html->document = 0;
+ html->quirks = BINDING_QUIRKS_MODE_NONE;
html->encoding = 0;
html->base_url = c->url;
html->base_target = NULL;
@@ -116,8 +133,7 @@ bool html_create(struct content *c, const char *params[])
html->background_colour = NS_TRANSPARENT;
html->stylesheet_count = 0;
html->stylesheet_content = 0;
- html->style = 0;
- html->working_stylesheet = 0;
+ html->select_ctx = NULL;
html->object_count = 0;
html->object = 0;
html->forms = 0;
@@ -130,6 +146,14 @@ bool html_create(struct content *c, const char *params[])
html->box = 0;
html->font_func = &nsfont;
+ lerror = lwc_create_context(myrealloc, c, &dict);
+ if (lerror != lwc_error_ok) {
+ error = BINDING_NOMEM;
+ goto error;
+ }
+
+ html->dict = lwc_context_ref(dict);
+
for (i = 0; params[i]; i += 2) {
if (strcasecmp(params[i], "charset") == 0) {
html->encoding = talloc_strdup(c, params[i + 1]);
@@ -343,7 +367,8 @@ bool html_convert(struct content *c, int width, int height)
}
c->data.html.document =
- binding_get_document(c->data.html.parser_binding);
+ binding_get_document(c->data.html.parser_binding,
+ &c->data.html.quirks);
/*xmlDebugDumpDocument(stderr, c->data.html.document);*/
if (!c->data.html.document) {
@@ -467,7 +492,7 @@ bool html_convert(struct content *c, int width, int height)
option_min_reflow_period : time_taken * 1.25));
LOG(("Scheduling relayout no sooner than %dcs",
c->reformat_time - wallclock()));
- /*box_dump(c->data.html.layout->children, 0);*/
+ /*box_dump(stderr, c->data.html.layout->children, 0);*/
/* Destroy the parser binding */
binding_destroy_tree(c->data.html.parser_binding);
@@ -778,16 +803,17 @@ bool html_find_stylesheets(struct content *c, xmlNode *html)
union content_msg_data msg_data;
url_func_result res;
struct content **stylesheet_content;
+ css_error error;
/* stylesheet 0 is the base style sheet,
- * stylesheet 1 is the adblocking stylesheet,
- * stylesheet 2 is any <style> elements */
+ * stylesheet 1 is the quirks mode style sheet,
+ * stylesheet 2 is the adblocking stylesheet */
c->data.html.stylesheet_content = talloc_array(c, struct content *,
STYLESHEET_START);
if (!c->data.html.stylesheet_content)
goto no_memory;
- c->data.html.stylesheet_content[STYLESHEET_ADBLOCK] = 0;
- c->data.html.stylesheet_content[STYLESHEET_STYLE] = 0;
+ c->data.html.stylesheet_content[STYLESHEET_QUIRKS] = NULL;
+ c->data.html.stylesheet_content[STYLESHEET_ADBLOCK] = NULL;
c->data.html.stylesheet_count = STYLESHEET_START;
c->active = 0;
@@ -805,6 +831,22 @@ bool html_find_stylesheets(struct content *c, xmlNode *html)
STYLESHEET_BASE, c->width, c->height,
0, 0, false, c);
+ if (c->data.html.quirks == BINDING_QUIRKS_MODE_FULL) {
+ c->data.html.stylesheet_content[STYLESHEET_QUIRKS] =
+ fetchcache(quirks_stylesheet_url,
+ html_convert_css_callback, (intptr_t) c,
+ STYLESHEET_QUIRKS, c->width, c->height,
+ true, 0, 0, false, false);
+ if (c->data.html.stylesheet_content[STYLESHEET_QUIRKS] == NULL)
+ goto no_memory;
+ c->active++;
+ fetchcache_go(c->data.html.
+ stylesheet_content[STYLESHEET_QUIRKS],
+ c->url, html_convert_css_callback,
+ (intptr_t) c, STYLESHEET_QUIRKS, c->width,
+ c->height, 0, 0, false, c);
+ }
+
if (option_block_ads) {
c->data.html.stylesheet_content[STYLESHEET_ADBLOCK] =
fetchcache(adblock_stylesheet_url,
@@ -931,31 +973,14 @@ bool html_find_stylesheets(struct content *c, xmlNode *html)
i++;
} else if (strcmp((const char *) node->name, "style") == 0) {
- if (!html_process_style_element(c, node))
+ if (!html_process_style_element(c, i, node))
return false;
+ i++;
}
}
c->data.html.stylesheet_count = i;
- if (c->data.html.stylesheet_content[STYLESHEET_STYLE] != 0) {
- if (css_convert(c->data.html.
- stylesheet_content[STYLESHEET_STYLE], c->width,
- c->height)) {
- if (!content_add_user(c->data.html.
- stylesheet_content[STYLESHEET_STYLE],
- html_convert_css_callback,
- (intptr_t) c, STYLESHEET_STYLE)) {
- /* no memory */
- c->data.html.stylesheet_content[STYLESHEET_STYLE] = 0;
- goto no_memory;
- }
- } else {
- /* conversion failed */
- c->data.html.stylesheet_content[STYLESHEET_STYLE] = 0;
- }
- }
-
/* complete the fetches */
while (c->active != 0) {
if (c->active != last_active) {
@@ -974,29 +999,23 @@ bool html_find_stylesheets(struct content *c, xmlNode *html)
return false;
}
- assert(c->data.html.stylesheet_content[STYLESHEET_BASE]);
- css_set_origin(c->data.html.stylesheet_content[STYLESHEET_BASE],
- CSS_ORIGIN_UA);
-
- /* any of our other stylesheet pointers could be NULL at this point if
- * the CSS file(s) failed to load/fetch */
- if (c->data.html.stylesheet_content[STYLESHEET_ADBLOCK])
- css_set_origin(c->data.html.stylesheet_content[
- STYLESHEET_ADBLOCK], CSS_ORIGIN_UA);
- if (c->data.html.stylesheet_content[STYLESHEET_STYLE])
- css_set_origin(c->data.html.stylesheet_content[
- STYLESHEET_STYLE], CSS_ORIGIN_AUTHOR);
- for (i = STYLESHEET_START; i != c->data.html.stylesheet_count; i++)
- if (c->data.html.stylesheet_content[i])
- css_set_origin(c->data.html.stylesheet_content[i],
- CSS_ORIGIN_AUTHOR);
-
- c->data.html.working_stylesheet = css_make_working_stylesheet(
- c->data.html.stylesheet_content,
- c->data.html.stylesheet_count);
- if (!c->data.html.working_stylesheet)
+ /* Create selection context */
+ error = css_select_ctx_create(myrealloc, c, &c->data.html.select_ctx);
+ if (error != CSS_OK)
goto no_memory;
+ /* Add sheets to it */
+ for (i = STYLESHEET_BASE; i != c->data.html.stylesheet_count; i++) {
+ if (c->data.html.stylesheet_content[i]) {
+ error = css_select_ctx_append_sheet(
+ c->data.html.select_ctx,
+ c->data.html.stylesheet_content[i]->
+ data.css.sheet);
+ if (error != CSS_OK)
+ goto no_memory;
+ }
+ }
+
return true;
no_memory:
@@ -1010,15 +1029,19 @@ no_memory:
* Process an inline stylesheet in the document.
*
* \param c content structure
+ * \param index Index of stylesheet in stylesheet_content array
* \param style xml node of style element
* \return true on success, false if an error occurred
*/
-bool html_process_style_element(struct content *c, xmlNode *style)
+bool html_process_style_element(struct content *c, unsigned int index,
+ xmlNode *style)
{
xmlNode *child;
char *type, *media, *data;
union content_msg_data msg_data;
+ struct content **stylesheet_content;
+ const char *params[] = { 0 };
/* type='text/css', or not present (invalid but common) */
if ((type = (char *) xmlGetProp(style, (const xmlChar *) "type"))) {
@@ -1039,20 +1062,24 @@ bool html_process_style_element(struct content *c, xmlNode *style)
xmlFree(media);
}
+ /* Extend array */
+ stylesheet_content = talloc_realloc(c, c->data.html.stylesheet_content,
+ struct content *, index + 1);
+ if (stylesheet_content == NULL)
+ goto no_memory;
+
+ c->data.html.stylesheet_content = stylesheet_content;
+
/* create stylesheet */
- if (c->data.html.stylesheet_content[STYLESHEET_STYLE] == 0) {
- const char *params[] = { 0 };
- c->data.html.stylesheet_content[STYLESHEET_STYLE] =
- content_create(c->data.html.base_url);
- if (!c->data.html.stylesheet_content[STYLESHEET_STYLE])
- goto no_memory;
- if (!content_set_type(c->data.html.
- stylesheet_content[STYLESHEET_STYLE],
- CONTENT_CSS, "text/css", params))
- /** \todo not necessarily caused by
- * memory exhaustion */
- goto no_memory;
- }
+ c->data.html.stylesheet_content[index] =
+ content_create(c->data.html.base_url);
+ if (c->data.html.stylesheet_content[index] == NULL)
+ goto no_memory;
+ if (!content_set_type(c->data.html.stylesheet_content[index],
+ CONTENT_CSS, "text/css", params, c))
+ /** \todo not necessarily caused by
+ * memory exhaustion */
+ goto no_memory;
/* can't just use xmlNodeGetContent(style), because that won't
* give the content of comments which may be used to 'hide'
@@ -1060,7 +1087,7 @@ bool html_process_style_element(struct content *c, xmlNode *style)
for (child = style->children; child != 0; child = child->next) {
data = (char *) xmlNodeGetContent(child);
if (!content_process_data(c->data.html.
- stylesheet_content[STYLESHEET_STYLE],
+ stylesheet_content[index],
data, strlen(data))) {
xmlFree(data);
/** \todo not necessarily caused by
@@ -1070,6 +1097,21 @@ bool html_process_style_element(struct content *c, xmlNode *style)
xmlFree(data);
}
+ /* Convert the content */
+ if (nscss_convert(c->data.html.stylesheet_content[index], c->width,
+ c->height)) {
+ if (!content_add_user(c->data.html.stylesheet_content[index],
+ html_convert_css_callback,
+ (intptr_t) c, index)) {
+ /* no memory */
+ c->data.html.stylesheet_content[index] = NULL;
+ goto no_memory;
+ }
+ } else {
+ /* conversion failed */
+ c->data.html.stylesheet_content[index] = NULL;
+ }
+
return true;
no_memory:
@@ -1181,7 +1223,7 @@ void html_convert_css_callback(content_msg msg, struct content *css,
* \return true on success, false on memory exhaustion
*/
-bool html_fetch_object(struct content *c, char *url, struct box *box,
+bool html_fetch_object(struct content *c, const char *url, struct box *box,
const content_type *permitted_types,
int available_width, int available_height,
bool background)
@@ -1693,10 +1735,10 @@ void html_reformat(struct content *c, int width, int height)
/* width and height are at least margin box of document */
c->width = layout->x + layout->padding[LEFT] + layout->width +
- layout->padding[RIGHT] + layout->border[RIGHT] +
+ layout->padding[RIGHT] + layout->border[RIGHT].width +
layout->margin[RIGHT];
c->height = layout->y + layout->padding[TOP] + layout->height +
- layout->padding[BOTTOM] + layout->border[BOTTOM] +
+ layout->padding[BOTTOM] + layout->border[BOTTOM].width +
layout->margin[BOTTOM];
/* if boxes overflow right or bottom edge, expand to contain it */
@@ -1757,6 +1799,12 @@ void html_destroy(struct content *c)
c->data.html.iframe = NULL;
}
+ /* Destroy selection context */
+ if (c->data.html.select_ctx) {
+ css_select_ctx_destroy(c->data.html.select_ctx);
+ c->data.html.select_ctx = NULL;
+ }
+
/* Free stylesheets */
if (c->data.html.stylesheet_count) {
for (i = 0; i != c->data.html.stylesheet_count; i++) {
@@ -1768,11 +1816,6 @@ void html_destroy(struct content *c)
}
}
- talloc_free(c->data.html.working_stylesheet);
-
- /*if (c->data.html.style)
- css_free_style(c->data.html.style);*/
-
/* Free objects */
for (i = 0; i != c->data.html.object_count; i++) {
LOG(("object %i %p", i, c->data.html.object[i].content));
@@ -1784,6 +1827,8 @@ void html_destroy(struct content *c)
c->data.html.object[i].content);
}
}
+
+ lwc_context_unref(c->data.html.dict);
}
void html_destroy_frameset(struct content_html_frames *frameset) {
diff --git a/render/html.h b/render/html.h
index e6c322e14..b41406659 100644
--- a/render/html.h
+++ b/render/html.h
@@ -42,12 +42,13 @@ struct plotters;
/* entries in stylesheet_content */
#define STYLESHEET_BASE 0 /* base style sheet */
-#define STYLESHEET_ADBLOCK 1 /* adblocking stylesheet */
-#define STYLESHEET_STYLE 2 /* <style> elements (not cached) */
+#define STYLESHEET_QUIRKS 1 /* quirks mode stylesheet */
+#define STYLESHEET_ADBLOCK 2 /* adblocking stylesheet */
#define STYLESHEET_START 3 /* start of document stylesheets */
extern char *default_stylesheet_url;
extern char *adblock_stylesheet_url;
+extern char *quirks_stylesheet_url;
struct frame_dimension {
float value;
@@ -117,6 +118,9 @@ struct content_html_iframe {
struct content_html_data {
void *parser_binding;
xmlDoc *document;
+ binding_quirks_mode quirks; /**< Quirkyness of document */
+
+ lwc_context *dict; /**< Internment context for this document */
char *encoding; /**< Encoding of source, 0 if unknown. */
binding_encoding_source encoding_source;
@@ -133,9 +137,8 @@ struct content_html_data {
unsigned int stylesheet_count;
/** Stylesheets. Each may be 0. */
struct content **stylesheet_content;
- struct css_style *style; /**< Base style. */
- /** Working stylesheet. */
- struct css_working_stylesheet *working_stylesheet;
+ /**< Style selection context */
+ css_select_ctx *select_ctx;
/** Number of entries in object. */
unsigned int object_count;
@@ -168,12 +171,13 @@ struct content_html_data {
extern bool html_redraw_debug;
-bool html_create(struct content *c, const char *params[]);
+bool html_create(struct content *c, struct content *parent,
+ const char *params[]);
bool html_process_data(struct content *c, char *data, unsigned int size);
bool html_convert(struct content *c, int width, int height);
void html_reformat(struct content *c, int width, int height);
void html_destroy(struct content *c);
-bool html_fetch_object(struct content *c, char *url, struct box *box,
+bool html_fetch_object(struct content *c, const char *url, struct box *box,
const content_type *permitted_types,
int available_width, int available_height,
bool background);
diff --git a/render/html_redraw.c b/render/html_redraw.c
index 309b81332..735c241a3 100644
--- a/render/html_redraw.c
+++ b/render/html_redraw.c
@@ -32,6 +32,7 @@
#include "utils/config.h"
#include "content/content.h"
#include "css/css.h"
+#include "css/utils.h"
#include "desktop/gui.h"
#include "desktop/plotters.h"
#include "desktop/knockout.h"
@@ -67,7 +68,7 @@ static bool html_redraw_borders(struct box *box, int x_parent, int y_parent,
bool html_redraw_inline_borders(struct box *box, int x0, int y0, int x1, int y1,
float scale, bool first, bool last);
static bool html_redraw_border_plot(int i, int *p, colour c,
- css_border_style style, int thickness);
+ enum css_border_style style, int thickness);
static bool html_redraw_checkbox(int x, int y, int width, int height,
bool selected);
static bool html_redraw_radio(int x, int y, int width, int height,
@@ -193,6 +194,7 @@ bool html_redraw_box(struct box *box,
int x0, y0, x1, y1;
int x_scrolled, y_scrolled;
struct box *bg_box = NULL;
+ css_color bgcol = 0;
if (html_redraw_printing && box->printed)
return true;
@@ -208,10 +210,10 @@ bool html_redraw_box(struct box *box,
padding_width = padding_left + box->width + box->padding[RIGHT];
padding_height = padding_top + box->height +
box->padding[BOTTOM];
- border_left = box->border[LEFT];
- border_top = box->border[TOP];
- border_right = box->border[RIGHT];
- border_bottom = box->border[BOTTOM];
+ border_left = box->border[LEFT].width;
+ border_top = box->border[TOP].width;
+ border_right = box->border[RIGHT].width;
+ border_bottom = box->border[BOTTOM].width;
} else {
x = (x_parent + box->x) * scale;
y = (y_parent + box->y) * scale;
@@ -227,14 +229,15 @@ bool html_redraw_box(struct box *box,
box->padding[RIGHT]) * scale;
padding_height = (box->padding[TOP] + box->height +
box->padding[BOTTOM]) * scale;
- border_left = box->border[LEFT] * scale;
- border_top = box->border[TOP] * scale;
- border_right = box->border[RIGHT] * scale;
- border_bottom = box->border[BOTTOM] * scale;
+ border_left = box->border[LEFT].width * scale;
+ border_top = box->border[TOP].width * scale;
+ border_right = box->border[RIGHT].width * scale;
+ border_bottom = box->border[BOTTOM].width * scale;
}
/* calculate rectangle covering this box and descendants */
- if (box->style && box->style->overflow != CSS_OVERFLOW_VISIBLE) {
+ if (box->style && css_computed_overflow(box->style) !=
+ CSS_OVERFLOW_VISIBLE) {
x0 = x - border_left;
y0 = y - border_top;
x1 = x + padding_width + border_right;
@@ -296,7 +299,8 @@ bool html_redraw_box(struct box *box,
}
/* if visibility is hidden render children only */
- if (box->style && box->style->visibility == CSS_VISIBILITY_HIDDEN) {
+ if (box->style && css_computed_visibility(box->style) ==
+ CSS_VISIBILITY_HIDDEN) {
if ((plot.group_start) && (!plot.group_start("hidden box")))
return false;
if (!html_redraw_box_children(box, x_parent, y_parent,
@@ -346,20 +350,21 @@ bool html_redraw_box(struct box *box,
*/
if (!box->parent) {
/* Root box */
- if (box->style &&
- (box->style->background_color !=
- NS_TRANSPARENT ||
+ if (box->style && (css_computed_background_color(box->style,
+ &bgcol) != CSS_BACKGROUND_COLOR_TRANSPARENT ||
box->background)) {
/* With its own background */
bg_box = box;
} else if (!box->style ||
- (box->style->background_color ==
- NS_TRANSPARENT &&
+ (css_computed_background_color(box->style,
+ &bgcol) == CSS_BACKGROUND_COLOR_TRANSPARENT &&
!box->background)) {
/* Without its own background */
if (box->children && box->children->style &&
- (box->children->style->
- background_color != NS_TRANSPARENT ||
+ (css_computed_background_color(
+ box->children->style,
+ &bgcol) !=
+ CSS_BACKGROUND_COLOR_TRANSPARENT ||
box->children->background)) {
/* But body has one, so use that */
bg_box = box->children;
@@ -367,14 +372,14 @@ bool html_redraw_box(struct box *box,
}
} else if (box->parent && !box->parent->parent) {
/* Body box */
- if (box->style &&
- (box->style->background_color !=
- NS_TRANSPARENT ||
+ if (box->style && (css_computed_background_color(box->style,
+ &bgcol) != CSS_BACKGROUND_COLOR_TRANSPARENT ||
box->background)) {
/* With a background */
if (box->parent->style &&
- (box->parent->style->background_color !=
- NS_TRANSPARENT ||
+ (css_computed_background_color(
+ box->parent->style, &bgcol) !=
+ CSS_BACKGROUND_COLOR_TRANSPARENT ||
box->parent->background)) {
/* Root has own background; process normally */
bg_box = box;
@@ -395,8 +400,9 @@ bool html_redraw_box(struct box *box,
bg_box->type != BOX_TEXT &&
bg_box->type != BOX_INLINE_END &&
(bg_box->type != BOX_INLINE || bg_box->object) &&
- ((bg_box->style->background_color != NS_TRANSPARENT) ||
- (bg_box->background))) {
+ (css_computed_background_color(bg_box->style,
+ &bgcol) != CSS_BACKGROUND_COLOR_TRANSPARENT ||
+ bg_box->background)) {
/* find intersection of clip box and border edge */
int px0, py0, px1, py1;
px0 = x - border_left < x0 ? x0 : x - border_left;
@@ -451,7 +457,8 @@ bool html_redraw_box(struct box *box,
/* backgrounds and borders for non-replaced inlines */
if (box->style && box->type == BOX_INLINE && box->inline_end &&
- (box->style->background_color != NS_TRANSPARENT ||
+ (css_computed_background_color(box->style, &bgcol) !=
+ CSS_BACKGROUND_COLOR_TRANSPARENT ||
box->background || border_top || border_right ||
border_bottom || border_left)) {
/* inline backgrounds and borders span other boxes and may
@@ -482,15 +489,15 @@ bool html_redraw_box(struct box *box,
ib_y = y_parent + ib->y;
ib_p_width = ib->padding[LEFT] + ib->width +
ib->padding[RIGHT];
- ib_b_left = ib->border[LEFT];
- ib_b_right = ib->border[RIGHT];
+ ib_b_left = ib->border[LEFT].width;
+ ib_b_right = ib->border[RIGHT].width;
} else {
ib_x = (x_parent + ib->x) * scale;
ib_y = (y_parent + ib->y) * scale;
ib_p_width = (ib->padding[LEFT] + ib->width +
ib->padding[RIGHT]) * scale;
- ib_b_left = ib->border[LEFT] * scale;
- ib_b_right = ib->border[RIGHT] * scale;
+ ib_b_left = ib->border[LEFT].width * scale;
+ ib_b_right = ib->border[RIGHT].width * scale;
}
if (ib->inline_new_line && ib != box) {
@@ -587,7 +594,8 @@ bool html_redraw_box(struct box *box,
}
/* clip to the padding edge for boxes with overflow hidden or scroll */
- if (box->style && box->style->overflow != CSS_OVERFLOW_VISIBLE) {
+ if (box->style && css_computed_overflow(box->style) !=
+ CSS_OVERFLOW_VISIBLE) {
x0 = x;
y0 = y;
x1 = x + padding_width;
@@ -607,7 +615,7 @@ bool html_redraw_box(struct box *box,
/* text decoration */
if (box->type != BOX_TEXT && box->style &&
- box->style->text_decoration !=
+ css_computed_text_decoration(box->style) !=
CSS_TEXT_DECORATION_NONE)
if (!html_redraw_text_decoration(box, x_parent, y_parent,
scale, current_background_color))
@@ -665,8 +673,10 @@ bool html_redraw_box(struct box *box,
/* scrollbars */
if (box->style && box->type != BOX_BR && box->type != BOX_TABLE &&
box->type != BOX_INLINE &&
- (box->style->overflow == CSS_OVERFLOW_SCROLL ||
- box->style->overflow == CSS_OVERFLOW_AUTO))
+ (css_computed_overflow(box->style) ==
+ CSS_OVERFLOW_SCROLL ||
+ css_computed_overflow(box->style) ==
+ CSS_OVERFLOW_AUTO))
if (!html_redraw_scrollbars(box, scale, x, y,
padding_width, padding_height,
current_background_color))
@@ -984,10 +994,10 @@ bool html_redraw_caret(struct caret *c, colour current_background_color,
bool html_redraw_borders(struct box *box, int x_parent, int y_parent,
int p_width, int p_height, float scale)
{
- int top = box->border[TOP];
- int right = box->border[RIGHT];
- int bottom = box->border[BOTTOM];
- int left = box->border[LEFT];
+ int top = box->border[TOP].width;
+ int right = box->border[RIGHT].width;
+ int bottom = box->border[BOTTOM].width;
+ int left = box->border[LEFT].width;
int x, y;
unsigned int i;
int p[20];
@@ -1017,12 +1027,19 @@ bool html_redraw_borders(struct box *box, int x_parent, int y_parent,
p[18] = x - left; p[19] = y - top;
for (i = 0; i != 4; i++) {
- if (box->border[i] == 0)
+ colour col = 0;
+
+ if (box->border[i].width == 0)
continue;
- if (!html_redraw_border_plot(i, p,
- box->style->border[i].color,
- box->style->border[i].style,
- box->border[i] * scale))
+
+ if (box->border[i].color == CSS_BORDER_COLOR_TRANSPARENT) {
+ col = NS_TRANSPARENT;
+ } else {
+ col = nscss_color_to_ns(box->border[i].c);
+ }
+
+ if (!html_redraw_border_plot(i, p, col, box->border[i].style,
+ box->border[i].width * scale))
return false;
}
@@ -1047,10 +1064,11 @@ bool html_redraw_borders(struct box *box, int x_parent, int y_parent,
bool html_redraw_inline_borders(struct box *box, int x0, int y0, int x1, int y1,
float scale, bool first, bool last)
{
- int top = box->border[TOP];
- int right = box->border[RIGHT];
- int bottom = box->border[BOTTOM];
- int left = box->border[LEFT];
+ int top = box->border[TOP].width;
+ int right = box->border[RIGHT].width;
+ int bottom = box->border[BOTTOM].width;
+ int left = box->border[LEFT].width;
+ colour col;
int p[20];
if (scale != 1.0) {
@@ -1074,26 +1092,54 @@ bool html_redraw_inline_borders(struct box *box, int x0, int y0, int x1, int y1,
assert(box->style);
- if (box->border[LEFT] && first)
- if (!html_redraw_border_plot(LEFT, p,
- box->style->border[LEFT].color,
- box->style->border[LEFT].style, left))
+ if (box->border[LEFT].width && first) {
+ if (box->border[LEFT].color == CSS_BORDER_COLOR_TRANSPARENT)
+ col = NS_TRANSPARENT;
+ else
+ col = nscss_color_to_ns(box->border[LEFT].c);
+
+ if (!html_redraw_border_plot(LEFT, p, col,
+ box->border[LEFT].style,
+ left))
return false;
- if (box->border[TOP])
- if (!html_redraw_border_plot(TOP, p,
- box->style->border[TOP].color,
- box->style->border[TOP].style, top))
+ }
+
+ if (box->border[TOP].width) {
+ if (box->border[TOP].color == CSS_BORDER_COLOR_TRANSPARENT)
+ col = NS_TRANSPARENT;
+ else
+ col = nscss_color_to_ns(box->border[TOP].c);
+
+ if (!html_redraw_border_plot(TOP, p, col,
+ box->border[TOP].style,
+ top))
return false;
- if (box->border[BOTTOM])
- if (!html_redraw_border_plot(BOTTOM, p,
- box->style->border[BOTTOM].color,
- box->style->border[BOTTOM].style, bottom))
+ }
+
+ if (box->border[BOTTOM].width) {
+ if (box->border[BOTTOM].color == CSS_BORDER_COLOR_TRANSPARENT)
+ col = NS_TRANSPARENT;
+ else
+ col = nscss_color_to_ns(box->border[BOTTOM].c);
+
+ if (!html_redraw_border_plot(BOTTOM, p, col,
+ box->border[BOTTOM].style,
+ bottom))
return false;
- if (box->border[RIGHT] && last)
- if (!html_redraw_border_plot(RIGHT, p,
- box->style->border[RIGHT].color,
- box->style->border[RIGHT].style, right))
+ }
+
+ if (box->border[RIGHT].width && last) {
+ if (box->border[RIGHT].color == CSS_BORDER_COLOR_TRANSPARENT)
+ col = NS_TRANSPARENT;
+ else
+ col = nscss_color_to_ns(box->border[RIGHT].c);
+
+ if (!html_redraw_border_plot(RIGHT, p, col,
+ box->border[RIGHT].style,
+ right))
return false;
+ }
+
return true;
}
@@ -1128,7 +1174,7 @@ static plot_style_t plot_style_fillbdr_dlight = {
*/
bool html_redraw_border_plot(int i, int *p, colour c,
- css_border_style style, int thickness)
+ enum css_border_style style, int thickness)
{
int z[8];
unsigned int light = i;
@@ -1449,7 +1495,10 @@ bool html_redraw_background(int x, int y, struct box *box, float scale,
int px0 = clip_x0, py0 = clip_y0, px1 = clip_x1, py1 = clip_y1;
int ox = x, oy = y;
int width, height;
+ css_fixed hpos = 0, vpos = 0;
+ css_unit hunit = CSS_UNIT_PX, vunit = CSS_UNIT_PX;
struct box *parent;
+ css_color bgcol;
plot_style_t pstyle_fill_bg = {
.fill_type = PLOT_OP_TYPE_SOLID,
.fill_colour = *background_colour,
@@ -1479,7 +1528,7 @@ bool html_redraw_background(int x, int y, struct box *box, float scale,
box->padding[BOTTOM];
}
/* handle background-repeat */
- switch (background->style->background_repeat) {
+ switch (css_computed_background_repeat(background->style)) {
case CSS_BACKGROUND_REPEAT_REPEAT:
repeat_x = repeat_y = true;
/* optimisation: only plot the colour if
@@ -1501,50 +1550,39 @@ bool html_redraw_background(int x, int y, struct box *box, float scale,
}
/* handle background-position */
- switch (background->style->background_position.horz.pos) {
- case CSS_BACKGROUND_POSITION_PERCENT:
- x += (width - background->background->width) *
- scale *
- background->style->background_position.
- horz.value.percent / 100;
- break;
- case CSS_BACKGROUND_POSITION_LENGTH:
- x += (int) (css_len2px(&background->style->
- background_position.horz.value.length,
- background->style) * scale);
- break;
- default:
- break;
+ css_computed_background_position(background->style,
+ &hpos, &hunit, &vpos, &vunit);
+ if (hunit == CSS_UNIT_PCT) {
+ x += (width - background->background->width) *
+ scale * FIXTOFLT(hpos) / 100.;
+ } else {
+ x += (int) (FIXTOFLT(nscss_len2px(hpos, hunit,
+ background->style)) * scale);
}
- switch (background->style->background_position.vert.pos) {
- case CSS_BACKGROUND_POSITION_PERCENT:
- y += (height - background->background->height) *
- scale *
- background->style->background_position.
- vert.value.percent / 100;
- break;
- case CSS_BACKGROUND_POSITION_LENGTH:
- y += (int) (css_len2px(&background->style->
- background_position.vert.value.length,
- background->style) * scale);
- break;
- default:
- break;
+ if (vunit == CSS_UNIT_PCT) {
+ y += (height - background->background->height) *
+ scale * FIXTOFLT(vpos) / 100.;
+ } else {
+ y += (int) (FIXTOFLT(nscss_len2px(vpos, vunit,
+ background->style)) * scale);
}
}
/* special case for table rows as their background needs
* to be clipped to all the cells */
if (box->type == BOX_TABLE_ROW) {
+ css_fixed h = 0, v = 0;
+ css_unit hu = CSS_UNIT_PX, vu = CSS_UNIT_PX;
+
for (parent = box->parent;
((parent) && (parent->type != BOX_TABLE));
parent = parent->parent);
assert(parent && (parent->style));
- clip_to_children =
- (parent->style->border_spacing.horz.value > 0) ||
- (parent->style->border_spacing.vert.value > 0);
+ css_computed_border_spacing(parent->style, &h, &hu, &v, &vu);
+
+ clip_to_children = (h > 0) || (v > 0);
if (clip_to_children)
clip_box = box->children;
@@ -1572,8 +1610,9 @@ bool html_redraw_background(int x, int y, struct box *box, float scale,
/* <td> attributes override <tr> */
if ((clip_x0 >= clip_x1) || (clip_y0 >= clip_y1) ||
- (clip_box->style->background_color !=
- NS_TRANSPARENT) ||
+ (css_computed_background_color(
+ clip_box->style, &bgcol) !=
+ CSS_BACKGROUND_COLOR_TRANSPARENT) ||
(clip_box->background &&
clip_box->background->bitmap &&
bitmap_get_opaque(
@@ -1582,11 +1621,10 @@ bool html_redraw_background(int x, int y, struct box *box, float scale,
}
/* plot the background colour */
- if (background->style->background_color != NS_TRANSPARENT) {
- *background_colour =
- background->style->background_color;
- pstyle_fill_bg.fill_colour =
- background->style->background_color;
+ if (css_computed_background_color(background->style, &bgcol) !=
+ CSS_BACKGROUND_COLOR_TRANSPARENT) {
+ *background_colour = nscss_color_to_ns(bgcol);
+ pstyle_fill_bg.fill_colour = *background_colour;
if (plot_colour)
if (!plot.rectangle(clip_x0, clip_y0,
clip_x1, clip_y1,
@@ -1670,6 +1708,9 @@ bool html_redraw_inline_background(int x, int y, struct box *box, float scale,
bool repeat_y = false;
bool plot_colour = true;
bool plot_content;
+ css_fixed hpos = 0, vpos = 0;
+ css_unit hunit = CSS_UNIT_PX, vunit = CSS_UNIT_PX;
+ css_color bgcol;
plot_style_t pstyle_fill_bg = {
.fill_type = PLOT_OP_TYPE_SOLID,
.fill_colour = *background_colour,
@@ -1682,7 +1723,7 @@ bool html_redraw_inline_background(int x, int y, struct box *box, float scale,
if (plot_content) {
/* handle background-repeat */
- switch (box->style->background_repeat) {
+ switch (css_computed_background_repeat(box->style)) {
case CSS_BACKGROUND_REPEAT_REPEAT:
repeat_x = repeat_y = true;
/* optimisation: only plot the colour if
@@ -1704,57 +1745,35 @@ bool html_redraw_inline_background(int x, int y, struct box *box, float scale,
}
/* handle background-position */
- switch (box->style->background_position.horz.pos) {
- case CSS_BACKGROUND_POSITION_PERCENT:
- x += (px1 - px0 -
- box->background->width * scale) *
- box->style->background_position.
- horz.value.percent / 100;
-
- if (!repeat_x &&
- ((box->style->
- background_position.
- horz.value.percent < 2 &&
- !first) ||
- (box->style->
- background_position.
- horz.value.percent > 98 &&
- !last))) {
- plot_content = false;
- }
- break;
- case CSS_BACKGROUND_POSITION_LENGTH:
- x += (int) (css_len2px(&box->style->
- background_position.horz.value.length,
- box->style) * scale);
- break;
- default:
- break;
+ css_computed_background_position(box->style,
+ &hpos, &hunit, &vpos, &vunit);
+ if (hunit == CSS_UNIT_PCT) {
+ x += (px1 - px0 - box->background->width * scale) *
+ FIXTOFLT(hpos) / 100.;
+
+ if (!repeat_x && ((hpos < 2 && !first) ||
+ (hpos > 98 && !last))){
+ plot_content = false;
+ }
+ } else {
+ x += (int) (FIXTOFLT(nscss_len2px(hpos, hunit,
+ box->style)) * scale);
}
- switch (box->style->background_position.vert.pos) {
- case CSS_BACKGROUND_POSITION_PERCENT:
- y += (py1 - py0 -
- box->background->height * scale) *
- box->style->background_position.
- vert.value.percent / 100;
- break;
- case CSS_BACKGROUND_POSITION_LENGTH:
- y += (int) (css_len2px(&box->style->
- background_position.vert.value.length,
- box->style) * scale);
- break;
- default:
- break;
+ if (vunit == CSS_UNIT_PCT) {
+ y += (py1 - py0 - box->background->height * scale) *
+ FIXTOFLT(vpos) / 100.;
+ } else {
+ y += (int) (FIXTOFLT(nscss_len2px(vpos, vunit,
+ box->style)) * scale);
}
}
/* plot the background colour */
- if (box->style->background_color != NS_TRANSPARENT) {
- *background_colour =
- box->style->background_color;
- pstyle_fill_bg.fill_colour =
- box->style->background_color;
+ if (css_computed_background_color(box->style, &bgcol) !=
+ CSS_BACKGROUND_COLOR_TRANSPARENT) {
+ *background_colour = nscss_color_to_ns(bgcol);
+ pstyle_fill_bg.fill_colour = *background_colour;
if (plot_colour)
if (!plot.rectangle(clip_x0, clip_y0,
@@ -1820,36 +1839,40 @@ bool html_redraw_text_decoration(struct box *box,
int x_parent, int y_parent, float scale,
colour background_colour)
{
- static const css_text_decoration decoration[] = {
+ static const enum css_text_decoration decoration[] = {
CSS_TEXT_DECORATION_UNDERLINE, CSS_TEXT_DECORATION_OVERLINE,
CSS_TEXT_DECORATION_LINE_THROUGH };
static const float line_ratio[] = { 0.9, 0.1, 0.5 };
- int colour;
+ colour fgcol;
unsigned int i;
+ css_color col;
+
+ css_computed_color(box->style, &col);
+ fgcol = nscss_color_to_ns(col);
/* antialias colour for under/overline */
- if (html_redraw_printing)
- colour = box->style->color;
- else
- colour = blend_colour(background_colour, box->style->color);
+ if (html_redraw_printing == false)
+ fgcol = blend_colour(background_colour, fgcol);
if (box->type == BOX_INLINE) {
if (!box->inline_end)
return true;
for (i = 0; i != NOF_ELEMENTS(decoration); i++)
- if (box->style->text_decoration & decoration[i])
+ if (css_computed_text_decoration(box->style) &
+ decoration[i])
if (!html_redraw_text_decoration_inline(box,
x_parent, y_parent, scale,
- colour, line_ratio[i]))
+ fgcol, line_ratio[i]))
return false;
} else {
for (i = 0; i != NOF_ELEMENTS(decoration); i++)
- if (box->style->text_decoration & decoration[i])
+ if (css_computed_text_decoration(box->style) &
+ decoration[i])
if (!html_redraw_text_decoration_block(box,
x_parent + box->x,
y_parent + box->y,
scale,
- colour, line_ratio[i]))
+ fgcol, line_ratio[i]))
return false;
}
@@ -2179,9 +2202,9 @@ bool html_redraw_scrollbars(struct box *box, float scale,
bool box_vscrollbar_present(const struct box * const box)
{
- return box->descendant_y0 < -box->border[TOP] ||
+ return box->descendant_y0 < -box->border[TOP].width ||
box->padding[TOP] + box->height + box->padding[BOTTOM] +
- box->border[BOTTOM] < box->descendant_y1;
+ box->border[BOTTOM].width < box->descendant_y1;
}
@@ -2194,9 +2217,9 @@ bool box_vscrollbar_present(const struct box * const box)
bool box_hscrollbar_present(const struct box * const box)
{
- return box->descendant_x0 < -box->border[LEFT] ||
+ return box->descendant_x0 < -box->border[LEFT].width ||
box->padding[LEFT] + box->width + box->padding[RIGHT] +
- box->border[RIGHT] < box->descendant_x1;
+ box->border[RIGHT].width < box->descendant_x1;
}
diff --git a/render/hubbub_binding.c b/render/hubbub_binding.c
index 279dd9933..1d8af25ca 100644
--- a/render/hubbub_binding.c
+++ b/render/hubbub_binding.c
@@ -41,6 +41,8 @@ typedef struct hubbub_ctx {
htmlDocPtr document;
bool owns_doc;
+ binding_quirks_mode quirks;
+
const char *encoding;
binding_encoding_source encoding_source;
@@ -147,6 +149,7 @@ binding_error binding_create_tree(void *arena, const char *charset, void **ctx)
: ENCODING_SOURCE_DETECTED;
c->document = NULL;
c->owns_doc = true;
+ c->quirks = BINDING_QUIRKS_MODE_NONE;
c->forms = NULL;
error = hubbub_parser_create(charset, true, myrealloc, arena,
@@ -239,13 +242,15 @@ const char *binding_get_encoding(void *ctx, binding_encoding_source *source)
return c->encoding != NULL ? c->encoding : "Windows-1252";
}
-xmlDocPtr binding_get_document(void *ctx)
+xmlDocPtr binding_get_document(void *ctx, binding_quirks_mode *quirks)
{
hubbub_ctx *c = (hubbub_ctx *) ctx;
xmlDocPtr doc = c->document;
c->owns_doc = false;
+ *quirks = c->quirks;
+
return doc;
}
@@ -744,6 +749,20 @@ hubbub_error add_attributes(void *ctx, void *node,
hubbub_error set_quirks_mode(void *ctx, hubbub_quirks_mode mode)
{
+ hubbub_ctx *c = (hubbub_ctx *) ctx;
+
+ switch (mode) {
+ case HUBBUB_QUIRKS_MODE_NONE:
+ c->quirks = BINDING_QUIRKS_MODE_NONE;
+ break;
+ case HUBBUB_QUIRKS_MODE_LIMITED:
+ c->quirks = BINDING_QUIRKS_MODE_LIMITED;
+ break;
+ case HUBBUB_QUIRKS_MODE_FULL:
+ c->quirks = BINDING_QUIRKS_MODE_FULL;
+ break;
+ }
+
return HUBBUB_OK;
}
diff --git a/render/layout.c b/render/layout.c
index 4d9adc468..411d6755e 100644
--- a/render/layout.c
+++ b/render/layout.c
@@ -40,6 +40,7 @@
#include <string.h>
#include <math.h>
#include "css/css.h"
+#include "css/utils.h"
#include "content/content.h"
#include "desktop/gui.h"
#include "desktop/options.h"
@@ -47,6 +48,7 @@
#include "render/font.h"
#include "render/form.h"
#include "render/layout.h"
+#include "render/table.h"
#define NDEBUG
#include "utils/log.h"
#undef NDEBUG
@@ -69,36 +71,36 @@ static bool layout_apply_minmax_height(struct box *box, struct box *container);
static void layout_block_add_scrollbar(struct box *box, int which);
static int layout_solve_width(int available_width, int width, int lm, int rm,
int max_width, int min_width,
- int margin[4], int padding[4], int border[4]);
+ int margin[4], int padding[4], struct box_border border[4]);
static void layout_float_find_dimensions(int available_width,
- struct css_style *style, struct box *box);
+ const css_computed_style *style, struct box *box);
static void layout_find_dimensions(int available_width, int viewport_height,
- struct box *box, struct css_style *style,
+ struct box *box, const css_computed_style *style,
int *width, int *height, int *max_width, int *min_width,
- int margin[4], int padding[4], int border[4]);
+ int margin[4], int padding[4], struct box_border border[4]);
static void layout_tweak_form_dimensions(struct box *box, bool percentage,
int available_width, bool setwidth, int *dimension);
-static int layout_clear(struct box *fl, css_clear clear);
+static int layout_clear(struct box *fl, enum css_clear clear);
static void find_sides(struct box *fl, int y0, int y1,
int *x0, int *x1, struct box **left, struct box **right);
static void layout_minmax_inline_container(struct box *inline_container,
const struct font_functions *font_func);
-static int line_height(struct css_style *style);
+static int line_height(const css_computed_style *style);
static bool layout_line(struct box *first, int *width, int *y,
int cx, int cy, struct box *cont, bool indent,
bool has_text_children,
struct content *content, struct box **next_box);
static struct box *layout_minmax_line(struct box *first, int *min, int *max,
const struct font_functions *font_func);
-static int layout_text_indent(struct css_style *style, int width);
+static int layout_text_indent(const css_computed_style *style, int width);
static bool layout_float(struct box *b, int width, struct content *content);
static void place_float_below(struct box *c, int width, int cx, int y,
struct box *cont);
static bool layout_table(struct box *box, int available_width,
struct content *content);
static void layout_move_children(struct box *box, int x, int y);
-static void calculate_mbp_width(struct css_style *style, unsigned int side,
- bool margin, bool border, bool padding,
+static void calculate_mbp_width(const css_computed_style *style,
+ unsigned int side, bool margin, bool border, bool padding,
int *fixed, float *frac);
static void layout_lists(struct box *box,
const struct font_functions *font_func);
@@ -137,11 +139,11 @@ bool layout_document(struct content *content, int width, int height)
layout_minmax_block(doc, font_func);
layout_block_find_dimensions(width, height, 0, 0, doc);
- doc->x = doc->margin[LEFT] + doc->border[LEFT];
- doc->y = doc->margin[TOP] + doc->border[TOP];
- width -= doc->margin[LEFT] + doc->border[LEFT] + doc->padding[LEFT] +
- doc->padding[RIGHT] + doc->border[RIGHT] +
- doc->margin[RIGHT];
+ doc->x = doc->margin[LEFT] + doc->border[LEFT].width;
+ doc->y = doc->margin[TOP] + doc->border[TOP].width;
+ width -= doc->margin[LEFT] + doc->border[LEFT].width +
+ doc->padding[LEFT] + doc->padding[RIGHT] +
+ doc->border[RIGHT].width + doc->margin[RIGHT];
if (width < 0)
width = 0;
doc->width = width;
@@ -150,18 +152,19 @@ bool layout_document(struct content *content, int width, int height)
/* make <html> and <body> fill available height */
if (doc->y + doc->padding[TOP] + doc->height + doc->padding[BOTTOM] +
- doc->border[BOTTOM] + doc->margin[BOTTOM] <
+ doc->border[BOTTOM].width + doc->margin[BOTTOM] <
height) {
doc->height = height - (doc->y + doc->padding[TOP] +
- doc->padding[BOTTOM] + doc->border[BOTTOM] +
+ doc->padding[BOTTOM] +
+ doc->border[BOTTOM].width +
doc->margin[BOTTOM]);
if (doc->children)
doc->children->height = doc->height -
(doc->children->margin[TOP] +
- doc->children->border[TOP] +
+ doc->children->border[TOP].width +
doc->children->padding[TOP] +
doc->children->padding[BOTTOM] +
- doc->children->border[BOTTOM] +
+ doc->children->border[BOTTOM].width +
doc->children->margin[BOTTOM]);
}
@@ -197,7 +200,8 @@ bool layout_block_context(struct box *block, int viewport_height,
int y = 0;
int lm, rm;
struct box *margin_box;
- struct css_length gadget_size; /* Checkbox / radio buttons */
+ css_fixed gadget_size;
+ css_unit gadget_unit; /* Checkbox / radio buttons */
assert(block->type == BOX_BLOCK ||
block->type == BOX_INLINE_BLOCK ||
@@ -267,10 +271,11 @@ bool layout_block_context(struct box *block, int viewport_height,
block->gadget->type == GADGET_CHECKBOX)) {
/* form checkbox or radio button
* if width or height is AUTO, set it to 1em */
- gadget_size.unit = CSS_UNIT_EM;
- gadget_size.value = 1;
+ gadget_unit = CSS_UNIT_EM;
+ gadget_size = INTTOFIX(1);
if (block->height == AUTO)
- block->height = css_len2px(&gadget_size, block->style);
+ block->height = FIXTOINT(nscss_len2px(gadget_size,
+ gadget_unit, block->style));
}
box = margin_box = block->children;
@@ -317,8 +322,10 @@ bool layout_block_context(struct box *block, int viewport_height,
*/
if (box->style &&
- (box->style->position == CSS_POSITION_ABSOLUTE||
- box->style->position == CSS_POSITION_FIXED)) {
+ (css_computed_position(box->style) ==
+ CSS_POSITION_ABSOLUTE ||
+ css_computed_position(box->style) ==
+ CSS_POSITION_FIXED)) {
box->x = box->parent->padding[LEFT];
/* absolute positioned; this element will establish
* its own block context when it gets laid out later,
@@ -328,9 +335,10 @@ bool layout_block_context(struct box *block, int viewport_height,
/* Clearance. */
y = 0;
- if (box->style && box->style->clear != CSS_CLEAR_NONE)
+ if (box->style && css_computed_clear(box->style) !=
+ CSS_CLEAR_NONE)
y = layout_clear(block->float_children,
- box->style->clear);
+ css_computed_clear(box->style));
/* Get top margin */
if (box->style) {
@@ -351,7 +359,7 @@ bool layout_block_context(struct box *block, int viewport_height,
if (box->type == BOX_BLOCK || box->object) {
if (!box->object && box->style &&
- box->style->overflow !=
+ css_computed_overflow(box->style) !=
CSS_OVERFLOW_VISIBLE) {
/* box establishes new block formatting context
* so available width may be diminished due to
@@ -381,7 +389,13 @@ bool layout_block_context(struct box *block, int viewport_height,
layout_block_add_scrollbar(box, BOTTOM);
}
} else if (box->type == BOX_TABLE) {
- if (box->style->width.width == CSS_WIDTH_AUTO) {
+ enum css_width wtype;
+ css_fixed width = 0;
+ css_unit unit = CSS_UNIT_PX;
+
+ wtype = css_computed_width(box->style, &width, &unit);
+
+ if (wtype == CSS_WIDTH_AUTO) {
/* max available width may be diminished due to
* floats. */
int x0, x1, top;
@@ -412,18 +426,18 @@ bool layout_block_context(struct box *block, int viewport_height,
/* Position box: horizontal. */
box->x = box->parent->padding[LEFT] + box->margin[LEFT] +
- box->border[LEFT];
+ box->border[LEFT].width;
cx += box->x;
/* Position box: vertical. */
if (box->type != BOX_BLOCK || y ||
- box->border[TOP] || box->padding[TOP]) {
+ box->border[TOP].width || box->padding[TOP]) {
margin_box->y += max_pos_margin - max_neg_margin;
cy += max_pos_margin - max_neg_margin;
max_pos_margin = max_neg_margin = 0;
margin_box = 0;
- box->y += box->border[TOP];
- cy += box->border[TOP];
+ box->y += box->border[TOP].width;
+ cy += box->border[TOP].width;
if (cy < y) {
box->y += y - cy;
cy = y;
@@ -433,7 +447,8 @@ bool layout_block_context(struct box *block, int viewport_height,
/* Unless the box has an overflow style of visible, the box
* establishes a new block context. */
if (box->type == BOX_BLOCK && box->style &&
- box->style->overflow != CSS_OVERFLOW_VISIBLE) {
+ css_computed_overflow(box->style) !=
+ CSS_OVERFLOW_VISIBLE) {
cy += max_pos_margin - max_neg_margin;
box->y += max_pos_margin - max_neg_margin;
@@ -449,7 +464,7 @@ bool layout_block_context(struct box *block, int viewport_height,
cx -= box->x;
cy += box->height + box->padding[BOTTOM] +
- box->border[BOTTOM];
+ box->border[BOTTOM].width;
max_pos_margin = max_neg_margin = 0;
if (max_pos_margin < box->margin[BOTTOM])
max_pos_margin = box->margin[BOTTOM];
@@ -457,7 +472,7 @@ bool layout_block_context(struct box *block, int viewport_height,
max_neg_margin = -box->margin[BOTTOM];
y = box->y + box->padding[TOP] + box->height +
box->padding[BOTTOM] +
- box->border[BOTTOM];
+ box->border[BOTTOM].width;
/* Skip children, because they are done in the new
* block context */
goto advance_to_next_box;
@@ -480,12 +495,19 @@ bool layout_block_context(struct box *block, int viewport_height,
struct box *left, *right;
y = cy;
while (1) {
+ enum css_width wtype;
+ css_fixed width = 0;
+ css_unit unit = CSS_UNIT_PX;
+
+ wtype = css_computed_width(box->style,
+ &width, &unit);
+
x0 = cx;
x1 = cx + box->parent->width;
find_sides(block->float_children, y,
y + box->height,
&x0, &x1, &left, &right);
- if (box->style->width.width == CSS_WIDTH_AUTO)
+ if (wtype == CSS_WIDTH_AUTO)
break;
if (box->width <= x1 - x0)
break;
@@ -527,7 +549,8 @@ bool layout_block_context(struct box *block, int viewport_height,
layout_block_add_scrollbar(box, BOTTOM);
}
- cy += box->height + box->padding[BOTTOM] + box->border[BOTTOM];
+ cy += box->height + box->padding[BOTTOM] +
+ box->border[BOTTOM].width;
max_pos_margin = max_neg_margin = 0;
if (max_pos_margin < box->margin[BOTTOM])
max_pos_margin = box->margin[BOTTOM];
@@ -535,7 +558,8 @@ bool layout_block_context(struct box *block, int viewport_height,
max_neg_margin = -box->margin[BOTTOM];
cx -= box->x;
y = box->y + box->padding[TOP] + box->height +
- box->padding[BOTTOM] + box->border[BOTTOM];
+ box->padding[BOTTOM] +
+ box->border[BOTTOM].width;
advance_to_next_box:
if (!box->next) {
/* No more siblings:
@@ -556,7 +580,8 @@ bool layout_block_context(struct box *block, int viewport_height,
/* Apply any min-height and max-height to
* boxes in normal flow */
- if (box->style && box->style->position !=
+ if (box->style &&
+ css_computed_position(box->style) !=
CSS_POSITION_ABSOLUTE &&
layout_apply_minmax_height(box,
NULL)) {
@@ -567,7 +592,7 @@ bool layout_block_context(struct box *block, int viewport_height,
}
cy += box->padding[BOTTOM] +
- box->border[BOTTOM];
+ box->border[BOTTOM].width;
if (max_pos_margin < box->margin[BOTTOM])
max_pos_margin = box->margin[BOTTOM];
else if (max_neg_margin < -box->margin[BOTTOM])
@@ -575,7 +600,7 @@ bool layout_block_context(struct box *block, int viewport_height,
cx -= box->x;
y = box->y + box->padding[TOP] + box->height +
box->padding[BOTTOM] +
- box->border[BOTTOM];
+ box->border[BOTTOM].width;
} while (box != block && !box->next);
if (box == block)
break;
@@ -589,7 +614,7 @@ bool layout_block_context(struct box *block, int viewport_height,
/* Increase height to contain any floats inside (CSS 2.1 10.6.7). */
for (box = block->float_children; box; box = box->next_float) {
y = box->y + box->height + box->padding[BOTTOM] +
- box->border[BOTTOM] + box->margin[BOTTOM];
+ box->border[BOTTOM].width + box->margin[BOTTOM];
if (cy < y)
cy = y;
}
@@ -600,7 +625,8 @@ bool layout_block_context(struct box *block, int viewport_height,
layout_block_add_scrollbar(block, BOTTOM);
}
- if (block->style && block->style->position != CSS_POSITION_ABSOLUTE) {
+ if (block->style && css_computed_position(block->style) !=
+ CSS_POSITION_ABSOLUTE) {
/* Block is in normal flow */
layout_apply_minmax_height(block, NULL);
}
@@ -624,12 +650,9 @@ void layout_minmax_block(struct box *block,
int min = 0, max = 0;
int extra_fixed = 0;
float extra_frac = 0;
- struct css_length size;
- struct css_length gadget_size; /* Checkbox / radio buttons */
- size.unit = CSS_UNIT_EM;
- size.value = 10;
- gadget_size.unit = CSS_UNIT_EM;
- gadget_size.value = 1;
+ enum css_width wtype;
+ css_fixed width = 0;
+ css_unit wunit = CSS_UNIT_PX;
assert(block->type == BOX_BLOCK ||
block->type == BOX_INLINE_BLOCK ||
@@ -639,22 +662,28 @@ void layout_minmax_block(struct box *block,
if (block->max_width != UNKNOWN_MAX_WIDTH)
return;
+ wtype = css_computed_width(block->style, &width, &wunit);
+
if (block->gadget && (block->gadget->type == GADGET_TEXTBOX ||
block->gadget->type == GADGET_PASSWORD ||
block->gadget->type == GADGET_FILE ||
block->gadget->type == GADGET_TEXTAREA) &&
- block->style &&
- block->style->width.width == CSS_WIDTH_AUTO) {
- min = max = css_len2px(&size, block->style);
+ block->style && wtype == CSS_WIDTH_AUTO) {
+ css_fixed size = INTTOFIX(10);
+ css_unit unit = CSS_UNIT_EM;
+
+ min = max = FIXTOINT(nscss_len2px(size, unit, block->style));
}
if (block->gadget && (block->gadget->type == GADGET_RADIO ||
block->gadget->type == GADGET_CHECKBOX) &&
- block->style &&
- block->style->width.width == CSS_WIDTH_AUTO) {
+ block->style && wtype == CSS_WIDTH_AUTO) {
+ css_fixed size = INTTOFIX(1);
+ css_unit unit = CSS_UNIT_EM;
+
/* form checkbox or radio button
* if width is AUTO, set it to 1em */
- min = max = css_len2px(&gadget_size, block->style);
+ min = max = FIXTOINT(nscss_len2px(size, unit, block->style));
}
if (block->object) {
@@ -686,9 +715,9 @@ void layout_minmax_block(struct box *block,
assert(child->max_width != UNKNOWN_MAX_WIDTH);
if (child->style &&
- (child->style->position ==
+ (css_computed_position(child->style) ==
CSS_POSITION_ABSOLUTE ||
- child->style->position ==
+ css_computed_position(child->style) ==
CSS_POSITION_FIXED)) {
/* This child is positioned out of normal flow,
* so it will have no affect on width */
@@ -708,18 +737,16 @@ void layout_minmax_block(struct box *block,
}
/* fixed width takes priority */
- if (block->type != BOX_TABLE_CELL &&
- block->style->width.width == CSS_WIDTH_LENGTH) {
- min = max = css_len2px(&block->style->width.value.length,
- block->style);
+ if (block->type != BOX_TABLE_CELL && wtype == CSS_WIDTH_SET &&
+ wunit != CSS_UNIT_PCT) {
+ min = max = FIXTOINT(nscss_len2px(width, wunit, block->style));
}
/* add margins, border, padding to min, max widths */
- if (block->gadget && (block->style->width.width == CSS_WIDTH_PERCENT ||
- (block->style->width.width == CSS_WIDTH_LENGTH &&
+ if (block->gadget && wtype == CSS_WIDTH_SET &&
(block->gadget->type == GADGET_SUBMIT ||
block->gadget->type == GADGET_RESET ||
- block->gadget->type == GADGET_BUTTON)))) {
+ block->gadget->type == GADGET_BUTTON)) {
/* some gadgets with specified width already include border and
* padding, so just get margin */
calculate_mbp_width(block->style, LEFT, true, false, false,
@@ -799,8 +826,8 @@ void layout_block_find_dimensions(int available_width, int viewport_height,
int height;
int *margin = box->margin;
int *padding = box->padding;
- int *border = box->border;
- struct css_style *style = box->style;
+ struct box_border *border = box->border;
+ const css_computed_style *style = box->style;
layout_find_dimensions(available_width, viewport_height, box, style,
&width, &height, &max_width, &min_width,
@@ -854,13 +881,13 @@ bool layout_apply_minmax_height(struct box *box, struct box *container)
bool updated = false;
/* Find containing block for percentage heights */
- if (box->style->position == CSS_POSITION_ABSOLUTE) {
+ if (css_computed_position(box->style) == CSS_POSITION_ABSOLUTE) {
/* Box is absolutely positioned */
assert(container);
containing_block = container;
} else if (box->float_container &&
- (box->style->float_ == CSS_FLOAT_LEFT ||
- box->style->float_ == CSS_FLOAT_RIGHT)) {
+ (css_computed_float(box->style) == CSS_FLOAT_LEFT ||
+ css_computed_float(box->style) == CSS_FLOAT_RIGHT)) {
/* Box is a float */
assert(box->parent && box->parent->parent &&
box->parent->parent->parent);
@@ -875,72 +902,73 @@ bool layout_apply_minmax_height(struct box *box, struct box *container)
}
if (box->style) {
+ enum css_height htype = CSS_HEIGHT_AUTO;
+ css_fixed length = 0;
+ css_unit unit = CSS_UNIT_PX;
+
+ if (containing_block) {
+ htype = css_computed_height(containing_block->style,
+ &length, &unit);
+ }
+
/* max-height */
- switch (box->style->max_height.max_height) {
- case CSS_MAX_HEIGHT_LENGTH:
- h = css_len2px(&box->style->max_height.value.length,
- box->style);
- if (h < box->height) {
- box->height = h;
- updated = true;
- }
- break;
- case CSS_MAX_HEIGHT_PERCENT:
- if (containing_block &&
+ if (css_computed_max_height(box->style, &length, &unit) ==
+ CSS_MAX_HEIGHT_SET) {
+ if (unit == CSS_UNIT_PCT) {
+ if (containing_block &&
containing_block->height != AUTO &&
- (box->style->position ==
+ (css_computed_position(box->style) ==
CSS_POSITION_ABSOLUTE ||
- (containing_block->style->height.
- height == CSS_HEIGHT_LENGTH ||
- containing_block->style->height.
- height == CSS_HEIGHT_PERCENT))) {
- /* Box is absolutely positioned or its
- * containing block has a valid specified
- * height. (CSS 2.1 Section 10.5) */
- h = box->style->max_height.value.percent *
+ htype == CSS_HEIGHT_SET)) {
+ /* Box is absolutely positioned or its
+ * containing block has a valid
+ * specified height. (CSS 2.1
+ * Section 10.5) */
+ h = FIXTOFLT(length) *
containing_block->height / 100;
+ if (h < box->height) {
+ box->height = h;
+ updated = true;
+ }
+ }
+ } else {
+ h = FIXTOINT(nscss_len2px(length, unit,
+ box->style));
if (h < box->height) {
box->height = h;
updated = true;
}
}
- break;
- default:
- break;
}
/* min-height */
- switch (box->style->min_height.min_height) {
- case CSS_MIN_HEIGHT_LENGTH:
- h = css_len2px(&box->style->min_height.value.length,
- box->style);
- if (h > box->height) {
- box->height = h;
- updated = true;
- }
- break;
- case CSS_MIN_HEIGHT_PERCENT:
- if (containing_block &&
+ if (css_computed_min_height(box->style, &length, &unit) ==
+ CSS_MIN_HEIGHT_SET) {
+ if (unit == CSS_UNIT_PCT) {
+ if (containing_block &&
containing_block->height != AUTO &&
- (box->style->position ==
+ (css_computed_position(box->style) ==
CSS_POSITION_ABSOLUTE ||
- (containing_block->style->height.
- height == CSS_HEIGHT_LENGTH ||
- containing_block->style->height.
- height == CSS_HEIGHT_PERCENT))) {
- /* Box is absolutely positioned or its
- * containing block has a valid specified
- * height. (CSS 2.1 Section 10.5) */
- h = box->style->min_height.value.percent *
+ htype == CSS_HEIGHT_SET)) {
+ /* Box is absolutely positioned or its
+ * containing block has a valid
+ * specified height. (CSS 2.1
+ * Section 10.5) */
+ h = FIXTOFLT(length) *
containing_block->height / 100;
+ if (h > box->height) {
+ box->height = h;
+ updated = true;
+ }
+ }
+ } else {
+ h = FIXTOINT(nscss_len2px(length, unit,
+ box->style));
if (h > box->height) {
box->height = h;
updated = true;
}
}
- break;
- default:
- break;
}
}
return updated;
@@ -955,18 +983,24 @@ bool layout_apply_minmax_height(struct box *box, struct box *container)
void layout_block_add_scrollbar(struct box *box, int which)
{
+ enum css_overflow overflow;
+
assert(box->type == BOX_BLOCK && (which == RIGHT || which == BOTTOM));
- if (box->style && (box->style->overflow == CSS_OVERFLOW_SCROLL ||
- box->style->overflow == CSS_OVERFLOW_AUTO)) {
+ if (box->style == NULL)
+ return;
+
+ overflow = css_computed_overflow(box->style);
+
+ if (overflow == CSS_OVERFLOW_SCROLL || overflow == CSS_OVERFLOW_AUTO) {
/* make space for scrollbars, unless height/width are AUTO */
if (which == BOTTOM && box->height != AUTO &&
- (box->style->overflow == CSS_OVERFLOW_SCROLL ||
+ (overflow == CSS_OVERFLOW_SCROLL ||
box_hscrollbar_present(box))) {
box->padding[BOTTOM] += SCROLLBAR_WIDTH;
}
if (which == RIGHT && box->width != AUTO &&
- (box->style->overflow == CSS_OVERFLOW_SCROLL ||
+ (overflow == CSS_OVERFLOW_SCROLL ||
box_vscrollbar_present(box))) {
box->width -= SCROLLBAR_WIDTH;
box->padding[RIGHT] += SCROLLBAR_WIDTH;
@@ -987,16 +1021,14 @@ void layout_block_add_scrollbar(struct box *box, int which)
* \param min_width Box min-width ( <=0 means no min-width to apply)
* \param margin[4] Current box margins. Updated with new box
* left / right margins
- * \param padding[4] Current box paddings. Updated with new box
- * left / right paddings
- * \param border[4] Current box border widths. Updated with new
- * box left / right border widths
+ * \param padding[4] Current box paddings.
+ * \param border[4] Current box border widths.
* \return New box width
*/
int layout_solve_width(int available_width, int width, int lm, int rm,
int max_width, int min_width,
- int margin[4], int padding[4], int border[4])
+ int margin[4], int padding[4], struct box_border border[4])
{
bool auto_width = false;
@@ -1013,8 +1045,9 @@ int layout_solve_width(int available_width, int width, int lm, int rm,
if (margin[RIGHT] == AUTO) margin[RIGHT] = rm;
width = available_width -
- (margin[LEFT] + border[LEFT] + padding[LEFT] +
- padding[RIGHT] + border[RIGHT] + margin[RIGHT]);
+ (margin[LEFT] + border[LEFT].width +
+ padding[LEFT] + padding[RIGHT] +
+ border[RIGHT].width + margin[RIGHT]);
width = width < 0 ? 0 : width;
auto_width = true;
}
@@ -1032,8 +1065,8 @@ int layout_solve_width(int available_width, int width, int lm, int rm,
if (!auto_width && margin[LEFT] == AUTO && margin[RIGHT] == AUTO) {
/* make the margins equal, centering the element */
margin[LEFT] = margin[RIGHT] = (available_width - lm - rm -
- (border[LEFT] + padding[LEFT] + width +
- padding[RIGHT] + border[RIGHT])) / 2;
+ (border[LEFT].width + padding[LEFT] + width +
+ padding[RIGHT] + border[RIGHT].width)) / 2;
if (margin[LEFT] < 0) {
margin[RIGHT] += margin[LEFT];
@@ -1044,14 +1077,16 @@ int layout_solve_width(int available_width, int width, int lm, int rm,
} else if (!auto_width && margin[LEFT] == AUTO) {
margin[LEFT] = available_width - lm -
- (border[LEFT] + padding[LEFT] + width +
- padding[RIGHT] + border[RIGHT] + margin[RIGHT]);
+ (border[LEFT].width + padding[LEFT] + width +
+ padding[RIGHT] + border[RIGHT].width +
+ margin[RIGHT]);
margin[LEFT] = margin[LEFT] < lm ? lm : margin[LEFT];
} else if (!auto_width) {
/* margin-right auto or "over-constrained" */
margin[RIGHT] = available_width - rm -
- (margin[LEFT] + border[LEFT] + padding[LEFT] +
- width + padding[RIGHT] + border[RIGHT]);
+ (margin[LEFT] + border[LEFT].width +
+ padding[LEFT] + width + padding[RIGHT] +
+ border[RIGHT].width);
}
return width;
@@ -1070,14 +1105,15 @@ int layout_solve_width(int available_width, int width, int lm, int rm,
*/
void layout_float_find_dimensions(int available_width,
- struct css_style *style, struct box *box)
+ const css_computed_style *style, struct box *box)
{
int width, height, max_width, min_width;
int *margin = box->margin;
int *padding = box->padding;
- int *border = box->border;
- int scrollbar_width = (style->overflow == CSS_OVERFLOW_SCROLL ||
- style->overflow == CSS_OVERFLOW_AUTO) ?
+ struct box_border *border = box->border;
+ int scrollbar_width =
+ (css_computed_overflow(style) == CSS_OVERFLOW_SCROLL ||
+ css_computed_overflow(style) == CSS_OVERFLOW_AUTO) ?
SCROLLBAR_WIDTH : 0;
layout_find_dimensions(available_width, -1, box, style, &width, &height,
@@ -1107,44 +1143,49 @@ void layout_float_find_dimensions(int available_width,
box->gadget->type == GADGET_PASSWORD ||
box->gadget->type == GADGET_FILE ||
box->gadget->type == GADGET_TEXTAREA)) {
- struct css_length size;
+ css_fixed size = 0;
+ css_unit unit = CSS_UNIT_EM;
+
/* Give sensible dimensions to gadgets, with auto width/height,
* that don't shrink to fit contained text. */
assert(box->style);
- size.unit = CSS_UNIT_EM;
if (box->gadget->type == GADGET_TEXTBOX ||
box->gadget->type == GADGET_PASSWORD ||
box->gadget->type == GADGET_FILE) {
if (width == AUTO) {
- size.value = 10;
- width = css_len2px(&size, box->style);
+ size = INTTOFIX(10);
+ width = FIXTOINT(nscss_len2px(size, unit,
+ box->style));
}
if (box->gadget->type == GADGET_FILE &&
height == AUTO) {
- size.value = 1.5;
- height = css_len2px(&size, box->style);
+ size = FLTTOFIX(1.5);
+ height = FIXTOINT(nscss_len2px(size, unit,
+ box->style));
}
}
if (box->gadget->type == GADGET_TEXTAREA) {
if (width == AUTO) {
- size.value = 10;
- width = css_len2px(&size, box->style);
+ size = INTTOFIX(10);
+ width = FIXTOINT(nscss_len2px(size, unit,
+ box->style));
} else {
width -= scrollbar_width;
}
if (height == AUTO) {
- size.value = 4;
- height = css_len2px(&size, box->style);
+ size = INTTOFIX(4);
+ height = FIXTOINT(nscss_len2px(size, unit,
+ box->style));
}
}
} else if (width == AUTO) {
/* CSS 2.1 section 10.3.5 */
width = min(max(box->min_width, available_width),
box->max_width);
- width -= box->margin[LEFT] + box->border[LEFT] +
+ width -= box->margin[LEFT] + box->border[LEFT].width +
box->padding[LEFT] + box->padding[RIGHT] +
- box->border[RIGHT] + box->margin[RIGHT];
+ box->border[RIGHT].width + box->margin[RIGHT];
if (max_width >= 0 && width > max_width) width = max_width;
if (min_width > 0 && width < min_width) width = min_width;
@@ -1183,33 +1224,37 @@ void layout_float_find_dimensions(int available_width,
*/
void layout_find_dimensions(int available_width, int viewport_height,
- struct box *box, struct css_style *style,
+ struct box *box, const css_computed_style *style,
int *width, int *height, int *max_width, int *min_width,
- int margin[4], int padding[4], int border[4])
+ int margin[4], int padding[4], struct box_border border[4])
{
struct box *containing_block = NULL;
unsigned int i;
bool percentage;
if (width) {
- switch (style->width.width) {
- case CSS_WIDTH_LENGTH:
- *width = css_len2px(&style->width.value.length, style);
- break;
- case CSS_WIDTH_PERCENT:
- *width = (style->width.value.percent *
- available_width) / 100;
- break;
- case CSS_WIDTH_AUTO:
- default:
+ enum css_width wtype;
+ css_fixed value = 0;
+ css_unit unit = CSS_UNIT_PX;
+
+ wtype = css_computed_width(style, &value, &unit);
+
+ if (wtype == CSS_WIDTH_SET) {
+ if (unit == CSS_UNIT_PCT) {
+ *width = (FIXTOFLT(value) * available_width)
+ / 100;
+ } else {
+ *width = FIXTOINT(nscss_len2px(value, unit,
+ style));
+ }
+ } else {
*width = AUTO;
- break;
}
/* specified gadget widths include borders and padding in some
* cases */
if (box->gadget && *width != AUTO) {
- percentage = style->width.width == CSS_WIDTH_PERCENT;
+ percentage = unit == CSS_UNIT_PCT;
layout_tweak_form_dimensions(box, percentage,
available_width, true, width);
@@ -1217,72 +1262,91 @@ void layout_find_dimensions(int available_width, int viewport_height,
}
if (height) {
- switch (style->height.height) {
- case CSS_HEIGHT_LENGTH:
- *height = css_len2px(&style->height.value.length,
- style);
- break;
- case CSS_HEIGHT_PERCENT:
- if (box->style->position == CSS_POSITION_ABSOLUTE) {
- /* Box is absolutely positioned */
- assert(box->float_container);
- containing_block = box->float_container;
- } else if (box->float_container &&
- box->style->position !=
- CSS_POSITION_ABSOLUTE &&
- (box->style->float_ ==
- CSS_FLOAT_LEFT ||
- box->style->float_ ==
- CSS_FLOAT_RIGHT)) {
- /* Box is a float */
- assert(box->parent && box->parent->parent &&
+ enum css_height htype;
+ css_fixed value = 0;
+ css_unit unit = CSS_UNIT_PX;
+
+ htype = css_computed_height(style, &value, &unit);
+
+ if (htype == CSS_HEIGHT_SET) {
+ if (unit == CSS_UNIT_PCT) {
+ enum css_height cbhtype;
+
+ if (css_computed_position(box->style) ==
+ CSS_POSITION_ABSOLUTE) {
+ /* Box is absolutely positioned */
+ assert(box->float_container);
+ containing_block = box->float_container;
+ } else if (box->float_container &&
+ css_computed_position(box->style) !=
+ CSS_POSITION_ABSOLUTE &&
+ (css_computed_float(box->style) ==
+ CSS_FLOAT_LEFT ||
+ css_computed_float(box->style) ==
+ CSS_FLOAT_RIGHT)) {
+ /* Box is a float */
+ assert(box->parent &&
+ box->parent->parent &&
box->parent->parent->parent);
- containing_block = box->parent->parent->parent;
- } else if (box->parent && box->parent->type !=
- BOX_INLINE_CONTAINER) {
- /* Box is a block level element */
- containing_block = box->parent;
- } else if (box->parent && box->parent->type ==
- BOX_INLINE_CONTAINER) {
- /* Box is an inline block */
- assert(box->parent->parent);
- containing_block = box->parent->parent;
- }
- if (containing_block &&
+
+ containing_block =
+ box->parent->parent->parent;
+ } else if (box->parent && box->parent->type !=
+ BOX_INLINE_CONTAINER) {
+ /* Box is a block level element */
+ containing_block = box->parent;
+ } else if (box->parent && box->parent->type ==
+ BOX_INLINE_CONTAINER) {
+ /* Box is an inline block */
+ assert(box->parent->parent);
+ containing_block = box->parent->parent;
+ }
+
+ if (containing_block) {
+ css_fixed f = 0;
+ css_unit u = CSS_UNIT_PX;
+
+ cbhtype = css_computed_height(
+ containing_block->style,
+ &f, &u);
+ }
+
+ if (containing_block &&
containing_block->height != AUTO &&
- (box->style->position ==
+ (css_computed_position(box->style) ==
CSS_POSITION_ABSOLUTE ||
- (containing_block->style->height.
- height == CSS_HEIGHT_LENGTH ||
- containing_block->style->height.
- height == CSS_HEIGHT_PERCENT))) {
- /* Box is absolutely positioned or its
- * containing block has a valid specified
- * height. (CSS 2.1 Section 10.5) */
- *height = style->height.value.percent *
- containing_block->height / 100;
- } else if ((!box->parent || !box->parent->parent) &&
- viewport_height >= 0) {
- /* If root element or it's child
- * (HTML or BODY) */
- *height = style->height.value.percent *
- viewport_height / 100;
+ cbhtype == CSS_HEIGHT_SET)) {
+ /* Box is absolutely positioned or its
+ * containing block has a valid
+ * specified height.
+ * (CSS 2.1 Section 10.5) */
+ *height = FIXTOFLT(value) *
+ containing_block->height /
+ 100;
+ } else if ((!box->parent ||
+ !box->parent->parent) &&
+ viewport_height >= 0) {
+ /* If root element or it's child
+ * (HTML or BODY) */
+ *height = FIXTOFLT(value) *
+ viewport_height / 100;
+ } else {
+ /* precentage height not permissible
+ * treat height as auto */
+ *height = AUTO;
+ }
} else {
- /* precentage height not permissible
- * treat height as auto */
- *height = AUTO;
+ *height = FIXTOINT(nscss_len2px(value, unit,
+ style));
}
- break;
- case CSS_HEIGHT_AUTO:
- default:
+ } else {
*height = AUTO;
- break;
}
/* specified gadget heights include borders and padding in
* some cases */
if (box->gadget && *height != AUTO) {
- percentage = style->height.height == CSS_HEIGHT_PERCENT;
+ percentage = unit == CSS_UNIT_PCT;
layout_tweak_form_dimensions(box, percentage,
available_width, false, height);
@@ -1290,53 +1354,60 @@ void layout_find_dimensions(int available_width, int viewport_height,
}
if (max_width) {
- switch (style->max_width.max_width) {
- case CSS_MAX_WIDTH_LENGTH:
- *max_width = css_len2px(&style->max_width.value.length,
- style);
- break;
- case CSS_MAX_WIDTH_PERCENT:
- *max_width = (style->max_width.value.percent *
- available_width) / 100;
- break;
- case CSS_MAX_WIDTH_NONE:
- default:
+ enum css_max_width type;
+ css_fixed value = 0;
+ css_unit unit = CSS_UNIT_PX;
+
+ type = css_computed_max_width(style, &value, &unit);
+
+ if (type == CSS_MAX_WIDTH_SET) {
+ if (unit == CSS_UNIT_PCT) {
+ *max_width = (FIXTOFLT(value) *
+ available_width) / 100;
+ } else {
+ *max_width = FIXTOINT(nscss_len2px(value, unit,
+ style));
+ }
+ } else {
/* Inadmissible */
*max_width = -1;
- break;
}
/* specified gadget widths include borders and padding in some
* cases */
if (box->gadget && *max_width != -1) {
- percentage = style->max_width.max_width ==
- CSS_WIDTH_PERCENT;
+ percentage = unit == CSS_UNIT_PCT;
+
layout_tweak_form_dimensions(box, percentage,
available_width, true, max_width);
}
}
if (min_width) {
- switch (style->min_width.min_width) {
- case CSS_MIN_WIDTH_LENGTH:
- *min_width = css_len2px(&style->min_width.value.
- length, style);
- break;
- case CSS_MIN_WIDTH_PERCENT:
- *min_width = (style->min_width.value.percent *
+ enum css_min_width type;
+ css_fixed value = 0;
+ css_unit unit = CSS_UNIT_PX;
+
+ type = css_computed_min_width(style, &value, &unit);
+
+ if (type == CSS_MIN_WIDTH_SET) {
+ if (unit == CSS_UNIT_PCT) {
+ *min_width = (FIXTOFLT(value) *
available_width) / 100;
- break;
- default:
+ } else {
+ *min_width = FIXTOINT(nscss_len2px(value, unit,
+ style));
+ }
+ } else {
/* Inadmissible */
*min_width = 0;
- break;
}
/* specified gadget widths include borders and padding in some
* cases */
if (box->gadget && *min_width != 0) {
- percentage = style->min_width.min_width ==
- CSS_WIDTH_PERCENT;
+ percentage = unit == CSS_UNIT_PCT;
+
layout_tweak_form_dimensions(box, percentage,
available_width, true, min_width);
}
@@ -1344,46 +1415,137 @@ void layout_find_dimensions(int available_width, int viewport_height,
for (i = 0; i != 4; i++) {
if (margin) {
- switch (style->margin[i].margin) {
- case CSS_MARGIN_LENGTH:
- margin[i] = css_len2px(&style->margin[i].
- value.length, style);
+ enum css_margin type = CSS_MARGIN_AUTO;;
+ css_fixed value = 0;
+ css_unit unit = CSS_UNIT_PX;
+
+ switch (i) {
+ case TOP:
+ type = css_computed_margin_top(style,
+ &value, &unit);
break;
- case CSS_MARGIN_PERCENT:
- margin[i] = available_width *
- style->margin[i].value.percent / 100;
+ case RIGHT:
+ type = css_computed_margin_right(style,
+ &value, &unit);
break;
- case CSS_MARGIN_AUTO:
- default:
- margin[i] = AUTO;
+ case BOTTOM:
+ type = css_computed_margin_bottom(style,
+ &value, &unit);
+ break;
+ case LEFT:
+ type = css_computed_margin_left(style,
+ &value, &unit);
break;
}
+
+ if (type == CSS_MARGIN_SET) {
+ if (unit == CSS_UNIT_PCT) {
+ margin[i] = available_width *
+ FIXTOFLT(value) / 100;
+ } else {
+ margin[i] = FIXTOINT(nscss_len2px(value,
+ unit, style));
+ }
+ } else {
+ margin[i] = AUTO;
+ }
}
if (padding) {
- switch (style->padding[i].padding) {
- case CSS_PADDING_PERCENT:
- padding[i] = available_width *
- style->padding[i].value.
- percent / 100;
+ enum css_padding type;
+ css_fixed value = 0;
+ css_unit unit = CSS_UNIT_PX;
+
+ switch (i) {
+ case TOP:
+ type = css_computed_padding_top(style,
+ &value, &unit);
break;
- case CSS_PADDING_LENGTH:
- default:
- padding[i] = css_len2px(&style->padding[i].
- value.length, style);
+ case RIGHT:
+ type = css_computed_padding_right(style,
+ &value, &unit);
+ break;
+ case BOTTOM:
+ type = css_computed_padding_bottom(style,
+ &value, &unit);
break;
+ case LEFT:
+ type = css_computed_padding_left(style,
+ &value, &unit);
+ break;
+ }
+
+ if (unit == CSS_UNIT_PCT) {
+ padding[i] = available_width *
+ FIXTOFLT(value) / 100;
+ } else {
+ padding[i] = FIXTOINT(nscss_len2px(value, unit,
+ style));
}
}
- if (border) {
- if (style->border[i].style == CSS_BORDER_STYLE_HIDDEN ||
- style->border[i].style ==
- CSS_BORDER_STYLE_NONE)
+ /* Table cell borders are populated in table.c */
+ if (border && box->type != BOX_TABLE_CELL) {
+ enum css_border_width wtype;
+ enum css_border_style bstyle = CSS_BORDER_STYLE_NONE;
+ enum css_border_color bcolor =
+ CSS_BORDER_COLOR_TRANSPARENT;
+ css_color color = 0;
+ css_fixed value = 0;
+ css_unit unit = CSS_UNIT_PX;
+
+ switch (i) {
+ case TOP:
+ wtype = css_computed_border_top_width(style,
+ &value, &unit);
+ bstyle = css_computed_border_top_style(style);
+ bcolor = css_computed_border_top_color(style,
+ &color);
+ break;
+ case RIGHT:
+ wtype = css_computed_border_right_width(style,
+ &value, &unit);
+ bstyle = css_computed_border_right_style(style);
+ bcolor = css_computed_border_right_color(style,
+ &color);
+ break;
+ case BOTTOM:
+ wtype = css_computed_border_bottom_width(style,
+ &value, &unit);
+ bstyle = css_computed_border_bottom_style(
+ style);
+ bcolor = css_computed_border_bottom_color(style,
+ &color);
+ break;
+ case LEFT:
+ wtype = css_computed_border_left_width(style,
+ &value, &unit);
+ bstyle = css_computed_border_left_style(style);
+ bcolor = css_computed_border_left_color(style,
+ &color);
+ break;
+ }
+
+ border[i].style = bstyle;
+ border[i].color = bcolor;
+ border[i].c = color;
+
+ if (bstyle == CSS_BORDER_STYLE_HIDDEN ||
+ bstyle == CSS_BORDER_STYLE_NONE)
/* spec unclear: following Mozilla */
- border[i] = 0;
+ border[i].width = 0;
else
- border[i] = css_len2px(&style->border[i].
- width.value, style);
+ border[i].width = FIXTOINT(nscss_len2px(value,
+ unit, style));
+
+ /* Special case for border-collapse: make all borders
+ * on table/table-row-group/table-row zero width. */
+ if (css_computed_border_collapse(style) ==
+ CSS_BORDER_COLLAPSE_COLLAPSE &&
+ (box->type == BOX_TABLE ||
+ box->type == BOX_TABLE_ROW_GROUP ||
+ box->type == BOX_TABLE_ROW))
+ border[i].width = 0;
}
}
}
@@ -1435,7 +1597,7 @@ void layout_tweak_form_dimensions(struct box *box, bool percentage,
* \return y coordinate relative to ancestor box for floats
*/
-int layout_clear(struct box *fl, css_clear clear)
+int layout_clear(struct box *fl, enum css_clear clear)
{
int y = 0;
for (; fl; fl = fl->next_float) {
@@ -1522,13 +1684,17 @@ bool layout_inline_container(struct box *inline_container, int width,
has_text_children = false;
for (c = inline_container->children; c; c = c->next) {
bool is_pre = false;
- if (c->style)
- is_pre = (c->style->white_space ==
- CSS_WHITE_SPACE_PRE ||
- c->style->white_space ==
- CSS_WHITE_SPACE_PRE_LINE ||
- c->style->white_space ==
- CSS_WHITE_SPACE_PRE_WRAP);
+
+ if (c->style) {
+ enum css_white_space whitespace;
+
+ whitespace = css_computed_white_space(c->style);
+
+ is_pre = (whitespace == CSS_WHITE_SPACE_PRE ||
+ whitespace == CSS_WHITE_SPACE_PRE_LINE ||
+ whitespace == CSS_WHITE_SPACE_PRE_WRAP);
+ }
+
if ((!c->object && c->text && (c->length || is_pre)) ||
c->type == BOX_BR)
has_text_children = true;
@@ -1600,31 +1766,50 @@ void layout_minmax_inline_container(struct box *inline_container,
* Calculate line height from a style.
*/
-int line_height(struct css_style *style)
+int line_height(const css_computed_style *style)
{
- float font_len;
+ enum css_line_height lhtype;
+ css_fixed lhvalue = 0;
+ css_unit lhunit = CSS_UNIT_PX;
+ css_fixed line_height;
assert(style);
- assert(style->line_height.size == CSS_LINE_HEIGHT_LENGTH ||
- style->line_height.size == CSS_LINE_HEIGHT_ABSOLUTE ||
- style->line_height.size == CSS_LINE_HEIGHT_PERCENT);
- /* take account of minimum font size option */
- if ((font_len = css_len2px(&style->font_size.value.length, 0)) <
- option_font_min_size * css_screen_dpi / 720.0)
- font_len = option_font_min_size * css_screen_dpi / 720.0;
+ lhtype = css_computed_line_height(style, &lhvalue, &lhunit);
+ if (lhtype == CSS_LINE_HEIGHT_NORMAL) {
+ /* Normal => use a constant of 1.3 * font-size */
+ lhvalue = FLTTOFIX(1.3);
+ lhtype = CSS_LINE_HEIGHT_NUMBER;
+ }
- switch (style->line_height.size) {
- case CSS_LINE_HEIGHT_LENGTH:
- return css_len2px(&style->line_height.value.length, style);
+ if (lhtype == CSS_LINE_HEIGHT_NUMBER ||
+ lhunit == CSS_UNIT_PCT) {
+ css_fixed fs = 0, px_fs;
+ css_unit fs_unit = CSS_UNIT_PX;
- case CSS_LINE_HEIGHT_ABSOLUTE:
- return style->line_height.value.absolute * font_len;
+ css_computed_font_size(style, &fs, &fs_unit);
- case CSS_LINE_HEIGHT_PERCENT:
- default:
- return style->line_height.value.percent * font_len / 100.0;
+ /* Convert to points */
+ fs = nscss_len2pt(fs, fs_unit);
+ fs_unit = CSS_UNIT_PT;
+
+ /* Clamp to configured minimum */
+ if (fs < FDIVI(INTTOFIX(option_font_min_size), 10))
+ fs = FDIVI(INTTOFIX(option_font_min_size), 10);
+
+ px_fs = nscss_len2px(fs, fs_unit, style);
+
+ if (lhtype == CSS_LINE_HEIGHT_NUMBER)
+ line_height = FMUL(lhvalue, px_fs);
+ else
+ line_height = FDIVI(FMUL(lhvalue, px_fs), 100);
+ } else {
+ assert(lhunit != CSS_UNIT_PCT);
+
+ line_height = nscss_len2px(lhvalue, lhunit, style);
}
+
+ return FIXTOINT(line_height);
}
@@ -1666,13 +1851,9 @@ bool layout_line(struct box *first, int *width, int *y,
int space_before = 0, space_after = 0;
unsigned int inline_count = 0;
unsigned int i;
- struct css_length gadget_size; /* Checkbox / radio buttons */
const struct font_functions *font_func = content->data.html.font_func;
plot_font_style_t fstyle;
- gadget_size.unit = CSS_UNIT_EM;
- gadget_size.value = 1;
-
LOG(("first %p, first->text '%.*s', width %i, y %i, cx %i, cy %i",
first, (int) first->length, first->text, *width,
*y, cx, cy));
@@ -1706,6 +1887,11 @@ bool layout_line(struct box *first, int *width, int *y,
* keep in sync with the loop in layout_minmax_line() */
LOG(("x0 %i, x1 %i, x1 - x0 %i", x0, x1, x1 - x0));
for (x = 0, b = first; x <= x1 - x0 && b != 0; b = b->next) {
+ enum css_width wtype;
+ enum css_height htype;
+ css_fixed value = 0;
+ css_unit unit = CSS_UNIT_PX;
+
assert(b->type == BOX_INLINE || b->type == BOX_INLINE_BLOCK ||
b->type == BOX_FLOAT_LEFT ||
b->type == BOX_FLOAT_RIGHT ||
@@ -1719,8 +1905,10 @@ bool layout_line(struct box *first, int *width, int *y,
if (b->type == BOX_FLOAT_LEFT || b->type == BOX_FLOAT_RIGHT)
continue;
if (b->type == BOX_INLINE_BLOCK &&
- (b->style->position == CSS_POSITION_ABSOLUTE ||
- b->style->position == CSS_POSITION_FIXED))
+ (css_computed_position(b->style) ==
+ CSS_POSITION_ABSOLUTE ||
+ css_computed_position(b->style) ==
+ CSS_POSITION_FIXED))
continue;
assert(b->style != NULL);
@@ -1732,13 +1920,15 @@ bool layout_line(struct box *first, int *width, int *y,
if (b->max_width != UNKNOWN_WIDTH)
if (!layout_float(b, *width, content))
return false;
- h = b->border[TOP] + b->padding[TOP] + b->height +
- b->padding[BOTTOM] + b->border[BOTTOM];
+ h = b->border[TOP].width + b->padding[TOP] + b->height +
+ b->padding[BOTTOM] +
+ b->border[BOTTOM].width;
if (height < h)
height = h;
- x += b->margin[LEFT] + b->border[LEFT] +
+ x += b->margin[LEFT] + b->border[LEFT].width +
b->padding[LEFT] + b->width +
- b->padding[RIGHT] + b->border[RIGHT] +
+ b->padding[RIGHT] +
+ b->border[RIGHT].width +
b->margin[RIGHT];
space_after = 0;
continue;
@@ -1751,7 +1941,7 @@ bool layout_line(struct box *first, int *width, int *y,
for (i = 0; i != 4; i++)
if (b->margin[i] == AUTO)
b->margin[i] = 0;
- x += b->margin[LEFT] + b->border[LEFT] +
+ x += b->margin[LEFT] + b->border[LEFT].width +
b->padding[LEFT];
if (b->inline_end) {
b->inline_end->margin[RIGHT] = b->margin[RIGHT];
@@ -1760,7 +1950,8 @@ bool layout_line(struct box *first, int *width, int *y,
b->inline_end->border[RIGHT] =
b->border[RIGHT];
} else {
- x += b->padding[RIGHT] + b->border[RIGHT] +
+ x += b->padding[RIGHT] +
+ b->border[RIGHT].width +
b->margin[RIGHT];
}
} else if (b->type == BOX_INLINE_END) {
@@ -1772,7 +1963,7 @@ bool layout_line(struct box *first, int *width, int *y,
} else {
space_after = 0;
}
- x += b->padding[RIGHT] + b->border[RIGHT] +
+ x += b->padding[RIGHT] + b->border[RIGHT].width +
b->margin[RIGHT];
continue;
}
@@ -1838,32 +2029,27 @@ bool layout_line(struct box *first, int *width, int *y,
assert(b->style);
/* calculate box width */
- switch (b->style->width.width) {
- case CSS_WIDTH_LENGTH:
- b->width = css_len2px(&b->style->width.value.length,
- b->style);
- break;
- case CSS_WIDTH_PERCENT:
- b->width = *width * b->style->width.value.percent / 100;
- break;
- case CSS_WIDTH_AUTO:
- default:
+ wtype = css_computed_width(b->style, &value, &unit);
+ if (wtype == CSS_WIDTH_SET) {
+ if (unit == CSS_UNIT_PCT) {
+ b->width = *width * FIXTOFLT(value) / 100;
+ } else {
+ b->width = FIXTOINT(nscss_len2px(value, unit,
+ b->style));
+ }
+ } else {
b->width = AUTO;
- break;
}
/* height */
- switch (b->style->height.height) {
- case CSS_HEIGHT_LENGTH:
- b->height = css_len2px(&b->style->height.value.length,
- b->style);
- break;
- case CSS_HEIGHT_AUTO:
- default:
+ htype = css_computed_height(b->style, &value, &unit);
+ if (htype == CSS_HEIGHT_SET) {
+ b->height = FIXTOINT(nscss_len2px(value, unit,
+ b->style));
+ } else {
b->height = AUTO;
- break;
}
-
+
if (b->object) {
if (b->width == AUTO && b->height == AUTO) {
b->width = b->object->width;
@@ -1886,15 +2072,20 @@ bool layout_line(struct box *first, int *width, int *y,
} else {
/* form control with no object */
if (b->width == AUTO)
- b->width = css_len2px(&gadget_size, b->style);
+ b->width = FIXTOINT(nscss_len2px(INTTOFIX(1),
+ CSS_UNIT_EM, b->style));
if (b->height == AUTO)
- b->height = css_len2px(&gadget_size, b->style);
+ b->height = FIXTOINT(nscss_len2px(INTTOFIX(1),
+ CSS_UNIT_EM, b->style));
}
if (b->object && b->object->type == CONTENT_HTML &&
b->width != b->object->available_width) {
+ htype = css_computed_height(b->style, &value, &unit);
+
content_reformat(b->object, b->width, b->height);
- if (b->style->height.height == CSS_HEIGHT_AUTO)
+
+ if (htype == CSS_HEIGHT_AUTO)
b->height = b->object->height;
}
@@ -1925,8 +2116,10 @@ bool layout_line(struct box *first, int *width, int *y,
for (x = x_previous = 0, b = first; x <= x1 - x0 && b; b = b->next) {
LOG(("pass 2: b %p, x %i", b, x));
if (b->type == BOX_INLINE_BLOCK &&
- (b->style->position == CSS_POSITION_ABSOLUTE ||
- b->style->position == CSS_POSITION_FIXED)) {
+ (css_computed_position(b->style) ==
+ CSS_POSITION_ABSOLUTE ||
+ css_computed_position(b->style) ==
+ CSS_POSITION_FIXED)) {
b->x = x + space_after;
} else if (b->type == BOX_INLINE ||
@@ -1941,16 +2134,17 @@ bool layout_line(struct box *first, int *width, int *y,
if ((b->type == BOX_INLINE && !b->inline_end) ||
b->type == BOX_INLINE_BLOCK) {
- b->x += b->margin[LEFT] + b->border[LEFT];
+ b->x += b->margin[LEFT] + b->border[LEFT].width;
x = b->x + b->padding[LEFT] + b->width +
b->padding[RIGHT] +
- b->border[RIGHT] +
+ b->border[RIGHT].width +
b->margin[RIGHT];
} else if (b->type == BOX_INLINE) {
- b->x += b->margin[LEFT] + b->border[LEFT];
+ b->x += b->margin[LEFT] + b->border[LEFT].width;
x = b->x + b->padding[LEFT] + b->width;
} else if (b->type == BOX_INLINE_END) {
- x += b->padding[RIGHT] + b->border[RIGHT] +
+ x += b->padding[RIGHT] +
+ b->border[RIGHT].width +
b->margin[RIGHT];
} else {
x += b->width;
@@ -1991,27 +2185,33 @@ bool layout_line(struct box *first, int *width, int *y,
if (!layout_float(d, *width, content))
return false;
- LOG(("%p : %d %d", d, d->margin[TOP], d->border[TOP]));
- d->x = d->margin[LEFT] + d->border[LEFT];
- d->y = d->margin[TOP] + d->border[TOP];
- b->width = d->margin[LEFT] + d->border[LEFT] +
+ LOG(("%p : %d %d", d, d->margin[TOP],
+ d->border[TOP].width));
+ d->x = d->margin[LEFT] + d->border[LEFT].width;
+ d->y = d->margin[TOP] + d->border[TOP].width;
+ b->width = d->margin[LEFT] + d->border[LEFT].width +
d->padding[LEFT] + d->width +
- d->padding[RIGHT] + d->border[RIGHT] +
+ d->padding[RIGHT] +
+ d->border[RIGHT].width +
d->margin[RIGHT];
- b->height = d->margin[TOP] + d->border[TOP] +
+ b->height = d->margin[TOP] + d->border[TOP].width +
d->padding[TOP] + d->height +
- d->padding[BOTTOM] + d->border[BOTTOM] +
+ d->padding[BOTTOM] +
+ d->border[BOTTOM].width +
d->margin[BOTTOM];
if (b->width > (x1 - x0) - x)
place_below = true;
- if (d->style && (d->style->clear == CSS_CLEAR_NONE ||
- (d->style->clear == CSS_CLEAR_LEFT &&
- left == 0) ||
- (d->style->clear == CSS_CLEAR_RIGHT &&
- right == 0) ||
- (d->style->clear == CSS_CLEAR_BOTH &&
- left == 0 && right == 0)) &&
+ if (d->style && (css_computed_clear(d->style) ==
+ CSS_CLEAR_NONE ||
+ (css_computed_clear(d->style) ==
+ CSS_CLEAR_LEFT && left == 0) ||
+ (css_computed_clear(d->style) ==
+ CSS_CLEAR_RIGHT &&
+ right == 0) ||
+ (css_computed_clear(d->style) ==
+ CSS_CLEAR_BOTH &&
+ left == 0 && right == 0)) &&
(!place_below ||
(left == 0 && right == 0 && x == 0)) &&
cy >= cont->clear_level) {
@@ -2044,7 +2244,7 @@ bool layout_line(struct box *first, int *width, int *y,
place_float_below(b, *width,
cx, fy + height, cont);
- if (d->style && d->style->clear !=
+ if (d->style && css_computed_clear(d->style) !=
CSS_CLEAR_NONE) {
/* to be cleared below existing
* floats */
@@ -2054,7 +2254,7 @@ bool layout_line(struct box *first, int *width, int *y,
b->x = cx + *width - b->width;
fy = layout_clear(cont->float_children,
- d->style->clear);
+ css_computed_clear(d->style));
if (fy > cont->clear_level)
cont->clear_level = fy;
if (b->y < fy)
@@ -2221,7 +2421,7 @@ bool layout_line(struct box *first, int *width, int *y,
}
/* set positions */
- switch (first->parent->parent->style->text_align) {
+ switch (css_computed_text_align(first->parent->parent->style)) {
case CSS_TEXT_ALIGN_RIGHT:
x0 = x1 - x;
break;
@@ -2243,20 +2443,24 @@ bool layout_line(struct box *first, int *width, int *y,
}
if ((d->type == BOX_INLINE && (d->object || d->gadget)) ||
d->type == BOX_INLINE_BLOCK) {
- d->y = *y + d->border[TOP] + d->margin[TOP];
+ d->y = *y + d->border[TOP].width + d->margin[TOP];
}
if (d->type == BOX_INLINE_BLOCK) {
d->x += x0;
}
if (d->type == BOX_INLINE_BLOCK &&
- (d->style->position == CSS_POSITION_ABSOLUTE ||
- d->style->position == CSS_POSITION_FIXED))
+ (css_computed_position(d->style) ==
+ CSS_POSITION_ABSOLUTE ||
+ css_computed_position(d->style) ==
+ CSS_POSITION_FIXED))
continue;
if ((d->type == BOX_INLINE && (d->object || d->gadget)) ||
d->type == BOX_INLINE_BLOCK) {
- h = d->margin[TOP] + d->border[TOP] + d->padding[TOP] +
- d->height + d->padding[BOTTOM] +
- d->border[BOTTOM] + d->margin[BOTTOM];
+ h = d->margin[TOP] + d->border[TOP].width +
+ d->padding[TOP] + d->height +
+ d->padding[BOTTOM] +
+ d->border[BOTTOM].width +
+ d->margin[BOTTOM];
if (used_height < h)
used_height = h;
}
@@ -2279,9 +2483,9 @@ bool layout_line(struct box *first, int *width, int *y,
}
/* handle clearance for br */
- if (br_box && br_box->style->clear != CSS_CLEAR_NONE) {
+ if (br_box && css_computed_clear(br_box->style) != CSS_CLEAR_NONE) {
int clear_y = layout_clear(cont->float_children,
- br_box->style->clear);
+ css_computed_clear(br_box->style));
if (used_height < clear_y - cy)
used_height = clear_y - cy;
}
@@ -2312,14 +2516,15 @@ struct box *layout_minmax_line(struct box *first,
float frac;
size_t i, j;
struct box *b;
- struct css_length gadget_size; /* Checkbox / radio buttons */
plot_font_style_t fstyle;
- gadget_size.unit = CSS_UNIT_EM;
- gadget_size.value = 1;
-
/* corresponds to the pass 1 loop in layout_line() */
for (b = first; b; b = b->next) {
+ enum css_width wtype;
+ enum css_height htype;
+ css_fixed value = 0;
+ css_unit unit = CSS_UNIT_PX;
+
assert(b->type == BOX_INLINE || b->type == BOX_INLINE_BLOCK ||
b->type == BOX_FLOAT_LEFT ||
b->type == BOX_FLOAT_RIGHT ||
@@ -2444,34 +2649,28 @@ struct box *layout_minmax_line(struct box *first,
assert(b->style);
/* calculate box width */
- switch (b->style->width.width) {
- case CSS_WIDTH_LENGTH:
- width = css_len2px(&b->style->width.value.length,
- b->style);
- if (width < 0)
- width = 0;
- break;
- case CSS_WIDTH_PERCENT:
- /*
- b->width = width * b->style->width.value.percent / 100;
- break;
- */
- case CSS_WIDTH_AUTO:
- default:
+ wtype = css_computed_width(b->style, &value, &unit);
+ if (wtype == CSS_WIDTH_SET) {
+ if (unit == CSS_UNIT_PCT) {
+ /*
+ b->width = width * FIXTOFLT(value) / 100
+ */
+ } else {
+ width = FIXTOINT(nscss_len2px(value, unit,
+ b->style));
+ if (width < 0)
+ width = 0;
+ }
+ } else {
width = AUTO;
- break;
}
/* height */
- switch (b->style->height.height) {
- case CSS_HEIGHT_LENGTH:
- height = css_len2px(&b->style->height.value.length,
- b->style);
- break;
- case CSS_HEIGHT_AUTO:
- default:
+ htype = css_computed_height(b->style, &value, &unit);
+ if (htype == CSS_HEIGHT_SET) {
+ height = FIXTOINT(nscss_len2px(value, unit, b->style));
+ } else {
height = AUTO;
- break;
}
if (b->object) {
@@ -2494,7 +2693,8 @@ struct box *layout_minmax_line(struct box *first,
} else {
/* form control with no object */
if (width == AUTO)
- width = css_len2px(&gadget_size, b->style);
+ width = FIXTOINT(nscss_len2px(INTTOFIX(1),
+ CSS_UNIT_EM, b->style));
}
if (min < width)
@@ -2522,15 +2722,17 @@ struct box *layout_minmax_line(struct box *first,
* \return length of indent
*/
-int layout_text_indent(struct css_style *style, int width)
+int layout_text_indent(const css_computed_style *style, int width)
{
- switch (style->text_indent.size) {
- case CSS_TEXT_INDENT_LENGTH:
- return css_len2px(&style->text_indent.value.length, style);
- case CSS_TEXT_INDENT_PERCENT:
- return width * style->text_indent.value.percent / 100;
- default:
- return 0;
+ css_fixed value = 0;
+ css_unit unit = CSS_UNIT_PX;
+
+ css_computed_text_indent(style, &value, &unit);
+
+ if (unit == CSS_UNIT_PCT) {
+ return width * FIXTOFLT(value) / 100;
+ } else {
+ return FIXTOINT(nscss_len2px(value, unit, style));
}
}
@@ -2644,7 +2846,11 @@ bool layout_table(struct box *table, int available_width,
struct box *row_group;
struct box **row_span_cell;
struct column *col;
- struct css_style *style = table->style;
+ const css_computed_style *style = table->style;
+ enum css_width wtype;
+ enum css_height htype;
+ css_fixed value = 0;
+ css_unit unit = CSS_UNIT_PX;
assert(table->type == BOX_TABLE);
assert(style);
@@ -2676,12 +2882,13 @@ bool layout_table(struct box *table, int available_width,
for (row = row_group->children; row; row = row->next) {
for (c = row->children; c; c = c->next) {
assert(c->style);
+ table_used_border_for_cell(c);
layout_find_dimensions(available_width, -1,
c, c->style, 0, 0, 0, 0, 0,
c->padding, c->border);
- if (c->style->overflow ==
+ if (css_computed_overflow(c->style) ==
CSS_OVERFLOW_SCROLL ||
- c->style->overflow ==
+ css_computed_overflow(c->style) ==
CSS_OVERFLOW_AUTO) {
c->padding[RIGHT] += SCROLLBAR_WIDTH;
c->padding[BOTTOM] += SCROLLBAR_WIDTH;
@@ -2691,92 +2898,104 @@ bool layout_table(struct box *table, int available_width,
}
/* border-spacing is used in the separated borders model */
- if (style->border_collapse == CSS_BORDER_COLLAPSE_SEPARATE) {
- border_spacing_h = css_len2px(&style->border_spacing.horz,
- style);
- border_spacing_v = css_len2px(&style->border_spacing.vert,
- style);
- }
+ if (css_computed_border_collapse(style) ==
+ CSS_BORDER_COLLAPSE_SEPARATE) {
+ css_fixed h = 0, v = 0;
+ css_unit hu = CSS_UNIT_PX, vu = CSS_UNIT_PX;
- /* find specified table width, or available width if auto-width */
- switch (style->width.width) {
- case CSS_WIDTH_LENGTH:
- table_width = css_len2px(&style->width.value.length, style);
+ css_computed_border_spacing(style, &h, &hu, &v, &vu);
- /* specified width includes border */
- table_width -= table->border[LEFT] + table->border[RIGHT];
- table_width = table_width < 0 ? 0 : table_width;
+ border_spacing_h = FIXTOINT(nscss_len2px(h, hu, style));
+ border_spacing_v = FIXTOINT(nscss_len2px(v, vu, style));
+ }
- auto_width = table_width;
- break;
- case CSS_WIDTH_PERCENT:
- table_width = ceil(available_width *
- style->width.value.percent / 100);
+ /* find specified table width, or available width if auto-width */
+ wtype = css_computed_width(style, &value, &unit);
+ if (wtype == CSS_WIDTH_SET) {
+ if (unit == CSS_UNIT_PCT) {
+ table_width = ceil(available_width *
+ FIXTOFLT(value) / 100);
+ } else {
+ table_width =
+ FIXTOINT(nscss_len2px(value, unit, style));
+ }
/* specified width includes border */
- table_width -= table->border[LEFT] + table->border[RIGHT];
+ table_width -= table->border[LEFT].width +
+ table->border[RIGHT].width;
table_width = table_width < 0 ? 0 : table_width;
auto_width = table_width;
- break;
- case CSS_WIDTH_AUTO:
- default:
+ } else {
table_width = AUTO;
auto_width = available_width -
((table->margin[LEFT] == AUTO ? 0 :
table->margin[LEFT]) +
- table->border[LEFT] +
+ table->border[LEFT].width +
table->padding[LEFT] +
table->padding[RIGHT] +
- table->border[RIGHT] +
+ table->border[RIGHT].width +
(table->margin[RIGHT] == AUTO ? 0 :
table->margin[RIGHT]));
- break;
}
/* Find any table height specified within CSS/HTML */
- if (style->height.height == CSS_HEIGHT_LENGTH) {
- /* This is the minimum height for the table (see 17.5.3) */
- min_height = css_len2px(&style->height.value.length, style);
- } else if (style->height.height == CSS_HEIGHT_PERCENT) {
- /* This is the minimum height for the table (see 17.5.3) */
- if (table->style->position == CSS_POSITION_ABSOLUTE) {
- /* Table is absolutely positioned */
- assert(table->float_container);
- containing_block = table->float_container;
- } else if (table->float_container &&
- table->style->position !=
- CSS_POSITION_ABSOLUTE &&
- (table->style->float_ ==
- CSS_FLOAT_LEFT ||
- table->style->float_ ==
- CSS_FLOAT_RIGHT)) {
- /* Table is a float */
- assert(table->parent && table->parent->parent &&
- table->parent->parent->parent);
- containing_block = table->parent->parent->parent;
- } else if (table->parent && table->parent->type !=
- BOX_INLINE_CONTAINER) {
- /* Table is a block level element */
- containing_block = table->parent;
- } else if (table->parent && table->parent->type ==
- BOX_INLINE_CONTAINER) {
- /* Table is an inline block */
- assert(table->parent->parent);
- containing_block = table->parent->parent;
- }
- if (containing_block && containing_block->height != AUTO &&
- (table->style->position ==
- CSS_POSITION_ABSOLUTE ||
- (containing_block->style->height.height ==
- CSS_HEIGHT_LENGTH ||
- containing_block->style->height.height ==
- CSS_HEIGHT_PERCENT))) {
- /* Table is absolutely positioned or its
- * containing block has a valid specified
- * height. (CSS 2.1 Section 10.5) */
- min_height = style->height.value.percent *
+ htype = css_computed_height(style, &value, &unit);
+ if (htype == CSS_HEIGHT_SET) {
+ if (unit == CSS_UNIT_PCT) {
+ /* This is the minimum height for the table
+ * (see 17.5.3) */
+ if (css_computed_position(table->style) ==
+ CSS_POSITION_ABSOLUTE) {
+ /* Table is absolutely positioned */
+ assert(table->float_container);
+ containing_block = table->float_container;
+ } else if (table->float_container &&
+ css_computed_position(table->style) !=
+ CSS_POSITION_ABSOLUTE &&
+ (css_computed_float(table->style) ==
+ CSS_FLOAT_LEFT ||
+ css_computed_float(table->style) ==
+ CSS_FLOAT_RIGHT)) {
+ /* Table is a float */
+ assert(table->parent && table->parent->parent &&
+ table->parent->parent->parent);
+ containing_block =
+ table->parent->parent->parent;
+ } else if (table->parent && table->parent->type !=
+ BOX_INLINE_CONTAINER) {
+ /* Table is a block level element */
+ containing_block = table->parent;
+ } else if (table->parent && table->parent->type ==
+ BOX_INLINE_CONTAINER) {
+ /* Table is an inline block */
+ assert(table->parent->parent);
+ containing_block = table->parent->parent;
+ }
+
+ if (containing_block) {
+ css_fixed ignored = 0;
+
+ htype = css_computed_height(
+ containing_block->style,
+ &ignored, &unit);
+ }
+
+ if (containing_block &&
+ containing_block->height != AUTO &&
+ (css_computed_position(table->style) ==
+ CSS_POSITION_ABSOLUTE ||
+ htype == CSS_HEIGHT_SET)) {
+ /* Table is absolutely positioned or its
+ * containing block has a valid specified
+ * height. (CSS 2.1 Section 10.5) */
+ min_height = FIXTOFLT(value) *
containing_block->height / 100;
+ }
+ } else {
+ /* This is the minimum height for the table
+ * (see 17.5.3) */
+ min_height = FIXTOINT(nscss_len2px(value, unit, style));
}
}
@@ -2950,20 +3169,21 @@ bool layout_table(struct box *table, int available_width,
int row_group_height = 0;
for (row = row_group->children; row; row = row->next) {
int row_height = 0;
- if (row->style->height.height == CSS_HEIGHT_LENGTH) {
- row_height = (int) css_len2px(&row->style->
- height.value.length,
- row->style);
+
+ htype = css_computed_height(row->style, &value, &unit);
+ if (htype == CSS_HEIGHT_SET && unit != CSS_UNIT_PCT) {
+ row_height = FIXTOINT(nscss_len2px(value, unit,
+ row->style));
}
for (c = row->children; c; c = c->next) {
assert(c->style);
c->width = xs[c->start_column + c->columns] -
xs[c->start_column] -
border_spacing_h -
- c->border[LEFT] -
+ c->border[LEFT].width -
c->padding[LEFT] -
c->padding[RIGHT] -
- c->border[RIGHT];
+ c->border[RIGHT].width;
c->float_children = 0;
c->height = AUTO;
@@ -2980,13 +3200,17 @@ bool layout_table(struct box *table, int available_width,
* until after vertical alignment is complete */
c->descendant_y0 = c->height;
c->descendant_y1 = c->padding[BOTTOM];
- if (c->style->height.height ==
- CSS_HEIGHT_LENGTH) {
+
+ htype = css_computed_height(c->style,
+ &value, &unit);
+
+ if (htype == CSS_HEIGHT_SET &&
+ unit != CSS_UNIT_PCT) {
/* some sites use height="1" or similar
* to attempt to make cells as small as
* possible, so treat it as a minimum */
- int h = (int) css_len2px(&c->style->
- height.value.length, c->style);
+ int h = FIXTOINT(nscss_len2px(value,
+ unit, c->style));
if (c->height < h)
c->height = h;
}
@@ -2994,24 +3218,25 @@ bool layout_table(struct box *table, int available_width,
*/
if (c->height < row_height)
c->height = row_height;
- c->x = xs[c->start_column] + c->border[LEFT];
- c->y = c->border[TOP];
+ c->x = xs[c->start_column] +
+ c->border[LEFT].width;
+ c->y = c->border[TOP].width;
for (i = 0; i != c->columns; i++) {
row_span[c->start_column + i] = c->rows;
excess_y[c->start_column + i] =
- c->border[TOP] +
+ c->border[TOP].width +
c->padding[TOP] +
c->height +
c->padding[BOTTOM] +
- c->border[BOTTOM];
+ c->border[BOTTOM].width;
row_span_cell[c->start_column + i] = 0;
}
row_span_cell[c->start_column] = c;
c->padding[BOTTOM] = -border_spacing_v -
- c->border[TOP] -
+ c->border[TOP].width -
c->padding[TOP] -
c->height -
- c->border[BOTTOM];
+ c->border[BOTTOM].width;
}
for (i = 0; i != columns; i++)
if (row_span[i] != 0)
@@ -3064,19 +3289,24 @@ bool layout_table(struct box *table, int available_width,
row_group = row_group->next) {
for (row = row_group->children; row; row = row->next) {
for (c = row->children; c; c = c->next) {
+ enum css_vertical_align vertical_align;
+
/* unextended bottom padding is in
* c->descendant_y1, and unextended
* cell height is in c->descendant_y0 */
spare_height = (c->padding[BOTTOM] -
c->descendant_y1) +
(c->height - c->descendant_y0);
- switch (c->style->vertical_align.type) {
+
+ vertical_align = css_computed_vertical_align(
+ c->style, &value, &unit);
+
+ switch (vertical_align) {
case CSS_VERTICAL_ALIGN_SUB:
case CSS_VERTICAL_ALIGN_SUPER:
case CSS_VERTICAL_ALIGN_TEXT_TOP:
case CSS_VERTICAL_ALIGN_TEXT_BOTTOM:
- case CSS_VERTICAL_ALIGN_LENGTH:
- case CSS_VERTICAL_ALIGN_PERCENT:
+ case CSS_VERTICAL_ALIGN_SET:
case CSS_VERTICAL_ALIGN_BASELINE:
/* todo: baseline alignment, for now
* just use ALIGN_TOP */
@@ -3094,7 +3324,6 @@ bool layout_table(struct box *table, int available_width,
layout_move_children(c, 0,
spare_height);
break;
- case CSS_VERTICAL_ALIGN_NOT_SET:
case CSS_VERTICAL_ALIGN_INHERIT:
assert(0);
break;
@@ -3134,6 +3363,9 @@ void layout_minmax_table(struct box *table,
float extra_frac = 0;
struct column *col = table->col;
struct box *row_group, *row, *cell;
+ enum css_width wtype;
+ css_fixed value = 0;
+ css_unit unit = CSS_UNIT_PX;
/* check if the widths have already been calculated */
if (table->max_width != UNKNOWN_MAX_WIDTH)
@@ -3148,9 +3380,15 @@ void layout_minmax_table(struct box *table,
}
/* border-spacing is used in the separated borders model */
- if (table->style->border_collapse == CSS_BORDER_COLLAPSE_SEPARATE)
- border_spacing_h = css_len2px(&table->style->
- border_spacing.horz, table->style);
+ if (css_computed_border_collapse(table->style) ==
+ CSS_BORDER_COLLAPSE_SEPARATE) {
+ css_fixed h = 0, v = 0;
+ css_unit hu = CSS_UNIT_PX, vu = CSS_UNIT_PX;
+
+ css_computed_border_spacing(table->style, &h, &hu, &v, &vu);
+
+ border_spacing_h = FIXTOINT(nscss_len2px(h, hu, table->style));
+ }
/* 1st pass: consider cells with colspan 1 only */
for (row_group = table->children; row_group; row_group =row_group->next)
@@ -3249,9 +3487,9 @@ void layout_minmax_table(struct box *table,
}
/* fixed width takes priority, unless it is too narrow */
- if (table->style->width.width == CSS_WIDTH_LENGTH) {
- int width = css_len2px(&table->style->width.value.length,
- table->style);
+ wtype = css_computed_width(table->style, &value, &unit);
+ if (wtype == CSS_WIDTH_SET && unit != CSS_UNIT_PCT) {
+ int width = FIXTOINT(nscss_len2px(value, unit, table->style));
if (table_min < width)
table_min = width;
if (table_max < width)
@@ -3309,35 +3547,77 @@ void layout_move_children(struct box *box, int x, int y)
* \param frac increased by sum of fractional margin and padding
*/
-void calculate_mbp_width(struct css_style *style, unsigned int side,
+void calculate_mbp_width(const css_computed_style *style, unsigned int side,
bool margin, bool border, bool padding,
int *fixed, float *frac)
{
+ typedef uint8_t (*len_func)(const css_computed_style *style,
+ css_fixed *length, css_unit *unit);
+
+ static len_func margin_funcs[4] = {
+ css_computed_margin_top,
+ css_computed_margin_right,
+ css_computed_margin_bottom,
+ css_computed_margin_left
+ };
+ static len_func padding_funcs[4] = {
+ css_computed_padding_top,
+ css_computed_padding_right,
+ css_computed_padding_bottom,
+ css_computed_padding_left
+ };
+ static struct {
+ len_func width;
+ uint8_t (*style)(const css_computed_style *style);
+ } border_funcs[4] = {
+ { css_computed_border_top_width,
+ css_computed_border_top_style },
+ { css_computed_border_right_width,
+ css_computed_border_right_style },
+ { css_computed_border_bottom_width,
+ css_computed_border_bottom_style },
+ { css_computed_border_left_width,
+ css_computed_border_left_style }
+ };
+
+ css_fixed value = 0;
+ css_unit unit = CSS_UNIT_PX;
+
assert(style);
/* margin */
if (margin) {
- if (style->margin[side].margin == CSS_MARGIN_LENGTH)
- *fixed += css_len2px(&style->margin[side].value.length,
- style);
- else if (style->margin[side].margin == CSS_MARGIN_PERCENT)
- *frac += style->margin[side].value.percent * 0.01;
+ enum css_margin type;
+
+ type = margin_funcs[side](style, &value, &unit);
+ if (type == CSS_MARGIN_SET) {
+ if (unit == CSS_UNIT_PCT) {
+ *frac += FIXTOFLT(value) * 0.01;
+ } else {
+ *fixed += FIXTOINT(nscss_len2px(value, unit,
+ style));
+ }
+ }
}
/* border */
if (border) {
- if (style->border[side].style != CSS_BORDER_STYLE_NONE)
- *fixed += css_len2px(&style->border[side].width.value,
- style);
+ if (border_funcs[side].style(style) !=
+ CSS_BORDER_STYLE_NONE) {
+ border_funcs[side].width(style, &value, &unit);
+
+ *fixed += FIXTOINT(nscss_len2px(value, unit, style));
+ }
}
/* padding */
if (padding) {
- if (style->padding[side].padding == CSS_PADDING_LENGTH)
- *fixed += css_len2px(&style->padding[side].value.length,
- style);
- else if (style->padding[side].padding == CSS_PADDING_PERCENT)
- *frac += style->padding[side].value.percent * 0.01;
+ padding_funcs[side](style, &value, &unit);
+ if (unit == CSS_UNIT_PCT) {
+ *frac += FIXTOFLT(value) * 0.01;
+ } else {
+ *fixed += FIXTOINT(nscss_len2px(value, unit, style));
+ }
}
}
@@ -3424,7 +3704,8 @@ void layout_position_relative(struct box *root, struct box *fp, int fx, int fy)
continue;
/* If relatively positioned, get offsets */
- if (box->style && box->style->position == CSS_POSITION_RELATIVE)
+ if (box->style && css_computed_position(box->style) ==
+ CSS_POSITION_RELATIVE)
layout_compute_relative_offset(box, &x, &y);
else
x = y = 0;
@@ -3432,8 +3713,10 @@ void layout_position_relative(struct box *root, struct box *fp, int fx, int fy)
/* Adjust float coordinates.
* (note float x and y are relative to their block formatting
* context box and not their parent) */
- if (box->style && (box->style->float_ == CSS_FLOAT_LEFT ||
- box->style->float_ == CSS_FLOAT_RIGHT) &&
+ if (box->style && (css_computed_float(box->style) ==
+ CSS_FLOAT_LEFT ||
+ css_computed_float(box->style) ==
+ CSS_FLOAT_RIGHT) &&
(fx != 0 || fy != 0)) {
/* box is a float and there is a float offset to
* apply */
@@ -3463,7 +3746,8 @@ void layout_position_relative(struct box *root, struct box *fp, int fx, int fy)
/* Ignore things we're not interested in. */
if (!box->style || (box->style &&
- box->style->position != CSS_POSITION_RELATIVE))
+ css_computed_position(box->style) !=
+ CSS_POSITION_RELATIVE))
continue;
box->x += x;
@@ -3498,10 +3782,12 @@ void layout_compute_relative_offset(struct box *box, int *x, int *y)
struct box *containing_block;
assert(box && box->parent && box->style &&
- box->style->position == CSS_POSITION_RELATIVE);
+ css_computed_position(box->style) ==
+ CSS_POSITION_RELATIVE);
- if (box->float_container && (box->style->float_ == CSS_FLOAT_LEFT ||
- box->style->float_ == CSS_FLOAT_RIGHT)) {
+ if (box->float_container && (css_computed_float(box->style) ==
+ CSS_FLOAT_LEFT ||
+ css_computed_float(box->style) == CSS_FLOAT_RIGHT)) {
containing_block = box->float_container;
} else {
containing_block = box->parent;
@@ -3522,11 +3808,12 @@ void layout_compute_relative_offset(struct box *box, int *x, int *y)
/* over constrained => examine direction property
* of containing block */
if (containing_block->style) {
- if (box->parent->style->direction ==
+ if (css_computed_direction(containing_block->style) ==
CSS_DIRECTION_LTR)
/* left wins */
right = -left;
- else if (box->parent->style->direction ==
+ else if (css_computed_direction(
+ containing_block->style) ==
CSS_DIRECTION_RTL)
/* right wins */
left = -right;
@@ -3576,21 +3863,25 @@ bool layout_position_absolute(struct box *box,
for (c = box->children; c; c = c->next) {
if ((c->type == BOX_BLOCK || c->type == BOX_TABLE ||
c->type == BOX_INLINE_BLOCK) &&
- (c->style->position == CSS_POSITION_ABSOLUTE ||
- c->style->position == CSS_POSITION_FIXED)) {
+ (css_computed_position(c->style) ==
+ CSS_POSITION_ABSOLUTE ||
+ css_computed_position(c->style) ==
+ CSS_POSITION_FIXED)) {
if (!layout_absolute(c, containing_block,
cx, cy, content))
return false;
if (!layout_position_absolute(c, c, 0, 0, content))
return false;
- } else if (c->style &&
- c->style->position == CSS_POSITION_RELATIVE) {
+ } else if (c->style && css_computed_position(c->style) ==
+ CSS_POSITION_RELATIVE) {
if (!layout_position_absolute(c, c, 0, 0, content))
return false;
} else {
int px, py;
- if (c->style && (c->style->float_ == CSS_FLOAT_LEFT ||
- c->style->float_ == CSS_FLOAT_RIGHT)) {
+ if (c->style && (css_computed_float(c->style) ==
+ CSS_FLOAT_LEFT ||
+ css_computed_float(c->style) ==
+ CSS_FLOAT_RIGHT)) {
/* Float x/y coords are relative to nearest
* ansestor with float_children, rather than
* relative to parent. Need to get x/y relative
@@ -3639,7 +3930,7 @@ bool layout_absolute(struct box *box, struct box *containing_block,
int width, height, max_width, min_width;
int *margin = box->margin;
int *padding = box->padding;
- int *border = box->border;
+ struct box_border *border = box->border;
int available_width = containing_block->width;
int space;
@@ -3680,8 +3971,9 @@ bool layout_absolute(struct box *box, struct box *containing_block,
/* 10.3.7 */
LOG(("%i + %i + %i + %i + %i + %i + %i + %i + %i = %i",
- left, margin[LEFT], border[LEFT], padding[LEFT], width,
- padding[RIGHT], border[RIGHT], margin[RIGHT], right,
+ left, margin[LEFT], border[LEFT].width,
+ padding[LEFT], width, padding[RIGHT],
+ border[RIGHT].width, margin[RIGHT], right,
containing_block->width));
if (left == AUTO && width == AUTO && right == AUTO) {
if (margin[LEFT] == AUTO)
@@ -3692,19 +3984,19 @@ bool layout_absolute(struct box *box, struct box *containing_block,
width = min(max(box->min_width, available_width),
box->max_width);
- width -= box->margin[LEFT] + box->border[LEFT] +
+ width -= box->margin[LEFT] + box->border[LEFT].width +
box->padding[LEFT] + box->padding[RIGHT] +
- box->border[RIGHT] + box->margin[RIGHT];
+ box->border[RIGHT].width + box->margin[RIGHT];
/* Adjust for {min|max}-width */
if (max_width >= 0 && width > max_width) width = max_width;
if (min_width > 0 && width < min_width) width = min_width;
right = containing_block->width -
- left -
- margin[LEFT] - border[LEFT] - padding[LEFT] -
- width -
- padding[RIGHT] - border[RIGHT] - margin[RIGHT];
+ left -
+ margin[LEFT] - border[LEFT].width - padding[LEFT] -
+ width -
+ padding[RIGHT] - border[RIGHT].width - margin[RIGHT];
} else if (left != AUTO && width != AUTO && right != AUTO) {
/* Adjust for {min|max}-width */
@@ -3713,9 +4005,9 @@ bool layout_absolute(struct box *box, struct box *containing_block,
if (margin[LEFT] == AUTO && margin[RIGHT] == AUTO) {
space = containing_block->width -
- left - border[LEFT] -
+ left - border[LEFT].width -
padding[LEFT] - width - padding[RIGHT] -
- border[RIGHT] - right;
+ border[RIGHT].width - right;
if (space < 0) {
margin[LEFT] = 0;
margin[RIGHT] = space;
@@ -3724,19 +4016,22 @@ bool layout_absolute(struct box *box, struct box *containing_block,
}
} else if (margin[LEFT] == AUTO) {
margin[LEFT] = containing_block->width -
- left - border[LEFT] -
+ left - border[LEFT].width -
padding[LEFT] - width - padding[RIGHT] -
- border[RIGHT] - margin[RIGHT] - right;
+ border[RIGHT].width - margin[RIGHT] -
+ right;
} else if (margin[RIGHT] == AUTO) {
margin[RIGHT] = containing_block->width -
- left - margin[LEFT] - border[LEFT] -
+ left - margin[LEFT] -
+ border[LEFT].width -
padding[LEFT] - width - padding[RIGHT] -
- border[RIGHT] - right;
+ border[RIGHT].width - right;
} else {
right = containing_block->width -
- left - margin[LEFT] - border[LEFT] -
+ left - margin[LEFT] -
+ border[LEFT].width -
padding[LEFT] - width - padding[RIGHT] -
- border[RIGHT] - margin[RIGHT];
+ border[RIGHT].width - margin[RIGHT];
}
} else {
if (margin[LEFT] == AUTO)
@@ -3749,9 +4044,9 @@ bool layout_absolute(struct box *box, struct box *containing_block,
width = min(max(box->min_width, available_width),
box->max_width);
- width -= box->margin[LEFT] + box->border[LEFT] +
+ width -= box->margin[LEFT] + box->border[LEFT].width +
box->padding[LEFT] + box->padding[RIGHT] +
- box->border[RIGHT] + box->margin[RIGHT];
+ box->border[RIGHT].width + box->margin[RIGHT];
/* Adjust for {min|max}-width */
if (max_width >= 0 && width > max_width)
@@ -3760,9 +4055,10 @@ bool layout_absolute(struct box *box, struct box *containing_block,
width = min_width;
left = containing_block->width -
- margin[LEFT] - border[LEFT] -
+ margin[LEFT] - border[LEFT].width -
padding[LEFT] - width - padding[RIGHT] -
- border[RIGHT] - margin[RIGHT] - right;
+ border[RIGHT].width - margin[RIGHT] -
+ right;
} else if (left == AUTO && width != AUTO && right == AUTO) {
/* Adjust for {min|max}-width */
@@ -3773,17 +4069,18 @@ bool layout_absolute(struct box *box, struct box *containing_block,
left = static_left;
right = containing_block->width -
- left - margin[LEFT] - border[LEFT] -
+ left - margin[LEFT] -
+ border[LEFT].width -
padding[LEFT] - width - padding[RIGHT] -
- border[RIGHT] - margin[RIGHT];
+ border[RIGHT].width - margin[RIGHT];
} else if (left != AUTO && width == AUTO && right == AUTO) {
available_width -= left;
width = min(max(box->min_width, available_width),
box->max_width);
- width -= box->margin[LEFT] + box->border[LEFT] +
+ width -= box->margin[LEFT] + box->border[LEFT].width +
box->padding[LEFT] + box->padding[RIGHT] +
- box->border[RIGHT] + box->margin[RIGHT];
+ box->border[RIGHT].width + box->margin[RIGHT];
/* Adjust for {min|max}-width */
if (max_width >= 0 && width > max_width)
@@ -3792,9 +4089,10 @@ bool layout_absolute(struct box *box, struct box *containing_block,
width = min_width;
right = containing_block->width -
- left - margin[LEFT] - border[LEFT] -
+ left - margin[LEFT] -
+ border[LEFT].width -
padding[LEFT] - width - padding[RIGHT] -
- border[RIGHT] - margin[RIGHT];
+ border[RIGHT].width - margin[RIGHT];
} else if (left == AUTO && width != AUTO && right != AUTO) {
/* Adjust for {min|max}-width */
@@ -3804,14 +4102,17 @@ bool layout_absolute(struct box *box, struct box *containing_block,
width = min_width;
left = containing_block->width -
- margin[LEFT] - border[LEFT] -
+ margin[LEFT] - border[LEFT].width -
padding[LEFT] - width - padding[RIGHT] -
- border[RIGHT] - margin[RIGHT] - right;
+ border[RIGHT].width - margin[RIGHT] -
+ right;
} else if (left != AUTO && width == AUTO && right != AUTO) {
width = containing_block->width -
- left - margin[LEFT] - border[LEFT] -
+ left - margin[LEFT] -
+ border[LEFT].width -
padding[LEFT] - padding[RIGHT] -
- border[RIGHT] - margin[RIGHT] - right;
+ border[RIGHT].width - margin[RIGHT] -
+ right;
/* Adjust for {min|max}-width */
if (max_width >= 0 && width > max_width)
@@ -3828,17 +4129,19 @@ bool layout_absolute(struct box *box, struct box *containing_block,
width = min_width;
right = containing_block->width -
- left - margin[LEFT] - border[LEFT] -
+ left - margin[LEFT] -
+ border[LEFT].width -
padding[LEFT] - width - padding[RIGHT] -
- border[RIGHT] - margin[RIGHT];
+ border[RIGHT].width - margin[RIGHT];
}
}
LOG(("%i + %i + %i + %i + %i + %i + %i + %i + %i = %i",
- left, margin[LEFT], border[LEFT], padding[LEFT], width,
- padding[RIGHT], border[RIGHT], margin[RIGHT], right,
+ left, margin[LEFT], border[LEFT].width, padding[LEFT],
+ width, padding[RIGHT], border[RIGHT].width,
+ margin[RIGHT], right,
containing_block->width));
- box->x = left + margin[LEFT] + border[LEFT] - cx;
+ box->x = left + margin[LEFT] + border[LEFT].width - cx;
if (containing_block->type == BOX_BLOCK ||
containing_block->type == BOX_INLINE_BLOCK ||
containing_block->type == BOX_TABLE_CELL) {
@@ -3865,8 +4168,9 @@ bool layout_absolute(struct box *box, struct box *containing_block,
/* 10.6.4 */
LOG(("%i + %i + %i + %i + %i + %i + %i + %i + %i = %i",
- top, margin[TOP], border[TOP], padding[TOP], height,
- padding[BOTTOM], border[BOTTOM], margin[BOTTOM], bottom,
+ top, margin[TOP], border[TOP].width, padding[TOP],
+ height, padding[BOTTOM], border[BOTTOM].width,
+ margin[BOTTOM], bottom,
containing_block->height));
if (top == AUTO && height == AUTO && bottom == AUTO) {
top = static_top;
@@ -3876,33 +4180,33 @@ bool layout_absolute(struct box *box, struct box *containing_block,
if (margin[BOTTOM] == AUTO)
margin[BOTTOM] = 0;
bottom = containing_block->height -
- top - margin[TOP] - border[TOP] -
+ top - margin[TOP] - border[TOP].width -
padding[TOP] - height - padding[BOTTOM] -
- border[BOTTOM] - margin[BOTTOM];
+ border[BOTTOM].width - margin[BOTTOM];
} else if (top != AUTO && height != AUTO && bottom != AUTO) {
if (margin[TOP] == AUTO && margin[BOTTOM] == AUTO) {
space = containing_block->height -
- top - border[TOP] - padding[TOP] -
+ top - border[TOP].width - padding[TOP] -
height - padding[BOTTOM] -
- border[BOTTOM] - bottom;
+ border[BOTTOM].width - bottom;
margin[TOP] = margin[BOTTOM] = space / 2;
} else if (margin[TOP] == AUTO) {
margin[TOP] = containing_block->height -
- top - border[TOP] - padding[TOP] -
+ top - border[TOP].width - padding[TOP] -
height - padding[BOTTOM] -
- border[BOTTOM] - margin[BOTTOM] -
+ border[BOTTOM].width - margin[BOTTOM] -
bottom;
} else if (margin[BOTTOM] == AUTO) {
margin[BOTTOM] = containing_block->height -
- top - margin[TOP] - border[TOP] -
+ top - margin[TOP] - border[TOP].width -
padding[TOP] - height -
- padding[BOTTOM] - border[BOTTOM] -
+ padding[BOTTOM] - border[BOTTOM].width -
bottom;
} else {
bottom = containing_block->height -
- top - margin[TOP] - border[TOP] -
+ top - margin[TOP] - border[TOP].width -
padding[TOP] - height -
- padding[BOTTOM] - border[BOTTOM] -
+ padding[BOTTOM] - border[BOTTOM].width -
margin[BOTTOM];
}
} else {
@@ -3913,50 +4217,51 @@ bool layout_absolute(struct box *box, struct box *containing_block,
if (top == AUTO && height == AUTO && bottom != AUTO) {
height = box->height;
top = containing_block->height -
- margin[TOP] - border[TOP] -
+ margin[TOP] - border[TOP].width -
padding[TOP] - height -
- padding[BOTTOM] - border[BOTTOM] -
+ padding[BOTTOM] - border[BOTTOM].width -
margin[BOTTOM] - bottom;
} else if (top == AUTO && height != AUTO && bottom == AUTO) {
top = static_top;
bottom = containing_block->height -
- top - margin[TOP] - border[TOP] -
+ top - margin[TOP] - border[TOP].width -
padding[TOP] - height -
- padding[BOTTOM] - border[BOTTOM] -
+ padding[BOTTOM] - border[BOTTOM].width -
margin[BOTTOM];
} else if (top != AUTO && height == AUTO && bottom == AUTO) {
height = box->height;
bottom = containing_block->height -
- top - margin[TOP] - border[TOP] -
+ top - margin[TOP] - border[TOP].width -
padding[TOP] - height -
- padding[BOTTOM] - border[BOTTOM] -
+ padding[BOTTOM] - border[BOTTOM].width -
margin[BOTTOM];
} else if (top == AUTO && height != AUTO && bottom != AUTO) {
top = containing_block->height -
- margin[TOP] - border[TOP] -
+ margin[TOP] - border[TOP].width -
padding[TOP] - height -
- padding[BOTTOM] - border[BOTTOM] -
+ padding[BOTTOM] - border[BOTTOM].width -
margin[BOTTOM] - bottom;
} else if (top != AUTO && height == AUTO && bottom != AUTO) {
height = containing_block->height -
- top - margin[TOP] - border[TOP] -
+ top - margin[TOP] - border[TOP].width -
padding[TOP] - padding[BOTTOM] -
- border[BOTTOM] - margin[BOTTOM] -
+ border[BOTTOM].width - margin[BOTTOM] -
bottom;
} else if (top != AUTO && height != AUTO && bottom == AUTO) {
bottom = containing_block->height -
- top - margin[TOP] - border[TOP] -
+ top - margin[TOP] - border[TOP].width -
padding[TOP] - height -
- padding[BOTTOM] - border[BOTTOM] -
+ padding[BOTTOM] - border[BOTTOM].width -
margin[BOTTOM];
}
}
LOG(("%i + %i + %i + %i + %i + %i + %i + %i + %i = %i",
- top, margin[TOP], border[TOP], padding[TOP], height,
- padding[BOTTOM], border[BOTTOM], margin[BOTTOM], bottom,
+ top, margin[TOP], border[TOP].width, padding[TOP],
+ height, padding[BOTTOM], border[BOTTOM].width,
+ margin[BOTTOM], bottom,
containing_block->height));
- box->y = top + margin[TOP] + border[TOP] - cy;
+ box->y = top + margin[TOP] + border[TOP].width - cy;
if (containing_block->type == BOX_BLOCK ||
containing_block->type == BOX_INLINE_BLOCK ||
containing_block->type == BOX_TABLE_CELL) {
@@ -3991,49 +4296,67 @@ void layout_compute_offsets(struct box *box,
struct box *containing_block,
int *top, int *right, int *bottom, int *left)
{
+ uint32_t type;
+ css_fixed value = 0;
+ css_unit unit = CSS_UNIT_PX;
+
assert(containing_block->width != UNKNOWN_WIDTH &&
containing_block->width != AUTO &&
containing_block->height != AUTO);
/* left */
- if (box->style->pos[LEFT].pos == CSS_POS_PERCENT)
- *left = ((box->style->pos[LEFT].value.percent *
- containing_block->width) / 100);
- else if (box->style->pos[LEFT].pos == CSS_POS_LENGTH)
- *left = css_len2px(&box->style->pos[LEFT].value.length,
- box->style);
- else
+ type = css_computed_left(box->style, &value, &unit);
+ if (type == CSS_LEFT_SET) {
+ if (unit == CSS_UNIT_PCT) {
+ *left = (FIXTOFLT(value) *
+ containing_block->width) / 100;
+ } else {
+ *left = FIXTOINT(nscss_len2px(value, unit, box->style));
+ }
+ } else {
*left = AUTO;
+ }
/* right */
- if (box->style->pos[RIGHT].pos == CSS_POS_PERCENT)
- *right = ((box->style->pos[RIGHT].value.percent *
- containing_block->width) / 100);
- else if (box->style->pos[RIGHT].pos == CSS_POS_LENGTH)
- *right = css_len2px(&box->style->pos[RIGHT].value.length,
- box->style);
- else
+ type = css_computed_right(box->style, &value, &unit);
+ if (type == CSS_RIGHT_SET) {
+ if (unit == CSS_UNIT_PCT) {
+ *right = (FIXTOFLT(value) *
+ containing_block->width) / 100;
+ } else {
+ *right = FIXTOINT(nscss_len2px(value, unit,
+ box->style));
+ }
+ } else {
*right = AUTO;
+ }
/* top */
- if (box->style->pos[TOP].pos == CSS_POS_PERCENT)
- *top = ((box->style->pos[TOP].value.percent *
- containing_block->height) / 100);
- else if (box->style->pos[TOP].pos == CSS_POS_LENGTH)
- *top = css_len2px(&box->style->pos[TOP].value.length,
- box->style);
- else
+ type = css_computed_top(box->style, &value, &unit);
+ if (type == CSS_TOP_SET) {
+ if (unit == CSS_UNIT_PCT) {
+ *top = (FIXTOFLT(value) *
+ containing_block->height) / 100;
+ } else {
+ *top = FIXTOINT(nscss_len2px(value, unit, box->style));
+ }
+ } else {
*top = AUTO;
+ }
/* bottom */
- if (box->style->pos[BOTTOM].pos == CSS_POS_PERCENT)
- *bottom = ((box->style->pos[BOTTOM].value.percent *
- containing_block->height) / 100);
- else if (box->style->pos[BOTTOM].pos == CSS_POS_LENGTH)
- *bottom = css_len2px(&box->style->pos[BOTTOM].value.length,
- box->style);
- else
+ type = css_computed_bottom(box->style, &value, &unit);
+ if (type == CSS_BOTTOM_SET) {
+ if (unit == CSS_UNIT_PCT) {
+ *bottom = (FIXTOFLT(value) *
+ containing_block->height) / 100;
+ } else {
+ *bottom = FIXTOINT(nscss_len2px(value, unit,
+ box->style));
+ }
+ } else {
*bottom = AUTO;
+ }
}
@@ -4056,12 +4379,12 @@ void layout_calculate_descendant_bboxes(struct box *box)
assert(0);
}
- box->descendant_x0 = -box->border[LEFT];
- box->descendant_y0 = -box->border[TOP];
+ box->descendant_x0 = -box->border[LEFT].width;
+ box->descendant_y0 = -box->border[TOP].width;
box->descendant_x1 = box->padding[LEFT] + box->width +
- box->padding[RIGHT] + box->border[RIGHT];
+ box->padding[RIGHT] + box->border[RIGHT].width;
box->descendant_y1 = box->padding[TOP] + box->height +
- box->padding[BOTTOM] + box->border[BOTTOM];
+ box->padding[BOTTOM] + box->border[BOTTOM].width;
if (box->type == BOX_INLINE || box->type == BOX_TEXT)
return;
@@ -4103,7 +4426,8 @@ void layout_calculate_descendant_bboxes(struct box *box)
layout_calculate_descendant_bboxes(child);
- if (box->style && box->style->overflow == CSS_OVERFLOW_HIDDEN)
+ if (box->style && css_computed_overflow(box->style) ==
+ CSS_OVERFLOW_HIDDEN)
continue;
if (child->x + child->descendant_x0 < box->descendant_x0)
diff --git a/render/list.c b/render/list.c
index 84b5beffc..8f951a857 100644
--- a/render/list.c
+++ b/render/list.c
@@ -57,9 +57,9 @@ static const int list_counter_decimal[] = { 1, 4, 5, 9,
/ sizeof(list_counter_decimal[0]))
-static struct list_counter *render_list_find_counter(char *name);
+static struct list_counter *render_list_find_counter(const char *name);
static char *render_list_encode_counter(struct list_counter_state *state,
- css_list_style_type style);
+ enum css_list_style_type style);
static char *render_list_encode_roman(int value);
/*
@@ -72,7 +72,7 @@ static void render_list_counter_output(char *name);
* \param name the name of the counter to find
* \return the counter, or NULL if it couldn't be found/created.
*/
-static struct list_counter *render_list_find_counter(char *name) {
+static struct list_counter *render_list_find_counter(const char *name) {
struct list_counter *counter;
assert(name);
@@ -131,7 +131,7 @@ void render_list_destroy_counters(void) {
* \param value the value to reset the counter to
* \return true on success, false on failure.
*/
-bool render_list_counter_reset(char *name, int value) {
+bool render_list_counter_reset(const char *name, int value) {
struct list_counter *counter;
struct list_counter_state *state;
struct list_counter_state *link;
@@ -166,7 +166,7 @@ bool render_list_counter_reset(char *name, int value) {
* \param value the value to increment the counter by
* \return true on success, false on failure.
*/
-bool render_list_counter_increment(char *name, int value) {
+bool render_list_counter_increment(const char *name, int value) {
struct list_counter *counter;
assert(name);
@@ -196,7 +196,7 @@ bool render_list_counter_increment(char *name, int value) {
* \param name the name of the counter to end the scope for
* \return true on success, false on failure.
*/
-bool render_list_counter_end_scope(char *name) {
+bool render_list_counter_end_scope(const char *name) {
struct list_counter *counter;
assert(name);
@@ -216,28 +216,40 @@ bool render_list_counter_end_scope(char *name) {
* \param css_counter the counter to convert
* \return a textual representation of the counter, or NULL on failure
*/
-char *render_list_counter(struct css_counter *css_counter) {
+char *render_list_counter(const css_computed_content_item *css_counter) {
struct list_counter *counter;
struct list_counter_state *state;
char *compound = NULL;
char *merge, *extend;
+ lwc_string *name = NULL, *sep = NULL;
+ uint8_t style;
assert(css_counter);
- counter = render_list_find_counter(css_counter->name);
+
+ if (css_counter->type == CSS_COMPUTED_CONTENT_COUNTER) {
+ name = css_counter->data.counter.name;
+ style = css_counter->data.counter.style;
+ } else {
+ assert(css_counter->type == CSS_COMPUTED_CONTENT_COUNTERS);
+
+ name = css_counter->data.counters.name;
+ sep = css_counter->data.counters.sep;
+ style = css_counter->data.counters.style;
+ }
+
+ counter = render_list_find_counter(lwc_string_data(name));
if (!counter) {
LOG(("Failed to find/create counter for conversion"));
return NULL;
}
/* handle counter() first */
- if (!css_counter->separator)
- return render_list_encode_counter(counter->state,
- css_counter->style);
+ if (sep == NULL)
+ return render_list_encode_counter(counter->state, style);
/* loop through all states for counters() */
for (state = counter->first; state; state = state->next) {
- merge = render_list_encode_counter(state,
- css_counter->style);
+ merge = render_list_encode_counter(state, style);
if (!merge) {
free(compound);
return NULL;
@@ -258,14 +270,14 @@ char *render_list_counter(struct css_counter *css_counter) {
}
if (state->next) {
merge = realloc(compound, strlen(compound) +
- strlen(css_counter->separator) + 1);
+ lwc_string_length(sep) + 1);
if (!merge) {
LOG(("No memory for realloc()"));
free(compound);
return NULL;
}
compound = merge;
- strcat(compound, css_counter->separator);
+ strcat(compound, lwc_string_data(sep));
}
}
return compound;
@@ -280,7 +292,7 @@ char *render_list_counter(struct css_counter *css_counter) {
* \return a textual representation of the counter state, or NULL on failure
*/
static char *render_list_encode_counter(struct list_counter_state *state,
- css_list_style_type style) {
+ enum css_list_style_type style) {
char *result = NULL;
int i;
@@ -338,10 +350,7 @@ static char *render_list_encode_counter(struct list_counter_state *state,
return NULL;
result[0] = '\0';
break;
- case CSS_LIST_STYLE_TYPE_INHERIT:
- case CSS_LIST_STYLE_TYPE_UNKNOWN:
- case CSS_LIST_STYLE_TYPE_NOT_SET:
- assert(0);
+ default:
break;
}
diff --git a/render/list.h b/render/list.h
index 5206a3cc6..626eb5941 100644
--- a/render/list.h
+++ b/render/list.h
@@ -25,11 +25,13 @@
#include <stdbool.h>
+#include "css/css.h"
+
void render_list_destroy_counters(void);
-bool render_list_counter_reset(char *name, int value);
-bool render_list_counter_increment(char *name, int value);
-bool render_list_counter_end_scope(char *name);
-char *render_list_counter(struct css_counter *css_counter);
+bool render_list_counter_reset(const char *name, int value);
+bool render_list_counter_increment(const char *name, int value);
+bool render_list_counter_end_scope(const char *name);
+char *render_list_counter(const css_computed_content_item *css_counter);
void render_list_test(void);
diff --git a/render/loosen.c b/render/loosen.c
deleted file mode 100644
index 85136d89b..000000000
--- a/render/loosen.c
+++ /dev/null
@@ -1,501 +0,0 @@
-/*
- * Copyright 2008 Adam Blokus <adamblokus@gmail.com>
- *
- * 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/>.
- */
-
-#include <stdbool.h>
-#include <assert.h>
-
-#include "content/content.h"
-
-#include "render/box.h"
-#include "render/font.h"
-
-#include "render/layout.h"
-#include "render/loosen.h"
-
-#include "utils/log.h"
-#include "utils/talloc.h"
-
-#define AUTO INT_MIN
-#define LOOSEN_MIN_TEXT_SIZE 10
-
-static bool loosen_text(struct box *text, int width, struct content *content);
-
-static bool loosen_table(struct box *box, int available_width,
- struct content *content);
-
-static bool loosen_position_static(struct box *box, int width, int cx,
- struct content *content);
-
-static bool loosen_shrink_object(struct box *box, int width);
-
-static bool loosen_all_first_pass(struct box *box, int width, int cx,
- struct content *content);
-static bool loosen_all_second_pass(struct box *box, int width, int cx,
- struct content *content);
-static bool loosen_all_margins_paddings(struct box *box, int width, int cx,
- struct content *content);
-
-static bool loosen_shrink_text(struct box *box);
-
-/**
- * Main loosing procedure
- * \param content Reformated content - talloc memory pool for new boxes
- * \param layout Root of the loosened box tree
- * \param width Width the content is intended to fit
- * \param height Height of a single page - to be taken into consideration for \
- * preventing elements for being cropped at top/bottom edges of pages.
- * \return true if successful, false otherwise (lack of memory)
-*/
-bool loosen_document_layout(struct content *content, struct box *layout,
- int width, int height)
-{
- /* Optional try - if the current layout is not more than xx% too wide,
- * maybe we scale the content to preserve the original layout?
- */
-
- if (!loosen_all_first_pass(layout, width, 0, content))
- return false;
- layout->min_width = 0;
- layout->max_width = UNKNOWN_MAX_WIDTH;
- content_reformat(content, width, 0);
-
- /*Check if pass 1 was enough - if re-layouting doesn't give
- *us the right width, go on to pass 2. And again - if pass 2 was not
- *enough - go on to pass 3
- */
-
- if (content->width > width) {
- if (!loosen_all_second_pass(layout, width, 0, content))
- return false;
- layout->min_width = 0;
- layout->max_width = UNKNOWN_MAX_WIDTH;
- content_reformat(content, width, 0);
- }
-
- if (content->width > width) {
- if (!loosen_all_margins_paddings(layout, width, 0, content))
- return false;
- layout->min_width = 0;
- layout->max_width = UNKNOWN_MAX_WIDTH;
- content_reformat(content, width, 0);
- }
-
- return true;
-}
-
-/** Primarily - break too wide words into pieces.
- * \param text - the box that contains text to be broken
- * \param width Width the content is intended to fit
- * \param content talloc memory pool for new boxes
- * \return true if successful, false otherwise
-*/
-bool loosen_text(struct box *text, int width, struct content *content)
-{
- size_t offset;
- int actual_x;
-
- int *breaks;
- int break_count, i;
-
- unsigned int position;
- const struct font_functions *font_func;
-
- plot_font_style_t fstyle;
-
- font_plot_style_from_css(text->style, &fstyle);
-
- if (content->type == CONTENT_HTML)
- font_func = content->data.html.font_func;
- else
- return false;
-
- if (text->width <= width) {
- LOG(("loosen_text called unnecessary?"));
- /*Still - not an error for this function*/
- return true;
- }
-
- breaks = malloc( sizeof(int) * text->length);
- if (breaks == NULL)
- return false;
-
- break_count = 0;
- position = 0;
-
- while (position < text->length) {
- font_func->font_position_in_string(&fstyle,
- text->text + position,
- text->length - position,
- width, &offset, &actual_x);
-
- if (offset < text->length - position) {
- /*Another break*/
- LOG(("Current text broken at offset %zu",
- position + offset));
- breaks[break_count++] = position + offset-1;
- }
-
- position += offset;
- }
-
- text->text = talloc_realloc(content, text->text, char,
- text->length + break_count);
-
- i = text->length-1;
- text->length = text->length + break_count;
-
- for (; i>=0; i--) {
- text->text[i + break_count] = text->text[i];
- if (i == breaks[break_count - 1]) {
- break_count--;
- text->text[i + break_count] = ' ';
- }
- }
-
- free(breaks);
-
- return true;
-}
-
-/**
- * Changing table layout and structure to fit the contents width.
- * Firstly the borders are collapsed and the text is shrunken.
- * Secondly the text is loosened( this can be helpful for all data tables which
- * contain only text)
- * In the most extreme case - the table has no influence on the width
- * (each row is broken into one-cell rows).
- * \param table - the box that contains table to be broken
- * \param width Width the content is intended to fit
- * \param content talloc memory pool for new boxes
- * \return true if successful, false otherwise
- */
-bool loosen_table(struct box *table, int width, struct content *content)
-{
- struct box *row_group, *row, *cell, *br, *prev, *inline_container;
-
- struct box *text, *child;
- const struct font_functions *font_func;
- float scale;
- int new_width;
-
- if (table->min_width <= width)
- return true;
-
- if (content->type == CONTENT_HTML)
- font_func = content->data.html.font_func;
- else
- return false;
-
- table->style->border_collapse = CSS_BORDER_COLLAPSE_COLLAPSE;
-
- if (!loosen_shrink_text(table))
- return false;
-
- if (!loosen_all_margins_paddings(table, width, 0, content))
- return false;
-
- scale = width;
- scale /= table->min_width;
-
- for (row_group = table->children; row_group;
- row_group = row_group->next) {
- for (row = row_group->children; row; row = row->next) {
- for (cell = row->children; cell; cell = cell->next) {
- for (child = cell->children; child;
- child = child->next) {
- if (child->children)
- text = child->children;
- else
- continue;
-
- /*text in nested boxes won't be broken*/
- if (text->type != BOX_TEXT)
- continue;
-
-
- /*break the words propotionally to the
- current cell width*/
- new_width = (float)cell->width * scale * 0.9;
- loosen_text(text, new_width, content);
- }
- }
- }
- }
-
-
- /*check if the table is loosend enough...*/
- layout_minmax_table(table, font_func);
- if (table->min_width <= width)
- return true;
-
-
- /*...in case it's not continue with bigger changes,
- table cells are changed into inline containers*/
- inline_container = box_create(0, 0, 0, 0, 0, content);
- inline_container->type = BOX_INLINE_CONTAINER;
- inline_container->parent = table;
- inline_container->style = talloc_memdup(content, table->style,
- sizeof *table->style);
-
- prev = NULL;
-
- for (row_group = table->children; row_group;
- row_group = row_group->next) {
- for (row = row_group->children; row; row = row->next) {
-
- for (cell = row->children; cell; cell = cell->next) {
- cell->type = BOX_INLINE_BLOCK;
- cell->prev = prev;
- cell->parent = inline_container;
- cell->max_width = width;
- cell->min_width = 0;
-
- if (prev!=NULL)
- prev->next = cell;
- else
- inline_container->children = cell;
-
- prev = cell;
- }
-
- br = box_create(0, 0, 0, 0, 0, content);
- br->type = BOX_BR;
- br->parent = inline_container;
- br->prev = prev;
- br->style = talloc_memdup(content, table->style,
- sizeof *table->style);
- br->style->clear = CSS_CLEAR_BOTH;
-
- if (prev != NULL)
- prev->next = br;
- else
- inline_container->children = br;
-
- prev = br;
- }
- }
- inline_container->last = prev;
-
- table->type = BOX_BLOCK;
- table->children = table->last = inline_container;
- table->col = NULL;
-
- return true;
-}
-
-/**
-* Recursively step through the box tree applying LOOSEN_MIN_TEXT_SIZE wherever
-* text is found
-* \param box the box where the shrinking should be started
-* \return true if successful, false otherwise
-*/
-bool loosen_shrink_text(struct box *box)
-{
- struct box *child;
-
- box->max_width = UNKNOWN_MAX_WIDTH;
-
- if (box->type == BOX_TEXT) {
- box->style->font_size.size = CSS_FONT_SIZE_LENGTH;
- box->style->font_size.value.length.unit = CSS_UNIT_PX;
- box->style->font_size.value.length.value = LOOSEN_MIN_TEXT_SIZE;
- }
- else if (box->children)
- for(child = box->children; child; child = child->next)
- if (!loosen_shrink_text(child))
- return false;
-
- return true;
-}
-
-
-/**
- * Change absolute and relative positioned elements into block elements
- * in case they are positioned to far to the rigth
- * \param box - the box that should be changed
- * \param width Width the content is intended to fit
- * \param cx current x - not yet in use
- * \param content talloc memory pool for new boxes
- * \return true if successful, false otherwise
- */
-bool loosen_position_static(struct box *box, int width, int cx,
- struct content *content)
-{
- assert(box->style);
-
- if (box->style->position == CSS_POSITION_ABSOLUTE) {
- box->style->position = CSS_POSITION_NOT_SET;
- }
-
- return true;
-}
-
-/**
- * Shrink an object (esp. an image) to fit the page-width
- * \note Not sure wheter it won't be better for images to be cropped
- * \param box - the box that should be changed
- * \param width Width the content is intended to fit
- * \return true if successful, false otherwise
-*/
-bool loosen_shrink_object(struct box *box, int width)
-{
- assert(box->object != NULL);
-
- box->height = AUTO;
- box->width = width;
-
- if (box->style) {
- box->style->width.width = CSS_WIDTH_PERCENT;
- box->style->width.value.percent = 100;
- box->style->height.height= CSS_HEIGHT_AUTO;
- }
-
- return true;
-}
-
-/**
- * Pass 1 of loosening - do such obvious changes as: breaking too long words,
- * moving absolute positioned objects into the visibile scope of width.
- * \param box - the box that should be changed
- * \param width Width the content is intended to fit
- * \param cx current x - not yet in use
- * \param content talloc memory pool for new boxes
- * \return true if successful, false otherwise
-*/
-bool loosen_all_first_pass(struct box *box, int width, int cx,
- struct content *content)
-{
- struct box* c;
- int x;
-
- for (c = box->children; c ; c = c->next) {
- x = cx + c->x;
- if (c->children != NULL)
- if (!loosen_all_first_pass(c, width, x, content))
- return false;
-
- if (c->style) {
- if (c->style->position == CSS_POSITION_RELATIVE ||
- c->style->position == CSS_POSITION_ABSOLUTE )
- if (!loosen_position_static(c, width, cx, content))
- return false;
- if ( c->style->width.width == CSS_WIDTH_LENGTH &&
- css_len2px(&c->style->width.value.length, c->style) > width)
- c->style->width.width = CSS_WIDTH_NOT_SET;
- }
-
- if (c->object && c->width > width)
- if (!loosen_shrink_object(c, width))
- return false;
-
- if (c->type == BOX_TEXT) {
- if (!loosen_text(c, width, content))
- return false;
- }
-
- c->min_width = 0;
- c->max_width = UNKNOWN_MAX_WIDTH;
-
- }
-
- return true;
-}
-
-/**
- * Pass 2 of loosening - break tables
- * \param box - the box that should be changed
- * \param width Width the content is intended to fit
- * \param cx current x - not yet in use
- * \param content talloc memory pool for new boxes
- * \return true if successful, false otherwise
- */
-bool loosen_all_second_pass(struct box *box, int width, int cx,
- struct content *content)
-{
- struct box *c;
- int x;
-
- for (c = box->children; c; c = c->next) {
- x = cx + c->x;
- if (c->children != NULL)
- if (!loosen_all_second_pass(c, width, x, content))
- return false;
-
- switch (c->type) {
- case BOX_TABLE:
- if (!loosen_table(c, width, content))
- return false;
- break;
- default:
- break;
- }
-
- c->min_width = 0;
- c->max_width = UNKNOWN_MAX_WIDTH;
- }
-
- return true;
-}
-
-
-/**
- * Pass 3 of loosening -zero all margins and paddings
- * \param box - the box that should be changed
- * \param width Width the content is intended to fit
- * \param cx current x - not yet in use
- * \param content talloc memory pool for new boxes
- * \return true if successful, false otherwise
- */
-bool loosen_all_margins_paddings(struct box *box, int width, int cx,
- struct content *content)
-{
- struct box *c;
- int x;
-
- for (c = box->children; c; c = c->next) {
- x = cx + c->x;
- if (c->children != NULL)
- if (!loosen_all_margins_paddings(c, width, x, content))
- return false;
-
- c->padding[LEFT] = c->padding[RIGHT] = 0;
- c->margin[LEFT] = c->margin[RIGHT] = 0;
-
- if (c->style) {
- c->style->margin[LEFT].margin = CSS_MARGIN_PERCENT;
- c->style->margin[LEFT].value.percent = 0;
-
- c->style->margin[RIGHT].margin = CSS_MARGIN_PERCENT;
- c->style->margin[RIGHT].value.percent = 0;
-
- c->style->padding[LEFT].padding = CSS_PADDING_PERCENT;
- c->style->padding[LEFT].value.percent = 0;
-
- c->style->padding[RIGHT].padding = CSS_PADDING_PERCENT;
- c->style->padding[RIGHT].value.percent = 0;
-
- }
-
- c->min_width = 0;
- c->max_width = UNKNOWN_MAX_WIDTH;
-
- }
-
- return true;
-}
-
diff --git a/render/loosen.h b/render/loosen.h
deleted file mode 100644
index a5b3822bd..000000000
--- a/render/loosen.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2008 Adam Blokus <adamblokus@gmail.com>
- *
- * 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
-General idea - a set of routines working themselves recursively through
-the box tree and trying to change the layout of the document as little
-as possible to acquire the desired width ( - to make it fit in a printed
-page ), where possible - also taking the dividing height into consideration,
-to prevent objects being cut by ends of pages.
-*/
-
-#ifndef NETSURF_RENDER_LOOSEN_H
-#define NETSURF_RENDER_LOOSEN_H
-#include <stdbool.h>
-
-bool loosen_document_layout(struct content *content, struct box *layout,
- int width, int height);
-
-#endif
diff --git a/render/parser_binding.h b/render/parser_binding.h
index d50b4e3b9..1641058bd 100644
--- a/render/parser_binding.h
+++ b/render/parser_binding.h
@@ -39,6 +39,12 @@ typedef enum binding_encoding_source {
ENCODING_SOURCE_META
} binding_encoding_source;
+typedef enum binding_quirks_mode {
+ BINDING_QUIRKS_MODE_NONE,
+ BINDING_QUIRKS_MODE_LIMITED,
+ BINDING_QUIRKS_MODE_FULL
+} binding_quirks_mode;
+
binding_error binding_create_tree(void *arena, const char *charset, void **ctx);
binding_error binding_destroy_tree(void *ctx);
@@ -46,7 +52,7 @@ binding_error binding_parse_chunk(void *ctx, const uint8_t *data, size_t len);
binding_error binding_parse_completed(void *ctx);
const char *binding_get_encoding(void *ctx, binding_encoding_source *source);
-xmlDocPtr binding_get_document(void *ctx);
+xmlDocPtr binding_get_document(void *ctx, binding_quirks_mode *quirks);
struct form *binding_get_forms(void *ctx);
struct form_control *binding_get_control_for_node(void *ctx, xmlNodePtr node);
diff --git a/render/table.c b/render/table.c
index d3134f687..aad3e38c2 100644
--- a/render/table.c
+++ b/render/table.c
@@ -23,6 +23,7 @@
#include <assert.h>
#include "css/css.h"
+#include "css/utils.h"
#include "render/box.h"
#include "render/table.h"
#define NDEBUG
@@ -30,15 +31,29 @@
#undef NDEBUG
#include "utils/talloc.h"
-
-static void table_collapse_borders_h(struct box *parent, struct box *child,
- bool *first);
-static void table_collapse_borders_v(struct box *row, struct box *cell,
- unsigned int columns);
-static void table_collapse_borders_cell(struct box *cell, struct box *right,
- struct box *bottom);
-static void table_remove_borders(struct css_style *style);
-struct box *table_find_cell(struct box *table, unsigned int x, unsigned int y);
+/**
+ * Container for border values during table border calculations
+ */
+struct border {
+ enum css_border_style style; /**< border-style */
+ enum css_border_color color; /**< border-color type */
+ css_color c; /**< border-color value */
+ css_fixed width; /**< border-width length */
+ css_unit unit; /**< border-width units */
+};
+
+static void table_used_left_border_for_cell(struct box *cell);
+static void table_used_top_border_for_cell(struct box *cell);
+static void table_used_right_border_for_cell(struct box *cell);
+static void table_used_bottom_border_for_cell(struct box *cell);
+static bool table_border_is_more_eyecatching(const struct border *a,
+ box_type a_src, const struct border *b, box_type b_src);
+static void table_cell_top_process_table(struct box *table, struct border *a,
+ box_type *a_src);
+static bool table_cell_top_process_group(struct box *cell, struct box *group,
+ struct border *a, box_type *a_src);
+static bool table_cell_top_process_row(struct box *cell, struct box *row,
+ struct border *a, box_type *a_src);
/**
@@ -75,6 +90,10 @@ bool table_calculate_column_types(struct box *table)
for (row_group = table->children; row_group; row_group =row_group->next)
for (row = row_group->children; row; row = row->next)
for (cell = row->children; cell; cell = cell->next) {
+ enum css_width type;
+ css_fixed value = 0;
+ css_unit unit = CSS_UNIT_PX;
+
assert(cell->type == BOX_TABLE_CELL);
assert(cell->style);
@@ -82,17 +101,21 @@ bool table_calculate_column_types(struct box *table)
continue;
i = cell->start_column;
- if (cell->style->position != CSS_POSITION_ABSOLUTE &&
- cell->style->position != CSS_POSITION_FIXED) {
+ if (css_computed_position(cell->style) !=
+ CSS_POSITION_ABSOLUTE &&
+ css_computed_position(cell->style) !=
+ CSS_POSITION_FIXED) {
col[i].positioned = false;
}
+ type = css_computed_width(cell->style, &value, &unit);
+
/* fixed width takes priority over any other width type */
if (col[i].type != COLUMN_WIDTH_FIXED &&
- cell->style->width.width == CSS_WIDTH_LENGTH) {
+ type == CSS_WIDTH_SET && unit != CSS_UNIT_PCT) {
col[i].type = COLUMN_WIDTH_FIXED;
- col[i].width = css_len2px(&cell->style->
- width.value.length, cell->style);
+ col[i].width = FIXTOINT(nscss_len2px(value, unit,
+ cell->style));
if (col[i].width < 0)
col[i].width = 0;
continue;
@@ -101,12 +124,12 @@ bool table_calculate_column_types(struct box *table)
if (col[i].type != COLUMN_WIDTH_UNKNOWN)
continue;
- if (cell->style->width.width == CSS_WIDTH_PERCENT) {
+ if (type == CSS_WIDTH_SET && unit == CSS_UNIT_PCT) {
col[i].type = COLUMN_WIDTH_PERCENT;
- col[i].width = cell->style->width.value.percent;
+ col[i].width = FIXTOINT(value);
if (col[i].width < 0)
col[i].width = 0;
- } else if (cell->style->width.width == CSS_WIDTH_AUTO) {
+ } else if (type == CSS_WIDTH_AUTO) {
col[i].type = COLUMN_WIDTH_AUTO;
}
}
@@ -118,6 +141,9 @@ bool table_calculate_column_types(struct box *table)
unsigned int fixed_columns = 0, percent_columns = 0,
auto_columns = 0, unknown_columns = 0;
int fixed_width = 0, percent_width = 0;
+ enum css_width type;
+ css_fixed value = 0;
+ css_unit unit = CSS_UNIT_PX;
if (cell->columns == 1)
continue;
@@ -145,14 +171,16 @@ bool table_calculate_column_types(struct box *table)
if (!unknown_columns)
continue;
+ type = css_computed_width(cell->style, &value, &unit);
+
/* if cell is fixed width, and all spanned columns are fixed
* or unknown width, split extra width among unknown columns */
- if (cell->style->width.width == CSS_WIDTH_LENGTH &&
+ if (type == CSS_WIDTH_SET && unit != CSS_UNIT_PCT &&
fixed_columns + unknown_columns ==
cell->columns) {
- int width = (css_len2px(&cell->style->
- width.value.length, cell->style) -
- fixed_width) / unknown_columns;
+ int width = (FIXTOFLT(nscss_len2px(value, unit,
+ cell->style)) - fixed_width) /
+ unknown_columns;
if (width < 0)
width = 0;
for (j = 0; j != cell->columns; j++) {
@@ -164,10 +192,10 @@ bool table_calculate_column_types(struct box *table)
}
/* as above for percentage width */
- if (cell->style->width.width == CSS_WIDTH_PERCENT &&
+ if (type == CSS_WIDTH_SET && unit == CSS_UNIT_PCT &&
percent_columns + unknown_columns ==
cell->columns) {
- int width = (cell->style->width.value.percent -
+ int width = (FIXTOFLT(value) -
percent_width) / unknown_columns;
if (width < 0)
width = 0;
@@ -195,212 +223,734 @@ bool table_calculate_column_types(struct box *table)
return true;
}
-
/**
- * Handle collapsing border model.
+ * Calculate used values of border-{trbl}-{style,color,width} for table cells.
*
- * \param table box of type BOX_TABLE
+ * \param cell Table cell to consider
+ *
+ * \post \a cell's border array is populated
*/
+void table_used_border_for_cell(struct box *cell)
+{
+ int side;
+
+ assert(cell->type == BOX_TABLE_CELL);
+
+ if (css_computed_border_collapse(cell->style) ==
+ CSS_BORDER_COLLAPSE_SEPARATE) {
+ css_fixed width = 0;
+ css_unit unit = CSS_UNIT_PX;
+
+ /* Left border */
+ cell->border[LEFT].style =
+ css_computed_border_left_style(cell->style);
+ cell->border[LEFT].color =
+ css_computed_border_left_color(cell->style,
+ &cell->border[LEFT].c);
+ css_computed_border_left_width(cell->style, &width, &unit);
+ cell->border[LEFT].width =
+ FIXTOINT(nscss_len2px(width, unit, cell->style));
+
+ /* Top border */
+ cell->border[TOP].style =
+ css_computed_border_top_style(cell->style);
+ cell->border[TOP].color =
+ css_computed_border_top_color(cell->style,
+ &cell->border[TOP].c);
+ css_computed_border_top_width(cell->style, &width, &unit);
+ cell->border[TOP].width =
+ FIXTOINT(nscss_len2px(width, unit, cell->style));
+
+ /* Right border */
+ cell->border[RIGHT].style =
+ css_computed_border_right_style(cell->style);
+ cell->border[RIGHT].color =
+ css_computed_border_right_color(cell->style,
+ &cell->border[RIGHT].c);
+ css_computed_border_right_width(cell->style, &width, &unit);
+ cell->border[RIGHT].width =
+ FIXTOINT(nscss_len2px(width, unit, cell->style));
+
+ /* Bottom border */
+ cell->border[BOTTOM].style =
+ css_computed_border_bottom_style(cell->style);
+ cell->border[BOTTOM].color =
+ css_computed_border_bottom_color(cell->style,
+ &cell->border[BOTTOM].c);
+ css_computed_border_bottom_width(cell->style, &width, &unit);
+ cell->border[BOTTOM].width =
+ FIXTOINT(nscss_len2px(width, unit, cell->style));
+ } else {
+ /* Left border */
+ table_used_left_border_for_cell(cell);
+
+ /* Top border */
+ table_used_top_border_for_cell(cell);
+
+ /* Right border */
+ table_used_right_border_for_cell(cell);
+
+ /* Bottom border */
+ table_used_bottom_border_for_cell(cell);
+ }
+
+ /* Finally, ensure that any borders configured as
+ * hidden or none have zero width. (c.f. layout_find_dimensions) */
+ for (side = 0; side != 4; side++) {
+ if (cell->border[side].style == CSS_BORDER_STYLE_HIDDEN ||
+ cell->border[side].style ==
+ CSS_BORDER_STYLE_NONE)
+ cell->border[side].width = 0;
+ }
+}
+
+/******************************************************************************
+ * Helpers for used border calculations *
+ ******************************************************************************/
-void table_collapse_borders(struct box *table)
+/**
+ * Calculate used values of border-left-{style,color,width}
+ *
+ * \param cell Table cell to consider
+ */
+void table_used_left_border_for_cell(struct box *cell)
{
- bool first;
- unsigned int i, j;
- struct box *row_group, *row, *cell;
+ struct border a, b;
+ box_type a_src, b_src;
+
+ /** \todo Need column and column_group, too */
+
+ /* Initialise to computed left border for cell */
+ a.style = css_computed_border_left_style(cell->style);
+ a.color = css_computed_border_left_color(cell->style, &a.c);
+ css_computed_border_left_width(cell->style, &a.width, &a.unit);
+ a_src = BOX_TABLE_CELL;
+
+ if (cell->prev != NULL || cell->start_column != 0) {
+ /* Cell to the left -- consider its right border */
+ struct box *prev = NULL;
+
+ if (cell->prev == NULL) {
+ struct box *row;
+
+ /* Spanned from a previous row */
+ for (row = cell->parent; row != NULL; row = row->prev) {
+ for (prev = row->children; prev != NULL;
+ prev = prev->next) {
+ if (prev->start_column +
+ prev->columns ==
+ cell->start_column)
+ break;
+ }
- assert(table->type == BOX_TABLE);
-
- /* 1st stage: collapse all borders down to the cells */
- first = true;
- for (row_group = table->children; row_group;
- row_group = row_group->next) {
- assert(row_group->type == BOX_TABLE_ROW_GROUP);
- assert(row_group->style);
- table_collapse_borders_h(table, row_group, &first);
- first = row_group->children != NULL;
- for (row = row_group->children; row; row = row->next) {
- assert(row->type == BOX_TABLE_ROW);
- assert(row->style);
- table_collapse_borders_h(row_group, row, &first);
- for (cell = row->children; cell; cell = cell->next) {
- assert(cell->type == BOX_TABLE_CELL);
- assert(cell->style);
- table_collapse_borders_v(row, cell,
- table->columns);
+ if (prev != NULL)
+ break;
}
- table_remove_borders(row->style);
+
+ assert(prev != NULL);
+ } else {
+ prev = cell->prev;
+ }
+
+ b.style = css_computed_border_right_style(prev->style);
+ b.color = css_computed_border_right_color(prev->style, &b.c);
+ css_computed_border_right_width(prev->style, &b.width, &b.unit);
+ b_src = BOX_TABLE_CELL;
+
+ if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+ a = b;
+ a_src = b_src;
+ }
+ } else {
+ /* First cell in row, so consider rows and row group */
+ struct box *row = cell->parent;
+ struct box *group = row->parent;
+ struct box *table = group->parent;
+ unsigned int rows = cell->rows;
+
+ while (rows-- > 0 && row != NULL) {
+ /* Spanned rows -- consider their left border */
+ b.style = css_computed_border_left_style(row->style);
+ b.color = css_computed_border_left_color(
+ row->style, &b.c);
+ css_computed_border_left_width(
+ row->style, &b.width, &b.unit);
+ b_src = BOX_TABLE_ROW;
+
+ if (table_border_is_more_eyecatching(&a, a_src,
+ &b, b_src)) {
+ a = b;
+ a_src = b_src;
+ }
+
+ row = row->next;
+ }
+
+ /** \todo can cells span row groups? */
+
+ /* Row group -- consider its left border */
+ b.style = css_computed_border_left_style(group->style);
+ b.color = css_computed_border_left_color(group->style, &b.c);
+ css_computed_border_left_width(group->style, &b.width, &b.unit);
+ b_src = BOX_TABLE_ROW_GROUP;
+
+ if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+ a = b;
+ a_src = b_src;
+ }
+
+ /* The table itself -- consider its left border */
+ b.style = css_computed_border_left_style(table->style);
+ b.color = css_computed_border_left_color(table->style, &b.c);
+ css_computed_border_left_width(table->style, &b.width, &b.unit);
+ b_src = BOX_TABLE;
+
+ if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+ a = b;
+ a_src = b_src;
}
- table_remove_borders(row_group->style);
}
- table_remove_borders(table->style);
-
- /* 2nd stage: rather than building a grid of cells, we slowly look up the
- * cell we want to collapse with */
- for (i = 0; i < table->columns; i++) {
- for (j = 0; j < table->rows; j++) {
- table_collapse_borders_cell(
- table_find_cell(table, i, j),
- table_find_cell(table, i + 1, j),
- table_find_cell(table, i, j + 1));
+
+ /* a now contains the used left border for the cell */
+ cell->border[LEFT].style = a.style;
+ cell->border[LEFT].color = a.color;
+ cell->border[LEFT].c = a.c;
+ cell->border[LEFT].width =
+ FIXTOINT(nscss_len2px(a.width, a.unit, cell->style));
+}
+
+/**
+ * Calculate used values of border-top-{style,color,width}
+ *
+ * \param cell Table cell to consider
+ */
+void table_used_top_border_for_cell(struct box *cell)
+{
+ struct border a, b;
+ box_type a_src, b_src;
+ struct box *row = cell->parent;
+ bool process_group = false;
+
+ /* Initialise to computed top border for cell */
+ a.style = css_computed_border_top_style(cell->style);
+ a.color = css_computed_border_top_color(cell->style, &a.c);
+ css_computed_border_top_width(cell->style, &a.width, &a.unit);
+ a_src = BOX_TABLE_CELL;
+
+ /* Top border of row */
+ b.style = css_computed_border_top_style(row->style);
+ b.color = css_computed_border_top_color(row->style, &b.c);
+ css_computed_border_top_width(row->style, &b.width, &b.unit);
+ b_src = BOX_TABLE_ROW;
+
+ if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+ a = b;
+ a_src = b_src;
+ }
+
+ if (row->prev != NULL) {
+ /* Consider row(s) above */
+ while (table_cell_top_process_row(cell, row->prev,
+ &a, &a_src) == false) {
+ if (row->prev->prev == NULL) {
+ /* Consider row group */
+ process_group = true;
+ break;
+ } else {
+ row = row->prev;
+ }
}
+ } else {
+ process_group = true;
}
- /* 3rd stage: remove redundant borders */
- first = true;
- for (row_group = table->children; row_group;
- row_group = row_group->next) {
- for (row = row_group->children; row; row = row->next) {
- for (cell = row->children; cell; cell = cell->next) {
- if (!first) {
- cell->style->border[TOP].style =
- CSS_BORDER_STYLE_NONE;
- cell->style->border[TOP].width.value.value =
- 0;
- cell->style->border[TOP].width.value.unit =
- CSS_UNIT_PX;
- }
- if (cell->start_column > 0) {
- cell->style->border[LEFT].style =
- CSS_BORDER_STYLE_NONE;
- cell->style->border[LEFT].width.value.value =
- 0;
- cell->style->border[LEFT].width.value.unit =
- CSS_UNIT_PX;
+ if (process_group) {
+ struct box *group = row->parent;
+
+ /* Top border of row group */
+ b.style = css_computed_border_top_style(group->style);
+ b.color = css_computed_border_top_color(group->style, &b.c);
+ css_computed_border_top_width(group->style, &b.width, &b.unit);
+ b_src = BOX_TABLE_ROW_GROUP;
+
+ if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+ a = b;
+ a_src = b_src;
+ }
+
+ if (group->prev == NULL) {
+ /* Top border of table */
+ table_cell_top_process_table(group->parent, &a, &a_src);
+ } else {
+ /* Process previous group(s) */
+ while (table_cell_top_process_group(cell, group->prev,
+ &a, &a_src) == false) {
+ if (group->prev->prev == NULL) {
+ /* Top border of table */
+ table_cell_top_process_table(
+ group->parent,
+ &a, &a_src);
+ break;
+ } else {
+ group = group->prev;
}
}
- first = false;
}
}
-}
+ /* a now contains the used top border for the cell */
+ cell->border[TOP].style = a.style;
+ cell->border[TOP].color = a.color;
+ cell->border[TOP].c = a.c;
+ cell->border[TOP].width =
+ FIXTOINT(nscss_len2px(a.width, a.unit, cell->style));
+}
/**
- * Collapse the borders of two boxes together.
+ * Calculate used values of border-right-{style,color,width}
+ *
+ * \param cell Table cell to consider
*/
-
-void table_collapse_borders_v(struct box *row, struct box *cell, unsigned int columns)
+void table_used_right_border_for_cell(struct box *cell)
{
- struct css_border *border;
+ struct border a, b;
+ box_type a_src, b_src;
+
+ /** \todo Need column and column_group, too */
+
+ /* Initialise to computed right border for cell */
+ a.style = css_computed_border_right_style(cell->style);
+ a.color = css_computed_border_right_color(cell->style, &a.c);
+ css_computed_border_right_width(cell->style, &a.width, &a.unit);
+ a_src = BOX_TABLE_CELL;
+
+ if (cell->next != NULL || cell->start_column + cell->columns !=
+ cell->parent->parent->parent->columns) {
+ /* Cell is not at right edge of table -- no right border */
+ a.style = CSS_BORDER_STYLE_NONE;
+ a.width = 0;
+ a.unit = CSS_UNIT_PX;
+ } else {
+ /* Last cell in row, so consider rows and row group */
+ struct box *row = cell->parent;
+ struct box *group = row->parent;
+ struct box *table = group->parent;
+ unsigned int rows = cell->rows;
+
+ while (rows-- > 0 && row != NULL) {
+ /* Spanned rows -- consider their right border */
+ b.style = css_computed_border_right_style(row->style);
+ b.color = css_computed_border_right_color(
+ row->style, &b.c);
+ css_computed_border_right_width(
+ row->style, &b.width, &b.unit);
+ b_src = BOX_TABLE_ROW;
+
+ if (table_border_is_more_eyecatching(&a, a_src,
+ &b, b_src)) {
+ a = b;
+ a_src = b_src;
+ }
- if (cell->start_column == 0) {
- border = css_eyecatching_border(&row->style->border[LEFT], row->style,
- &cell->style->border[LEFT], cell->style);
- cell->style->border[LEFT] = *border;
- }
- border = css_eyecatching_border(&row->style->border[TOP], row->style,
- &cell->style->border[TOP], cell->style);
- cell->style->border[TOP] = *border;
- border = css_eyecatching_border(&row->style->border[BOTTOM], row->style,
- &cell->style->border[BOTTOM], cell->style);
- cell->style->border[BOTTOM] = *border;
- if ((cell->start_column + cell->columns) == columns) {
- border = css_eyecatching_border(&row->style->border[RIGHT], row->style,
- &cell->style->border[RIGHT], cell->style);
- cell->style->border[RIGHT] = *border;
+ row = row->next;
+ }
+
+ /** \todo can cells span row groups? */
+
+ /* Row group -- consider its right border */
+ b.style = css_computed_border_right_style(group->style);
+ b.color = css_computed_border_right_color(group->style, &b.c);
+ css_computed_border_right_width(group->style,
+ &b.width, &b.unit);
+ b_src = BOX_TABLE_ROW_GROUP;
+
+ if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+ a = b;
+ a_src = b_src;
+ }
+
+ /* The table itself -- consider its right border */
+ b.style = css_computed_border_right_style(table->style);
+ b.color = css_computed_border_right_color(table->style, &b.c);
+ css_computed_border_right_width(table->style,
+ &b.width, &b.unit);
+ b_src = BOX_TABLE;
+
+ if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+ a = b;
+ a_src = b_src;
+ }
}
-}
+ /* a now contains the used right border for the cell */
+ cell->border[RIGHT].style = a.style;
+ cell->border[RIGHT].color = a.color;
+ cell->border[RIGHT].c = a.c;
+ cell->border[RIGHT].width =
+ FIXTOINT(nscss_len2px(a.width, a.unit, cell->style));
+}
/**
- * Collapse the borders of two boxes together.
+ * Calculate used values of border-bottom-{style,color,width}
+ *
+ * \param cell Table cell to consider
*/
-
-void table_collapse_borders_h(struct box *parent, struct box *child, bool *first)
+void table_used_bottom_border_for_cell(struct box *cell)
{
- struct css_border *border;
+ struct border a, b;
+ box_type a_src, b_src;
+ struct box *row = cell->parent;
+ unsigned int rows = cell->rows;
+
+ /* Initialise to computed bottom border for cell */
+ a.style = css_computed_border_bottom_style(cell->style);
+ a.color = css_computed_border_bottom_color(cell->style, &a.c);
+ css_computed_border_bottom_width(cell->style, &a.width, &a.unit);
+ a_src = BOX_TABLE_CELL;
+
+ while (rows-- > 0 && row != NULL)
+ row = row->next;
+
+ /** \todo Can cells span row groups? */
+
+ if (row != NULL) {
+ /* Cell is not at bottom edge of table -- no bottom border */
+ a.style = CSS_BORDER_STYLE_NONE;
+ a.width = 0;
+ a.unit = CSS_UNIT_PX;
+ } else {
+ /* Cell at bottom of table, so consider row and row group */
+ struct box *row = cell->parent;
+ struct box *group = row->parent;
+ struct box *table = group->parent;
+
+ /* Bottom border of row */
+ b.style = css_computed_border_bottom_style(row->style);
+ b.color = css_computed_border_bottom_color(row->style, &b.c);
+ css_computed_border_bottom_width(row->style, &b.width, &b.unit);
+ b_src = BOX_TABLE_ROW;
+
+ if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+ a = b;
+ a_src = b_src;
+ }
- if (*first) {
- border = css_eyecatching_border(&parent->style->border[TOP], parent->style,
- &child->style->border[TOP], child->style);
- child->style->border[TOP] = *border;
- *first = false;
- }
- border = css_eyecatching_border(&parent->style->border[LEFT], parent->style,
- &child->style->border[LEFT], child->style);
- child->style->border[LEFT] = *border;
- border = css_eyecatching_border(&parent->style->border[RIGHT], parent->style,
- &child->style->border[RIGHT], child->style);
- child->style->border[RIGHT] = *border;
- if (!child->next) {
- border = css_eyecatching_border(&parent->style->border[BOTTOM], parent->style,
- &child->style->border[BOTTOM], child->style);
- child->style->border[BOTTOM] = *border;
+ /* Row group -- consider its bottom border */
+ b.style = css_computed_border_bottom_style(group->style);
+ b.color = css_computed_border_bottom_color(group->style, &b.c);
+ css_computed_border_bottom_width(group->style,
+ &b.width, &b.unit);
+ b_src = BOX_TABLE_ROW_GROUP;
+
+ if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+ a = b;
+ a_src = b_src;
+ }
+
+ /* The table itself -- consider its bottom border */
+ b.style = css_computed_border_bottom_style(table->style);
+ b.color = css_computed_border_bottom_color(table->style, &b.c);
+ css_computed_border_bottom_width(table->style,
+ &b.width, &b.unit);
+ b_src = BOX_TABLE;
+
+ if (table_border_is_more_eyecatching(&a, a_src, &b, b_src)) {
+ a = b;
+ a_src = b_src;
+ }
}
-}
+ /* a now contains the used bottom border for the cell */
+ cell->border[BOTTOM].style = a.style;
+ cell->border[BOTTOM].color = a.color;
+ cell->border[BOTTOM].c = a.c;
+ cell->border[BOTTOM].width =
+ FIXTOINT(nscss_len2px(a.width, a.unit, cell->style));
+}
/**
- * Collapse the borders of two boxes together.
+ * Determine if a border style is more eyecatching than another
+ *
+ * \param a Reference border style
+ * \param a_src Source of \a a
+ * \param b Candidate border style
+ * \param b_src Source of \a b
+ * \return True if \a b is more eyecatching than \a a
*/
+bool table_border_is_more_eyecatching(const struct border *a,
+ box_type a_src, const struct border *b, box_type b_src)
+{
+ css_fixed awidth, bwidth;
+ int impact = 0;
-void table_collapse_borders_cell(struct box *cell, struct box *right,
- struct box *bottom) {
- struct css_border *border;
+ /* See CSS 2.1 $17.6.2.1 */
- if (!cell)
- return;
+ /* 1 + 2 -- hidden beats everything, none beats nothing */
+ if (a->style == CSS_BORDER_STYLE_HIDDEN ||
+ b->style == CSS_BORDER_STYLE_NONE)
+ return false;
+
+ if (b->style == CSS_BORDER_STYLE_HIDDEN ||
+ a->style == CSS_BORDER_STYLE_NONE)
+ return true;
+
+ /* 3a -- wider borders beat narrow ones */
+ /* The widths must be absolute, which will be the case
+ * if they've come from a computed style. */
+ assert(a->unit != CSS_UNIT_EM && a->unit != CSS_UNIT_EX);
+ assert(b->unit != CSS_UNIT_EM && b->unit != CSS_UNIT_EX);
+ awidth = nscss_len2px(a->width, a->unit, NULL);
+ bwidth = nscss_len2px(b->width, b->unit, NULL);
- if ((right) && (right != cell)) {
- border = css_eyecatching_border(&cell->style->border[RIGHT], cell->style,
- &right->style->border[LEFT], right->style);
- cell->style->border[RIGHT] = *border;
+ if (awidth < bwidth)
+ return true;
+ else if (bwidth < awidth)
+ return false;
+ /* 3b -- sort by style */
+ switch (a->style) {
+ case CSS_BORDER_STYLE_DOUBLE: impact++;
+ case CSS_BORDER_STYLE_SOLID: impact++;
+ case CSS_BORDER_STYLE_DASHED: impact++;
+ case CSS_BORDER_STYLE_DOTTED: impact++;
+ case CSS_BORDER_STYLE_RIDGE: impact++;
+ case CSS_BORDER_STYLE_OUTSET: impact++;
+ case CSS_BORDER_STYLE_GROOVE: impact++;
+ case CSS_BORDER_STYLE_INSET: impact++;
+ default:
+ break;
}
- if ((bottom) && (bottom != cell)) {
- border = css_eyecatching_border(&cell->style->border[BOTTOM], cell->style,
- &bottom->style->border[TOP], bottom->style);
- cell->style->border[BOTTOM] = *border;
+
+ switch (b->style) {
+ case CSS_BORDER_STYLE_DOUBLE: impact--;
+ case CSS_BORDER_STYLE_SOLID: impact--;
+ case CSS_BORDER_STYLE_DASHED: impact--;
+ case CSS_BORDER_STYLE_DOTTED: impact--;
+ case CSS_BORDER_STYLE_RIDGE: impact--;
+ case CSS_BORDER_STYLE_OUTSET: impact--;
+ case CSS_BORDER_STYLE_GROOVE: impact--;
+ case CSS_BORDER_STYLE_INSET: impact--;
+ default:
+ break;
}
+
+ if (impact < 0)
+ return true;
+ else if (impact > 0)
+ return false;
+
+ /* 4a -- sort by origin */
+ impact = 0;
+
+ switch (a_src) {
+ case BOX_TABLE_CELL: impact++;
+ case BOX_TABLE_ROW: impact++;
+ case BOX_TABLE_ROW_GROUP: impact++;
+ /** \todo COL/COL_GROUP */
+ case BOX_TABLE: impact++;
+ default:
+ break;
+ }
+
+ switch (b_src) {
+ case BOX_TABLE_CELL: impact--;
+ case BOX_TABLE_ROW: impact--;
+ case BOX_TABLE_ROW_GROUP: impact--;
+ /** \todo COL/COL_GROUP */
+ case BOX_TABLE: impact--;
+ default:
+ break;
+ }
+
+ if (impact < 0)
+ return true;
+ else if (impact > 0)
+ return false;
+
+ /* 4b -- furthest left (if direction: ltr) and towards top wins */
+ /** \todo Currently assumes b satisifies this */
+ return true;
}
+/******************************************************************************
+ * Helpers for top border collapsing *
+ ******************************************************************************/
/**
- * Removes all borders.
+ * Process a table
+ *
+ * \param table Table to process
+ * \param a Current border style for cell
+ * \param a_src Source of \a a
+ *
+ * \post \a a will be updated with most eyecatching style
+ * \post \a a_src will be updated also
*/
+void table_cell_top_process_table(struct box *table, struct border *a,
+ box_type *a_src)
+{
+ struct border b;
+ box_type b_src;
+
+ /* Top border of table */
+ b.style = css_computed_border_top_style(table->style);
+ b.color = css_computed_border_top_color(table->style, &b.c);
+ css_computed_border_top_width(table->style, &b.width, &b.unit);
+ b_src = BOX_TABLE;
+
+ if (table_border_is_more_eyecatching(a, *a_src, &b, b_src)) {
+ *a = b;
+ *a_src = b_src;
+ }
+}
-void table_remove_borders(struct css_style *style)
+/**
+ * Process a group
+ *
+ * \param cell Cell being considered
+ * \param group Group to process
+ * \param a Current border style for cell
+ * \param a_src Source of \a a
+ * \return true if group has non-empty rows, false otherwise
+ *
+ * \post \a a will be updated with most eyecatching style
+ * \post \a a_src will be updated also
+ */
+bool table_cell_top_process_group(struct box *cell, struct box *group,
+ struct border *a, box_type *a_src)
{
- int i;
+ struct border b;
+ box_type b_src;
+
+ /* Bottom border of group */
+ b.style = css_computed_border_bottom_style(group->style);
+ b.color = css_computed_border_bottom_color(group->style, &b.c);
+ css_computed_border_bottom_width(group->style, &b.width, &b.unit);
+ b_src = BOX_TABLE_ROW_GROUP;
+
+ if (table_border_is_more_eyecatching(a, *a_src, &b, b_src)) {
+ *a = b;
+ *a_src = b_src;
+ }
- for (i = 0; i < 4; i++) {
- style->border[i].style = CSS_BORDER_STYLE_NONE;
- style->border[i].width.value.value = 0;
- style->border[i].width.value.unit = CSS_UNIT_PX;
+ if (group->last != NULL) {
+ /* Process rows in group, starting with last */
+ struct box *row = group->last;
+
+ while (table_cell_top_process_row(cell, row,
+ a, a_src) == false) {
+ if (row->prev == NULL) {
+ return false;
+ } else {
+ row = row->prev;
+ }
+ }
+ } else {
+ /* Group is empty, so consider its top border */
+ b.style = css_computed_border_top_style(group->style);
+ b.color = css_computed_border_top_color(group->style, &b.c);
+ css_computed_border_top_width(group->style, &b.width, &b.unit);
+ b_src = BOX_TABLE_ROW_GROUP;
+
+ if (table_border_is_more_eyecatching(a, *a_src, &b, b_src)) {
+ *a = b;
+ *a_src = b_src;
+ }
+
+ return false;
}
-}
+ return true;
+}
/**
- * Find a cell occupying a particular position in a table grid.
+ * Process a row
+ *
+ * \param cell Cell being considered
+ * \param row Row to process
+ * \param a Current border style for cell
+ * \param a_src Source of \a a
+ * \return true if row has cells, false otherwise
+ *
+ * \post \a a will be updated with most eyecatching style
+ * \post \a a_src will be updated also
*/
-
-struct box *table_find_cell(struct box *table, unsigned int x,
- unsigned int y)
+bool table_cell_top_process_row(struct box *cell, struct box *row,
+ struct border *a, box_type *a_src)
{
- struct box *row_group, *row, *cell;
- unsigned int row_num = 0;
-
- if (table->columns <= x || table->rows <= y)
- return 0;
+ struct border b;
+ box_type b_src;
+
+ /* Bottom border of row */
+ b.style = css_computed_border_bottom_style(row->style);
+ b.color = css_computed_border_bottom_color(row->style, &b.c);
+ css_computed_border_bottom_width(row->style, &b.width, &b.unit);
+ b_src = BOX_TABLE_ROW;
+
+ if (table_border_is_more_eyecatching(a, *a_src, &b, b_src)) {
+ *a = b;
+ *a_src = b_src;
+ }
- row_group = table->children;
- row = row_group->children;
+ if (row->children == NULL) {
+ /* Row is empty, so consider its top border */
+ b.style = css_computed_border_top_style(row->style);
+ b.color = css_computed_border_top_color(row->style, &b.c);
+ css_computed_border_top_width(row->style, &b.width, &b.unit);
+ b_src = BOX_TABLE_ROW;
- while (row_num != y) {
- if (row->next) {
- row = row->next;
- } else {
- row_group = row_group->next;
- row = row_group->children;
+ if (table_border_is_more_eyecatching(a, *a_src, &b, b_src)) {
+ *a = b;
+ *a_src = b_src;
}
- row_num++;
- }
+ return false;
+ } else {
+ /* Process cells that are directly above the cell being
+ * considered. They may not be in this row, but in one of the
+ * rows above it in the case where rowspan > 1. */
+ struct box *c;
+ bool processed = false;
+
+ while (processed == false) {
+ for (c = row->children; c != NULL; c = c->next) {
+ /* Ignore cells to the left */
+ if (c->start_column + c->columns <
+ cell->start_column)
+ continue;
+ /* Ignore cells to the right */
+ if (c->start_column >= cell->start_column +
+ cell->columns)
+ continue;
+
+ /* Flag that we've processed a cell */
+ processed = true;
+
+ /* Consider bottom border */
+ b.style = css_computed_border_bottom_style(
+ c->style);
+ b.color = css_computed_border_bottom_color(
+ c->style, &b.c);
+ css_computed_border_bottom_width(c->style,
+ &b.width, &b.unit);
+ b_src = BOX_TABLE_CELL;
+
+ if (table_border_is_more_eyecatching(a, *a_src,
+ &b, b_src)) {
+ *a = b;
+ *a_src = b_src;
+ }
+ }
- for (cell = row->children; cell; cell = cell->next)
- if (cell->start_column <= x &&
- x < cell->start_column + cell->columns)
- break;
+ if (processed == false) {
+ /* There must be a preceding row */
+ assert(row->prev != NULL);
+
+ row = row->prev;
+ }
+ }
+ }
- return cell;
+ return true;
}
+
diff --git a/render/table.h b/render/table.h
index 9a83d6394..ecd3043b5 100644
--- a/render/table.h
+++ b/render/table.h
@@ -29,6 +29,6 @@
struct box;
bool table_calculate_column_types(struct box *table);
-void table_collapse_borders(struct box *table);
+void table_used_border_for_cell(struct box *cell);
#endif
diff --git a/render/textplain.c b/render/textplain.c
index dd3d168f9..256d9b8db 100644
--- a/render/textplain.c
+++ b/render/textplain.c
@@ -30,6 +30,7 @@
#include <iconv.h>
#include "content/content.h"
#include "css/css.h"
+#include "css/utils.h"
#include "desktop/gui.h"
#include "desktop/plotters.h"
#include "desktop/selection.h"
@@ -51,7 +52,7 @@
static plot_font_style_t textplain_style = {
.family = PLOT_FONT_FAMILY_MONOSPACE,
- .size = 10,
+ .size = 10 * FONT_SIZE_SCALE,
.weight = 400,
.flags = FONTF_NONE,
.background = 0xffffff,
@@ -69,7 +70,8 @@ static float textplain_line_height(void);
* Create a CONTENT_TEXTPLAIN.
*/
-bool textplain_create(struct content *c, const char *params[])
+bool textplain_create(struct content *c, struct content *parent,
+ const char *params[])
{
unsigned int i;
char *utf8_data;
@@ -733,6 +735,7 @@ float textplain_line_height(void)
/* Size is in points, so convert to pixels.
* Then use a constant line height of 1.2 x font size.
*/
- return (textplain_style.size * css_screen_dpi / 72) * 1.2;
+ return FIXTOFLT(FDIVI((FMUL(FLTTOFIX(1.2),
+ FMULI(nscss_screen_dpi, textplain_style.size))), 72));
}
diff --git a/render/textplain.h b/render/textplain.h
index 972405fe6..10609a71b 100644
--- a/render/textplain.h
+++ b/render/textplain.h
@@ -46,7 +46,8 @@ struct content_textplain_data {
int formatted_width;
};
-bool textplain_create(struct content *c, const char *params[]);
+bool textplain_create(struct content *c, struct content *parent,
+ const char *params[]);
bool textplain_process_data(struct content *c, char *data, unsigned int size);
bool textplain_convert(struct content *c, int width, int height);
void textplain_reformat(struct content *c, int width, int height);