[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:
parent
ce0d001eb1
commit
74ef206f53
36
render/box.c
36
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(" ");
|
||||
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
112
render/css.c
112
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;
|
||||
}
|
||||
puts(";");
|
||||
printf("\twidth: ");
|
||||
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;
|
||||
}
|
||||
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;
|
||||
|
|
19
render/css.h
19
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"
|
||||
|
@ -38,6 +38,20 @@ struct css_style {
|
|||
struct css_length length;
|
||||
} 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,
|
||||
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
326
render/layout.c
326
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
c = layout_line(c, width, &y, cy + y, cont);
|
||||
}
|
||||
|
||||
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
|
||||
*
|
||||
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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]} {
|
||||
|
|
|
@ -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>
|
||||
|
@ -54,23 +54,21 @@ char * xstrdup(const char * const s)
|
|||
return c;
|
||||
}
|
||||
|
||||
#define CHUNK 0x100
|
||||
|
||||
char * load(const char * const path)
|
||||
{
|
||||
FILE * fp = fopen(path, "r");
|
||||
unsigned int l = 0;
|
||||
char * buf = malloc(CHUNK);
|
||||
if (buf == 0) die("Out of memory in load()");
|
||||
while (1) {
|
||||
unsigned int i;
|
||||
for (i = 0; i != CHUNK && (buf[l] = fgetc(fp)) != EOF; i++, l++)
|
||||
;
|
||||
if (i != CHUNK) break;
|
||||
buf = xrealloc(buf, l + CHUNK);
|
||||
}
|
||||
buf[l] = 0;
|
||||
fclose(fp);
|
||||
FILE * fp = fopen(path, "rb");
|
||||
char * buf;
|
||||
long size, read;
|
||||
|
||||
if (fp == 0) die("Failed to open file");
|
||||
if (fseek(fp, 0, SEEK_END) != 0) die("fseek() failed");
|
||||
if ((size = ftell(fp)) == -1) die("ftell() failed");
|
||||
buf = xcalloc(size, 1);
|
||||
|
||||
if (fseek(fp, 0, SEEK_SET) != 0) die("fseek() failed");
|
||||
read = fread(buf, 1, size, fp);
|
||||
if (read < size) die("fread() failed");
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue