[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
This commit is contained in:
James Bursa 2002-06-18 21:24:21 +00:00
parent ce0d001eb1
commit 74ef206f53
11 changed files with 405 additions and 159 deletions

View File

@ -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> #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 box * inline_container_c;
struct css_style * style; struct css_style * style;
xmlNode * c; xmlNode * c;
xmlChar * s;
if (n->type == XML_ELEMENT_NODE) { if (n->type == XML_ELEMENT_NODE) {
/* work out the style for this element */ /* work out the style for this element */
*selector = xrealloc(*selector, (depth + 1) * sizeof(struct css_selector)); *selector = xrealloc(*selector, (depth + 1) * sizeof(struct css_selector));
(*selector)[depth].element = n->name; (*selector)[depth].element = n->name;
(*selector)[depth].class = (*selector)[depth].id = 0; (*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); 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) { if (n->type == XML_TEXT_NODE) {
box->type = BOX_INLINE; box->type = BOX_INLINE;
box->text = squash_whitespace(n->content); box->text = squash_whitespace(n->content);
box->length = strlen(box->text);
} else { } else {
box->type = BOX_FLOAT; box->type = BOX_FLOAT;
box->style = style; box->style = style;
@ -204,23 +207,26 @@ void box_dump(struct box * box, unsigned int depth)
{ {
unsigned int i; unsigned int i;
struct box * c; struct box * c;
for (i = 0; i < depth; i++)
printf(" ");
printf("x%li y%li w%li h%li ", box->x, box->y, box->width, box->height); for (i = 0; i < depth; i++)
fprintf(stderr, " ");
fprintf(stderr, "x%li y%li w%li h%li ", box->x, box->y, box->width, box->height);
switch (box->type) { switch (box->type) {
case BOX_BLOCK: printf("BOX_BLOCK <%s>\n", box->node->name); break; case BOX_BLOCK: fprintf(stderr, "BOX_BLOCK <%s> ", box->node->name); break;
case BOX_INLINE_CONTAINER: printf("BOX_INLINE_CONTAINER\n"); break; case BOX_INLINE_CONTAINER: fprintf(stderr, "BOX_INLINE_CONTAINER "); break;
case BOX_INLINE: printf("BOX_INLINE '%s'\n", box->text); break; case BOX_INLINE: fprintf(stderr, "BOX_INLINE '%.*s' ", box->length, box->text); break;
case BOX_TABLE: printf("BOX_TABLE <%s>\n", box->node->name); break; case BOX_TABLE: fprintf(stderr, "BOX_TABLE <%s> ", box->node->name); break;
case BOX_TABLE_ROW: printf("BOX_TABLE_ROW <%s>\n", box->node->name); break; case BOX_TABLE_ROW: fprintf(stderr, "BOX_TABLE_ROW <%s> ", box->node->name); break;
case BOX_TABLE_CELL: printf("BOX_TABLE_CELL <%s>\n", box->node->name); break; case BOX_TABLE_CELL: fprintf(stderr, "BOX_TABLE_CELL <%s> ", box->node->name); break;
case BOX_FLOAT: printf("BOX_FLOAT <%s>\n", box->node->name); break; case BOX_FLOAT: fprintf(stderr, "BOX_FLOAT <%s> ", box->node->name); break;
default: printf("Unknown box type\n"); 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) for (c = box->children; c != 0; c = c->next)
box_dump(c, depth + 1); box_dump(c, depth + 1);
} }

View File

@ -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 * parent;
struct box * float_children; struct box * float_children;
struct box * next_float; struct box * next_float;
font_id font;
}; };
/** /**

View File

@ -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> #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_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_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_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_width(struct css_style * const style, const char * const value);
static void parse_selector(struct css_selector * sel, char * const str); static void parse_selector(struct css_selector * sel, char * const str);
static unsigned int hash_str(const char * 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_length(const struct css_length * const length);
static void dump_selector(const struct css_selector * const sel); static void dump_selector(const struct css_selector * const sel);
static void dump_rule(const struct rule * rule); 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 = { const struct css_style css_base_style = {
CSS_DISPLAY_BLOCK, CSS_DISPLAY_BLOCK,
CSS_FLOAT_NONE, CSS_FLOAT_NONE,
{ CSS_FONT_SIZE_ABSOLUTE, 10.0 }, { CSS_FONT_SIZE_LENGTH, {12, CSS_UNIT_PT} },
{ CSS_HEIGHT_AUTO }, { CSS_HEIGHT_AUTO },
{ CSS_LINE_HEIGHT_ABSOLUTE, 1.2 },
CSS_TEXT_ALIGN_LEFT,
{ CSS_WIDTH_AUTO } { CSS_WIDTH_AUTO }
}; };
@ -63,6 +65,8 @@ const struct css_style css_empty_style = {
CSS_FLOAT_INHERIT, CSS_FLOAT_INHERIT,
{ CSS_FONT_SIZE_INHERIT }, { CSS_FONT_SIZE_INHERIT },
{ CSS_HEIGHT_AUTO }, { CSS_HEIGHT_AUTO },
{ CSS_LINE_HEIGHT_INHERIT },
CSS_TEXT_ALIGN_INHERIT,
{ CSS_WIDTH_AUTO } { CSS_WIDTH_AUTO }
}; };
@ -71,6 +75,8 @@ const struct css_style css_blank_style = {
CSS_FLOAT_NONE, CSS_FLOAT_NONE,
{ CSS_FONT_SIZE_INHERIT }, { CSS_FONT_SIZE_INHERIT },
{ CSS_HEIGHT_AUTO }, { CSS_HEIGHT_AUTO },
{ CSS_LINE_HEIGHT_INHERIT },
CSS_TEXT_ALIGN_INHERIT,
{ CSS_WIDTH_AUTO } { CSS_WIDTH_AUTO }
}; };
@ -118,8 +124,9 @@ static void parse_font_size(struct css_style * const style, const char * const v
unsigned int i; unsigned int i;
for (i = 0; i < sizeof(font_size) / sizeof(struct font_size); i++) { for (i = 0; i < sizeof(font_size) / sizeof(struct font_size); i++) {
if (strcmp(value, font_size[i].keyword) == 0) { if (strcmp(value, font_size[i].keyword) == 0) {
style->font_size.size = CSS_FONT_SIZE_ABSOLUTE; style->font_size.size = CSS_FONT_SIZE_LENGTH;
style->font_size.value.absolute = font_size[i].size; style->font_size.value.length.unit = CSS_UNIT_PT;
style->font_size.value.length.value = font_size[i].size * 12;
return; return;
} }
} }
@ -144,6 +151,23 @@ static void parse_height(struct css_style * const style, const char * const valu
style->height.height = CSS_HEIGHT_LENGTH; 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) static void parse_width(struct css_style * const style, const char * const value)
{ {
if (strcmp(value, "auto") == 0) if (strcmp(value, "auto") == 0)
@ -163,6 +187,8 @@ static struct property {
{ "float", parse_float }, { "float", parse_float },
{ "font-size", parse_font_size }, { "font-size", parse_font_size },
{ "height", parse_height }, { "height", parse_height },
{ "line-height", parse_line_height },
{ "text-align", parse_text_align },
{ "width", parse_width }, { "width", parse_width },
}; };
@ -183,7 +209,7 @@ void css_parse_property_list(struct css_style * style, char * str)
*value = 0; value++; *value = 0; value++;
prop = strip(str); prop = strip(str);
value = strip(value); 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++) { for (i = 0; i < sizeof(property) / sizeof(struct property); i++) {
if (strcmp(prop, property[i].name) == 0) { if (strcmp(prop, property[i].name) == 0) {
@ -325,10 +351,10 @@ void css_get_style(struct css_stylesheet * stylesheet, struct css_selector * sel
} else { } else {
qsort(decl, decls, sizeof(struct decl), (int (*) (const void *, const void *)) cmpdecl); qsort(decl, decls, sizeof(struct decl), (int (*) (const void *, const void *)) cmpdecl);
for (d = 0; d < decls; d++) { for (d = 0; d < decls; d++) {
/* printf("%i: 0x%lx\n", d, decl[d].score); */ /* fprintf(stderr, "%i: 0x%lx\n", d, decl[d].score); */
/* css_dump_rule(decl[d].rule); */ /* dump_rule(decl[d].rule);*/
css_cascade(style, decl[d].rule->style); 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); struct rule * rule = find_rule(stylesheet, selector, selectors);
if (rule == 0) { if (rule == 0) {
unsigned int h = hash_str(selector[selectors - 1].element); 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 = xcalloc(1, sizeof(struct rule));
rule->selector = selector; rule->selector = selector;
rule->selectors = selectors; rule->selectors = selectors;
@ -350,7 +376,7 @@ static void update_style(struct css_stylesheet * stylesheet, struct css_selector
rule->next = stylesheet->hash[h]; rule->next = stylesheet->hash[h];
stylesheet->hash[h] = rule; stylesheet->hash[h] = rule;
} else { } else {
/*printf("update_style: already present - updating\n");*/ /*fprintf(stderr, "update_style: already present - updating\n");*/
css_parse_property_list(rule->style, str); css_parse_property_list(rule->style, str);
free(selector); free(selector);
} }
@ -392,7 +418,7 @@ void css_parse_stylesheet(struct css_stylesheet * stylesheet, char * str)
if (comma != 0) *comma = 0; if (comma != 0) *comma = 0;
sel_str = strip(sels_str); sel_str = strip(sels_str);
/*printf("css_parse_stylesheet: %s\n", sel_str);*/ /*fprintf(stderr, "css_parse_stylesheet: %s\n", sel_str);*/
do { do {
space = strchr(sel_str, ' '); space = strchr(sel_str, ' ');
if (space != 0) *space = 0; 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) 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]); css_unit_name[length->unit]);
} }
void css_dump_style(const struct css_style * const style) void css_dump_style(const struct css_style * const style)
{ {
puts("{"); fprintf(stderr, "{ ");
printf("\tdisplay: %s;\n", css_display_name[style->display]); fprintf(stderr, "display: %s; ", css_display_name[style->display]);
printf("\tfloat: %s;\n", css_float_name[style->float_]); fprintf(stderr, "float: %s; ", css_float_name[style->float_]);
printf("\tfont-size: "); fprintf(stderr, "font-size: ");
switch (style->font_size.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_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_PERCENT: fprintf(stderr, "%g%%", style->font_size.value.percent); break;
case CSS_FONT_SIZE_INHERIT: printf("inherit"); break; case CSS_FONT_SIZE_INHERIT: fprintf(stderr, "inherit"); break;
default: printf("UNKNOWN"); break; default: fprintf(stderr, "UNKNOWN"); break;
} }
puts(";"); fprintf(stderr, "; ");
printf("\theight: "); fprintf(stderr, "height: ");
switch (style->height.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; case CSS_HEIGHT_LENGTH: dump_length(&style->height.length); break;
default: printf("UNKNOWN"); break; default: fprintf(stderr, "UNKNOWN"); break;
} }
puts(";"); fprintf(stderr, "; ");
printf("\twidth: "); 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;
}
fprintf(stderr, "; ");
fprintf(stderr, "text-align: %s; ", css_text_align_name[style->text_align]);
fprintf(stderr, "width: ");
switch (style->width.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_LENGTH: dump_length(&style->width.value.length); break;
case CSS_WIDTH_PERCENT: printf("%g%%", style->width.value.percent); break; case CSS_WIDTH_PERCENT: fprintf(stderr, "%g%%", style->width.value.percent); break;
default: printf("UNKNOWN"); break; default: fprintf(stderr, "UNKNOWN"); break;
} }
puts(";"); fprintf(stderr, "; ");
puts("}"); fprintf(stderr, "}");
} }
static void dump_selector(const struct css_selector * const sel) static void dump_selector(const struct css_selector * const sel)
{ {
if (sel->class != 0) if (sel->class != 0)
printf("%s.%s ", sel->element, sel->class); fprintf(stderr, "'%s'.'%s' ", sel->element, sel->class);
else if (sel->id != 0) else if (sel->id != 0)
printf("%s#%s ", sel->element, sel->id); fprintf(stderr, "'%s'#'%s' ", sel->element, sel->id);
else else
printf("%s ", sel->element); fprintf(stderr, "'%s' ", sel->element);
} }
static void dump_rule(const struct rule * rule) 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); 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; unsigned int i;
for (i = 0; i < HASH_SIZE; i++) { for (i = 0; i < HASH_SIZE; i++) {
struct rule * rule; struct rule * rule;
printf("hash %i:\n", i); fprintf(stderr, "hash %i:\n", i);
for (rule = stylesheet->hash[i]; rule != 0; rule = rule->next) for (rule = stylesheet->hash[i]; rule != 0; rule = rule->next)
dump_rule(rule); dump_rule(rule);
} }
@ -552,7 +588,7 @@ int main(int argv, char *argc[])
css_dump_style(style); css_dump_style(style);
} }
/* printf("%x %x\n", r, r2); */ /* fprintf(stderr, "%x %x\n", r, r2); */
/* struct css_style *s; /* struct css_style *s;
struct css_selector *sel; struct css_selector *sel;

View File

@ -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" #include "css_enum.h"
@ -38,6 +38,20 @@ struct css_style {
struct css_length length; struct css_length length;
} height; } 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 { struct {
enum { CSS_WIDTH_AUTO, enum { CSS_WIDTH_AUTO,
CSS_WIDTH_LENGTH, CSS_WIDTH_LENGTH,
@ -52,7 +66,7 @@ struct css_style {
struct css_stylesheet; struct css_stylesheet;
struct css_selector { struct css_selector {
char * element; const char * element;
char * class; char * class;
char * id; 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); unsigned int selectors, struct css_style * style);
void css_parse_stylesheet(struct css_stylesheet * stylesheet, char * str); void css_parse_stylesheet(struct css_stylesheet * stylesheet, char * str);
void css_dump_style(const struct css_style * const style); 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_cascade(struct css_style * const style, const struct css_style * const apply);
void css_parse_property_list(struct css_style * style, char * str); void css_parse_property_list(struct css_style * style, char * str);

View File

@ -11,11 +11,10 @@ css_font_style normal italic oblique
css_font_variant normal smallcaps css_font_variant normal smallcaps
css_font_weight normal bold bolder lighter 100 200 300 400 500 600 700 800 900 css_font_weight normal bold bolder lighter 100 200 300 400 500 600 700 800 900
css_letter_spacing normal length css_letter_spacing normal length
css_line_height normal length number percent
css_list_style_position outside inside css_list_style_position outside inside
css_list_style_type disc circle square decimal lower_alpha lower_roman upper_alpha upper_roman none css_list_style_type disc circle square decimal lower_alpha lower_roman upper_alpha upper_roman none
css_margin auto length percent 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_decoration none blink line_through overline underline
css_text_transform none capitalize lowercase uppercase css_text_transform none capitalize lowercase uppercase
css_vertical_align baseline bottom middle sub super text_bottom text_top top percent css_vertical_align baseline bottom middle sub super text_bottom text_top top percent

View File

@ -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 <assert.h>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "css.h"
#include "font.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; return split;
} }
unsigned long font_width(struct css_style * style, const char * text, unsigned int length)
{
return length * 7;
}

View File

@ -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); 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, struct font_split font_split(struct font_set * font_set, font_id id, const char * text,
unsigned long width, int force); unsigned long width, int force);
unsigned long font_width(struct css_style * style, const char * text, unsigned int length);

View File

@ -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> #include <assert.h>
@ -18,16 +18,20 @@
* internal functions * 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, void layout_block(struct box * box, unsigned long width, struct box * cont,
unsigned long cx, unsigned long cy); unsigned long cx, unsigned long cy);
unsigned long layout_block_children(struct box * box, unsigned long width, struct box * cont, unsigned long layout_block_children(struct box * box, unsigned long width, struct box * cont,
unsigned long cx, unsigned long cy); unsigned long cx, unsigned long cy);
void find_sides(struct box * fl, unsigned long y0, unsigned long y1, 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, void layout_inline_container(struct box * box, unsigned long width, struct box * cont,
unsigned long cx, unsigned long cy); 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, void layout_table(struct box * box, unsigned long width, struct box * cont,
unsigned long cx, unsigned long cy); 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 * 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) { switch (length->unit) {
case CSS_UNIT_EM: return length->value * em; case CSS_UNIT_EM: return length->value * len(&style->font_size.value.length, 0);
case CSS_UNIT_EX: return length->value * em * 0.6; 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_PX: return length->value;
case CSS_UNIT_IN: return length->value * 90.0; case CSS_UNIT_IN: return length->value * 90.0;
case CSS_UNIT_CM: return length->value * 35.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 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) void layout_document(struct box * doc, unsigned long width)
{ {
doc->float_children = 0; doc->float_children = 0;
layout_block(doc, width, doc, 0, 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, void layout_block(struct box * box, unsigned long width, struct box * cont,
unsigned long cx, unsigned long cy) unsigned long cx, unsigned long cy)
{ {
struct css_style * style = box->style; struct css_style * style = box->style;
assert(box->type == BOX_BLOCK || box->type == BOX_FLOAT);
switch (style->width.width) { switch (style->width.width) {
case CSS_WIDTH_AUTO: case CSS_WIDTH_AUTO:
/* take all available width */
box->width = width; box->width = width;
break; break;
case CSS_WIDTH_LENGTH: case CSS_WIDTH_LENGTH:
box->width = len(&style->width.value.length, 20); box->width = len(&style->width.value.length, box->style);
break; break;
case CSS_WIDTH_PERCENT: case CSS_WIDTH_PERCENT:
box->width = width * style->width.value.percent / 100; 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); box->height = layout_block_children(box, box->width, cont, cx, cy);
switch (style->height.height) { switch (style->height.height) {
case CSS_HEIGHT_AUTO: case CSS_HEIGHT_AUTO:
/* use the computed height */
break; break;
case CSS_HEIGHT_LENGTH: case CSS_HEIGHT_LENGTH:
box->height = len(&style->height.length, 20); box->height = len(&style->height.length, box->style);
break; 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 layout_block_children(struct box * box, unsigned long width, struct box * cont,
unsigned long cx, unsigned long cy) unsigned long cx, unsigned long cy)
{ {
struct box * c; struct box * c;
unsigned long y = 0; 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) { for (c = box->children; c != 0; c = c->next) {
switch (c->type) { switch (c->type) {
case BOX_BLOCK: case BOX_BLOCK:
@ -122,91 +158,233 @@ unsigned long layout_block_children(struct box * box, unsigned long width, struc
return y; 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, 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) { for (; fl; fl = fl->next_float) {
if (y0 <= fl->y + fl->height && fl->y <= y1) { 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; *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; *x1 = fl->x;
*right = fl;
}
} }
} }
fprintf(stderr, "find_sides: y0 %li y1 %li => x0 %li x1 %li\n", y0, y1, *x0, *x1); 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, void layout_inline_container(struct box * box, unsigned long width, struct box * cont,
unsigned long cx, unsigned long cy) unsigned long cx, unsigned long cy)
{ {
/* TODO: write this */
struct box * c; struct box * c;
unsigned long y = 0; 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); assert(box->type == BOX_INLINE_CONTAINER);
x = x0;
for (c = box->children; c != 0; ) { for (c = box->children; c != 0; ) {
if (c->type == BOX_FLOAT) { c = layout_line(c, width, &y, cy + y, cont);
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;
}
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;
} 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;
c2 = memcpy(xcalloc(1, sizeof(struct box)), c, sizeof(struct box));
c2->text = split.end;
c2->next = c->next;
c->next = c2;
c = c2;
}
} }
box->width = width; box->width = width;
box->height = y + 30; 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);
}
}
/* 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 {
/* 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 = 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, fit\n");
}
c->width = wp;
}
/* 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 * layout a table
* *
@ -235,7 +413,7 @@ void layout_table(struct box * table, unsigned long width, struct box * cont,
/* find table width */ /* find table width */
switch (table->style->width.width) { switch (table->style->width.width) {
case CSS_WIDTH_LENGTH: case CSS_WIDTH_LENGTH:
table_width = len(&table->style->width.value.length, 20); table_width = len(&table->style->width.value.length, table->style);
break; break;
case CSS_WIDTH_PERCENT: case CSS_WIDTH_PERCENT:
table_width = width * table->style->width.value.percent / 100; 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); assert(c->type == BOX_TABLE_CELL);
switch (c->style->width.width) { switch (c->style->width.width) {
case CSS_WIDTH_LENGTH: case CSS_WIDTH_LENGTH:
used_width += len(&c->style->width.value.length, 20); used_width += len(&c->style->width.value.length, c->style);
break; break;
case CSS_WIDTH_PERCENT: case CSS_WIDTH_PERCENT:
used_width += table_width * c->style->width.value.percent / 100; 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) { for (i = 1, c = table->children->children; c != 0; i++, c = c->next) {
switch (c->style->width.width) { switch (c->style->width.width) {
case CSS_WIDTH_LENGTH: 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; break;
case CSS_WIDTH_PERCENT: case CSS_WIDTH_PERCENT:
x += table_width * c->style->width.value.percent / 100 + extra_width; 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: case CSS_HEIGHT_AUTO:
break; break;
case CSS_HEIGHT_LENGTH: case CSS_HEIGHT_LENGTH:
c->height = len(&c->style->height.length, 10); c->height = len(&c->style->height.length, c->style);
break; break;
} }
c->x = xs[i]; c->x = xs[i];

View File

@ -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> #include <assert.h>
@ -15,7 +15,7 @@
#include "layout.h" #include "layout.h"
/** /**
* internal functions * internal functions
*/ */
void render_plain_element(char * g, struct box * box, unsigned long x, unsigned long y); 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; xmlDoc * doc;
struct box * doc_box = xcalloc(1, sizeof(struct box)); struct box * doc_box = xcalloc(1, sizeof(struct box));
struct box * html_box; struct box * html_box;
char * f;
if (argc < 3) die("usage: render htmlfile cssfile"); if (argc < 3) die("usage: render htmlfile cssfile");
fprintf(stderr, "Parsing html...\n");
doc = htmlParseFile(argv[1], 0); doc = htmlParseFile(argv[1], 0);
if (doc == 0) die("htmlParseFile failed"); 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 (c == 0) die("no element in document");
if (strcmp(c->name, "html")) die("document is not html"); if (strcmp(c->name, "html")) die("document is not html");
fprintf(stderr, "Parsing css...\n");
f = load(argv[2]);
stylesheet = css_new_stylesheet(); 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)); memcpy(style, &css_base_style, sizeof(struct css_style));
doc_box->type = BOX_BLOCK; doc_box->type = BOX_BLOCK;
doc_box->node = c; doc_box->node = c;
fprintf(stderr, "XML tree to box tree...\n");
xml_to_box(c, style, stylesheet, &selector, 0, doc_box, 0); xml_to_box(c, style, stylesheet, &selector, 0, doc_box, 0);
html_box = doc_box->children; 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); layout_document(html_box, 600);
/* box_dump(html_box, 0);*/ box_dump(html_box, 0);
/* render_plain(html_box);*/ /* render_plain(html_box);*/
fprintf(stderr, "Rendering...\n");
printf("%li %li\n", html_box->width, html_box->height); printf("%li %li\n", html_box->width, html_box->height);
render_dump(html_box, 0, 0); render_dump(html_box, 0, 0);
return 0; return 0;
} }

