summaryrefslogtreecommitdiff
path: root/render
diff options
context:
space:
mode:
authorJames Bursa <james@netsurf-browser.org>2002-06-18 21:24:21 +0000
committerJames Bursa <james@netsurf-browser.org>2002-06-18 21:24:21 +0000
commit74ef206f532445a03a9463d4c0a5e0715e9808b4 (patch)
treee66380bb885014983388486e62785321a02d65de /render
parentce0d001eb13221644242270985975e967a32b297 (diff)
downloadnetsurf-74ef206f532445a03a9463d4c0a5e0715e9808b4.tar.gz
netsurf-74ef206f532445a03a9463d4c0a5e0715e9808b4.tar.bz2
[project @ 2002-06-18 21:24:21 by bursa]
Improved inline and float layout, new CSS properties, better debug output. svn path=/import/netsurf/; revision=20
Diffstat (limited to 'render')
-rw-r--r--render/box.c34
-rw-r--r--render/box.h3
-rw-r--r--render/css.c112
-rw-r--r--render/css.h19
-rw-r--r--render/css_enums3
-rw-r--r--render/font.c7
-rw-r--r--render/font.h3
-rw-r--r--render/layout.c316
-rw-r--r--render/render.c23
-rw-r--r--render/show.tcl2
10 files changed, 385 insertions, 137 deletions
diff --git a/render/box.c b/render/box.c
index cb94fca36..79327602d 100644
--- a/render/box.c
+++ b/render/box.c
@@ -1,5 +1,5 @@
/**
- * $Id: box.c,v 1.4 2002/05/21 21:32:35 bursa Exp $
+ * $Id: box.c,v 1.5 2002/06/18 21:24:21 bursa Exp $
*/
#include <assert.h>
@@ -62,13 +62,15 @@ struct box * xml_to_box(xmlNode * n, struct css_style * parent_style, struct css
struct box * inline_container_c;
struct css_style * style;
xmlNode * c;
+ xmlChar * s;
if (n->type == XML_ELEMENT_NODE) {
/* work out the style for this element */
*selector = xrealloc(*selector, (depth + 1) * sizeof(struct css_selector));
(*selector)[depth].element = n->name;
(*selector)[depth].class = (*selector)[depth].id = 0;
-
+ if ((s = xmlGetProp(n, "class")))
+ (*selector)[depth].class = s;
style = box_get_style(stylesheet, parent_style, n, *selector, depth + 1);
}
@@ -87,6 +89,7 @@ struct box * xml_to_box(xmlNode * n, struct css_style * parent_style, struct css
if (n->type == XML_TEXT_NODE) {
box->type = BOX_INLINE;
box->text = squash_whitespace(n->content);
+ box->length = strlen(box->text);
} else {
box->type = BOX_FLOAT;
box->style = style;
@@ -204,23 +207,26 @@ void box_dump(struct box * box, unsigned int depth)
{
unsigned int i;
struct box * c;
-
+
for (i = 0; i < depth; i++)
- printf(" ");
+ fprintf(stderr, " ");
- printf("x%li y%li w%li h%li ", box->x, box->y, box->width, box->height);
+ fprintf(stderr, "x%li y%li w%li h%li ", box->x, box->y, box->width, box->height);
switch (box->type) {
- case BOX_BLOCK: printf("BOX_BLOCK <%s>\n", box->node->name); break;
- case BOX_INLINE_CONTAINER: printf("BOX_INLINE_CONTAINER\n"); break;
- case BOX_INLINE: printf("BOX_INLINE '%s'\n", box->text); break;
- case BOX_TABLE: printf("BOX_TABLE <%s>\n", box->node->name); break;
- case BOX_TABLE_ROW: printf("BOX_TABLE_ROW <%s>\n", box->node->name); break;
- case BOX_TABLE_CELL: printf("BOX_TABLE_CELL <%s>\n", box->node->name); break;
- case BOX_FLOAT: printf("BOX_FLOAT <%s>\n", box->node->name); break;
- default: printf("Unknown box type\n");
+ case BOX_BLOCK: fprintf(stderr, "BOX_BLOCK <%s> ", box->node->name); break;
+ case BOX_INLINE_CONTAINER: fprintf(stderr, "BOX_INLINE_CONTAINER "); break;
+ case BOX_INLINE: fprintf(stderr, "BOX_INLINE '%.*s' ", box->length, box->text); break;
+ case BOX_TABLE: fprintf(stderr, "BOX_TABLE <%s> ", box->node->name); break;
+ case BOX_TABLE_ROW: fprintf(stderr, "BOX_TABLE_ROW <%s> ", box->node->name); break;
+ case BOX_TABLE_CELL: fprintf(stderr, "BOX_TABLE_CELL <%s> ", box->node->name); break;
+ case BOX_FLOAT: fprintf(stderr, "BOX_FLOAT <%s> ", box->node->name); break;
+ default: fprintf(stderr, "Unknown box type ");
}
-
+ if (box->style)
+ css_dump_style(box->style);
+ fprintf(stderr, "\n");
+
for (c = box->children; c != 0; c = c->next)
box_dump(c, depth + 1);
}
diff --git a/render/box.h b/render/box.h
index 9140fd9ed..0aa8e56f3 100644
--- a/render/box.h
+++ b/render/box.h
@@ -1,5 +1,5 @@
/**
- * $Id: box.h,v 1.2 2002/05/27 23:21:11 bursa Exp $
+ * $Id: box.h,v 1.3 2002/06/18 21:24:21 bursa Exp $
*/
/**
@@ -20,7 +20,6 @@ struct box {
struct box * parent;
struct box * float_children;
struct box * next_float;
- font_id font;
};
/**
diff --git a/render/css.c b/render/css.c
index beb3afa1a..2e59027c8 100644
--- a/render/css.c
+++ b/render/css.c
@@ -1,5 +1,5 @@
/**
- * $Id: css.c,v 1.3 2002/05/18 08:23:39 bursa Exp $
+ * $Id: css.c,v 1.4 2002/06/18 21:24:21 bursa Exp $
*/
#include <string.h>
@@ -35,6 +35,7 @@ static void parse_display(struct css_style * const style, const char * const val
static void parse_float(struct css_style * const style, const char * const value);
static void parse_font_size(struct css_style * const style, const char * const value);
static void parse_height(struct css_style * const style, const char * const value);
+static void parse_text_align(struct css_style * const style, const char * const value);
static void parse_width(struct css_style * const style, const char * const value);
static void parse_selector(struct css_selector * sel, char * const str);
static unsigned int hash_str(const char * str);
@@ -48,13 +49,14 @@ static void update_style(struct css_stylesheet * stylesheet, struct css_selector
static void dump_length(const struct css_length * const length);
static void dump_selector(const struct css_selector * const sel);
static void dump_rule(const struct rule * rule);
-static void css_dump_stylesheet(const struct css_stylesheet * stylesheet);
const struct css_style css_base_style = {
CSS_DISPLAY_BLOCK,
CSS_FLOAT_NONE,
- { CSS_FONT_SIZE_ABSOLUTE, 10.0 },
+ { CSS_FONT_SIZE_LENGTH, {12, CSS_UNIT_PT} },
{ CSS_HEIGHT_AUTO },
+ { CSS_LINE_HEIGHT_ABSOLUTE, 1.2 },
+ CSS_TEXT_ALIGN_LEFT,
{ CSS_WIDTH_AUTO }
};
@@ -63,6 +65,8 @@ const struct css_style css_empty_style = {
CSS_FLOAT_INHERIT,
{ CSS_FONT_SIZE_INHERIT },
{ CSS_HEIGHT_AUTO },
+ { CSS_LINE_HEIGHT_INHERIT },
+ CSS_TEXT_ALIGN_INHERIT,
{ CSS_WIDTH_AUTO }
};
@@ -71,6 +75,8 @@ const struct css_style css_blank_style = {
CSS_FLOAT_NONE,
{ CSS_FONT_SIZE_INHERIT },
{ CSS_HEIGHT_AUTO },
+ { CSS_LINE_HEIGHT_INHERIT },
+ CSS_TEXT_ALIGN_INHERIT,
{ CSS_WIDTH_AUTO }
};
@@ -118,8 +124,9 @@ static void parse_font_size(struct css_style * const style, const char * const v
unsigned int i;
for (i = 0; i < sizeof(font_size) / sizeof(struct font_size); i++) {
if (strcmp(value, font_size[i].keyword) == 0) {
- style->font_size.size = CSS_FONT_SIZE_ABSOLUTE;
- style->font_size.value.absolute = font_size[i].size;
+ style->font_size.size = CSS_FONT_SIZE_LENGTH;
+ style->font_size.value.length.unit = CSS_UNIT_PT;
+ style->font_size.value.length.value = font_size[i].size * 12;
return;
}
}
@@ -144,6 +151,23 @@ static void parse_height(struct css_style * const style, const char * const valu
style->height.height = CSS_HEIGHT_LENGTH;
}
+static void parse_line_height(struct css_style * const style, const char * const value)
+{
+ if (strcmp(value, "normal") == 0)
+ style->line_height.size = CSS_LINE_HEIGHT_ABSOLUTE,
+ style->line_height.value.absolute = 1.0;
+ else if (strrchr(value, '%'))
+ style->line_height.size = CSS_LINE_HEIGHT_PERCENT,
+ style->line_height.value.percent = atof(value);
+ else if (parse_length(&style->line_height.value.length, value) == 0)
+ style->line_height.size = CSS_LINE_HEIGHT_LENGTH;
+}
+
+static void parse_text_align(struct css_style * const style, const char * const value)
+{
+ style->text_align = css_text_align_parse(value);
+}
+
static void parse_width(struct css_style * const style, const char * const value)
{
if (strcmp(value, "auto") == 0)
@@ -163,6 +187,8 @@ static struct property {
{ "float", parse_float },
{ "font-size", parse_font_size },
{ "height", parse_height },
+ { "line-height", parse_line_height },
+ { "text-align", parse_text_align },
{ "width", parse_width },
};
@@ -183,7 +209,7 @@ void css_parse_property_list(struct css_style * style, char * str)
*value = 0; value++;
prop = strip(str);
value = strip(value);
- /*printf("css_parse: '%s' => '%s'\n", prop, value);*/
+ /*fprintf(stderr, "css_parse: '%s' => '%s'\n", prop, value);*/
for (i = 0; i < sizeof(property) / sizeof(struct property); i++) {
if (strcmp(prop, property[i].name) == 0) {
@@ -325,10 +351,10 @@ void css_get_style(struct css_stylesheet * stylesheet, struct css_selector * sel
} else {
qsort(decl, decls, sizeof(struct decl), (int (*) (const void *, const void *)) cmpdecl);
-
+
for (d = 0; d < decls; d++) {
-/* printf("%i: 0x%lx\n", d, decl[d].score); */
-/* css_dump_rule(decl[d].rule); */
+/* fprintf(stderr, "%i: 0x%lx\n", d, decl[d].score); */
+/* dump_rule(decl[d].rule);*/
css_cascade(style, decl[d].rule->style);
}
}
@@ -340,7 +366,7 @@ static void update_style(struct css_stylesheet * stylesheet, struct css_selector
struct rule * rule = find_rule(stylesheet, selector, selectors);
if (rule == 0) {
unsigned int h = hash_str(selector[selectors - 1].element);
- /*printf("update_style: not present - adding\n");*/
+ /*fprintf(stderr, "update_style: not present - adding\n");*/
rule = xcalloc(1, sizeof(struct rule));
rule->selector = selector;
rule->selectors = selectors;
@@ -350,7 +376,7 @@ static void update_style(struct css_stylesheet * stylesheet, struct css_selector
rule->next = stylesheet->hash[h];
stylesheet->hash[h] = rule;
} else {
- /*printf("update_style: already present - updating\n");*/
+ /*fprintf(stderr, "update_style: already present - updating\n");*/
css_parse_property_list(rule->style, str);
free(selector);
}
@@ -392,7 +418,7 @@ void css_parse_stylesheet(struct css_stylesheet * stylesheet, char * str)
if (comma != 0) *comma = 0;
sel_str = strip(sels_str);
- /*printf("css_parse_stylesheet: %s\n", sel_str);*/
+ /*fprintf(stderr, "css_parse_stylesheet: %s\n", sel_str);*/
do {
space = strchr(sel_str, ' ');
if (space != 0) *space = 0;
@@ -418,50 +444,60 @@ void css_parse_stylesheet(struct css_stylesheet * stylesheet, char * str)
static void dump_length(const struct css_length * const length)
{
- printf("%g%s", length->value,
+ fprintf(stderr, "%g%s", length->value,
css_unit_name[length->unit]);
}
void css_dump_style(const struct css_style * const style)
{
- puts("{");
- printf("\tdisplay: %s;\n", css_display_name[style->display]);
- printf("\tfloat: %s;\n", css_float_name[style->float_]);
- printf("\tfont-size: ");
+ fprintf(stderr, "{ ");
+ fprintf(stderr, "display: %s; ", css_display_name[style->display]);
+ fprintf(stderr, "float: %s; ", css_float_name[style->float_]);
+ fprintf(stderr, "font-size: ");
switch (style->font_size.size) {
- case CSS_FONT_SIZE_ABSOLUTE: printf("[%g]", style->font_size.value.absolute); break;
+ case CSS_FONT_SIZE_ABSOLUTE: fprintf(stderr, "[%g]", style->font_size.value.absolute); break;
case CSS_FONT_SIZE_LENGTH: dump_length(&style->font_size.value.length); break;
- case CSS_FONT_SIZE_PERCENT: printf("%g%%", style->font_size.value.percent); break;
- case CSS_FONT_SIZE_INHERIT: printf("inherit"); break;
- default: printf("UNKNOWN"); break;
+ case CSS_FONT_SIZE_PERCENT: fprintf(stderr, "%g%%", style->font_size.value.percent); break;
+ case CSS_FONT_SIZE_INHERIT: fprintf(stderr, "inherit"); break;
+ default: fprintf(stderr, "UNKNOWN"); break;
}
- puts(";");
- printf("\theight: ");
+ fprintf(stderr, "; ");
+ fprintf(stderr, "height: ");
switch (style->height.height) {
- case CSS_HEIGHT_AUTO: printf("auto"); break;
+ case CSS_HEIGHT_AUTO: fprintf(stderr, "auto"); break;
case CSS_HEIGHT_LENGTH: dump_length(&style->height.length); break;
- default: printf("UNKNOWN"); break;
+ default: fprintf(stderr, "UNKNOWN"); break;
+ }
+ fprintf(stderr, "; ");
+ fprintf(stderr, "line-height: ");
+ switch (style->line_height.size) {
+ case CSS_LINE_HEIGHT_ABSOLUTE: fprintf(stderr, "[%g]", style->line_height.value.absolute); break;
+ case CSS_LINE_HEIGHT_LENGTH: dump_length(&style->line_height.value.length); break;
+ case CSS_LINE_HEIGHT_PERCENT: fprintf(stderr, "%g%%", style->line_height.value.percent); break;
+ case CSS_LINE_HEIGHT_INHERIT: fprintf(stderr, "inherit"); break;
+ default: fprintf(stderr, "UNKNOWN"); break;
}
- puts(";");
- printf("\twidth: ");
+ fprintf(stderr, "; ");
+ fprintf(stderr, "text-align: %s; ", css_text_align_name[style->text_align]);
+ fprintf(stderr, "width: ");
switch (style->width.width) {
- case CSS_WIDTH_AUTO: printf("auto"); break;
+ case CSS_WIDTH_AUTO: fprintf(stderr, "auto"); break;
case CSS_WIDTH_LENGTH: dump_length(&style->width.value.length); break;
- case CSS_WIDTH_PERCENT: printf("%g%%", style->width.value.percent); break;
- default: printf("UNKNOWN"); break;
+ case CSS_WIDTH_PERCENT: fprintf(stderr, "%g%%", style->width.value.percent); break;
+ default: fprintf(stderr, "UNKNOWN"); break;
}
- puts(";");
- puts("}");
+ fprintf(stderr, "; ");
+ fprintf(stderr, "}");
}
static void dump_selector(const struct css_selector * const sel)
{
if (sel->class != 0)
- printf("%s.%s ", sel->element, sel->class);
+ fprintf(stderr, "'%s'.'%s' ", sel->element, sel->class);
else if (sel->id != 0)
- printf("%s#%s ", sel->element, sel->id);
+ fprintf(stderr, "'%s'#'%s' ", sel->element, sel->id);
else
- printf("%s ", sel->element);
+ fprintf(stderr, "'%s' ", sel->element);
}
static void dump_rule(const struct rule * rule)
@@ -472,12 +508,12 @@ static void dump_rule(const struct rule * rule)
css_dump_style(rule->style);
}
-static void css_dump_stylesheet(const struct css_stylesheet * stylesheet)
+void css_dump_stylesheet(const struct css_stylesheet * stylesheet)
{
unsigned int i;
for (i = 0; i < HASH_SIZE; i++) {
struct rule * rule;
- printf("hash %i:\n", i);
+ fprintf(stderr, "hash %i:\n", i);
for (rule = stylesheet->hash[i]; rule != 0; rule = rule->next)
dump_rule(rule);
}
@@ -552,7 +588,7 @@ int main(int argv, char *argc[])
css_dump_style(style);
}
-/* printf("%x %x\n", r, r2); */
+/* fprintf(stderr, "%x %x\n", r, r2); */
/* struct css_style *s;
struct css_selector *sel;
diff --git a/render/css.h b/render/css.h
index 425db27f4..2a963f4f3 100644
--- a/render/css.h
+++ b/render/css.h
@@ -1,5 +1,5 @@
/**
- * $Id: css.h,v 1.2 2002/05/04 21:17:06 bursa Exp $
+ * $Id: css.h,v 1.3 2002/06/18 21:24:21 bursa Exp $
*/
#include "css_enum.h"
@@ -39,6 +39,20 @@ struct css_style {
} height;
struct {
+ enum { CSS_LINE_HEIGHT_INHERIT,
+ CSS_LINE_HEIGHT_ABSOLUTE,
+ CSS_LINE_HEIGHT_LENGTH,
+ CSS_LINE_HEIGHT_PERCENT } size;
+ union {
+ float absolute;
+ struct css_length length;
+ float percent;
+ } value;
+ } line_height;
+
+ css_text_align text_align;
+
+ struct {
enum { CSS_WIDTH_AUTO,
CSS_WIDTH_LENGTH,
CSS_WIDTH_PERCENT } width;
@@ -52,7 +66,7 @@ struct css_style {
struct css_stylesheet;
struct css_selector {
- char * element;
+ const char * element;
char * class;
char * id;
};
@@ -69,6 +83,7 @@ void css_get_style(struct css_stylesheet * stylesheet, struct css_selector * sel
unsigned int selectors, struct css_style * style);
void css_parse_stylesheet(struct css_stylesheet * stylesheet, char * str);
void css_dump_style(const struct css_style * const style);
+void css_dump_stylesheet(const struct css_stylesheet * stylesheet);
void css_cascade(struct css_style * const style, const struct css_style * const apply);
void css_parse_property_list(struct css_style * style, char * str);
diff --git a/render/css_enums b/render/css_enums
index 4f8a3f8b0..0f5b7a87e 100644
--- a/render/css_enums
+++ b/render/css_enums
@@ -11,11 +11,10 @@ css_font_style normal italic oblique
css_font_variant normal smallcaps
css_font_weight normal bold bolder lighter 100 200 300 400 500 600 700 800 900
css_letter_spacing normal length
-css_line_height normal length number percent
css_list_style_position outside inside
css_list_style_type disc circle square decimal lower_alpha lower_roman upper_alpha upper_roman none
css_margin auto length percent
-css_text_align left right center justify
+css_text_align inherit left right center justify
css_text_decoration none blink line_through overline underline
css_text_transform none capitalize lowercase uppercase
css_vertical_align baseline bottom middle sub super text_bottom text_top top percent
diff --git a/render/font.c b/render/font.c
index 6ac3a656a..01f3cde09 100644
--- a/render/font.c
+++ b/render/font.c
@@ -1,11 +1,12 @@
/**
- * $Id: font.c,v 1.2 2002/05/11 15:22:24 bursa Exp $
+ * $Id: font.c,v 1.3 2002/06/18 21:24:21 bursa Exp $
*/
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
+#include "css.h"
#include "font.h"
/**
@@ -66,4 +67,8 @@ struct font_split font_split(struct font_set * font_set, font_id id, const char
return split;
}
+unsigned long font_width(struct css_style * style, const char * text, unsigned int length)
+{
+ return length * 7;
+}
diff --git a/render/font.h b/render/font.h
index 4d789a208..2ab98aaef 100644
--- a/render/font.h
+++ b/render/font.h
@@ -1,5 +1,5 @@
/**
- * $Id: font.h,v 1.2 2002/05/11 15:22:24 bursa Exp $
+ * $Id: font.h,v 1.3 2002/06/18 21:24:21 bursa Exp $
*/
/**
@@ -24,4 +24,5 @@ font_id font_add(struct font_set * font_set, const char * name, unsigned int wei
void font_set_free(struct font_set * font_set);
struct font_split font_split(struct font_set * font_set, font_id id, const char * text,
unsigned long width, int force);
+unsigned long font_width(struct css_style * style, const char * text, unsigned int length);
diff --git a/render/layout.c b/render/layout.c
index b7030a658..36c018a9e 100644
--- a/render/layout.c
+++ b/render/layout.c
@@ -1,5 +1,5 @@
/**
- * $Id: layout.c,v 1.5 2002/05/27 23:21:11 bursa Exp $
+ * $Id: layout.c,v 1.6 2002/06/18 21:24:21 bursa Exp $
*/
#include <assert.h>
@@ -18,16 +18,20 @@
* internal functions
*/
-signed long len(struct css_length * length, unsigned long em);
+signed long len(struct css_length * length, struct css_style * style);
void layout_block(struct box * box, unsigned long width, struct box * cont,
unsigned long cx, unsigned long cy);
unsigned long layout_block_children(struct box * box, unsigned long width, struct box * cont,
unsigned long cx, unsigned long cy);
void find_sides(struct box * fl, unsigned long y0, unsigned long y1,
- unsigned long * x0, unsigned long * x1);
+ unsigned long * x0, unsigned long * x1, struct box ** left, struct box ** right);
void layout_inline_container(struct box * box, unsigned long width, struct box * cont,
unsigned long cx, unsigned long cy);
+signed long line_height(struct css_style * style);
+struct box * layout_line(struct box * first, unsigned long width, unsigned long * y,
+ unsigned long cy, struct box * cont);
+void place_float_below(struct box * c, unsigned long width, unsigned long y, struct box * cont);
void layout_table(struct box * box, unsigned long width, struct box * cont,
unsigned long cx, unsigned long cy);
@@ -35,11 +39,12 @@ void layout_table(struct box * box, unsigned long width, struct box * cont,
* convert a struct css_length to pixels
*/
-signed long len(struct css_length * length, unsigned long em)
+signed long len(struct css_length * length, struct css_style * style)
{
+ assert(!((length->unit == CSS_UNIT_EM || length->unit == CSS_UNIT_EX) && style == 0));
switch (length->unit) {
- case CSS_UNIT_EM: return length->value * em;
- case CSS_UNIT_EX: return length->value * em * 0.6;
+ case CSS_UNIT_EM: return length->value * len(&style->font_size.value.length, 0);
+ case CSS_UNIT_EX: return length->value * len(&style->font_size.value.length, 0) * 0.6;
case CSS_UNIT_PX: return length->value;
case CSS_UNIT_IN: return length->value * 90.0;
case CSS_UNIT_CM: return length->value * 35.0;
@@ -55,22 +60,43 @@ signed long len(struct css_length * length, unsigned long em)
* layout algorithm
*/
+/**
+ * layout_document -- calculate positions of boxes in a document
+ *
+ * doc root of document box tree
+ * width page width
+ */
+
void layout_document(struct box * doc, unsigned long width)
{
doc->float_children = 0;
layout_block(doc, width, doc, 0, 0);
}
+
+/**
+ * layout_block -- position block and recursively layout children
+ *
+ * box block box to layout
+ * width horizontal space available
+ * cont ancestor box which defines horizontal space, for inlines
+ * cx, cy box position relative to cont
+ */
+
void layout_block(struct box * box, unsigned long width, struct box * cont,
unsigned long cx, unsigned long cy)
{
struct css_style * style = box->style;
+
+ assert(box->type == BOX_BLOCK || box->type == BOX_FLOAT);
+
switch (style->width.width) {
case CSS_WIDTH_AUTO:
+ /* take all available width */
box->width = width;
break;
case CSS_WIDTH_LENGTH:
- box->width = len(&style->width.value.length, 20);
+ box->width = len(&style->width.value.length, box->style);
break;
case CSS_WIDTH_PERCENT:
box->width = width * style->width.value.percent / 100;
@@ -79,19 +105,29 @@ void layout_block(struct box * box, unsigned long width, struct box * cont,
box->height = layout_block_children(box, box->width, cont, cx, cy);
switch (style->height.height) {
case CSS_HEIGHT_AUTO:
+ /* use the computed height */
break;
case CSS_HEIGHT_LENGTH:
- box->height = len(&style->height.length, 20);
+ box->height = len(&style->height.length, box->style);
break;
}
}
+
+/**
+ * layout_block_children -- recursively layout block children
+ *
+ * (as above)
+ */
+
unsigned long layout_block_children(struct box * box, unsigned long width, struct box * cont,
unsigned long cx, unsigned long cy)
{
struct box * c;
unsigned long y = 0;
-
+
+ assert(box->type == BOX_BLOCK || box->type == BOX_FLOAT || box->type == BOX_TABLE_CELL);
+
for (c = box->children; c != 0; c = c->next) {
switch (c->type) {
case BOX_BLOCK:
@@ -122,91 +158,233 @@ unsigned long layout_block_children(struct box * box, unsigned long width, struc
return y;
}
+
+/**
+ * find_sides -- find left and right margins
+ *
+ * fl first float in float list
+ * y0, y1 y range to search
+ * x1, x1 margins updated
+ * left float on left if present
+ * right float on right if present
+ */
+
void find_sides(struct box * fl, unsigned long y0, unsigned long y1,
- unsigned long * x0, unsigned long * x1)
+ unsigned long * x0, unsigned long * x1, struct box ** left, struct box ** right)
{
+ *left = *right = 0;
for (; fl; fl = fl->next_float) {
if (y0 <= fl->y + fl->height && fl->y <= y1) {
- if (fl->style->float_ == CSS_FLOAT_LEFT && *x0 < fl->x + fl->width)
+ if (fl->style->float_ == CSS_FLOAT_LEFT && *x0 < fl->x + fl->width) {
*x0 = fl->x + fl->width;
- else if (fl->style->float_ == CSS_FLOAT_RIGHT && fl->x < *x1)
+ *left = fl;
+ } else if (fl->style->float_ == CSS_FLOAT_RIGHT && fl->x < *x1) {
*x1 = fl->x;
+ *right = fl;
+ }
}
}
fprintf(stderr, "find_sides: y0 %li y1 %li => x0 %li x1 %li\n", y0, y1, *x0, *x1);
}
+
+/**
+ * layout_inline_container -- layout lines of text or inline boxes with floats
+ *
+ * box inline container
+ * width horizontal space available
+ * cont ancestor box which defines horizontal space, for inlines
+ * cx, cy box position relative to cont
+ */
+
void layout_inline_container(struct box * box, unsigned long width, struct box * cont,
unsigned long cx, unsigned long cy)
{
- /* TODO: write this */
struct box * c;
unsigned long y = 0;
- unsigned long x = 0;
- unsigned long x0 = cx, x1 = cx + width;
- const char * end;
- struct box * c2;
- struct font_split split;
- find_sides(cont->float_children, cy + y, cy + y, &x0, &x1);
- x = x0;
+ assert(box->type == BOX_INLINE_CONTAINER);
for (c = box->children; c != 0; ) {
- if (c->type == BOX_FLOAT) {
- c->float_children = 0;
- layout_block(c, width, c, 0, 0);
- c->x = cx;
- c->y = cy + y + 30;
- fprintf(stderr, "float at %li %li, size %li %li\n", c->x, c->y, c->width, c->height);
- c->next_float = cont->float_children;
- cont->float_children = c;
- c = c->next;
- continue;
+ c = layout_line(c, width, &y, cy + y, cont);
+ }
+
+ box->width = width;
+ box->height = y;
+}
+
+
+signed long line_height(struct css_style * style)
+{
+ assert(style->line_height.size == CSS_LINE_HEIGHT_LENGTH ||
+ style->line_height.size == CSS_LINE_HEIGHT_ABSOLUTE);
+
+ if (style->line_height.size == CSS_LINE_HEIGHT_LENGTH)
+ return len(&style->line_height.value.length, style);
+ else
+ return style->line_height.value.absolute * len(&style->font_size.value.length, 0);
+}
+
+
+struct box * layout_line(struct box * first, unsigned long width, unsigned long * y,
+ unsigned long cy, struct box * cont)
+{
+ unsigned long height;
+ unsigned long x0 = 0;
+ unsigned long x1 = width;
+ unsigned long x, h, xp;
+ struct box * left;
+ struct box * right;
+ struct box * b;
+ struct box * c;
+ struct box * d;
+
+ fprintf(stderr, "layout_line: '%.*s' %li %li %li\n", first->length, first->text, width, *y, cy);
+
+ /* find sides at top of line */
+ find_sides(cont->float_children, cy, cy, &x0, &x1, &left, &right);
+
+ /* get minimum line height from containing block */
+ height = line_height(first->parent->parent->style);
+
+ /* pass 1: find height of line assuming sides at top of line */
+ for (x = 0, b = first; x < x1 - x0 && b != 0; b = b->next) {
+ assert(b->type == BOX_INLINE || b->type == BOX_FLOAT);
+ if (b->type == BOX_INLINE) {
+ h = line_height(b->style ? b->style : b->parent->parent->style);
+ b->height = h;
+ if (h > height) height = h;
+ x += font_width(b->style, b->text, b->length);
}
-
- assert(c->type == BOX_INLINE);
-
- split = font_split(0, c->font, c->text, x1 - x, x == x0);
- if (*(split.end) == 0) {
- /* fits into this line */
- c->x = x;
- c->y = y;
- c->width = split.width;
- c->height = split.height;
- c->length = split.end - c->text;
- x += c->width;
- c = c->next;
- } else if (split.end == c->text) {
- /* doesn't fit at all: move down a line */
- y += 30;
- x0 = cx;
- x1 = cx + width;
- find_sides(cont->float_children, cy + y, cy + y, &x0, &x1);
- x = x0;
+ }
+
+ /* find new sides using this height */
+ find_sides(cont->float_children, cy, cy + height, &x0, &x1, &left, &right);
+
+ /* pass 2: place boxes in line */
+ for (x = xp = 0, b = first; x < x1 - x0 && b != 0; b = b->next) {
+ if (b->type == BOX_INLINE) {
+ b->x = x;
+ xp = x;
+ b->width = font_width(b->style, b->text, b->length);
+ x += b->width;
+ c = b;
+ fprintf(stderr, "layout_line: '%.*s' %li %li\n", b->length, b->text, xp, x);
+ } else {
+ b->float_children = 0;
+ css_dump_style(b->style);
+ layout_block(b, width, b, 0, 0);
+ if (b->width < (x1 - x0) - x || (left == 0 && right == 0 && x == 0)) {
+ /* fits next to this line, or this line is empty with no floats */
+ if (b->style->float_ == CSS_FLOAT_LEFT) {
+ b->x = x0;
+ x0 += b->width;
+ left = b;
+ } else {
+ b->x = x1 - b->width;
+ x1 -= b->width;
+ right = b;
+ }
+ b->y = cy;
+ fprintf(stderr, "layout_line: float fits %li %li, edges %li %li\n",
+ b->x, b->y, x0, x1);
+ } else {
+ /* doesn't fit: place below */
+ place_float_below(b, width, cy + height + 1, cont);
+ fprintf(stderr, "layout_line: float doesn't fit %li %li\n", b->x, b->y);
+ }
+ b->next_float = cont->float_children;
+ cont->float_children = b;
+ }
+ }
+
+ if (x1 - x0 < x) {
+ /* the last box went over the end */
+ char * space = strchr(c->text, ' ');
+ char * space2 = space;
+ unsigned long w = font_width(c->style, c->text, space - c->text), wp = w;
+ struct box * c2;
+
+ if (x1 - x0 < xp + w && left == 0 && right == 0 && c == first) {
+ /* first word doesn't fit, but no floats and first on line so force in */
+ c2 = memcpy(xcalloc(1, sizeof(struct box)), c, sizeof(struct box));
+ c2->text = space + 1;
+ c2->length = c->length - (c2->text - c->text);
+ c->length = space - c->text;
+ c2->next = c->next;
+ c->next = c2;
+ b = c2;
+ fprintf(stderr, "layout_line: overflow, forcing\n");
+ } else if (x1 - x0 < xp + w) {
+ /* first word doesn't fit, but full width not available so leave for later */
+ b = c;
+ fprintf(stderr, "layout_line: overflow, leaving\n");
} else {
- /* split into two lines */
- c->x = x;
- c->y = y;
- c->width = split.width;
- c->height = split.height;
- c->length = split.end - c->text;
- y += 30;
- x0 = cx;
- x1 = cx + width;
- find_sides(cont->float_children, cy + y, cy + y, &x0, &x1);
- x = x0;
+ /* fit as many words as possible */
+ while (xp + w < x1 - x0) {
+ fprintf(stderr, "%li + %li = %li < %li = %li - %li\n",
+ xp, w, xp + w, x1 - x0, x1, x0);
+ space = space2;
+ wp = w;
+ space2 = strchr(space + 1, ' ');
+ w = font_width(c->style, c->text, space2 - c->text);
+ }
c2 = memcpy(xcalloc(1, sizeof(struct box)), c, sizeof(struct box));
- c2->text = split.end;
+ c2->text = space + 1;
+ c2->length = c->length - (c2->text - c->text);
+ c->length = space - c->text;
c2->next = c->next;
c->next = c2;
- c = c2;
+ b = c2;
+ fprintf(stderr, "layout_line: overflow, fit\n");
}
+ c->width = wp;
}
- box->width = width;
- box->height = y + 30;
+ /* set positions */
+ for (d = first; d != b; d = d->next) {
+ if (d->type == BOX_INLINE) {
+ d->x += x0;
+ d->y = *y;
+ }
+ }
+
+ *y += height + 1;
+ return b;
}
+
+
+void place_float_below(struct box * c, unsigned long width, unsigned long y, struct box * cont)
+{
+ unsigned long x0, x1, yy = y;
+ struct box * left;
+ struct box * right;
+ do {
+ y = yy;
+ x0 = 0;
+ x1 = width;
+ find_sides(cont->float_children, y, y, &x0, &x1, &left, &right);
+ if (left != 0 && right != 0) {
+ yy = (left->y + left->height < right->y + right->height ?
+ left->y + left->height : right->y + right->height) + 1;
+ } else if (left == 0 && right != 0) {
+ yy = right->y + right->height + 1;
+ } else if (left != 0 && right == 0) {
+ yy = left->y + left->height + 1;
+ }
+ } while (!((left == 0 && right == 0) || (c->width < x1 - x0)));
+
+ if (c->style->float_ == CSS_FLOAT_LEFT) {
+ c->x = x0;
+ } else {
+ c->x = x1 - c->width;
+ }
+ c->y = y;
+}
+
+
+
/**
* layout a table
*
@@ -235,7 +413,7 @@ void layout_table(struct box * table, unsigned long width, struct box * cont,
/* find table width */
switch (table->style->width.width) {
case CSS_WIDTH_LENGTH:
- table_width = len(&table->style->width.value.length, 20);
+ table_width = len(&table->style->width.value.length, table->style);
break;
case CSS_WIDTH_PERCENT:
table_width = width * table->style->width.value.percent / 100;
@@ -252,7 +430,7 @@ void layout_table(struct box * table, unsigned long width, struct box * cont,
assert(c->type == BOX_TABLE_CELL);
switch (c->style->width.width) {
case CSS_WIDTH_LENGTH:
- used_width += len(&c->style->width.value.length, 20);
+ used_width += len(&c->style->width.value.length, c->style);
break;
case CSS_WIDTH_PERCENT:
used_width += table_width * c->style->width.value.percent / 100;
@@ -277,7 +455,7 @@ void layout_table(struct box * table, unsigned long width, struct box * cont,
for (i = 1, c = table->children->children; c != 0; i++, c = c->next) {
switch (c->style->width.width) {
case CSS_WIDTH_LENGTH:
- x += len(&c->style->width.value.length, 10) + extra_width;
+ x += len(&c->style->width.value.length, c->style) + extra_width;
break;
case CSS_WIDTH_PERCENT:
x += table_width * c->style->width.value.percent / 100 + extra_width;
@@ -305,7 +483,7 @@ void layout_table(struct box * table, unsigned long width, struct box * cont,
case CSS_HEIGHT_AUTO:
break;
case CSS_HEIGHT_LENGTH:
- c->height = len(&c->style->height.length, 10);
+ c->height = len(&c->style->height.length, c->style);
break;
}
c->x = xs[i];
diff --git a/render/render.c b/render/render.c
index 0ec17fb37..66009fe65 100644
--- a/render/render.c
+++ b/render/render.c
@@ -1,5 +1,5 @@
/**
- * $Id: render.c,v 1.12 2002/05/27 23:21:11 bursa Exp $
+ * $Id: render.c,v 1.13 2002/06/18 21:24:21 bursa Exp $
*/
#include <assert.h>
@@ -15,7 +15,7 @@
#include "layout.h"
/**
- * internal functions
+ * internal functions
*/
void render_plain_element(char * g, struct box * box, unsigned long x, unsigned long y);
@@ -141,9 +141,11 @@ int main(int argc, char *argv[])
xmlDoc * doc;
struct box * doc_box = xcalloc(1, sizeof(struct box));
struct box * html_box;
+ char * f;
if (argc < 3) die("usage: render htmlfile cssfile");
-
+
+ fprintf(stderr, "Parsing html...\n");
doc = htmlParseFile(argv[1], 0);
if (doc == 0) die("htmlParseFile failed");
@@ -152,22 +154,29 @@ int main(int argc, char *argv[])
if (c == 0) die("no element in document");
if (strcmp(c->name, "html")) die("document is not html");
+ fprintf(stderr, "Parsing css...\n");
+ f = load(argv[2]);
stylesheet = css_new_stylesheet();
- css_parse_stylesheet(stylesheet, load(argv[2]));
+ css_parse_stylesheet(stylesheet, f);
+/* css_dump_stylesheet(stylesheet);*/
memcpy(style, &css_base_style, sizeof(struct css_style));
doc_box->type = BOX_BLOCK;
doc_box->node = c;
+ fprintf(stderr, "XML tree to box tree...\n");
xml_to_box(c, style, stylesheet, &selector, 0, doc_box, 0);
html_box = doc_box->children;
- /*box_dump(html_box, 0);*/
+ box_dump(html_box, 0);
+ fprintf(stderr, "Layout document...\n");
layout_document(html_box, 600);
-/* box_dump(html_box, 0);*/
+ box_dump(html_box, 0);
/* render_plain(html_box);*/
+
+ fprintf(stderr, "Rendering...\n");
printf("%li %li\n", html_box->width, html_box->height);
render_dump(html_box, 0, 0);
-
+
return 0;
}
diff --git a/render/show.tcl b/render/show.tcl
index 4adc48287..2688c6cc8 100644
--- a/render/show.tcl
+++ b/render/show.tcl
@@ -10,7 +10,7 @@ proc rect {x y w h n t c} {
set y [expr $y+8]
.can create rectangle $x $y [expr $x+$w] [expr $y+$h] -fill $c
.can create text $x $y -anchor nw -text $n -fill red -font "arial 18 bold"
- .can create text $x [expr $y+$h] -anchor sw -text $t -font "courier 32"
+ .can create text $x [expr $y+$h] -anchor sw -text $t -font "courier 12"
}
while {-1 != [gets stdin line]} {