mirror of
https://github.com/netsurf-browser/netsurf
synced 2024-12-26 22:09:43 +03:00
Initial work for display: list-item support
svn path=/trunk/netsurf/; revision=3028
This commit is contained in:
parent
2d4276ee41
commit
7bd710a71c
@ -495,6 +495,10 @@ void box_dump(struct box *box, unsigned int depth)
|
||||
case BOX_FLOAT_RIGHT: fprintf(stderr, "FLOAT_RIGHT "); break;
|
||||
case BOX_BR: fprintf(stderr, "BR "); break;
|
||||
case BOX_TEXT: fprintf(stderr, "TEXT "); break;
|
||||
case BOX_LIST: fprintf(stderr, "LIST "); break;
|
||||
case BOX_LIST_ITEM: fprintf(stderr, "LIST_ITEM "); break;
|
||||
case BOX_LIST_MARKER: fprintf(stderr, "LIST_MARKER "); break;
|
||||
case BOX_LIST_PRINCIPAL: fprintf(stderr, "LIST_PRINCIPAL "); break;
|
||||
default: fprintf(stderr, "Unknown box type ");
|
||||
}
|
||||
|
||||
|
13
render/box.h
13
render/box.h
@ -60,15 +60,19 @@
|
||||
* A box tree is "normalized" if the following is satisfied:
|
||||
* \code
|
||||
* parent permitted child nodes
|
||||
* BLOCK, INLINE_BLOCK BLOCK, INLINE_CONTAINER, TABLE
|
||||
* BLOCK, INLINE_BLOCK BLOCK, INLINE_CONTAINER, TABLE, LIST
|
||||
* INLINE_CONTAINER INLINE, INLINE_BLOCK, FLOAT_LEFT, FLOAT_RIGHT, BR, TEXT,
|
||||
* INLINE_END
|
||||
* INLINE none
|
||||
* TABLE at least 1 TABLE_ROW_GROUP
|
||||
* TABLE_ROW_GROUP at least 1 TABLE_ROW
|
||||
* TABLE_ROW at least 1 TABLE_CELL
|
||||
* TABLE_CELL BLOCK, INLINE_CONTAINER, TABLE (same as BLOCK)
|
||||
* FLOAT_(LEFT|RIGHT) exactly 1 BLOCK or TABLE \endcode
|
||||
* TABLE_CELL BLOCK, INLINE_CONTAINER, TABLE, LIST (same as BLOCK)
|
||||
* FLOAT_(LEFT|RIGHT) exactly 1 BLOCK or TABLE
|
||||
* LIST at least 1 LIST_ITEM
|
||||
* LIST_ITEM exactly 1 LIST_MARKER and exactly 1 LIST_PRINCIPAL
|
||||
* LIST_PRINCIPAL BLOCK, INLINE_CONTAINER, TABLE, LIST (same as BLOCK)
|
||||
* \endcode
|
||||
*/
|
||||
|
||||
#ifndef _NETSURF_RENDER_BOX_H_
|
||||
@ -93,7 +97,8 @@ typedef enum {
|
||||
BOX_TABLE_ROW_GROUP,
|
||||
BOX_FLOAT_LEFT, BOX_FLOAT_RIGHT,
|
||||
BOX_INLINE_BLOCK, BOX_BR, BOX_TEXT,
|
||||
BOX_INLINE_END
|
||||
BOX_INLINE_END,
|
||||
BOX_LIST, BOX_LIST_ITEM, BOX_LIST_MARKER, BOX_LIST_PRINCIPAL
|
||||
} box_type;
|
||||
|
||||
struct rect {
|
||||
|
@ -205,7 +205,7 @@ static const box_type box_map[] = {
|
||||
0, /*CSS_DISPLAY_INHERIT,*/
|
||||
BOX_INLINE, /*CSS_DISPLAY_INLINE,*/
|
||||
BOX_BLOCK, /*CSS_DISPLAY_BLOCK,*/
|
||||
BOX_BLOCK, /*CSS_DISPLAY_LIST_ITEM,*/
|
||||
BOX_LIST_ITEM, /*CSS_DISPLAY_LIST_ITEM,*/
|
||||
BOX_INLINE, /*CSS_DISPLAY_RUN_IN,*/
|
||||
BOX_INLINE_BLOCK, /*CSS_DISPLAY_INLINE_BLOCK,*/
|
||||
BOX_TABLE, /*CSS_DISPLAY_TABLE,*/
|
||||
@ -350,6 +350,10 @@ bool box_construct_element(xmlNode *n, struct content *content,
|
||||
return true;
|
||||
}
|
||||
|
||||
/* if this is a list item, then reset the box type */
|
||||
if (style->display == CSS_DISPLAY_LIST_ITEM)
|
||||
box->type = BOX_LIST_ITEM;
|
||||
|
||||
if (!*inline_container &&
|
||||
(box->type == BOX_INLINE ||
|
||||
box->type == BOX_BR ||
|
||||
@ -394,6 +398,59 @@ bool box_construct_element(xmlNode *n, struct content *content,
|
||||
&inline_container_c,
|
||||
href, target, title))
|
||||
return false;
|
||||
} else if (box->type == BOX_LIST_ITEM) {
|
||||
/* list item: create marker box and recurse */
|
||||
struct box *list_item;
|
||||
struct box *marker;
|
||||
|
||||
/* create container box */
|
||||
list_item = box_create(0, href, target, title, 0, content);
|
||||
if (!list_item)
|
||||
return false;
|
||||
list_item->type = BOX_LIST_ITEM;
|
||||
|
||||
/* create marker - effectively a single INLINE */
|
||||
/* marker style information is contained in PRINCIPAL box */
|
||||
marker = box_create(box->style, href, target, title, 0,
|
||||
content);
|
||||
if (!marker)
|
||||
return false;
|
||||
marker->type = BOX_LIST_MARKER;
|
||||
marker->clone = 1;
|
||||
|
||||
/** \todo marker content (list-style-type)
|
||||
* need to traverse up the tree to find containing BOX_LIST,
|
||||
* which contains the counter information */
|
||||
marker->text = talloc_strdup(content, "1.");
|
||||
if (!marker->text)
|
||||
return false;
|
||||
marker->space = 1;
|
||||
marker->length = 2;
|
||||
|
||||
if (style->list_style_image.type ==
|
||||
CSS_LIST_STYLE_IMAGE_URI) {
|
||||
if (!html_fetch_object(content,
|
||||
style->list_style_image.uri, marker,
|
||||
0, content->available_width, 1000,
|
||||
false))
|
||||
return false;
|
||||
}
|
||||
|
||||
/* make box into principal block for list */
|
||||
box->type = BOX_LIST_PRINCIPAL;
|
||||
|
||||
box_add_child(parent, list_item);
|
||||
box_add_child(list_item, marker);
|
||||
box_add_child(list_item, box);
|
||||
|
||||
/* and recurse */
|
||||
inline_container_c = 0;
|
||||
for (c = n->children; convert_children && c; c = c->next) {
|
||||
if (!convert_xml_to_box(c, content, style,
|
||||
box, &inline_container_c,
|
||||
href, target, title))
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (style->float_ == CSS_FLOAT_LEFT ||
|
||||
style->float_ == CSS_FLOAT_RIGHT) {
|
||||
|
@ -57,26 +57,32 @@ static bool calculate_table_row(struct columns *col_info,
|
||||
unsigned int col_span, unsigned int row_span,
|
||||
unsigned int *start_column);
|
||||
static bool box_normalise_inline_container(struct box *cont, struct content *c);
|
||||
static bool box_normalise_list(struct box *cont, struct content *c);
|
||||
static bool box_normalise_list_item(struct box *cont, struct content *c);
|
||||
|
||||
|
||||
/**
|
||||
* Ensure the box tree is correctly nested by adding and removing nodes.
|
||||
*
|
||||
* \param block box of type BLOCK, INLINE_BLOCK, or TABLE_CELL
|
||||
* \param block box of type BLOCK, INLINE_BLOCK, TABLE_CELL or LIST_PRINCIPAL
|
||||
* \param box_pool pool to allocate new boxes in
|
||||
* \return true on success, false on memory exhaustion
|
||||
*
|
||||
* The tree is modified to satisfy the following:
|
||||
* \code
|
||||
* parent permitted child nodes
|
||||
* BLOCK, INLINE_BLOCK BLOCK, INLINE_CONTAINER, TABLE
|
||||
* BLOCK, INLINE_BLOCK BLOCK, INLINE_CONTAINER, TABLE, LIST
|
||||
* INLINE_CONTAINER INLINE, INLINE_BLOCK, FLOAT_LEFT, FLOAT_RIGHT, BR, TEXT
|
||||
* INLINE, TEXT none
|
||||
* TABLE at least 1 TABLE_ROW_GROUP
|
||||
* TABLE_ROW_GROUP at least 1 TABLE_ROW
|
||||
* TABLE_ROW at least 1 TABLE_CELL
|
||||
* TABLE_CELL BLOCK, INLINE_CONTAINER, TABLE (same as BLOCK)
|
||||
* FLOAT_(LEFT|RIGHT) exactly 1 BLOCK or TABLE \endcode
|
||||
* FLOAT_(LEFT|RIGHT) exactly 1 BLOCK or TABLE
|
||||
* LIST at least 1 LIST_ITEM
|
||||
* LIST_ITEM exactly 1 LIST_MARKER and exactly 1 LIST_PRINCIPAL
|
||||
* LIST_PRINCIPAL BLOCK, INLINE_CONTAINER, TABLE, LIST (same as BLOCK)
|
||||
* \endcode
|
||||
*/
|
||||
|
||||
bool box_normalise_block(struct box *block, struct content *c)
|
||||
@ -84,12 +90,14 @@ bool box_normalise_block(struct box *block, struct content *c)
|
||||
struct box *child;
|
||||
struct box *next_child;
|
||||
struct box *table;
|
||||
struct box *list;
|
||||
struct css_style *style;
|
||||
|
||||
assert(block != 0);
|
||||
LOG(("block %p, block->type %u", block, block->type));
|
||||
assert(block->type == BOX_BLOCK || block->type == BOX_INLINE_BLOCK ||
|
||||
block->type == BOX_TABLE_CELL);
|
||||
block->type == BOX_TABLE_CELL ||
|
||||
block->type == BOX_LIST_PRINCIPAL);
|
||||
gui_multitask();
|
||||
|
||||
for (child = block->children; child != 0; child = next_child) {
|
||||
@ -158,6 +166,48 @@ bool box_normalise_block(struct box *block, struct content *c)
|
||||
if (!box_normalise_table(table, c))
|
||||
return false;
|
||||
break;
|
||||
case BOX_LIST:
|
||||
if (!box_normalise_list(child, c))
|
||||
return false;
|
||||
break;
|
||||
case BOX_LIST_ITEM:
|
||||
/* Insert implied BOX_LIST */
|
||||
style = css_duplicate_style(block->style);
|
||||
if (!style)
|
||||
return false;
|
||||
css_cascade(style, &css_blank_style);
|
||||
list = box_create(style, 0, 0, 0, 0, c);
|
||||
if (!list) {
|
||||
css_free_style(style);
|
||||
return false;
|
||||
}
|
||||
list->type = BOX_LIST;
|
||||
if (child->prev == 0)
|
||||
block->children = list;
|
||||
else
|
||||
child->prev->next = list;
|
||||
list->prev = child->prev;
|
||||
while (child != 0 && child->type == BOX_LIST_ITEM) {
|
||||
box_add_child(list, child);
|
||||
next_child = child->next;
|
||||
child->next = 0;
|
||||
child = next_child;
|
||||
}
|
||||
list->last->next = 0;
|
||||
list->next = next_child = child;
|
||||
if (list->next)
|
||||
list->next->prev = list;
|
||||
else
|
||||
block->last = list;
|
||||
list->parent = block;
|
||||
if (!box_normalise_list(list, c))
|
||||
return false;
|
||||
break;
|
||||
case BOX_LIST_MARKER:
|
||||
case BOX_LIST_PRINCIPAL:
|
||||
/* Should be wrapped in BOX_LIST_ITEM */
|
||||
assert(0);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
@ -205,6 +255,8 @@ bool box_normalise_table(struct box *table, struct content * c)
|
||||
case BOX_TABLE:
|
||||
case BOX_TABLE_ROW:
|
||||
case BOX_TABLE_CELL:
|
||||
case BOX_LIST:
|
||||
case BOX_LIST_ITEM:
|
||||
/* insert implied table row group */
|
||||
assert(table->style != NULL);
|
||||
style = css_duplicate_style(table->style);
|
||||
@ -233,12 +285,15 @@ bool box_normalise_table(struct box *table, struct content * c)
|
||||
child->type == BOX_INLINE_CONTAINER ||
|
||||
child->type == BOX_TABLE ||
|
||||
child->type == BOX_TABLE_ROW ||
|
||||
child->type == BOX_TABLE_CELL)) {
|
||||
child->type == BOX_TABLE_CELL ||
|
||||
child->type == BOX_LIST ||
|
||||
child->type == BOX_LIST_ITEM)) {
|
||||
box_add_child(row_group, child);
|
||||
next_child = child->next;
|
||||
child->next = 0;
|
||||
child = next_child;
|
||||
}
|
||||
assert(row_group->last != NULL);
|
||||
row_group->last->next = 0;
|
||||
row_group->next = next_child = child;
|
||||
if (row_group->next)
|
||||
@ -261,6 +316,11 @@ bool box_normalise_table(struct box *table, struct content * c)
|
||||
container by convert_xml_to_box() */
|
||||
assert(0);
|
||||
break;
|
||||
case BOX_LIST_MARKER:
|
||||
case BOX_LIST_PRINCIPAL:
|
||||
/* Should have been wrapped in BOX_LIST_ITEM */
|
||||
assert(0);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "%i\n", child->type);
|
||||
assert(0);
|
||||
@ -381,6 +441,8 @@ bool box_normalise_table_row_group(struct box *row_group,
|
||||
case BOX_TABLE:
|
||||
case BOX_TABLE_ROW_GROUP:
|
||||
case BOX_TABLE_CELL:
|
||||
case BOX_LIST:
|
||||
case BOX_LIST_ITEM:
|
||||
/* insert implied table row */
|
||||
assert(row_group->style != NULL);
|
||||
style = css_duplicate_style(row_group->style);
|
||||
@ -404,12 +466,15 @@ bool box_normalise_table_row_group(struct box *row_group,
|
||||
child->type == BOX_INLINE_CONTAINER ||
|
||||
child->type == BOX_TABLE ||
|
||||
child->type == BOX_TABLE_ROW_GROUP ||
|
||||
child->type == BOX_TABLE_CELL)) {
|
||||
child->type == BOX_TABLE_CELL ||
|
||||
child->type == BOX_LIST ||
|
||||
child->type == BOX_LIST_ITEM)) {
|
||||
box_add_child(row, child);
|
||||
next_child = child->next;
|
||||
child->next = 0;
|
||||
child = next_child;
|
||||
}
|
||||
assert(row->last != NULL);
|
||||
row->last->next = 0;
|
||||
row->next = next_child = child;
|
||||
if (row->next)
|
||||
@ -430,6 +495,11 @@ bool box_normalise_table_row_group(struct box *row_group,
|
||||
container by convert_xml_to_box() */
|
||||
assert(0);
|
||||
break;
|
||||
case BOX_LIST_MARKER:
|
||||
case BOX_LIST_PRINCIPAL:
|
||||
/* should have been wrapped in LIST_ITEM */
|
||||
assert(0);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
@ -480,6 +550,8 @@ bool box_normalise_table_row(struct box *row,
|
||||
case BOX_TABLE:
|
||||
case BOX_TABLE_ROW_GROUP:
|
||||
case BOX_TABLE_ROW:
|
||||
case BOX_LIST:
|
||||
case BOX_LIST_ITEM:
|
||||
/* insert implied table cell */
|
||||
assert(row->style != NULL);
|
||||
style = css_duplicate_style(row->style);
|
||||
@ -503,12 +575,15 @@ bool box_normalise_table_row(struct box *row,
|
||||
child->type == BOX_INLINE_CONTAINER ||
|
||||
child->type == BOX_TABLE ||
|
||||
child->type == BOX_TABLE_ROW_GROUP ||
|
||||
child->type == BOX_TABLE_ROW)) {
|
||||
child->type == BOX_TABLE_ROW ||
|
||||
child->type == BOX_LIST ||
|
||||
child->type == BOX_LIST_ITEM)) {
|
||||
box_add_child(cell, child);
|
||||
next_child = child->next;
|
||||
child->next = 0;
|
||||
child = next_child;
|
||||
}
|
||||
assert(cell->last != NULL);
|
||||
cell->last->next = 0;
|
||||
cell->next = next_child = child;
|
||||
if (cell->next)
|
||||
@ -528,6 +603,11 @@ bool box_normalise_table_row(struct box *row,
|
||||
container by convert_xml_to_box() */
|
||||
assert(0);
|
||||
break;
|
||||
case BOX_LIST_MARKER:
|
||||
case BOX_LIST_PRINCIPAL:
|
||||
/* should have been wrapped in a BOX_LIST_ITEM */
|
||||
assert(0);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
@ -703,6 +783,10 @@ bool box_normalise_inline_container(struct box *cont, struct content * c)
|
||||
case BOX_TABLE_ROW_GROUP:
|
||||
case BOX_TABLE_ROW:
|
||||
case BOX_TABLE_CELL:
|
||||
case BOX_LIST:
|
||||
case BOX_LIST_ITEM:
|
||||
case BOX_LIST_MARKER:
|
||||
case BOX_LIST_PRINCIPAL:
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
@ -712,3 +796,58 @@ bool box_normalise_inline_container(struct box *cont, struct content * c)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool box_normalise_list(struct box *cont, struct content *c)
|
||||
{
|
||||
struct box *child;
|
||||
struct box *next_child;
|
||||
|
||||
assert(cont != 0);
|
||||
assert(cont->type == BOX_LIST);
|
||||
|
||||
for (child = cont->children; child; child = next_child) {
|
||||
next_child = child->next;
|
||||
switch (child->type) {
|
||||
case BOX_LIST_ITEM:
|
||||
/* ok */
|
||||
if (!box_normalise_list_item(child, c))
|
||||
return false;
|
||||
break;
|
||||
case BOX_LIST_MARKER:
|
||||
case BOX_LIST_PRINCIPAL:
|
||||
/** \todo imply LIST_ITEM here? */
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool box_normalise_list_item(struct box *cont, struct content *c)
|
||||
{
|
||||
struct box *child;
|
||||
struct box *next_child;
|
||||
|
||||
assert(cont != 0);
|
||||
assert(cont->type == BOX_LIST_ITEM);
|
||||
|
||||
for (child = cont->children; child; child = next_child) {
|
||||
next_child = child->next;
|
||||
switch (child->type) {
|
||||
case BOX_LIST_MARKER:
|
||||
/* ok */
|
||||
break;
|
||||
case BOX_LIST_PRINCIPAL:
|
||||
/* ok */
|
||||
if (!box_normalise_block(child, c))
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
205
render/layout.c
205
render/layout.c
@ -48,6 +48,7 @@
|
||||
static void layout_minmax_block(struct box *block);
|
||||
static bool layout_block_object(struct box *block);
|
||||
static void layout_block_find_dimensions(int available_width, struct box *box);
|
||||
static void layout_list_find_dimensions(int available_width, struct box *box);
|
||||
static int layout_solve_width(int available_width, int width,
|
||||
int margin[4], int padding[4], int border[4]);
|
||||
static void layout_float_find_dimensions(int available_width,
|
||||
@ -59,6 +60,9 @@ static void layout_find_dimensions(int available_width,
|
||||
static int layout_clear(struct box *fl, css_clear clear);
|
||||
static void find_sides(struct box *fl, int y0, int y1,
|
||||
int *x0, int *x1, struct box **left, struct box **right);
|
||||
static void layout_minmax_list(struct box *box);
|
||||
static void layout_minmax_list_item(struct box *box);
|
||||
static bool layout_list(struct box *box, struct content *content);
|
||||
static void layout_minmax_inline_container(struct box *inline_container);
|
||||
static int line_height(struct css_style *style);
|
||||
static bool layout_line(struct box *first, int *width, int *y,
|
||||
@ -149,7 +153,7 @@ bool layout_document(struct content *content, int width, int height)
|
||||
/**
|
||||
* Layout a block formatting context.
|
||||
*
|
||||
* \param block BLOCK, INLINE_BLOCK, or TABLE_CELL to layout
|
||||
* \param block BLOCK, INLINE_BLOCK, TABLE_CELL or LIST_PRINCIPAL to layout
|
||||
* \param content memory pool for any new boxes
|
||||
* \return true on success, false on memory exhaustion
|
||||
*
|
||||
@ -168,7 +172,8 @@ bool layout_block_context(struct box *block, struct content *content)
|
||||
|
||||
assert(block->type == BOX_BLOCK ||
|
||||
block->type == BOX_INLINE_BLOCK ||
|
||||
block->type == BOX_TABLE_CELL);
|
||||
block->type == BOX_TABLE_CELL ||
|
||||
block->type == BOX_LIST_PRINCIPAL);
|
||||
|
||||
gui_multitask();
|
||||
|
||||
@ -210,7 +215,8 @@ bool layout_block_context(struct box *block, struct content *content)
|
||||
* to each in the order shown. */
|
||||
while (box) {
|
||||
assert(box->type == BOX_BLOCK || box->type == BOX_TABLE ||
|
||||
box->type == BOX_INLINE_CONTAINER);
|
||||
box->type == BOX_INLINE_CONTAINER ||
|
||||
box->type == BOX_LIST);
|
||||
assert(margin_box);
|
||||
|
||||
/* Tables are laid out before being positioned, because the
|
||||
@ -235,7 +241,8 @@ bool layout_block_context(struct box *block, struct content *content)
|
||||
return false;
|
||||
layout_solve_width(box->parent->width, box->width,
|
||||
box->margin, box->padding, box->border);
|
||||
}
|
||||
} else if (box->type == BOX_LIST)
|
||||
layout_list_find_dimensions(box->parent->width, box);
|
||||
|
||||
/* Position box: horizontal. */
|
||||
box->x = box->parent->padding[LEFT] + box->margin[LEFT] +
|
||||
@ -308,6 +315,9 @@ bool layout_block_context(struct box *block, struct content *content)
|
||||
cx = x0;
|
||||
box->y += y - cy;
|
||||
cy = y;
|
||||
} else if (box->type == BOX_LIST) {
|
||||
if (!layout_list(box, content))
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Advance to next box. */
|
||||
@ -386,7 +396,7 @@ bool layout_block_context(struct box *block, struct content *content)
|
||||
/**
|
||||
* Calculate minimum and maximum width of a block.
|
||||
*
|
||||
* \param block box of type BLOCK, INLINE_BLOCK, or TABLE_CELL
|
||||
* \param block box of type BLOCK, INLINE_BLOCK, TABLE_CELL, or LIST_PRINCIPAL
|
||||
* \post block->min_width and block->max_width filled in,
|
||||
* 0 <= block->min_width <= block->max_width
|
||||
*/
|
||||
@ -400,7 +410,8 @@ void layout_minmax_block(struct box *block)
|
||||
|
||||
assert(block->type == BOX_BLOCK ||
|
||||
block->type == BOX_INLINE_BLOCK ||
|
||||
block->type == BOX_TABLE_CELL);
|
||||
block->type == BOX_TABLE_CELL ||
|
||||
block->type == BOX_LIST_PRINCIPAL);
|
||||
|
||||
/* check if the widths have already been calculated */
|
||||
if (block->max_width != UNKNOWN_MAX_WIDTH)
|
||||
@ -427,6 +438,9 @@ void layout_minmax_block(struct box *block)
|
||||
case BOX_TABLE:
|
||||
layout_minmax_table(child);
|
||||
break;
|
||||
case BOX_LIST:
|
||||
layout_minmax_list(child);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
@ -562,6 +576,64 @@ void layout_block_find_dimensions(int available_width, struct box *box)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compute dimensions of box, margins, paddings, and borders for a list.
|
||||
*
|
||||
* Similar to layout_block_find_dimensions()
|
||||
*/
|
||||
|
||||
void layout_list_find_dimensions(int available_width, struct box *box)
|
||||
{
|
||||
int width, height;
|
||||
int *margin = box->margin;
|
||||
int *padding = box->padding;
|
||||
int *border = box->border;
|
||||
struct css_style *style = box->style;
|
||||
struct box *c;
|
||||
|
||||
layout_find_dimensions(available_width, style,
|
||||
&width, &height, margin, padding, border);
|
||||
|
||||
for (c = box->children; c; c = c->next) {
|
||||
struct box *marker, *principal;
|
||||
|
||||
marker = c->children;
|
||||
principal = marker->next;
|
||||
|
||||
/** \todo handle marker */
|
||||
marker->width = marker->height = 0;
|
||||
|
||||
layout_block_find_dimensions(available_width, principal);
|
||||
|
||||
if (width < principal->x + principal->width +
|
||||
principal->padding[RIGHT] +
|
||||
principal->border[RIGHT] +
|
||||
principal->margin[RIGHT])
|
||||
width = principal->x + principal->width +
|
||||
principal->padding[RIGHT] +
|
||||
principal->border[RIGHT] +
|
||||
principal->margin[RIGHT];
|
||||
|
||||
if (height < principal->y + principal->height +
|
||||
principal->padding[BOTTOM] +
|
||||
principal->border[BOTTOM] +
|
||||
principal->margin[BOTTOM])
|
||||
height = principal->y + principal->height +
|
||||
principal->padding[BOTTOM] +
|
||||
principal->border[BOTTOM] +
|
||||
principal->margin[BOTTOM];
|
||||
}
|
||||
|
||||
box->width = layout_solve_width(available_width, width, margin,
|
||||
padding, border);
|
||||
box->height = height;
|
||||
|
||||
if (margin[TOP] == AUTO)
|
||||
margin[TOP] = 0;
|
||||
if (margin[BOTTOM] == AUTO)
|
||||
margin[BOTTOM] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Solve the width constraint as given in CSS 2.1 section 10.3.3.
|
||||
*/
|
||||
@ -817,6 +889,127 @@ void find_sides(struct box *fl, int y0, int y1,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculate minimum and maximum widths of a list
|
||||
*/
|
||||
|
||||
void layout_minmax_list(struct box *box)
|
||||
{
|
||||
int min = 0, max = 0;
|
||||
struct box *c;
|
||||
|
||||
assert(box->type == BOX_LIST);
|
||||
|
||||
/* check if we've already calculated the width */
|
||||
if (box->max_width != UNKNOWN_MAX_WIDTH)
|
||||
return;
|
||||
|
||||
for (c = box->children; c; c = c->next) {
|
||||
layout_minmax_list_item(c);
|
||||
if (min < c->min_width)
|
||||
min = c->min_width;
|
||||
if (max < c->max_width)
|
||||
max = c->max_width;
|
||||
}
|
||||
|
||||
box->min_width = min;
|
||||
box->max_width = max;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculate minimum and maximum widths of a list item
|
||||
*/
|
||||
|
||||
void layout_minmax_list_item(struct box *box)
|
||||
{
|
||||
struct box *marker, *principal;
|
||||
|
||||
assert(box->type == BOX_LIST_ITEM);
|
||||
|
||||
/* check if we've already calculated the width */
|
||||
if (box->max_width != UNKNOWN_MAX_WIDTH)
|
||||
return;
|
||||
|
||||
marker = box->children;
|
||||
principal = marker->next;
|
||||
|
||||
layout_minmax_block(principal);
|
||||
|
||||
/** \todo what on earth are we expected to do with the marker?
|
||||
* AFAICS, none of Opera, Firefox nor Konqueror support
|
||||
* display: list-item with list-style-position: outside
|
||||
* In Opera/Firefox's case, they don't appear to bother to
|
||||
* generate the marker box (probably following the "optional"
|
||||
* wording of the spec - 12.5). Konqueror turns it into
|
||||
* list-style-position: inside. */
|
||||
marker->min_width = marker->max_width = 0;
|
||||
|
||||
box->min_width = principal->min_width + marker->min_width;
|
||||
box->max_width = principal->max_width + marker->max_width;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Layout a list
|
||||
*
|
||||
* \param box list box
|
||||
* \param content memory pool for any new boxes
|
||||
* \return true on success, false on memory exhaustion
|
||||
*/
|
||||
|
||||
bool layout_list(struct box *box, struct content *content)
|
||||
{
|
||||
struct box *c;
|
||||
int cy = 0;
|
||||
|
||||
assert(box->type == BOX_LIST);
|
||||
|
||||
for (c = box->children; c; c = c->next) {
|
||||
struct box *marker, *principal;
|
||||
|
||||
assert(c->type == BOX_LIST_ITEM);
|
||||
|
||||
marker = c->children;
|
||||
principal = marker->next;
|
||||
|
||||
c->x = 0;
|
||||
c->y = cy;
|
||||
|
||||
/** \todo handle marker */
|
||||
marker->x = marker->y = 0;
|
||||
|
||||
principal->x = 0;
|
||||
principal->y = 0;
|
||||
/* manipulate principal box's parent pointer so
|
||||
* layout_block_context has a parent style to play with */
|
||||
/** \todo is this sane? */
|
||||
principal->parent = box;
|
||||
layout_block_context(principal, content);
|
||||
principal->parent = c;
|
||||
|
||||
if (c->width == UNKNOWN_WIDTH)
|
||||
c->width = principal->x + principal->width +
|
||||
principal->padding[RIGHT] +
|
||||
principal->border[RIGHT] +
|
||||
principal->margin[RIGHT];
|
||||
|
||||
// if (c->height == AUTO)
|
||||
c->height = principal->y + principal->height +
|
||||
principal->padding[BOTTOM] +
|
||||
principal->border[BOTTOM] +
|
||||
principal->margin[BOTTOM];
|
||||
|
||||
cy += c->height;
|
||||
}
|
||||
|
||||
// if (box->height == AUTO)
|
||||
box->height = cy - box->padding[TOP];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Layout lines of text or inline boxes with floats.
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user