View File

@ -10,7 +10,7 @@ proc rect {x y w h n t c} {
set y [expr $y+8] set y [expr $y+8]
.can create rectangle $x $y [expr $x+$w] [expr $y+$h] -fill $c .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 $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]} { while {-1 != [gets stdin line]} {

View File

@ -1,5 +1,5 @@
/** /**
* $Id: utils.c,v 1.2 2002/05/21 21:27:29 bursa Exp $ * $Id: utils.c,v 1.3 2002/06/18 21:24:21 bursa Exp $
*/ */
#include <ctype.h> #include <ctype.h>
@ -54,23 +54,21 @@ char * xstrdup(const char * const s)
return c; return c;
} }
#define CHUNK 0x100
char * load(const char * const path) char * load(const char * const path)
{ {
FILE * fp = fopen(path, "r"); FILE * fp = fopen(path, "rb");
unsigned int l = 0; char * buf;
char * buf = malloc(CHUNK); long size, read;
if (buf == 0) die("Out of memory in load()");
while (1) { if (fp == 0) die("Failed to open file");
unsigned int i; if (fseek(fp, 0, SEEK_END) != 0) die("fseek() failed");
for (i = 0; i != CHUNK && (buf[l] = fgetc(fp)) != EOF; i++, l++) if ((size = ftell(fp)) == -1) die("ftell() failed");
; buf = xcalloc(size, 1);
if (i != CHUNK) break;
buf = xrealloc(buf, l + CHUNK); if (fseek(fp, 0, SEEK_SET) != 0) die("fseek() failed");
} read = fread(buf, 1, size, fp);
buf[l] = 0; if (read < size) die("fread() failed");
fclose(fp);
return buf; return buf;
} }