2003-06-30 16:44:03 +04:00
/*
2005-01-11 00:35:34 +03:00
* Copyright 2005 Richard Wilson < info @ tinct . net >
2006-01-16 01:25:40 +03:00
* Copyright 2006 James Bursa < bursa @ users . sourceforge . net >
2003-06-30 16:44:03 +04:00
* Copyright 2003 Phil Mellor < monkeyson @ users . sourceforge . net >
2007-08-08 20:16:03 +04:00
*
* This file is part of NetSurf , http : //www.netsurf-browser.org/
*
* NetSurf is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; version 2 of the License .
*
* NetSurf is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
2002-05-04 23:57:18 +04:00
*/
2004-02-11 20:15:36 +03:00
/** \file
* HTML layout ( implementation ) .
*
2005-07-02 22:17:51 +04:00
* Layout is carried out in two stages :
*
* - calculation of minimum / maximum box widths
* - layout ( position and dimensions )
*
* In most cases the functions for the two stages are a corresponding pair
* layout_minmax_X ( ) and layout_X ( ) .
2004-02-11 20:15:36 +03:00
*/
2005-01-13 23:29:24 +03:00
# define _GNU_SOURCE /* for strndup */
2002-05-04 23:57:18 +04:00
# include <assert.h>
# include <ctype.h>
2003-07-18 21:08:39 +04:00
# include <limits.h>
2004-02-02 01:42:40 +03:00
# include <stdbool.h>
2002-05-04 23:57:18 +04:00
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
2007-05-31 02:39:54 +04:00
# include "css/css.h"
# include "content/content.h"
2003-06-17 23:24:21 +04:00
# ifdef riscos
2007-05-31 02:39:54 +04:00
# include "desktop/gui.h"
2003-06-17 23:24:21 +04:00
# endif
2007-05-31 02:39:54 +04:00
# include "desktop/options.h"
# include "render/box.h"
# include "render/font.h"
2008-01-29 03:42:15 +03:00
# include "render/form.h"
2007-05-31 02:39:54 +04:00
# include "render/layout.h"
2003-03-26 00:51:29 +03:00
# define NDEBUG
2007-05-31 02:39:54 +04:00
# include "utils/log.h"
# include "utils/talloc.h"
# include "utils/utils.h"
2002-08-06 00:34:45 +04:00
2004-02-02 03:22:59 +03:00
# define AUTO INT_MIN
2002-05-04 23:57:18 +04:00
2005-07-02 22:17:51 +04:00
static void layout_minmax_block ( struct box * block ) ;
2006-09-17 01:48:28 +04:00
static bool layout_block_object ( struct box * block ) ;
2004-04-12 04:00:47 +04:00
static void layout_block_find_dimensions ( int available_width , struct box * box ) ;
2007-03-25 03:47:44 +04:00
static void layout_block_add_scrollbar ( struct box * box , int which ) ;
2004-04-12 04:00:47 +04:00
static int layout_solve_width ( int available_width , int width ,
int margin [ 4 ] , int padding [ 4 ] , int border [ 4 ] ) ;
2004-02-11 20:15:36 +03:00
static void layout_float_find_dimensions ( int available_width ,
struct css_style * style , struct box * box ) ;
static void layout_find_dimensions ( int available_width ,
2004-02-02 03:22:59 +03:00
struct css_style * style ,
2006-06-26 08:52:34 +04:00
int * width , int * height ,
2004-02-02 03:22:59 +03:00
int margin [ 4 ] , int padding [ 4 ] , int border [ 4 ] ) ;
2004-02-13 19:10:28 +03:00
static int layout_clear ( struct box * fl , css_clear clear ) ;
2004-02-11 20:15:36 +03:00
static void find_sides ( struct box * fl , int y0 , int y1 ,
int * x0 , int * x1 , struct box * * left , struct box * * right ) ;
2005-07-02 22:17:51 +04:00
static void layout_minmax_inline_container ( struct box * inline_container ) ;
2004-02-11 20:15:36 +03:00
static int line_height ( struct css_style * style ) ;
2006-09-10 17:27:08 +04:00
static bool layout_line ( struct box * first , int * width , int * y ,
2004-06-03 01:21:13 +04:00
int cx , int cy , struct box * cont , bool indent ,
2006-08-13 05:00:22 +04:00
bool has_text_children ,
2005-04-09 13:47:37 +04:00
struct content * content , struct box * * next_box ) ;
2005-07-02 22:17:51 +04:00
static struct box * layout_minmax_line ( struct box * first , int * min , int * max ) ;
2004-02-28 20:23:07 +03:00
static int layout_text_indent ( struct css_style * style , int width ) ;
2005-04-09 13:47:37 +04:00
static bool layout_float ( struct box * b , int width , struct content * content ) ;
2004-04-22 02:27:49 +04:00
static void place_float_below ( struct box * c , int width , int cx , int y ,
2004-02-11 20:15:36 +03:00
struct box * cont ) ;
2005-04-09 13:47:37 +04:00
static bool layout_table ( struct box * box , int available_width ,
struct content * content ) ;
2005-07-02 22:17:51 +04:00
static void layout_minmax_table ( struct box * table ) ;
2005-01-11 00:35:34 +03:00
static void layout_move_children ( struct box * box , int x , int y ) ;
2005-07-03 03:37:41 +04:00
static void calculate_mbp_width ( struct css_style * style , unsigned int side ,
int * fixed , float * frac ) ;
2006-11-05 15:58:24 +03:00
static void layout_lists ( struct box * box ) ;
2005-07-31 03:32:48 +04:00
static void layout_position_relative ( struct box * root ) ;
static void layout_compute_relative_offset ( struct box * box , int * x , int * y ) ;
2006-10-11 02:00:10 +04:00
static bool layout_position_absolute ( struct box * box ,
struct box * containing_block ,
int cx , int cy ,
struct content * content ) ;
static bool layout_absolute ( struct box * box , struct box * containing_block ,
int cx , int cy ,
2006-06-26 08:52:34 +04:00
struct content * content ) ;
static void layout_compute_offsets ( struct box * box ,
struct box * containing_block ,
int * top , int * right , int * bottom , int * left ) ;
2004-07-17 05:36:21 +04:00
2002-05-04 23:57:18 +04:00
/**
2004-02-02 03:22:59 +03:00
* Calculate positions of boxes in a document .
2002-06-19 01:24:21 +04:00
*
2005-04-14 23:54:24 +04:00
* \ param doc content of type CONTENT_HTML
2005-07-02 22:17:51 +04:00
* \ param width available width
* \ param height available height
2004-06-03 01:21:13 +04:00
* \ return true on success , false on memory exhaustion
2002-06-19 01:24:21 +04:00
*/
2005-07-02 22:17:51 +04:00
bool layout_document ( struct content * content , int width , int height )
2002-05-28 03:21:11 +04:00
{
2004-08-01 17:08:19 +04:00
bool ret ;
2005-04-09 13:47:37 +04:00
struct box * doc = content - > data . html . layout ;
assert ( content - > type = = CONTENT_HTML ) ;
2004-08-01 17:08:19 +04:00
2005-07-02 22:17:51 +04:00
layout_minmax_block ( doc ) ;
2004-02-11 20:15:36 +03:00
2004-04-12 04:00:47 +04:00
layout_block_find_dimensions ( width , doc ) ;
2004-02-11 20:15:36 +03:00
doc - > x = doc - > margin [ LEFT ] + doc - > border [ LEFT ] ;
doc - > y = doc - > margin [ TOP ] + doc - > border [ TOP ] ;
2005-07-02 22:17:51 +04:00
width - = doc - > margin [ LEFT ] + doc - > border [ LEFT ] + doc - > padding [ LEFT ] +
doc - > padding [ RIGHT ] + doc - > border [ RIGHT ] +
doc - > margin [ RIGHT ] ;
if ( width < 0 )
width = 0 ;
2004-04-12 04:00:47 +04:00
doc - > width = width ;
2004-08-01 17:08:19 +04:00
2005-04-09 13:47:37 +04:00
ret = layout_block_context ( doc , content ) ;
2004-08-01 17:08:19 +04:00
2005-07-02 22:17:51 +04:00
/* make <html> and <body> fill available height */
if ( doc - > y + doc - > padding [ TOP ] + doc - > height + doc - > padding [ BOTTOM ] +
doc - > border [ BOTTOM ] + doc - > margin [ BOTTOM ] <
height ) {
doc - > height = height - ( doc - > y + doc - > padding [ TOP ] +
doc - > padding [ BOTTOM ] + doc - > border [ BOTTOM ] +
doc - > margin [ BOTTOM ] ) ;
if ( doc - > children )
doc - > children - > height = doc - > height -
( doc - > children - > margin [ TOP ] +
doc - > children - > border [ TOP ] +
doc - > children - > padding [ TOP ] +
doc - > children - > padding [ BOTTOM ] +
doc - > children - > border [ BOTTOM ] +
doc - > children - > margin [ BOTTOM ] ) ;
}
2006-11-05 15:58:24 +03:00
layout_lists ( doc ) ;
2006-10-11 02:00:10 +04:00
layout_position_absolute ( doc , doc , 0 , 0 , content ) ;
2005-07-31 15:21:46 +04:00
layout_position_relative ( doc ) ;
2004-08-01 17:08:19 +04:00
layout_calculate_descendant_bboxes ( doc ) ;
return ret ;
2002-05-28 03:21:11 +04:00
}
2002-06-19 01:24:21 +04:00
2004-02-02 03:22:59 +03:00
/**
2004-04-12 04:00:47 +04:00
* Layout a block formatting context .
2004-02-02 03:22:59 +03:00
*
2006-11-05 15:58:24 +03:00
* \ param block BLOCK , INLINE_BLOCK , or TABLE_CELL to layout
2005-04-09 13:47:37 +04:00
* \ param content memory pool for any new boxes
2004-06-03 01:21:13 +04:00
* \ return true on success , false on memory exhaustion
2002-06-19 01:24:21 +04:00
*
2004-04-12 04:00:47 +04:00
* This function carries out layout of a block and its children , as described
* in CSS 2.1 9.4 .1 .
2002-06-19 01:24:21 +04:00
*/
2005-04-09 13:47:37 +04:00
bool layout_block_context ( struct box * block , struct content * content )
2002-05-04 23:57:18 +04:00
{
2004-04-12 04:00:47 +04:00
struct box * box ;
2006-09-17 01:48:28 +04:00
int cx , cy ; /**< current coordinates */
2004-04-12 04:00:47 +04:00
int max_pos_margin = 0 ;
int max_neg_margin = 0 ;
2006-10-09 02:46:25 +04:00
int y = 0 ;
2004-04-12 04:00:47 +04:00
struct box * margin_box ;
assert ( block - > type = = BOX_BLOCK | |
block - > type = = BOX_INLINE_BLOCK | |
2006-11-05 15:58:24 +03:00
block - > type = = BOX_TABLE_CELL ) ;
assert ( block - > width ! = UNKNOWN_WIDTH ) ;
assert ( block - > width ! = AUTO ) ;
2004-04-12 04:00:47 +04:00
2004-04-14 03:20:23 +04:00
gui_multitask ( ) ;
2005-11-06 14:00:33 +03:00
block - > float_children = 0 ;
2006-09-17 01:48:28 +04:00
/* special case if the block contains an object */
2006-12-27 00:51:08 +03:00
if ( block - > object ) {
if ( ! layout_block_object ( block ) )
return false ;
if ( block - > height = = AUTO ) {
if ( block - > object - > width )
block - > height = block - > object - > height *
( float ) block - > width /
block - > object - > width ;
else
block - > height = block - > object - > height ;
}
return true ;
}
2005-10-31 00:23:24 +03:00
2004-04-12 04:00:47 +04:00
box = margin_box = block - > children ;
2006-09-17 01:48:28 +04:00
/* set current coordinates to top-left of the block */
2005-07-24 18:29:32 +04:00
cx = 0 ;
2004-04-12 04:00:47 +04:00
cy = block - > padding [ TOP ] ;
if ( box )
box - > y = block - > padding [ TOP ] ;
2006-09-17 01:48:28 +04:00
/* Step through the descendants of the block in depth-first order, but
* not into the children of boxes which aren ' t blocks . For example , if
* the tree passed to this function looks like this ( box - > type shown ) :
*
* block - > BOX_BLOCK
* BOX_BLOCK * ( 1 )
* BOX_INLINE_CONTAINER * ( 2 )
* BOX_INLINE
* BOX_TEXT
* . . .
* BOX_BLOCK * ( 3 )
* BOX_TABLE * ( 4 )
* BOX_TABLE_ROW
* BOX_TABLE_CELL
* . . .
* BOX_TABLE_CELL
* . . .
* BOX_BLOCK * ( 5 )
* BOX_INLINE_CONTAINER * ( 6 )
* BOX_TEXT
* . . .
* then the while loop will visit each box marked with * , setting box
* to each in the order shown . */
2004-04-12 04:00:47 +04:00
while ( box ) {
assert ( box - > type = = BOX_BLOCK | | box - > type = = BOX_TABLE | |
2006-11-05 15:58:24 +03:00
box - > type = = BOX_INLINE_CONTAINER ) ;
2004-04-12 04:00:47 +04:00
assert ( margin_box ) ;
/* Tables are laid out before being positioned, because the
* position depends on the width which is calculated in
* table layout . Blocks and inline containers are positioned
* before being laid out , because width is not dependent on
* content , and the position is required during layout for
* correct handling of floats .
*/
2006-10-10 01:34:34 +04:00
if ( box - > style & &
( box - > style - > position = = CSS_POSITION_ABSOLUTE | |
box - > style - > position = = CSS_POSITION_FIXED ) ) {
2006-10-09 02:46:25 +04:00
box - > x = box - > parent - > padding [ LEFT ] ;
goto advance_to_next_box ;
}
2007-03-25 03:47:44 +04:00
if ( box - > type = = BOX_BLOCK | | box - > object ) {
2004-04-12 04:00:47 +04:00
layout_block_find_dimensions ( box - > parent - > width , box ) ;
2007-03-25 03:47:44 +04:00
layout_block_add_scrollbar ( box , RIGHT ) ;
layout_block_add_scrollbar ( box , BOTTOM ) ;
} else if ( box - > type = = BOX_TABLE ) {
2005-04-09 13:47:37 +04:00
if ( ! layout_table ( box , box - > parent - > width , content ) )
2004-06-03 01:21:13 +04:00
return false ;
2004-04-12 04:00:47 +04:00
layout_solve_width ( box - > parent - > width , box - > width ,
box - > margin , box - > padding , box - > border ) ;
2006-11-05 15:58:24 +03:00
}
2002-06-19 01:24:21 +04:00
2004-04-12 04:00:47 +04:00
/* Position box: horizontal. */
box - > x = box - > parent - > padding [ LEFT ] + box - > margin [ LEFT ] +
box - > border [ LEFT ] ;
cx + = box - > x ;
/* Position box: top margin. */
if ( max_pos_margin < box - > margin [ TOP ] )
max_pos_margin = box - > margin [ TOP ] ;
else if ( max_neg_margin < - box - > margin [ TOP ] )
max_neg_margin = - box - > margin [ TOP ] ;
/* Clearance. */
y = 0 ;
if ( box - > style & & box - > style - > clear ! = CSS_CLEAR_NONE )
y = layout_clear ( block - > float_children ,
box - > style - > clear ) ;
if ( box - > type ! = BOX_BLOCK | | y | |
box - > border [ TOP ] | | box - > padding [ TOP ] ) {
margin_box - > y + = max_pos_margin - max_neg_margin ;
cy + = max_pos_margin - max_neg_margin ;
max_pos_margin = max_neg_margin = 0 ;
margin_box = 0 ;
box - > y + = box - > border [ TOP ] ;
cy + = box - > border [ TOP ] ;
if ( cy < y ) {
box - > y + = y - cy ;
cy = y ;
}
}
2002-06-19 01:24:21 +04:00
2005-08-07 03:34:30 +04:00
LOG ( ( " box %p, cx %i, cy %i " , box , cx , cy ) ) ;
2004-04-12 04:00:47 +04:00
/* Layout (except tables). */
2005-10-31 00:23:24 +03:00
if ( box - > object ) {
2006-09-17 01:48:28 +04:00
if ( ! layout_block_object ( box ) )
return false ;
2005-10-31 00:23:24 +03:00
} else if ( box - > type = = BOX_INLINE_CONTAINER ) {
2004-04-12 04:00:47 +04:00
box - > width = box - > parent - > width ;
2004-06-03 01:21:13 +04:00
if ( ! layout_inline_container ( box , box - > width , block ,
2005-04-09 13:47:37 +04:00
cx , cy , content ) )
2004-06-03 01:21:13 +04:00
return false ;
2004-04-12 04:00:47 +04:00
} else if ( box - > type = = BOX_TABLE ) {
2004-04-14 03:20:23 +04:00
/* Move down to avoid floats if necessary. */
int x0 , x1 ;
struct box * left , * right ;
y = cy ;
while ( 1 ) {
x0 = cx ;
x1 = cx + box - > parent - > width ;
find_sides ( block - > float_children , y ,
y + box - > height ,
& x0 , & x1 , & left , & right ) ;
if ( box - > width < = x1 - x0 )
break ;
if ( ! left & & ! right )
break ;
else if ( ! left )
y = right - > y + right - > height + 1 ;
else if ( ! right )
y = left - > y + left - > height + 1 ;
else if ( left - > y + left - > height <
right - > y + right - > height )
y = left - > y + left - > height + 1 ;
else
y = right - > y + right - > height + 1 ;
2004-06-14 11:28:27 +04:00
}
box - > x + = x0 - cx ;
cx = x0 ;
box - > y + = y - cy ;
cy = y ;
2004-04-12 04:00:47 +04:00
}
2002-08-06 00:34:45 +04:00
2004-04-12 04:00:47 +04:00
/* Advance to next box. */
2005-10-31 00:23:24 +03:00
if ( box - > type = = BOX_BLOCK & & ! box - > object & & box - > children ) {
2006-07-02 21:36:27 +04:00
/* Down into children. */
2004-04-12 04:00:47 +04:00
y = box - > padding [ TOP ] ;
box = box - > children ;
box - > y = y ;
cy + = y ;
if ( ! margin_box ) {
max_pos_margin = max_neg_margin = 0 ;
margin_box = box ;
}
continue ;
2005-10-31 00:23:24 +03:00
} else if ( box - > type = = BOX_BLOCK | | box - > object )
2005-08-07 03:34:30 +04:00
cy + = box - > padding [ TOP ] ;
2007-03-25 03:47:44 +04:00
if ( box - > type = = BOX_BLOCK & & box - > height = = AUTO ) {
2004-04-12 21:32:45 +04:00
box - > height = 0 ;
2007-03-25 03:47:44 +04:00
layout_block_add_scrollbar ( box , BOTTOM ) ;
}
2004-04-12 04:00:47 +04:00
cy + = box - > height + box - > padding [ BOTTOM ] + box - > border [ BOTTOM ] ;
max_pos_margin = max_neg_margin = 0 ;
if ( max_pos_margin < box - > margin [ BOTTOM ] )
max_pos_margin = box - > margin [ BOTTOM ] ;
else if ( max_neg_margin < - box - > margin [ BOTTOM ] )
max_neg_margin = - box - > margin [ BOTTOM ] ;
2006-10-09 02:46:25 +04:00
cx - = box - > x ;
y = box - > y + box - > padding [ TOP ] + box - > height +
box - > padding [ BOTTOM ] + box - > border [ BOTTOM ] ;
advance_to_next_box :
2004-04-12 04:00:47 +04:00
if ( ! box - > next ) {
2006-07-02 21:36:27 +04:00
/* No more siblings: up to first ancestor with a
sibling . */
2004-04-12 21:32:45 +04:00
do {
2004-04-12 04:00:47 +04:00
box = box - > parent ;
2004-12-02 00:48:11 +03:00
if ( box = = block )
break ;
2007-03-25 03:47:44 +04:00
if ( box - > height = = AUTO ) {
2004-04-12 04:00:47 +04:00
box - > height = y - box - > padding [ TOP ] ;
2007-03-25 03:47:44 +04:00
if ( box - > type = = BOX_BLOCK )
layout_block_add_scrollbar ( box , BOTTOM ) ;
} else
2006-05-07 21:20:18 +04:00
cy + = box - > height -
( y - box - > padding [ TOP ] ) ;
2004-04-12 04:00:47 +04:00
cy + = box - > padding [ BOTTOM ] +
box - > border [ BOTTOM ] ;
if ( max_pos_margin < box - > margin [ BOTTOM ] )
max_pos_margin = box - > margin [ BOTTOM ] ;
else if ( max_neg_margin < - box - > margin [ BOTTOM ] )
max_neg_margin = - box - > margin [ BOTTOM ] ;
2006-10-09 02:46:25 +04:00
cx - = box - > x ;
y = box - > y + box - > padding [ TOP ] + box - > height +
box - > padding [ BOTTOM ] +
box - > border [ BOTTOM ] ;
2004-04-12 21:32:45 +04:00
} while ( box ! = block & & ! box - > next ) ;
2004-04-12 04:00:47 +04:00
if ( box = = block )
break ;
}
2006-07-02 21:36:27 +04:00
/* To next sibling. */
2004-04-12 04:00:47 +04:00
box = box - > next ;
box - > y = y ;
margin_box = box ;
2004-02-02 03:22:59 +03:00
}
2004-04-17 02:29:10 +04:00
/* Increase height to contain any floats inside (CSS 2.1 10.6.7). */
for ( box = block - > float_children ; box ; box = box - > next_float ) {
y = box - > y + box - > height + box - > padding [ BOTTOM ] +
box - > border [ BOTTOM ] + box - > margin [ BOTTOM ] ;
if ( cy < y )
cy = y ;
}
2007-03-25 03:47:44 +04:00
if ( block - > height = = AUTO ) {
2004-04-17 02:29:10 +04:00
block - > height = cy - block - > padding [ TOP ] ;
2007-03-25 03:47:44 +04:00
if ( block - > type = = BOX_BLOCK )
layout_block_add_scrollbar ( block , BOTTOM ) ;
}
2004-06-03 01:21:13 +04:00
return true ;
2004-02-02 03:22:59 +03:00
}
2005-07-02 22:17:51 +04:00
/**
* Calculate minimum and maximum width of a block .
*
2006-11-05 15:58:24 +03:00
* \ param block box of type BLOCK , INLINE_BLOCK , or TABLE_CELL
2005-07-22 01:48:41 +04:00
* \ post block - > min_width and block - > max_width filled in ,
* 0 < = block - > min_width < = block - > max_width
2005-07-02 22:17:51 +04:00
*/
void layout_minmax_block ( struct box * block )
{
struct box * child ;
int min = 0 , max = 0 ;
int extra_fixed = 0 ;
float extra_frac = 0 ;
assert ( block - > type = = BOX_BLOCK | |
block - > type = = BOX_INLINE_BLOCK | |
2006-11-05 15:58:24 +03:00
block - > type = = BOX_TABLE_CELL ) ;
2005-07-02 22:17:51 +04:00
/* check if the widths have already been calculated */
if ( block - > max_width ! = UNKNOWN_MAX_WIDTH )
return ;
2005-10-31 00:23:24 +03:00
if ( block - > object ) {
if ( block - > object - > type = = CONTENT_HTML ) {
layout_minmax_block ( block - > object - > data . html . layout ) ;
min = block - > object - > data . html . layout - > min_width ;
max = block - > object - > data . html . layout - > max_width ;
} else {
min = max = block - > object - > width ;
}
} else {
/* recurse through children */
for ( child = block - > children ; child ; child = child - > next ) {
switch ( child - > type ) {
case BOX_BLOCK :
layout_minmax_block ( child ) ;
break ;
case BOX_INLINE_CONTAINER :
layout_minmax_inline_container ( child ) ;
break ;
case BOX_TABLE :
layout_minmax_table ( child ) ;
break ;
default :
assert ( 0 ) ;
}
assert ( child - > max_width ! = UNKNOWN_MAX_WIDTH ) ;
if ( min < child - > min_width )
min = child - > min_width ;
if ( max < child - > max_width )
max = child - > max_width ;
2005-07-02 22:17:51 +04:00
}
}
if ( max < min ) {
2007-08-20 06:39:49 +04:00
box_dump ( stderr , block , 0 ) ;
2005-07-02 22:17:51 +04:00
assert ( 0 ) ;
}
/* fixed width takes priority */
if ( block - > type ! = BOX_TABLE_CELL & &
block - > style - > width . width = = CSS_WIDTH_LENGTH )
min = max = css_len2px ( & block - > style - > width . value . length ,
block - > style ) ;
/* add margins, border, padding to min, max widths */
2005-07-03 03:37:41 +04:00
calculate_mbp_width ( block - > style , LEFT , & extra_fixed , & extra_frac ) ;
calculate_mbp_width ( block - > style , RIGHT , & extra_fixed , & extra_frac ) ;
2005-07-22 01:48:41 +04:00
if ( extra_fixed < 0 )
extra_fixed = 0 ;
if ( extra_frac < 0 )
extra_frac = 0 ;
2005-07-02 22:17:51 +04:00
if ( 1.0 < = extra_frac )
extra_frac = 0.9 ;
block - > min_width = ( min + extra_fixed ) / ( 1.0 - extra_frac ) ;
block - > max_width = ( max + extra_fixed ) / ( 1.0 - extra_frac ) ;
2005-07-22 01:48:41 +04:00
assert ( 0 < = block - > min_width & & block - > min_width < = block - > max_width ) ;
2005-07-02 22:17:51 +04:00
}
2006-09-17 01:48:28 +04:00
/**
* Layout a block which contains an object .
*
* \ param block box of type BLOCK , INLINE_BLOCK , TABLE , or TABLE_CELL
* \ return true on success , false on memory exhaustion
*/
bool layout_block_object ( struct box * block )
{
assert ( block ) ;
assert ( block - > type = = BOX_BLOCK | |
block - > type = = BOX_INLINE_BLOCK | |
block - > type = = BOX_TABLE | |
block - > type = = BOX_TABLE_CELL ) ;
assert ( block - > object ) ;
LOG ( ( " block %p, object %s, width %i " , block , block - > object - > url ,
block - > width ) ) ;
if ( block - > object - > type = = CONTENT_HTML ) {
content_reformat ( block - > object , block - > width , 1 ) ;
block - > height = block - > object - > height ;
} else {
/* this case handled already in
* layout_block_find_dimensions ( ) */
}
return true ;
}
2004-02-02 03:22:59 +03:00
/**
2004-02-11 20:15:36 +03:00
* Compute dimensions of box , margins , paddings , and borders for a block - level
* element .
2004-05-21 18:26:59 +04:00
*
* See CSS 2.1 10.3 .3 , 10.3 .4 , 10.6 .2 , and 10.6 .3 .
2004-02-02 03:22:59 +03:00
*/
2004-04-12 04:00:47 +04:00
void layout_block_find_dimensions ( int available_width , struct box * box )
2004-02-02 03:22:59 +03:00
{
2006-06-26 08:52:34 +04:00
int width , height ;
2004-02-11 20:15:36 +03:00
int * margin = box - > margin ;
int * padding = box - > padding ;
int * border = box - > border ;
2004-04-12 04:00:47 +04:00
struct css_style * style = box - > style ;
2004-02-02 03:22:59 +03:00
2006-06-26 08:52:34 +04:00
layout_find_dimensions ( available_width , style ,
& width , & height , margin , padding , border ) ;
2004-04-12 21:32:45 +04:00
2005-10-31 00:23:24 +03:00
if ( box - > object & & box - > object - > type ! = CONTENT_HTML ) {
2004-05-21 18:26:59 +04:00
/* block-level replaced element, see 10.3.4 and 10.6.2 */
2006-06-26 08:52:34 +04:00
if ( width = = AUTO & & height = = AUTO ) {
2004-05-21 18:26:59 +04:00
width = box - > object - > width ;
2006-06-26 08:52:34 +04:00
height = box - > object - > height ;
2004-05-21 18:26:59 +04:00
} else if ( width = = AUTO ) {
if ( box - > object - > height )
width = box - > object - > width *
2006-06-26 08:52:34 +04:00
( float ) height /
2004-05-21 18:26:59 +04:00
box - > object - > height ;
else
width = box - > object - > width ;
2006-06-26 08:52:34 +04:00
} else if ( height = = AUTO ) {
2004-05-21 18:26:59 +04:00
if ( box - > object - > width )
2006-06-26 08:52:34 +04:00
height = box - > object - > height *
2004-05-21 18:26:59 +04:00
( float ) width /
box - > object - > width ;
else
2006-06-26 08:52:34 +04:00
height = box - > object - > height ;
2004-05-21 18:26:59 +04:00
}
}
box - > width = layout_solve_width ( available_width , width , margin ,
padding , border ) ;
2006-06-26 08:52:34 +04:00
box - > height = height ;
2004-05-21 18:26:59 +04:00
2007-03-25 03:47:44 +04:00
if ( margin [ TOP ] = = AUTO )
margin [ TOP ] = 0 ;
if ( margin [ BOTTOM ] = = AUTO )
margin [ BOTTOM ] = 0 ;
}
/**
* Manipulate a block ' s [ RB ] padding / height / width to accommodate scrollbars
*/
void layout_block_add_scrollbar ( struct box * box , int which )
{
assert ( box - > type = = BOX_BLOCK & & ( which = = RIGHT | | which = = BOTTOM ) ) ;
if ( box - > style & & ( box - > style - > overflow = = CSS_OVERFLOW_SCROLL | |
box - > style - > overflow = = CSS_OVERFLOW_AUTO ) ) {
/* make space for scrollbars, unless height/width are AUTO */
if ( which = = BOTTOM & & box - > height ! = AUTO & &
( box - > style - > overflow = = CSS_OVERFLOW_SCROLL | |
box_hscrollbar_present ( box ) ) ) {
2006-09-10 17:27:08 +04:00
box - > padding [ BOTTOM ] + = SCROLLBAR_WIDTH ;
}
2007-03-25 03:47:44 +04:00
if ( which = = RIGHT & & box - > width ! = AUTO & &
( box - > style - > overflow = = CSS_OVERFLOW_SCROLL | |
box_vscrollbar_present ( box ) ) ) {
2006-09-10 17:27:08 +04:00
box - > width - = SCROLLBAR_WIDTH ;
box - > padding [ RIGHT ] + = SCROLLBAR_WIDTH ;
}
2004-10-18 01:10:19 +04:00
}
2004-04-12 04:00:47 +04:00
}
/**
* Solve the width constraint as given in CSS 2.1 section 10.3 .3 .
*/
int layout_solve_width ( int available_width , int width ,
int margin [ 4 ] , int padding [ 4 ] , int border [ 4 ] )
{
2004-02-11 20:15:36 +03:00
if ( width = = AUTO ) {
/* any other 'auto' become 0 */
if ( margin [ LEFT ] = = AUTO )
margin [ LEFT ] = 0 ;
if ( margin [ RIGHT ] = = AUTO )
margin [ RIGHT ] = 0 ;
width = available_width -
( margin [ LEFT ] + border [ LEFT ] + padding [ LEFT ] +
2005-07-02 22:17:51 +04:00
padding [ RIGHT ] + border [ RIGHT ] + margin [ RIGHT ] ) ;
2004-02-11 20:15:36 +03:00
} else if ( margin [ LEFT ] = = AUTO & & margin [ RIGHT ] = = AUTO ) {
/* make the margins equal, centering the element */
margin [ LEFT ] = margin [ RIGHT ] = ( available_width -
( border [ LEFT ] + padding [ LEFT ] + width +
padding [ RIGHT ] + border [ RIGHT ] ) ) / 2 ;
2004-08-01 17:08:19 +04:00
if ( margin [ LEFT ] < 0 ) {
margin [ RIGHT ] + = margin [ LEFT ] ;
margin [ LEFT ] = 0 ;
}
2004-02-11 20:15:36 +03:00
} else if ( margin [ LEFT ] = = AUTO ) {
margin [ LEFT ] = available_width -
( border [ LEFT ] + padding [ LEFT ] + width +
2005-07-02 22:17:51 +04:00
padding [ RIGHT ] + border [ RIGHT ] + margin [ RIGHT ] ) ;
2004-02-11 20:15:36 +03:00
} else {
2005-07-31 03:32:48 +04:00
/* margin-right auto or "over-constrained" */
2004-02-11 20:15:36 +03:00
margin [ RIGHT ] = available_width -
( margin [ LEFT ] + border [ LEFT ] + padding [ LEFT ] +
width + padding [ RIGHT ] + border [ RIGHT ] ) ;
}
2004-04-12 04:00:47 +04:00
return width ;
2004-02-11 20:15:36 +03:00
}
2006-05-07 21:20:18 +04:00
2004-02-11 20:15:36 +03:00
/**
* Compute dimensions of box , margins , paddings , and borders for a floating
* element .
*/
void layout_float_find_dimensions ( int available_width ,
struct css_style * style , struct box * box )
{
2006-06-26 08:52:34 +04:00
int width , height ;
int * margin = box - > margin ;
int * padding = box - > padding ;
int * border = box - > border ;
2004-11-20 03:02:56 +03:00
int scrollbar_width = ( style - > overflow = = CSS_OVERFLOW_SCROLL | |
style - > overflow = = CSS_OVERFLOW_AUTO ) ?
2004-10-18 01:10:19 +04:00
SCROLLBAR_WIDTH : 0 ;
2004-02-11 20:15:36 +03:00
layout_find_dimensions ( available_width , style ,
2006-06-26 08:52:34 +04:00
& width , & height , margin , padding , border ) ;
2004-02-11 20:15:36 +03:00
2006-06-26 08:52:34 +04:00
if ( margin [ LEFT ] = = AUTO )
margin [ LEFT ] = 0 ;
if ( margin [ RIGHT ] = = AUTO )
margin [ RIGHT ] = 0 ;
2004-02-11 20:15:36 +03:00
2006-06-26 08:52:34 +04:00
padding [ RIGHT ] + = scrollbar_width ;
padding [ BOTTOM ] + = scrollbar_width ;
2004-10-18 01:10:19 +04:00
2005-10-31 00:23:24 +03:00
if ( box - > object & & box - > object - > type ! = CONTENT_HTML ) {
2004-05-21 18:26:59 +04:00
/* floating replaced element, see 10.3.6 and 10.6.2 */
2006-06-26 08:52:34 +04:00
if ( width = = AUTO & & height = = AUTO ) {
width = box - > object - > width ;
height = box - > object - > height ;
} else if ( width = = AUTO )
width = box - > object - > width * ( float ) height /
2004-05-21 18:26:59 +04:00
box - > object - > height ;
2006-06-26 08:52:34 +04:00
else if ( height = = AUTO )
height = box - > object - > height * ( float ) width /
2004-05-21 18:26:59 +04:00
box - > object - > width ;
2006-06-26 08:52:34 +04:00
} else if ( width = = AUTO ) {
2004-05-21 18:26:59 +04:00
/* CSS 2.1 section 10.3.5 */
2006-06-26 08:52:34 +04:00
width = min ( max ( box - > min_width , available_width ) , box - > max_width ) ;
width - = box - > margin [ LEFT ] + box - > border [ LEFT ] +
2005-07-03 03:37:41 +04:00
box - > padding [ LEFT ] + box - > padding [ RIGHT ] +
box - > border [ RIGHT ] + box - > margin [ RIGHT ] ;
2004-10-18 01:10:19 +04:00
} else {
2006-06-26 08:52:34 +04:00
width - = scrollbar_width ;
2004-05-21 18:26:59 +04:00
}
2006-06-26 08:52:34 +04:00
box - > width = width ;
box - > height = height ;
if ( margin [ TOP ] = = AUTO )
margin [ TOP ] = 0 ;
if ( margin [ BOTTOM ] = = AUTO )
margin [ BOTTOM ] = 0 ;
2004-02-11 20:15:36 +03:00
}
/**
2006-06-26 08:52:34 +04:00
* Calculate width , height , and thickness of margins , paddings , and borders .
2004-12-02 00:48:11 +03:00
*
* \ param available_width width of containing block
2006-06-26 08:52:34 +04:00
* \ param style style giving width , height , margins , paddings ,
* and borders
* \ param width updated to width , may be NULL
* \ param height updated to height , may be NULL
2005-04-14 23:54:24 +04:00
* \ param margin [ 4 ] filled with margins , may be NULL
* \ param padding [ 4 ] filled with paddings
* \ param border [ 4 ] filled with border widths
2004-02-11 20:15:36 +03:00
*/
void layout_find_dimensions ( int available_width ,
struct css_style * style ,
2006-06-26 08:52:34 +04:00
int * width , int * height ,
2004-02-11 20:15:36 +03:00
int margin [ 4 ] , int padding [ 4 ] , int border [ 4 ] )
{
unsigned int i ;
2006-06-26 08:52:34 +04:00
if ( width ) {
switch ( style - > width . width ) {
case CSS_WIDTH_LENGTH :
* width = css_len2px ( & style - > width . value . length ,
style ) ;
break ;
case CSS_WIDTH_PERCENT :
* width = available_width *
style - > width . value . percent / 100 ;
break ;
case CSS_WIDTH_AUTO :
default :
* width = AUTO ;
break ;
}
}
if ( height ) {
switch ( style - > height . height ) {
case CSS_HEIGHT_LENGTH :
* height = css_len2px ( & style - > height . length ,
style ) ;
break ;
case CSS_HEIGHT_AUTO :
default :
* height = AUTO ;
break ;
}
}
2004-02-02 03:22:59 +03:00
for ( i = 0 ; i ! = 4 ; i + + ) {
2004-12-02 00:48:11 +03:00
if ( margin ) {
switch ( style - > margin [ i ] . margin ) {
2004-02-02 03:22:59 +03:00
case CSS_MARGIN_LENGTH :
2005-07-02 22:17:51 +04:00
margin [ i ] = css_len2px ( & style - > margin [ i ] .
2004-12-02 00:48:11 +03:00
value . length , style ) ;
2004-02-02 03:22:59 +03:00
break ;
case CSS_MARGIN_PERCENT :
margin [ i ] = available_width *
2004-12-02 00:48:11 +03:00
style - > margin [ i ] . value . percent / 100 ;
2004-02-02 03:22:59 +03:00
break ;
case CSS_MARGIN_AUTO :
default :
margin [ i ] = AUTO ;
break ;
2004-12-02 00:48:11 +03:00
}
2004-02-02 03:22:59 +03:00
}
switch ( style - > padding [ i ] . padding ) {
2004-12-02 00:48:11 +03:00
case CSS_PADDING_PERCENT :
padding [ i ] = available_width *
style - > padding [ i ] . value . percent / 100 ;
break ;
case CSS_PADDING_LENGTH :
default :
2005-07-02 22:17:51 +04:00
padding [ i ] = css_len2px ( & style - > padding [ i ] .
2004-12-02 00:48:11 +03:00
value . length , style ) ;
break ;
2004-02-02 03:22:59 +03:00
}
2004-12-02 00:48:11 +03:00
if ( style - > border [ i ] . style = = CSS_BORDER_STYLE_HIDDEN | |
style - > border [ i ] . style = = CSS_BORDER_STYLE_NONE )
2004-02-02 03:22:59 +03:00
/* spec unclear: following Mozilla */
border [ i ] = 0 ;
else
2005-07-02 22:17:51 +04:00
border [ i ] = css_len2px ( & style - > border [ i ] .
2004-12-02 00:48:11 +03:00
width . value , style ) ;
2002-05-04 23:57:18 +04:00
}
}
2002-06-19 01:24:21 +04:00
2004-02-13 19:10:28 +03:00
/**
* Find y coordinate which clears all floats on left and / or right .
*
2005-04-14 23:54:24 +04:00
* \ param fl first float in float list
2004-02-13 19:10:28 +03:00
* \ param clear type of clear
* \ return y coordinate relative to ancestor box for floats
*/
int layout_clear ( struct box * fl , css_clear clear )
{
int y = 0 ;
for ( ; fl ; fl = fl - > next_float ) {
if ( ( clear = = CSS_CLEAR_LEFT | | clear = = CSS_CLEAR_BOTH ) & &
fl - > type = = BOX_FLOAT_LEFT )
if ( y < fl - > y + fl - > height + 1 )
y = fl - > y + fl - > height + 1 ;
if ( ( clear = = CSS_CLEAR_RIGHT | | clear = = CSS_CLEAR_BOTH ) & &
fl - > type = = BOX_FLOAT_RIGHT )
if ( y < fl - > y + fl - > height + 1 )
y = fl - > y + fl - > height + 1 ;
}
return y ;
}
2002-06-19 01:24:21 +04:00
/**
2004-02-11 20:15:36 +03:00
* Find left and right edges in a vertical range .
2002-06-19 01:24:21 +04:00
*
2005-04-14 23:54:24 +04:00
* \ param fl first float in float list
* \ param y0 start of y range to search
* \ param y1 end of y range to search
* \ param x0 start left edge , updated to available left edge
* \ param x1 start right edge , updated to available right edge
* \ param left returns float on left if present
2004-02-11 20:15:36 +03:00
* \ param right returns float on right if present
2002-06-19 01:24:21 +04:00
*/
2004-02-11 20:15:36 +03:00
void find_sides ( struct box * fl , int y0 , int y1 ,
int * x0 , int * x1 , struct box * * left , struct box * * right )
2002-05-28 03:21:11 +04:00
{
2004-02-11 20:15:36 +03:00
int fy0 , fy1 , fx0 , fx1 ;
LOG ( ( " y0 %i, y1 %i, x0 %i, x1 %i " , y0 , y1 , * x0 , * x1 ) ) ;
2002-06-19 01:24:21 +04:00
* left = * right = 0 ;
2002-05-28 03:21:11 +04:00
for ( ; fl ; fl = fl - > next_float ) {
2004-02-11 20:15:36 +03:00
fy0 = fl - > y ;
fy1 = fl - > y + fl - > height ;
if ( y0 < = fy1 & & fy0 < = y1 ) {
if ( fl - > type = = BOX_FLOAT_LEFT ) {
fx1 = fl - > x + fl - > width ;
if ( * x0 < fx1 ) {
* x0 = fx1 ;
* left = fl ;
}
} else if ( fl - > type = = BOX_FLOAT_RIGHT ) {
fx0 = fl - > x ;
if ( fx0 < * x1 ) {
* x1 = fx0 ;
* right = fl ;
}
2002-06-19 01:24:21 +04:00
}
2002-05-28 03:21:11 +04:00
}
}
2004-02-11 20:15:36 +03:00
LOG ( ( " x0 %i, x1 %i, left %p, right %p " , * x0 , * x1 , * left , * right ) ) ;
2002-05-28 03:21:11 +04:00
}
2002-06-19 01:24:21 +04:00
/**
2004-02-11 20:15:36 +03:00
* Layout lines of text or inline boxes with floats .
2002-06-19 01:24:21 +04:00
*
2005-04-14 23:54:24 +04:00
* \ param box inline container
2004-02-11 20:15:36 +03:00
* \ param width horizontal space available
2005-04-14 23:54:24 +04:00
* \ param cont ancestor box which defines horizontal space , for floats
* \ param cx box position relative to cont
* \ param cy box position relative to cont
2005-04-09 13:47:37 +04:00
* \ param content memory pool for any new boxes
2004-06-03 01:21:13 +04:00
* \ return true on success , false on memory exhaustion
2002-06-19 01:24:21 +04:00
*/
2005-07-02 22:17:51 +04:00
bool layout_inline_container ( struct box * inline_container , int width ,
2005-04-09 13:47:37 +04:00
struct box * cont , int cx , int cy , struct content * content )
2002-05-04 23:57:18 +04:00
{
2004-02-11 20:15:36 +03:00
bool first_line = true ;
2006-08-13 05:00:22 +04:00
bool has_text_children ;
2004-06-03 01:21:13 +04:00
struct box * c , * next ;
2004-02-11 20:15:36 +03:00
int y = 0 ;
2006-09-10 17:27:08 +04:00
int curwidth , maxwidth = width ;
2002-05-04 23:57:18 +04:00
2005-07-02 22:17:51 +04:00
assert ( inline_container - > type = = BOX_INLINE_CONTAINER ) ;
2002-05-28 03:21:11 +04:00
2005-07-02 22:17:51 +04:00
LOG ( ( " inline_container %p, width %i, cont %p, cx %i, cy %i " ,
inline_container , width , cont , cx , cy ) ) ;
2002-08-06 00:34:45 +04:00
2006-08-13 05:00:22 +04:00
has_text_children = false ;
2007-12-23 17:15:11 +03:00
for ( c = inline_container - > children ; c ; c = c - > next ) {
2007-12-23 19:09:02 +03:00
bool is_pre = false ;
if ( c - > style )
is_pre = ( c - > style - > white_space = = CSS_WHITE_SPACE_PRE | |
c - > style - > white_space = = CSS_WHITE_SPACE_PRE_LINE | |
c - > style - > white_space = = CSS_WHITE_SPACE_PRE_WRAP ) ;
2007-12-23 17:15:11 +03:00
if ( ( ! c - > object & & c - > text & & ( c - > length | | is_pre ) ) | | c - > type = = BOX_BR )
has_text_children = true ;
}
2006-09-10 17:27:08 +04:00
/** \todo fix wrapping so that a box with horizontal scrollbar will shrink back to 'width' if no word is wider than 'width' (Or just set curwidth = width and have the multiword lines wrap to the min width) */
2005-07-02 22:17:51 +04:00
for ( c = inline_container - > children ; c ; ) {
2004-02-28 20:23:07 +03:00
LOG ( ( " c %p " , c ) ) ;
2006-09-10 17:27:08 +04:00
curwidth = inline_container - > width ;
if ( ! layout_line ( c , & curwidth , & y , cx , cy + y , cont , first_line ,
2006-08-13 05:00:22 +04:00
has_text_children , content , & next ) )
2004-06-03 01:21:13 +04:00
return false ;
2006-09-10 17:27:08 +04:00
maxwidth = max ( maxwidth , curwidth ) ;
2004-06-03 01:21:13 +04:00
c = next ;
2004-02-11 20:15:36 +03:00
first_line = false ;
2002-06-19 01:24:21 +04:00
}
2006-09-10 17:27:08 +04:00
inline_container - > width = maxwidth ;
2005-07-02 22:17:51 +04:00
inline_container - > height = y ;
2004-06-03 01:21:13 +04:00
return true ;
2002-06-19 01:24:21 +04:00
}
2005-07-02 22:17:51 +04:00
/**
* Calculate minimum and maximum width of an inline container .
*
* \ param inline_container box of type INLINE_CONTAINER
2005-07-22 01:48:41 +04:00
* \ post inline_container - > min_width and inline_container - > max_width filled in ,
* 0 < = inline_container - > min_width < = inline_container - > max_width
2005-07-02 22:17:51 +04:00
*/
void layout_minmax_inline_container ( struct box * inline_container )
{
struct box * child ;
int line_min = 0 , line_max = 0 ;
int min = 0 , max = 0 ;
assert ( inline_container - > type = = BOX_INLINE_CONTAINER ) ;
/* check if the widths have already been calculated */
if ( inline_container - > max_width ! = UNKNOWN_MAX_WIDTH )
return ;
for ( child = inline_container - > children ; child ; ) {
child = layout_minmax_line ( child , & line_min , & line_max ) ;
if ( min < line_min )
min = line_min ;
if ( max < line_max )
max = line_max ;
}
inline_container - > min_width = min ;
inline_container - > max_width = max ;
2005-07-22 01:48:41 +04:00
assert ( 0 < = inline_container - > min_width & &
inline_container - > min_width < =
inline_container - > max_width ) ;
2005-07-02 22:17:51 +04:00
}
2004-02-11 20:15:36 +03:00
/**
* Calculate line height from a style .
*/
int line_height ( struct css_style * style )
2002-06-19 01:24:21 +04:00
{
2004-06-14 11:28:27 +04:00
float font_len ;
2004-04-15 20:18:19 +04:00
2004-02-11 20:15:36 +03:00
assert ( style ) ;
2002-06-19 01:24:21 +04:00
assert ( style - > line_height . size = = CSS_LINE_HEIGHT_LENGTH | |
2003-07-20 17:58:12 +04:00
style - > line_height . size = = CSS_LINE_HEIGHT_ABSOLUTE | |
style - > line_height . size = = CSS_LINE_HEIGHT_PERCENT ) ;
2002-06-19 01:24:21 +04:00
2004-06-14 11:28:27 +04:00
/* take account of minimum font size option */
2004-08-14 19:07:21 +04:00
if ( ( font_len = css_len2px ( & style - > font_size . value . length , 0 ) ) <
2007-08-19 14:08:49 +04:00
option_font_min_size * css_screen_dpi / 720.0 )
font_len = option_font_min_size * css_screen_dpi / 720.0 ;
2004-04-15 20:18:19 +04:00
2004-02-11 20:15:36 +03:00
switch ( style - > line_height . size ) {
case CSS_LINE_HEIGHT_LENGTH :
2005-06-06 00:54:37 +04:00
return css_len2px ( & style - > line_height . value . length ,
style ) ;
2004-02-11 20:15:36 +03:00
case CSS_LINE_HEIGHT_ABSOLUTE :
2004-04-15 20:18:19 +04:00
return style - > line_height . value . absolute * font_len ;
2004-02-11 20:15:36 +03:00
case CSS_LINE_HEIGHT_PERCENT :
default :
2004-04-15 20:18:19 +04:00
return style - > line_height . value . percent * font_len
2004-02-11 20:15:36 +03:00
/ 100.0 ;
}
2002-06-19 01:24:21 +04:00
}
2004-02-11 20:15:36 +03:00
/**
* Position a line of boxes in inline formatting context .
*
* \ param first box at start of line
2006-09-10 17:27:08 +04:00
* \ param width available width on input , updated with actual width on output
* ( may be incorrect if the line gets split ? )
2005-04-14 23:54:24 +04:00
* \ param y coordinate of top of line , updated on exit to bottom
* \ param cx coordinate of left of line relative to cont
* \ param cy coordinate of top of line relative to cont
* \ param cont ancestor box which defines horizontal space , for floats
2004-02-11 20:15:36 +03:00
* \ param indent apply any first - line indent
2006-08-13 05:00:22 +04:00
* \ param has_text_children at least one TEXT in the inline_container
2004-06-03 01:21:13 +04:00
* \ param next_box updated to first box for next line , or 0 at end
2005-04-09 13:47:37 +04:00
* \ param content memory pool for any new boxes
2004-06-03 01:21:13 +04:00
* \ return true on success , false on memory exhaustion
2004-02-11 20:15:36 +03:00
*/
2006-09-10 17:27:08 +04:00
bool layout_line ( struct box * first , int * width , int * y ,
2004-06-03 01:21:13 +04:00
int cx , int cy , struct box * cont , bool indent ,
2006-08-13 05:00:22 +04:00
bool has_text_children ,
2005-04-09 13:47:37 +04:00
struct content * content , struct box * * next_box )
2002-06-19 01:24:21 +04:00
{
2004-02-11 20:15:36 +03:00
int height , used_height ;
int x0 = 0 ;
2006-09-10 17:27:08 +04:00
int x1 = * width ;
2004-02-11 20:15:36 +03:00
int x , h , x_previous ;
2004-02-28 20:23:07 +03:00
struct box * left ;
struct box * right ;
struct box * b ;
struct box * split_box = 0 ;
struct box * d ;
2005-08-08 01:28:48 +04:00
struct box * br_box = 0 ;
2004-04-18 19:19:53 +04:00
bool move_y = false ;
2004-02-11 20:15:36 +03:00
int space_before = 0 , space_after = 0 ;
2004-03-26 04:35:35 +03:00
unsigned int inline_count = 0 ;
2005-05-24 02:14:09 +04:00
unsigned int i ;
2008-01-29 03:42:15 +03:00
int min_gadget_size = 0 ;
2002-06-19 01:24:21 +04:00
2005-07-24 18:29:32 +04:00
LOG ( ( " first %p, first->text '%.*s', width %i, y %i, cx %i, cy %i " ,
2006-09-10 17:27:08 +04:00
first , ( int ) first - > length , first - > text , * width ,
2005-07-24 18:29:32 +04:00
* y , cx , cy ) ) ;
2002-06-19 19:17:45 +04:00
2002-06-19 01:24:21 +04:00
/* find sides at top of line */
2004-02-11 20:15:36 +03:00
x0 + = cx ;
x1 + = cx ;
2002-06-19 01:24:21 +04:00
find_sides ( cont - > float_children , cy , cy , & x0 , & x1 , & left , & right ) ;
2004-02-11 20:15:36 +03:00
x0 - = cx ;
x1 - = cx ;
2002-06-19 01:24:21 +04:00
2006-03-27 01:41:18 +04:00
if ( indent )
2006-09-10 17:27:08 +04:00
x0 + = layout_text_indent ( first - > parent - > parent - > style , * width ) ;
2002-06-19 01:24:21 +04:00
2005-03-08 00:30:28 +03:00
if ( x1 < x0 )
x1 = x0 ;
2006-03-27 01:41:18 +04:00
/* get minimum line height from containing block */
2006-08-13 05:00:22 +04:00
if ( has_text_children )
used_height = height = line_height ( first - > parent - > parent - > style ) ;
else
/* inline containers with no text are usually for layout and
* look better with no minimum line - height */
used_height = height = 0 ;
2006-03-27 01:41:18 +04:00
2005-03-08 00:30:28 +03:00
/* pass 1: find height of line assuming sides at top of line: loop
2005-07-02 22:17:51 +04:00
* body executed at least once
* keep in sync with the loop in layout_minmax_line ( ) */
2006-03-27 01:41:18 +04:00
LOG ( ( " x0 %i, x1 %i, x1 - x0 %i " , x0 , x1 , x1 - x0 ) ) ;
2004-06-19 02:54:07 +04:00
for ( x = 0 , b = first ; x < = x1 - x0 & & b ! = 0 ; b = b - > next ) {
2003-09-22 02:47:08 +04:00
assert ( b - > type = = BOX_INLINE | | b - > type = = BOX_INLINE_BLOCK | |
2004-02-28 20:23:07 +03:00
b - > type = = BOX_FLOAT_LEFT | |
2004-04-18 19:19:53 +04:00
b - > type = = BOX_FLOAT_RIGHT | |
2005-06-06 00:54:37 +04:00
b - > type = = BOX_BR | | b - > type = = BOX_TEXT | |
b - > type = = BOX_INLINE_END ) ;
2006-03-27 01:41:18 +04:00
LOG ( ( " pass 1: b %p, x %i " , b , x ) ) ;
2004-03-26 04:35:35 +03:00
2005-07-02 22:17:51 +04:00
if ( b - > type = = BOX_BR )
break ;
if ( b - > type = = BOX_FLOAT_LEFT | | b - > type = = BOX_FLOAT_RIGHT )
continue ;
2006-11-04 22:17:11 +03:00
if ( b - > type = = BOX_INLINE_BLOCK & &
( b - > style - > position = = CSS_POSITION_ABSOLUTE | |
b - > style - > position = = CSS_POSITION_FIXED ) )
continue ;
2005-07-02 22:17:51 +04:00
2006-03-26 23:59:15 +04:00
x + = space_after ;
2004-03-26 04:35:35 +03:00
if ( b - > type = = BOX_INLINE_BLOCK ) {
2008-01-28 01:25:11 +03:00
if ( b - > max_width ! = UNKNOWN_WIDTH )
2006-09-10 17:27:08 +04:00
if ( ! layout_float ( b , * width , content ) )
2004-06-03 01:21:13 +04:00
return false ;
2004-03-26 04:35:35 +03:00
h = b - > border [ TOP ] + b - > padding [ TOP ] + b - > height +
b - > padding [ BOTTOM ] + b - > border [ BOTTOM ] ;
if ( height < h )
height = h ;
x + = b - > margin [ LEFT ] + b - > border [ LEFT ] +
b - > padding [ LEFT ] + b - > width +
b - > padding [ RIGHT ] + b - > border [ RIGHT ] +
b - > margin [ RIGHT ] ;
2005-04-02 22:24:47 +04:00
space_after = 0 ;
2004-02-28 20:23:07 +03:00
continue ;
2005-07-02 22:17:51 +04:00
}
2004-02-28 20:23:07 +03:00
2005-05-24 02:14:09 +04:00
if ( b - > type = = BOX_INLINE ) {
/* calculate borders, margins, and padding */
2006-09-10 17:27:08 +04:00
layout_find_dimensions ( * width , b - > style ,
2006-06-26 08:52:34 +04:00
0 , 0 , b - > margin , b - > padding , b - > border ) ;
2005-05-24 02:14:09 +04:00
for ( i = 0 ; i ! = 4 ; i + + )
if ( b - > margin [ i ] = = AUTO )
b - > margin [ i ] = 0 ;
2006-01-16 01:25:40 +03:00
x + = b - > margin [ LEFT ] + b - > border [ LEFT ] +
b - > padding [ LEFT ] ;
2005-06-06 00:54:37 +04:00
if ( b - > inline_end ) {
b - > inline_end - > margin [ RIGHT ] = b - > margin [ RIGHT ] ;
b - > inline_end - > padding [ RIGHT ] =
b - > padding [ RIGHT ] ;
b - > inline_end - > border [ RIGHT ] =
b - > border [ RIGHT ] ;
2006-01-16 01:25:40 +03:00
} else {
x + = b - > padding [ RIGHT ] + b - > border [ RIGHT ] +
b - > margin [ RIGHT ] ;
2005-06-06 00:54:37 +04:00
}
} else if ( b - > type = = BOX_INLINE_END ) {
b - > width = 0 ;
if ( b - > space ) {
/** \todo optimize out */
nsfont_width ( b - > style , " " , 1 , & space_after ) ;
} else {
space_after = 0 ;
}
2006-01-16 01:25:40 +03:00
x + = b - > padding [ RIGHT ] + b - > border [ RIGHT ] +
b - > margin [ RIGHT ] ;
2005-06-06 00:54:37 +04:00
continue ;
2005-05-24 02:14:09 +04:00
}
2004-05-21 18:26:59 +04:00
if ( ! b - > object & & ! b - > gadget ) {
/* inline non-replaced, 10.3.1 and 10.6.1 */
b - > height = line_height ( b - > style ? b - > style :
2004-02-28 20:23:07 +03:00
b - > parent - > parent - > style ) ;
2004-05-21 18:26:59 +04:00
if ( height < b - > height )
height = b - > height ;
2005-07-02 22:17:51 +04:00
if ( ! b - > text ) {
2004-05-21 18:26:59 +04:00
b - > width = 0 ;
2005-04-02 22:24:47 +04:00
space_after = 0 ;
2005-07-02 22:17:51 +04:00
continue ;
2005-04-02 22:24:47 +04:00
}
2003-01-07 02:53:40 +03:00
2005-07-02 22:17:51 +04:00
if ( b - > width = = UNKNOWN_WIDTH )
/** \todo handle errors */
nsfont_width ( b - > style , b - > text , b - > length ,
& b - > width ) ;
x + = b - > width ;
if ( b - > space )
/** \todo optimize out */
nsfont_width ( b - > style , " " , 1 , & space_after ) ;
else
space_after = 0 ;
2004-05-21 18:26:59 +04:00
continue ;
}
2005-04-02 22:24:47 +04:00
space_after = 0 ;
2004-05-21 18:26:59 +04:00
/* inline replaced, 10.3.2 and 10.6.2 */
assert ( b - > style ) ;
2008-01-29 03:42:15 +03:00
min_gadget_size = 0 ;
/* checkboxes and radiobuttons contain no text but need to
* follow configured min font size option */
if ( b - > gadget & & ( b - > gadget - > type = = GADGET_RADIO | |
b - > gadget - > type = = GADGET_CHECKBOX ) ) {
min_gadget_size = option_font_min_size * css_screen_dpi
/ 720.0 ;
min_gadget_size = min_gadget_size > css_len2px ( & b - >
style - > font_size . value . length , b - > style ) ?
min_gadget_size : 0 ;
}
2004-05-21 18:26:59 +04:00
/* calculate box width */
switch ( b - > style - > width . width ) {
case CSS_WIDTH_LENGTH :
2008-01-29 03:42:15 +03:00
b - > width = min_gadget_size ? css_screen_dpi *
option_font_min_size / 720.0 :
css_len2px ( & b - > style - > width . value .
length , b - > style ) ;
2004-05-21 18:26:59 +04:00
break ;
case CSS_WIDTH_PERCENT :
2008-01-29 03:42:15 +03:00
b - > width = min_gadget_size ? css_screen_dpi *
option_font_min_size / 720.0 :
css_len2px ( & b - > style - > width . value .
length , b - > style ) ;
2004-05-21 18:26:59 +04:00
break ;
case CSS_WIDTH_AUTO :
default :
b - > width = AUTO ;
break ;
}
/* height */
switch ( b - > style - > height . height ) {
case CSS_HEIGHT_LENGTH :
2008-01-29 03:42:15 +03:00
b - > height = min_gadget_size ? css_screen_dpi *
option_font_min_size / 720.0 :
css_len2px ( & b - > style - > height . length ,
b - > style ) ;
2004-05-21 18:26:59 +04:00
break ;
case CSS_HEIGHT_AUTO :
default :
b - > height = AUTO ;
break ;
}
2004-06-03 01:21:13 +04:00
if ( b - > object ) {
if ( b - > width = = AUTO & & b - > height = = AUTO ) {
2004-05-21 18:26:59 +04:00
b - > width = b - > object - > width ;
b - > height = b - > object - > height ;
2004-06-03 01:21:13 +04:00
} else if ( b - > width = = AUTO ) {
if ( b - > object - > height )
b - > width = b - > object - > width *
( float ) b - > height /
b - > object - > height ;
else
b - > width = b - > object - > width ;
} else if ( b - > height = = AUTO ) {
if ( b - > object - > width )
b - > height = b - > object - > height *
( float ) b - > width /
b - > object - > width ;
else
b - > height = b - > object - > height ;
}
} else {
/* form control with no object */
if ( b - > width = = AUTO )
b - > width = 0 ;
if ( b - > height = = AUTO )
b - > height = line_height ( b - > style ? b - > style :
b - > parent - > parent - > style ) ;
2004-05-21 18:26:59 +04:00
}
if ( b - > object & & b - > object - > type = = CONTENT_HTML & &
b - > width ! = b - > object - > available_width ) {
content_reformat ( b - > object , b - > width , b - > height ) ;
if ( b - > style - > height . height = = CSS_HEIGHT_AUTO )
b - > height = b - > object - > height ;
}
if ( height < b - > height )
height = b - > height ;
x + = b - > width ;
2002-06-19 01:24:21 +04:00
}
2002-06-19 19:17:45 +04:00
2002-06-19 01:24:21 +04:00
/* find new sides using this height */
2004-02-11 20:15:36 +03:00
x0 = cx ;
2006-09-10 17:27:08 +04:00
x1 = cx + * width ;
2004-02-28 20:23:07 +03:00
find_sides ( cont - > float_children , cy , cy + height , & x0 , & x1 ,
& left , & right ) ;
2004-02-11 20:15:36 +03:00
x0 - = cx ;
x1 - = cx ;
2002-06-19 01:24:21 +04:00
2004-05-21 18:26:59 +04:00
if ( indent )
2006-09-10 17:27:08 +04:00
x0 + = layout_text_indent ( first - > parent - > parent - > style , * width ) ;
2004-02-02 01:42:40 +03:00
2004-05-21 18:26:59 +04:00
if ( x1 < x0 )
x1 = x0 ;
2004-02-28 20:23:07 +03:00
2005-04-02 22:24:47 +04:00
space_after = space_before = 0 ;
2004-02-28 20:23:07 +03:00
/* pass 2: place boxes in line: loop body executed at least once */
2006-03-27 01:41:18 +04:00
LOG ( ( " x0 %i, x1 %i, x1 - x0 %i " , x0 , x1 , x1 - x0 ) ) ;
2004-02-28 20:23:07 +03:00
for ( x = x_previous = 0 , b = first ; x < = x1 - x0 & & b ; b = b - > next ) {
2006-03-27 01:41:18 +04:00
LOG ( ( " pass 2: b %p, x %i " , b , x ) ) ;
2006-11-04 22:17:11 +03:00
if ( b - > type = = BOX_INLINE_BLOCK & &
( b - > style - > position = = CSS_POSITION_ABSOLUTE | |
b - > style - > position = = CSS_POSITION_FIXED ) ) {
b - > x = x + space_after ;
} else if ( b - > type = = BOX_INLINE | |
b - > type = = BOX_INLINE_BLOCK | |
2005-06-06 00:54:37 +04:00
b - > type = = BOX_TEXT | |
b - > type = = BOX_INLINE_END ) {
2005-04-09 17:25:54 +04:00
assert ( b - > width ! = UNKNOWN_WIDTH ) ;
2004-02-11 20:15:36 +03:00
x_previous = x ;
x + = space_after ;
b - > x = x ;
2005-06-06 00:54:37 +04:00
if ( ( b - > type = = BOX_INLINE & & ! b - > inline_end ) | |
b - > type = = BOX_INLINE_BLOCK ) {
2004-02-11 20:15:36 +03:00
b - > x + = b - > margin [ LEFT ] + b - > border [ LEFT ] ;
2004-03-26 04:35:35 +03:00
x = b - > x + b - > padding [ LEFT ] + b - > width +
b - > padding [ RIGHT ] +
b - > border [ RIGHT ] +
b - > margin [ RIGHT ] ;
2005-06-06 00:54:37 +04:00
} else if ( b - > type = = BOX_INLINE ) {
b - > x + = b - > margin [ LEFT ] + b - > border [ LEFT ] ;
x = b - > x + b - > padding [ LEFT ] + b - > width ;
} else if ( b - > type = = BOX_INLINE_END ) {
x + = b - > padding [ RIGHT ] + b - > border [ RIGHT ] +
b - > margin [ RIGHT ] ;
} else {
2004-02-11 20:15:36 +03:00
x + = b - > width ;
2005-06-06 00:54:37 +04:00
}
2004-02-11 20:15:36 +03:00
2002-12-27 20:28:19 +03:00
space_before = space_after ;
2003-09-10 01:43:44 +04:00
if ( b - > object )
space_after = 0 ;
2005-06-06 00:54:37 +04:00
else if ( b - > text | | b - > type = = BOX_INLINE_END ) {
2005-02-20 16:18:21 +03:00
space_after = 0 ;
if ( b - > space )
/** \todo handle errors, optimize */
nsfont_width ( b - > style , " " , 1 ,
& space_after ) ;
} else
2002-12-30 01:27:35 +03:00
space_after = 0 ;
2004-02-28 20:23:07 +03:00
split_box = b ;
2004-04-18 19:19:53 +04:00
move_y = true ;
2004-03-26 04:35:35 +03:00
inline_count + + ;
2004-04-18 19:19:53 +04:00
} else if ( b - > type = = BOX_BR ) {
b - > x = x ;
b - > width = 0 ;
2005-08-08 01:28:48 +04:00
br_box = b ;
2004-04-18 19:19:53 +04:00
b = b - > next ;
split_box = 0 ;
move_y = true ;
break ;
2002-06-19 01:24:21 +04:00
} else {
2003-04-13 16:50:10 +04:00
/* float */
2005-11-06 14:00:33 +03:00
LOG ( ( " float %p " , b ) ) ;
2002-06-29 00:14:04 +04:00
d = b - > children ;
d - > float_children = 0 ;
2004-02-11 20:15:36 +03:00
2006-09-10 17:27:08 +04:00
if ( ! layout_float ( d , * width , content ) )
2004-06-03 01:21:13 +04:00
return false ;
2007-03-25 00:03:36 +03:00
LOG ( ( " %p : %d %d " , d , d - > margin [ TOP ] , d - > border [ TOP ] ) ) ;
2004-02-11 20:15:36 +03:00
d - > x = d - > margin [ LEFT ] + d - > border [ LEFT ] ;
d - > y = d - > margin [ TOP ] + d - > border [ TOP ] ;
b - > width = d - > margin [ LEFT ] + d - > border [ LEFT ] +
d - > padding [ LEFT ] + d - > width +
d - > padding [ RIGHT ] + d - > border [ RIGHT ] +
d - > margin [ RIGHT ] ;
b - > height = d - > margin [ TOP ] + d - > border [ TOP ] +
d - > padding [ TOP ] + d - > height +
d - > padding [ BOTTOM ] + d - > border [ BOTTOM ] +
d - > margin [ BOTTOM ] ;
2006-06-28 20:47:02 +04:00
if ( b - > width < = ( x1 - x0 ) - x | |
2006-04-09 22:59:07 +04:00
( left = = 0 & & right = = 0 & & x = = 0 ) ) {
/* fits next to this line, or this line is empty
* with no floats */
2002-06-29 00:14:04 +04:00
if ( b - > type = = BOX_FLOAT_LEFT ) {
2004-04-22 02:27:49 +04:00
b - > x = cx + x0 ;
2002-06-19 01:24:21 +04:00
x0 + = b - > width ;
left = b ;
} else {
2004-04-22 02:27:49 +04:00
b - > x = cx + x1 - b - > width ;
2002-06-19 01:24:21 +04:00
x1 - = b - > width ;
right = b ;
}
b - > y = cy ;
} else {
/* doesn't fit: place below */
2006-09-10 17:27:08 +04:00
place_float_below ( b , * width ,
2006-04-09 22:59:07 +04:00
cx , cy + height + 1 , cont ) ;
2002-06-19 01:24:21 +04:00
}
2005-11-06 14:00:33 +03:00
if ( cont - > float_children = = b ) {
LOG ( ( " float %p already placed " , b ) ) ;
2007-08-20 06:39:49 +04:00
box_dump ( stderr , cont , 0 ) ;
2005-11-06 14:00:33 +03:00
assert ( 0 ) ;
}
2002-06-19 01:24:21 +04:00
b - > next_float = cont - > float_children ;
cont - > float_children = b ;
2004-02-28 20:23:07 +03:00
split_box = 0 ;
2002-06-19 01:24:21 +04:00
}
}
2004-02-28 20:23:07 +03:00
if ( x1 - x0 < x & & split_box ) {
2002-06-19 01:24:21 +04:00
/* the last box went over the end */
2004-02-28 20:23:07 +03:00
unsigned int i ;
2005-02-20 16:18:21 +03:00
size_t space = 0 ;
2004-02-11 20:15:36 +03:00
int w ;
2002-06-19 01:24:21 +04:00
struct box * c2 ;
2002-12-27 20:28:19 +03:00
x = x_previous ;
2005-05-23 01:50:14 +04:00
if ( ( split_box - > type = = BOX_INLINE | |
split_box - > type = = BOX_TEXT ) & &
! split_box - > object & &
2004-03-26 04:35:35 +03:00
! split_box - > gadget & & split_box - > text ) {
2006-09-10 17:59:19 +04:00
/* skip leading spaces, otherwise code gets fooled into thinking it's all one long word */
2004-02-28 20:23:07 +03:00
for ( i = 0 ; i ! = split_box - > length & &
2006-09-10 17:59:19 +04:00
split_box - > text [ i ] = = ' ' ; i + + )
;
/* find end of word */
for ( ; i ! = split_box - > length & &
2004-02-28 20:23:07 +03:00
split_box - > text [ i ] ! = ' ' ; i + + )
;
2004-03-15 01:49:14 +03:00
if ( i ! = split_box - > length )
2004-02-28 20:23:07 +03:00
space = i ;
}
2002-12-27 20:28:19 +03:00
2004-02-28 20:23:07 +03:00
/* space != 0 implies split_box->text != 0 */
2003-01-07 02:53:40 +03:00
2002-06-21 22:16:24 +04:00
if ( space = = 0 )
2004-02-28 20:23:07 +03:00
w = split_box - > width ;
2003-01-07 02:53:40 +03:00
else
2005-02-20 16:18:21 +03:00
/** \todo handle errors */
nsfont_width ( split_box - > style , split_box - > text ,
space , & w ) ;
2002-06-21 22:16:24 +04:00
2006-04-09 22:59:07 +04:00
LOG ( ( " splitting: split_box %p \" %.*s \" , space %zu, w %i, "
" left %p, right %p, inline_count %u " ,
split_box , ( int ) split_box - > length ,
split_box - > text , space , w ,
left , right , inline_count ) ) ;
2004-03-26 04:35:35 +03:00
if ( ( space = = 0 | | x1 - x0 < = x + space_before + w ) & &
! left & & ! right & & inline_count = = 1 ) {
2006-04-09 22:59:07 +04:00
/* first word of box doesn't fit, but no floats and
* first box on line so force in */
2002-06-21 22:16:24 +04:00
if ( space = = 0 ) {
2003-01-07 02:53:40 +03:00
/* only one word in this box or not text */
2004-02-28 20:23:07 +03:00
b = split_box - > next ;
2002-06-21 22:16:24 +04:00
} else {
2002-12-27 20:28:19 +03:00
/* cut off first word for this line */
2005-04-09 13:47:37 +04:00
c2 = talloc_memdup ( content , split_box ,
sizeof * c2 ) ;
2004-06-03 01:21:13 +04:00
if ( ! c2 )
return false ;
2005-04-09 13:47:37 +04:00
c2 - > text = talloc_strndup ( content ,
split_box - > text + space + 1 ,
split_box - > length - ( space + 1 ) ) ;
2004-06-03 01:21:13 +04:00
if ( ! c2 - > text )
return false ;
2004-02-28 20:23:07 +03:00
c2 - > length = split_box - > length - ( space + 1 ) ;
2002-09-19 23:54:43 +04:00
c2 - > width = UNKNOWN_WIDTH ;
2003-09-10 01:43:44 +04:00
c2 - > clone = 1 ;
2004-02-28 20:23:07 +03:00
split_box - > length = space ;
split_box - > width = w ;
split_box - > space = 1 ;
c2 - > next = split_box - > next ;
split_box - > next = c2 ;
c2 - > prev = split_box ;
2003-09-24 01:48:22 +04:00
if ( c2 - > next )
c2 - > next - > prev = c2 ;
else
2003-09-23 22:35:44 +04:00
c2 - > parent - > last = c2 ;
2002-06-21 22:16:24 +04:00
b = c2 ;
}
2002-12-27 20:28:19 +03:00
x + = space_before + w ;
2006-04-09 22:59:07 +04:00
LOG ( ( " forcing " ) ) ;
} else if ( ( space = = 0 | | x1 - x0 < = x + space_before + w ) & &
inline_count = = 1 ) {
/* first word of first box doesn't fit, but a float is
* taking some of the width so move below it */
assert ( left | | right ) ;
used_height = 0 ;
if ( left ) {
LOG ( ( " cy %i, left->y %i, left->height %i " ,
cy , left - > y , left - > height ) ) ;
used_height = left - > y + left - > height - cy + 1 ;
LOG ( ( " used_height %i " , used_height ) ) ;
}
if ( right & & used_height <
right - > y + right - > height - cy + 1 )
used_height = right - > y + right - > height - cy + 1 ;
assert ( 0 < used_height ) ;
b = split_box ;
LOG ( ( " moving below float " ) ) ;
} else if ( space = = 0 | | x1 - x0 < = x + space_before + w ) {
/* first word of box doesn't fit so leave box for next
* line */
2004-02-28 20:23:07 +03:00
b = split_box ;
2006-04-09 22:59:07 +04:00
LOG ( ( " leaving for next line " ) ) ;
2003-01-07 02:53:40 +03:00
} else {
2002-06-19 01:24:21 +04:00
/* fit as many words as possible */
2002-06-21 22:16:24 +04:00
assert ( space ! = 0 ) ;
2005-02-20 16:18:21 +03:00
/** \todo handle errors */
nsfont_split ( split_box - > style ,
split_box - > text , split_box - > length ,
x1 - x0 - x - space_before , & space , & w ) ;
2005-07-24 18:29:32 +04:00
LOG ( ( " '%.*s' %i %zu %i " , ( int ) split_box - > length ,
2004-02-28 20:23:07 +03:00
split_box - > text , x1 - x0 , space , w ) ) ;
if ( space = = 0 )
space = 1 ;
2005-02-20 16:18:21 +03:00
if ( space ! = split_box - > length ) {
2005-04-09 13:47:37 +04:00
c2 = talloc_memdup ( content , split_box ,
sizeof * c2 ) ;
2005-02-20 16:18:21 +03:00
if ( ! c2 )
return false ;
2005-04-09 13:47:37 +04:00
c2 - > text = talloc_strndup ( content ,
split_box - > text + space + 1 ,
split_box - > length - ( space + 1 ) ) ;
2005-02-20 16:18:21 +03:00
if ( ! c2 - > text )
return false ;
c2 - > length = split_box - > length - ( space + 1 ) ;
c2 - > width = UNKNOWN_WIDTH ;
c2 - > clone = 1 ;
split_box - > length = space ;
split_box - > width = w ;
split_box - > space = 1 ;
c2 - > next = split_box - > next ;
split_box - > next = c2 ;
c2 - > prev = split_box ;
if ( c2 - > next )
c2 - > next - > prev = c2 ;
else
c2 - > parent - > last = c2 ;
b = c2 ;
}
2002-12-27 20:28:19 +03:00
x + = space_before + w ;
2006-04-09 22:59:07 +04:00
LOG ( ( " fitting words " ) ) ;
2002-05-04 23:57:18 +04:00
}
2004-04-18 19:19:53 +04:00
move_y = true ;
2002-05-04 23:57:18 +04:00
}
2002-06-19 01:24:21 +04:00
/* set positions */
2002-06-19 19:17:45 +04:00
switch ( first - > parent - > parent - > style - > text_align ) {
case CSS_TEXT_ALIGN_RIGHT : x0 = x1 - x ; break ;
case CSS_TEXT_ALIGN_CENTER : x0 = ( x0 + ( x1 - x ) ) / 2 ; break ;
2004-06-14 11:28:27 +04:00
default : break ; /* leave on left */
2002-06-19 19:17:45 +04:00
}
2004-02-02 01:42:40 +03:00
2002-06-19 01:24:21 +04:00
for ( d = first ; d ! = b ; d = d - > next ) {
2008-01-27 14:59:01 +03:00
if ( d - > type = = BOX_INLINE | | d - > type = = BOX_BR | |
d - > type = = BOX_TEXT | |
2005-06-06 00:54:37 +04:00
d - > type = = BOX_INLINE_END ) {
2002-06-19 01:24:21 +04:00
d - > x + = x0 ;
2005-05-24 02:14:09 +04:00
d - > y = * y - d - > padding [ TOP ] ;
}
2008-01-28 03:58:31 +03:00
if ( ( d - > type = = BOX_INLINE & & ( d - > object | | d - > gadget ) ) | |
d - > type = = BOX_INLINE_BLOCK ) {
2008-01-27 20:39:14 +03:00
d - > y = * y + d - > border [ TOP ] + d - > margin [ TOP ] ;
2008-01-27 14:59:01 +03:00
}
2008-01-28 05:01:04 +03:00
if ( d - > type = = BOX_INLINE_BLOCK ) {
d - > x + = x0 ;
}
2006-11-04 22:17:11 +03:00
if ( d - > type = = BOX_INLINE_BLOCK & &
( d - > style - > position = = CSS_POSITION_ABSOLUTE | |
d - > style - > position = = CSS_POSITION_FIXED ) )
continue ;
2005-05-24 02:14:09 +04:00
if ( ( d - > type = = BOX_INLINE & & ( d - > object | | d - > gadget ) ) | |
d - > type = = BOX_INLINE_BLOCK ) {
2008-01-27 20:39:14 +03:00
h = d - > margin [ TOP ] + d - > border [ TOP ] + d - > padding [ TOP ] +
d - > height + d - > padding [ BOTTOM ] +
d - > border [ BOTTOM ] + d - > margin [ BOTTOM ] ;
2004-03-26 04:35:35 +03:00
if ( used_height < h )
used_height = h ;
2002-06-19 01:24:21 +04:00
}
}
2002-06-19 19:17:45 +04:00
2004-03-26 04:35:35 +03:00
assert ( b ! = first | | ( move_y & & 0 < used_height & & ( left | | right ) ) ) ;
2005-08-01 01:57:07 +04:00
/* handle clearance for br */
2005-08-08 01:28:48 +04:00
if ( br_box & & br_box - > style - > clear ! = CSS_CLEAR_NONE ) {
2005-08-01 01:57:07 +04:00
int clear_y = layout_clear ( cont - > float_children ,
2005-08-08 01:28:48 +04:00
br_box - > style - > clear ) ;
2005-08-01 01:57:07 +04:00
if ( used_height < clear_y - cy )
used_height = clear_y - cy ;
}
if ( move_y )
* y + = used_height ;
2004-06-03 01:21:13 +04:00
* next_box = b ;
2006-09-10 17:27:08 +04:00
* width = x ; /* return actual width */
2004-06-03 01:21:13 +04:00
return true ;
2002-05-04 23:57:18 +04:00
}
2002-06-19 01:24:21 +04:00
2005-07-02 22:17:51 +04:00
/**
* Calculate minimum and maximum width of a line .
*
* \ param first a box in an inline container
* \ param line_min updated to minimum width of line starting at first
* \ param line_max updated to maximum width of line starting at first
* \ return first box in next line , or 0 if no more lines
2005-07-22 01:48:41 +04:00
* \ post 0 < = * line_min < = * line_max
2005-07-02 22:17:51 +04:00
*/
struct box * layout_minmax_line ( struct box * first ,
int * line_min , int * line_max )
{
2005-07-03 03:37:41 +04:00
int min = 0 , max = 0 , width , height , fixed ;
float frac ;
2005-07-02 22:17:51 +04:00
size_t i , j ;
struct box * b ;
2008-01-29 03:42:15 +03:00
int min_gadget_size = 0 ;
2005-07-02 22:17:51 +04:00
/* corresponds to the pass 1 loop in layout_line() */
for ( b = first ; b ; b = b - > next ) {
assert ( b - > type = = BOX_INLINE | | b - > type = = BOX_INLINE_BLOCK | |
b - > type = = BOX_FLOAT_LEFT | |
b - > type = = BOX_FLOAT_RIGHT | |
b - > type = = BOX_BR | | b - > type = = BOX_TEXT | |
b - > type = = BOX_INLINE_END ) ;
2005-07-03 03:37:41 +04:00
LOG ( ( " %p: min %i, max %i " , b , min , max ) ) ;
2005-07-02 22:17:51 +04:00
if ( b - > type = = BOX_BR ) {
b = b - > next ;
break ;
}
if ( b - > type = = BOX_FLOAT_LEFT | | b - > type = = BOX_FLOAT_RIGHT ) {
assert ( b - > children ) ;
if ( b - > children - > type = = BOX_BLOCK )
layout_minmax_block ( b - > children ) ;
else
layout_minmax_table ( b - > children ) ;
b - > min_width = b - > children - > min_width ;
b - > max_width = b - > children - > max_width ;
if ( min < b - > min_width )
min = b - > min_width ;
max + = b - > max_width ;
continue ;
}
if ( b - > type = = BOX_INLINE_BLOCK ) {
layout_minmax_block ( b ) ;
if ( min < b - > min_width )
min = b - > min_width ;
max + = b - > max_width ;
continue ;
}
if ( b - > type = = BOX_INLINE ) {
2005-07-03 03:37:41 +04:00
fixed = frac = 0 ;
calculate_mbp_width ( b - > style , LEFT , & fixed , & frac ) ;
if ( ! b - > inline_end )
calculate_mbp_width ( b - > style , RIGHT ,
& fixed , & frac ) ;
2005-07-21 02:08:56 +04:00
if ( 0 < fixed )
max + = fixed ;
2005-07-03 03:37:41 +04:00
/* \todo update min width, consider fractional extra */
2005-07-02 22:17:51 +04:00
} else if ( b - > type = = BOX_INLINE_END ) {
2005-07-03 03:37:41 +04:00
fixed = frac = 0 ;
calculate_mbp_width ( b - > inline_end - > style , RIGHT ,
& fixed , & frac ) ;
2005-07-21 02:08:56 +04:00
if ( 0 < fixed )
max + = fixed ;
2005-07-03 03:37:41 +04:00
if ( b - > next & & b - > space ) {
nsfont_width ( b - > style , " " , 1 , & width ) ;
max + = width ;
}
2005-07-02 22:17:51 +04:00
continue ;
}
if ( ! b - > object & & ! b - > gadget ) {
/* inline non-replaced, 10.3.1 and 10.6.1 */
if ( ! b - > text )
continue ;
if ( b - > width = = UNKNOWN_WIDTH )
/** \todo handle errors */
nsfont_width ( b - > style , b - > text , b - > length ,
& b - > width ) ;
max + = b - > width ;
if ( b - > next & & b - > space ) {
nsfont_width ( b - > style , " " , 1 , & width ) ;
max + = width ;
}
/* min = widest word */
i = 0 ;
do {
for ( j = i ; j ! = b - > length & &
b - > text [ j ] ! = ' ' ; j + + )
;
nsfont_width ( b - > style , b - > text + i ,
j - i , & width ) ;
if ( min < width )
min = width ;
i = j + 1 ;
} while ( j ! = b - > length ) ;
continue ;
}
/* inline replaced, 10.3.2 and 10.6.2 */
assert ( b - > style ) ;
2008-01-29 03:42:15 +03:00
min_gadget_size = 0 ;
/* checkboxes and radiobuttons contain no text but need to
* follow configured min font size option */
if ( b - > gadget & & ( b - > gadget - > type = = GADGET_RADIO | |
b - > gadget - > type = = GADGET_CHECKBOX ) ) {
min_gadget_size = option_font_min_size * css_screen_dpi
/ 720.0 ;
min_gadget_size = min_gadget_size > css_len2px ( & b - >
style - > font_size . value . length , b - > style ) ?
min_gadget_size : 0 ;
}
2005-07-02 22:17:51 +04:00
/* calculate box width */
switch ( b - > style - > width . width ) {
case CSS_WIDTH_LENGTH :
2008-01-29 03:42:15 +03:00
width = min_gadget_size ? css_screen_dpi *
option_font_min_size / 720.0 :
css_len2px ( & b - > style - > width . value .
length , b - > style ) ;
2005-07-02 22:17:51 +04:00
break ;
case CSS_WIDTH_PERCENT :
/*b->width = width *
b - > style - > width . value . percent /
100 ;
break ; */
case CSS_WIDTH_AUTO :
default :
width = AUTO ;
break ;
}
/* height */
switch ( b - > style - > height . height ) {
case CSS_HEIGHT_LENGTH :
2008-01-29 03:42:15 +03:00
height = min_gadget_size ? css_screen_dpi *
option_font_min_size / 720.0 :
css_len2px ( & b - > style - > height . length ,
b - > style ) ;
2005-07-02 22:17:51 +04:00
break ;
case CSS_HEIGHT_AUTO :
default :
height = AUTO ;
break ;
}
if ( b - > object ) {
if ( width = = AUTO & & height = = AUTO ) {
width = b - > object - > width ;
} else if ( width = = AUTO ) {
if ( b - > object - > height )
width = b - > object - > width *
( float ) height /
b - > object - > height ;
else
width = b - > object - > width ;
}
} else {
/* form control with no object */
if ( width = = AUTO )
width = 0 ;
}
if ( min < width )
min = width ;
max + = width ;
}
/* \todo first line text-indent */
* line_min = min ;
* line_max = max ;
2005-07-03 03:37:41 +04:00
LOG ( ( " line_min %i, line_max %i " , min , max ) ) ;
2005-07-02 22:17:51 +04:00
assert ( b ! = first ) ;
2005-07-22 01:48:41 +04:00
assert ( 0 < = * line_min & & * line_min < = * line_max ) ;
2005-07-02 22:17:51 +04:00
return b ;
}
2004-02-28 20:23:07 +03:00
/**
* Calculate the text - indent length .
*
* \ param style style of block
* \ param width width of containing block
* \ return length of indent
*/
int layout_text_indent ( struct css_style * style , int width )
{
switch ( style - > text_indent . size ) {
case CSS_TEXT_INDENT_LENGTH :
2005-07-02 22:17:51 +04:00
return css_len2px ( & style - > text_indent . value . length ,
style ) ;
2004-02-28 20:23:07 +03:00
case CSS_TEXT_INDENT_PERCENT :
return width * style - > text_indent . value . percent / 100 ;
default :
return 0 ;
}
}
2004-03-26 04:35:35 +03:00
/**
* Layout the contents of a float or inline block .
*
2005-04-14 23:54:24 +04:00
* \ param b float or inline block box
2004-03-26 04:35:35 +03:00
* \ param width available width
2005-04-09 13:47:37 +04:00
* \ param content memory pool for any new boxes
2004-06-03 01:21:13 +04:00
* \ return true on success , false on memory exhaustion
2004-03-26 04:35:35 +03:00
*/
2005-04-09 13:47:37 +04:00
bool layout_float ( struct box * b , int width , struct content * content )
2004-03-26 04:35:35 +03:00
{
2006-11-05 15:58:24 +03:00
assert ( b - > type = = BOX_TABLE | | b - > type = = BOX_BLOCK | |
b - > type = = BOX_INLINE_BLOCK ) ;
2004-03-26 04:35:35 +03:00
layout_float_find_dimensions ( width , b - > style , b ) ;
2004-04-12 04:00:47 +04:00
if ( b - > type = = BOX_TABLE ) {
2005-04-09 13:47:37 +04:00
if ( ! layout_table ( b , width , content ) )
2004-06-03 01:21:13 +04:00
return false ;
2004-04-12 04:00:47 +04:00
if ( b - > margin [ LEFT ] = = AUTO )
b - > margin [ LEFT ] = 0 ;
if ( b - > margin [ RIGHT ] = = AUTO )
b - > margin [ RIGHT ] = 0 ;
2007-03-25 00:03:36 +03:00
if ( b - > margin [ TOP ] = = AUTO )
b - > margin [ TOP ] = 0 ;
if ( b - > margin [ BOTTOM ] = = AUTO )
b - > margin [ BOTTOM ] = 0 ;
2004-04-12 04:00:47 +04:00
} else
2005-04-09 13:47:37 +04:00
return layout_block_context ( b , content ) ;
2004-06-03 01:21:13 +04:00
return true ;
2004-03-26 04:35:35 +03:00
}
2004-02-11 20:15:36 +03:00
/**
* Position a float in the first available space .
*
2005-04-14 23:54:24 +04:00
* \ param c float box to position
2004-02-11 20:15:36 +03:00
* \ param width available width
2005-04-14 23:54:24 +04:00
* \ param cx x coordinate relative to cont to place float right of
* \ param y y coordinate relative to cont to place float below
* \ param cont ancestor box which defines horizontal space , for floats
2004-02-11 20:15:36 +03:00
*/
2002-06-19 19:17:45 +04:00
2004-04-22 02:27:49 +04:00
void place_float_below ( struct box * c , int width , int cx , int y ,
2004-02-11 20:15:36 +03:00
struct box * cont )
2002-06-19 01:24:21 +04:00
{
2004-02-11 20:15:36 +03:00
int x0 , x1 , yy = y ;
2002-06-19 01:24:21 +04:00
struct box * left ;
struct box * right ;
2005-08-07 03:34:30 +04:00
LOG ( ( " c %p, width %i, cx %i, y %i, cont %p " , c , width , cx , y , cont ) ) ;
2002-06-19 01:24:21 +04:00
do {
y = yy ;
2004-04-22 02:27:49 +04:00
x0 = cx ;
x1 = cx + width ;
2002-06-19 01:24:21 +04:00
find_sides ( cont - > float_children , y , y , & x0 , & x1 , & left , & right ) ;
if ( left ! = 0 & & right ! = 0 ) {
2005-07-02 22:17:51 +04:00
yy = ( left - > y + left - > height <
right - > y + right - > height ?
left - > y + left - > height :
right - > y + right - > height ) + 1 ;
2002-06-19 01:24:21 +04:00
} else if ( left = = 0 & & right ! = 0 ) {
yy = right - > y + right - > height + 1 ;
} else if ( left ! = 0 & & right = = 0 ) {
yy = left - > y + left - > height + 1 ;
}
2004-02-11 20:15:36 +03:00
} while ( ! ( ( left = = 0 & & right = = 0 ) | | ( c - > width < x1 - x0 ) ) ) ;
2002-06-19 19:17:45 +04:00
2002-06-29 00:14:04 +04:00
if ( c - > type = = BOX_FLOAT_LEFT ) {
2002-06-19 01:24:21 +04:00
c - > x = x0 ;
} else {
c - > x = x1 - c - > width ;
}
c - > y = y ;
}
2002-05-04 23:57:18 +04:00
/**
2004-05-21 18:26:59 +04:00
* Layout a table .
2004-06-03 01:21:13 +04:00
*
2005-04-14 23:54:24 +04:00
* \ param table table to layout
2004-12-02 00:48:11 +03:00
* \ param available_width width of containing block
2005-04-14 23:54:24 +04:00
* \ param content memory pool for any new boxes
2004-06-03 01:21:13 +04:00
* \ return true on success , false on memory exhaustion
2002-05-04 23:57:18 +04:00
*/
2004-06-03 01:21:13 +04:00
bool layout_table ( struct box * table , int available_width ,
2005-04-09 13:47:37 +04:00
struct content * content )
2002-05-04 23:57:18 +04:00
{
2002-09-18 23:36:28 +04:00
unsigned int columns = table - > columns ; /* total columns */
2003-09-12 22:30:44 +04:00
unsigned int i ;
2004-02-11 20:15:36 +03:00
unsigned int * row_span ;
int * excess_y ;
int table_width , min_width = 0 , max_width = 0 ;
int required_width = 0 ;
2005-04-09 13:47:37 +04:00
int x , remainder = 0 , count = 0 ;
2004-02-11 20:15:36 +03:00
int table_height = 0 ;
int * xs ; /* array of column x positions */
2004-04-12 04:00:47 +04:00
int auto_width ;
2004-05-21 18:26:59 +04:00
int spare_width ;
int relative_sum = 0 ;
2004-12-02 00:48:11 +03:00
int border_spacing_h = 0 , border_spacing_v = 0 ;
2005-01-11 00:35:34 +03:00
int spare_height ;
2002-08-18 20:46:45 +04:00
struct box * c ;
struct box * row ;
struct box * row_group ;
2003-07-07 01:10:12 +04:00
struct box * * row_span_cell ;
2004-06-03 01:21:13 +04:00
struct column * col ;
2004-04-12 04:00:47 +04:00
struct css_style * style = table - > style ;
2002-05-04 23:57:18 +04:00
assert ( table - > type = = BOX_TABLE ) ;
2004-04-12 04:00:47 +04:00
assert ( style ) ;
assert ( table - > children & & table - > children - > children ) ;
assert ( columns ) ;
2002-08-06 00:34:45 +04:00
2004-12-02 00:48:11 +03:00
/* allocate working buffers */
2004-06-03 01:21:13 +04:00
col = malloc ( columns * sizeof col [ 0 ] ) ;
excess_y = malloc ( columns * sizeof excess_y [ 0 ] ) ;
row_span = malloc ( columns * sizeof row_span [ 0 ] ) ;
row_span_cell = malloc ( columns * sizeof row_span_cell [ 0 ] ) ;
xs = malloc ( ( columns + 1 ) * sizeof xs [ 0 ] ) ;
if ( ! col | | ! xs | | ! row_span | | ! excess_y | | ! row_span_cell ) {
free ( col ) ;
free ( excess_y ) ;
free ( row_span ) ;
free ( row_span_cell ) ;
free ( xs ) ;
return false ;
}
2003-09-12 22:30:44 +04:00
memcpy ( col , table - > col , sizeof ( col [ 0 ] ) * columns ) ;
2002-09-18 23:36:28 +04:00
2004-12-02 00:48:11 +03:00
/* find margins, paddings, and borders for table and cells */
2006-06-26 08:52:34 +04:00
layout_find_dimensions ( available_width , style , 0 , 0 , table - > margin ,
2004-04-12 04:00:47 +04:00
table - > padding , table - > border ) ;
2004-12-02 00:48:11 +03:00
for ( row_group = table - > children ; row_group ;
row_group = row_group - > next ) {
for ( row = row_group - > children ; row ; row = row - > next ) {
for ( c = row - > children ; c ; c = c - > next ) {
assert ( c - > style ) ;
layout_find_dimensions ( available_width ,
2006-06-26 08:52:34 +04:00
c - > style , 0 , 0 , 0 ,
2004-12-02 00:48:11 +03:00
c - > padding , c - > border ) ;
2004-12-06 00:42:08 +03:00
if ( c - > style - > overflow = =
CSS_OVERFLOW_SCROLL | |
c - > style - > overflow = =
CSS_OVERFLOW_AUTO ) {
c - > padding [ RIGHT ] + = SCROLLBAR_WIDTH ;
c - > padding [ BOTTOM ] + = SCROLLBAR_WIDTH ;
}
2004-12-02 00:48:11 +03:00
}
}
}
/* border-spacing is used in the separated borders model */
if ( style - > border_collapse = = CSS_BORDER_COLLAPSE_SEPARATE ) {
2005-07-02 22:17:51 +04:00
border_spacing_h = css_len2px ( & style - > border_spacing . horz ,
2004-12-02 00:48:11 +03:00
style ) ;
2005-07-02 22:17:51 +04:00
border_spacing_v = css_len2px ( & style - > border_spacing . vert ,
2004-12-02 00:48:11 +03:00
style ) ;
}
2002-05-04 23:57:18 +04:00
2004-12-02 00:48:11 +03:00
/* find specified table width, or available width if auto-width */
2004-04-12 04:00:47 +04:00
switch ( style - > width . width ) {
2004-12-02 00:48:11 +03:00
case CSS_WIDTH_LENGTH :
2005-07-02 22:17:51 +04:00
table_width = css_len2px ( & style - > width . value . length , style ) ;
2004-12-02 00:48:11 +03:00
auto_width = table_width ;
break ;
case CSS_WIDTH_PERCENT :
2005-03-22 19:29:16 +03:00
table_width = ceil ( available_width *
style - > width . value . percent / 100 ) ;
2004-12-02 00:48:11 +03:00
auto_width = table_width ;
break ;
case CSS_WIDTH_AUTO :
default :
table_width = AUTO ;
auto_width = available_width -
( ( table - > margin [ LEFT ] = = AUTO ? 0 :
table - > margin [ LEFT ] ) +
table - > border [ LEFT ] +
table - > padding [ LEFT ] +
table - > padding [ RIGHT ] +
table - > border [ RIGHT ] +
( table - > margin [ RIGHT ] = = AUTO ? 0 :
2005-04-14 23:54:24 +04:00
table - > margin [ RIGHT ] ) ) ;
2004-12-02 00:48:11 +03:00
break ;
2004-04-12 04:00:47 +04:00
}
2002-08-06 00:34:45 +04:00
2004-12-02 00:48:11 +03:00
/* calculate width required by cells */
2003-09-12 22:30:44 +04:00
for ( i = 0 ; i ! = columns ; i + + ) {
2005-07-24 18:29:32 +04:00
LOG ( ( " table %p, column %u: type %s, width %i, min %i, max %i " ,
table , i ,
( ( const char * [ ] ) { " UNKNOWN " , " FIXED " , " AUTO " ,
" PERCENT " , " RELATIVE " } ) [ col [ i ] . type ] ,
col [ i ] . width , col [ i ] . min , col [ i ] . max ) ) ;
2004-05-28 02:13:20 +04:00
if ( col [ i ] . type = = COLUMN_WIDTH_FIXED ) {
if ( col [ i ] . width < col [ i ] . min )
col [ i ] . width = col [ i ] . max = col [ i ] . min ;
else
col [ i ] . min = col [ i ] . max = col [ i ] . width ;
2003-09-15 00:32:05 +04:00
required_width + = col [ i ] . width ;
2004-05-28 02:13:20 +04:00
} else if ( col [ i ] . type = = COLUMN_WIDTH_PERCENT ) {
2004-04-12 04:00:47 +04:00
int width = col [ i ] . width * auto_width / 100 ;
2004-12-02 00:48:11 +03:00
required_width + = col [ i ] . min < width ? width :
col [ i ] . min ;
2003-09-15 00:32:05 +04:00
} else
required_width + = col [ i ] . min ;
2005-07-24 18:29:32 +04:00
LOG ( ( " required_width %i " , required_width ) ) ;
2003-09-12 22:30:44 +04:00
}
2004-12-02 00:48:11 +03:00
required_width + = ( columns + 1 ) * border_spacing_h ;
2003-09-12 22:30:44 +04:00
2004-04-12 04:00:47 +04:00
LOG ( ( " width %i, min %i, max %i, auto %i, required %i " ,
table_width , table - > min_width , table - > max_width ,
auto_width , required_width ) ) ;
if ( auto_width < required_width ) {
2003-09-12 22:30:44 +04:00
/* table narrower than required width for columns:
* treat percentage widths as maximums */
for ( i = 0 ; i ! = columns ; i + + ) {
2004-05-21 18:26:59 +04:00
if ( col [ i ] . type = = COLUMN_WIDTH_RELATIVE )
continue ;
2003-09-12 22:30:44 +04:00
if ( col [ i ] . type = = COLUMN_WIDTH_PERCENT ) {
2004-04-12 04:00:47 +04:00
col [ i ] . max = auto_width * col [ i ] . width / 100 ;
2003-09-12 22:30:44 +04:00
if ( col [ i ] . max < col [ i ] . min )
col [ i ] . max = col [ i ] . min ;
}
min_width + = col [ i ] . min ;
max_width + = col [ i ] . max ;
}
} else {
/* take percentages exactly */
for ( i = 0 ; i ! = columns ; i + + ) {
2004-05-21 18:26:59 +04:00
if ( col [ i ] . type = = COLUMN_WIDTH_RELATIVE )
continue ;
2003-09-12 22:30:44 +04:00
if ( col [ i ] . type = = COLUMN_WIDTH_PERCENT ) {
2004-04-12 04:00:47 +04:00
int width = auto_width * col [ i ] . width / 100 ;
2003-09-12 22:30:44 +04:00
if ( width < col [ i ] . min )
width = col [ i ] . min ;
col [ i ] . min = col [ i ] . width = col [ i ] . max = width ;
col [ i ] . type = COLUMN_WIDTH_FIXED ;
}
min_width + = col [ i ] . min ;
max_width + = col [ i ] . max ;
2002-09-19 23:54:43 +04:00
}
}
2004-05-21 18:26:59 +04:00
/* allocate relative widths */
spare_width = auto_width ;
for ( i = 0 ; i ! = columns ; i + + ) {
if ( col [ i ] . type = = COLUMN_WIDTH_RELATIVE )
relative_sum + = col [ i ] . width ;
2004-05-28 03:45:26 +04:00
else if ( col [ i ] . type = = COLUMN_WIDTH_FIXED )
2004-05-21 18:26:59 +04:00
spare_width - = col [ i ] . width ;
2004-05-28 03:45:26 +04:00
else
spare_width - = col [ i ] . min ;
2004-05-21 18:26:59 +04:00
}
2004-12-02 00:48:11 +03:00
spare_width - = ( columns + 1 ) * border_spacing_h ;
2004-06-14 11:28:27 +04:00
if ( relative_sum ! = 0 ) {
if ( spare_width < 0 )
spare_width = 0 ;
for ( i = 0 ; i ! = columns ; i + + ) {
if ( col [ i ] . type = = COLUMN_WIDTH_RELATIVE ) {
2005-07-02 22:17:51 +04:00
col [ i ] . min = ceil ( col [ i ] . max =
( float ) spare_width
2004-06-14 11:28:27 +04:00
* ( float ) col [ i ] . width
2005-03-22 19:29:16 +03:00
/ relative_sum ) ;
2004-06-14 11:28:27 +04:00
min_width + = col [ i ] . min ;
max_width + = col [ i ] . max ;
}
2004-05-21 18:26:59 +04:00
}
}
2004-12-02 00:48:11 +03:00
min_width + = ( columns + 1 ) * border_spacing_h ;
max_width + = ( columns + 1 ) * border_spacing_h ;
2004-05-21 18:26:59 +04:00
2004-04-12 04:00:47 +04:00
if ( auto_width < = min_width ) {
2002-09-18 23:36:28 +04:00
/* not enough space: minimise column widths */
2003-09-12 22:30:44 +04:00
for ( i = 0 ; i < columns ; i + + ) {
2003-09-12 02:02:06 +04:00
col [ i ] . width = col [ i ] . min ;
2002-05-04 23:57:18 +04:00
}
2003-09-12 18:37:26 +04:00
table_width = min_width ;
2004-04-12 04:00:47 +04:00
} else if ( max_width < = auto_width ) {
2002-12-28 01:29:45 +03:00
/* more space than maximum width */
2004-04-12 04:00:47 +04:00
if ( table_width = = AUTO ) {
2002-12-28 01:29:45 +03:00
/* for auto-width tables, make columns max width */
2003-09-12 22:30:44 +04:00
for ( i = 0 ; i < columns ; i + + ) {
2003-09-12 02:02:06 +04:00
col [ i ] . width = col [ i ] . max ;
2002-12-28 01:29:45 +03:00
}
table_width = max_width ;
} else {
/* for fixed-width tables, distribute the extra space too */
2003-07-09 00:54:19 +04:00
unsigned int flexible_columns = 0 ;
2003-09-12 22:30:44 +04:00
for ( i = 0 ; i ! = columns ; i + + )
2003-09-12 02:02:06 +04:00
if ( col [ i ] . type ! = COLUMN_WIDTH_FIXED )
2003-07-09 00:54:19 +04:00
flexible_columns + + ;
if ( flexible_columns = = 0 ) {
2004-02-11 20:15:36 +03:00
int extra = ( table_width - max_width ) / columns ;
2005-03-22 19:29:16 +03:00
remainder = ( table_width - max_width ) - ( extra * columns ) ;
for ( i = 0 ; i ! = columns ; i + + ) {
2003-09-12 02:02:06 +04:00
col [ i ] . width = col [ i ] . max + extra ;
2005-03-22 19:29:16 +03:00
count - = remainder ;
if ( count < 0 ) {
col [ i ] . width + + ;
count + = columns ;
}
}
2003-07-09 00:54:19 +04:00
} else {
2004-02-11 20:15:36 +03:00
int extra = ( table_width - max_width ) / flexible_columns ;
2005-03-22 19:29:16 +03:00
remainder = ( table_width - max_width ) - ( extra * flexible_columns ) ;
2003-09-12 22:30:44 +04:00
for ( i = 0 ; i ! = columns ; i + + )
2005-03-22 19:29:16 +03:00
if ( col [ i ] . type ! = COLUMN_WIDTH_FIXED ) {
2003-09-12 02:02:06 +04:00
col [ i ] . width = col [ i ] . max + extra ;
2005-03-22 19:29:16 +03:00
count - = remainder ;
if ( count < 0 ) {
col [ i ] . width + + ;
count + = flexible_columns ;
}
}
2002-12-28 01:29:45 +03:00
}
2002-09-18 23:36:28 +04:00
}
2003-01-04 01:19:39 +03:00
} else {
/* space between min and max: fill it exactly */
2004-04-12 04:00:47 +04:00
float scale = ( float ) ( auto_width - min_width ) /
2003-09-12 18:37:26 +04:00
( float ) ( max_width - min_width ) ;
2004-04-14 03:20:23 +04:00
/* fprintf(stderr, "filling, scale %f\n", scale); */
2003-09-12 22:30:44 +04:00
for ( i = 0 ; i < columns ; i + + ) {
2004-04-14 03:20:23 +04:00
col [ i ] . width = col [ i ] . min + ( int ) ( 0.5 +
( col [ i ] . max - col [ i ] . min ) * scale ) ;
2002-09-18 23:36:28 +04:00
}
2004-04-12 04:00:47 +04:00
table_width = auto_width ;
2003-01-04 01:19:39 +03:00
}
2002-06-19 19:17:45 +04:00
2004-12-02 00:48:11 +03:00
xs [ 0 ] = x = border_spacing_h ;
2003-07-07 01:10:12 +04:00
for ( i = 0 ; i ! = columns ; i + + ) {
2004-12-02 00:48:11 +03:00
x + = col [ i ] . width + border_spacing_h ;
2002-09-18 23:36:28 +04:00
xs [ i + 1 ] = x ;
2003-07-07 01:10:12 +04:00
row_span [ i ] = 0 ;
excess_y [ i ] = 0 ;
row_span_cell [ i ] = 0 ;
2002-05-04 23:57:18 +04:00
}
2003-07-08 00:30:51 +04:00
2002-05-04 23:57:18 +04:00
/* position cells */
2004-12-02 00:48:11 +03:00
table_height = border_spacing_v ;
for ( row_group = table - > children ; row_group ;
row_group = row_group - > next ) {
2004-02-11 20:15:36 +03:00
int row_group_height = 0 ;
2004-12-02 00:48:11 +03:00
for ( row = row_group - > children ; row ; row = row - > next ) {
2007-10-11 00:33:15 +04:00
int row_height = 0 ;
2004-12-02 00:48:11 +03:00
for ( c = row - > children ; c ; c = c - > next ) {
assert ( c - > style ) ;
c - > width = xs [ c - > start_column + c - > columns ] -
xs [ c - > start_column ] -
border_spacing_h -
c - > border [ LEFT ] -
c - > padding [ LEFT ] -
c - > padding [ RIGHT ] -
c - > border [ RIGHT ] ;
2002-08-18 20:46:45 +04:00
c - > float_children = 0 ;
2004-04-12 21:32:45 +04:00
c - > height = AUTO ;
2005-04-09 13:47:37 +04:00
if ( ! layout_block_context ( c , content ) ) {
2004-06-03 01:21:13 +04:00
free ( col ) ;
free ( excess_y ) ;
free ( row_span ) ;
free ( row_span_cell ) ;
free ( xs ) ;
return false ;
}
2005-01-11 22:39:49 +03:00
/* warning: c->descendant_y0 and c->descendant_y1 used as temporary
2005-01-11 17:16:40 +03:00
* storage until after vertical alignment is complete */
c - > descendant_y0 = c - > height ;
2005-01-11 00:35:34 +03:00
c - > descendant_y1 = c - > padding [ BOTTOM ] ;
2004-12-02 00:48:11 +03:00
if ( c - > style - > height . height = =
CSS_HEIGHT_LENGTH ) {
/* some sites use height="1" or similar
* to attempt to make cells as small as
* possible , so treat it as a minimum */
int h = ( int ) css_len2px ( & c - > style - >
height . length , c - > style ) ;
2004-04-12 21:32:45 +04:00
if ( c - > height < h )
2003-03-09 00:25:56 +03:00
c - > height = h ;
}
2004-12-02 00:48:11 +03:00
c - > x = xs [ c - > start_column ] + c - > border [ LEFT ] ;
c - > y = c - > border [ TOP ] ;
2003-07-07 01:10:12 +04:00
for ( i = 0 ; i ! = c - > columns ; i + + ) {
row_span [ c - > start_column + i ] = c - > rows ;
2004-12-02 00:48:11 +03:00
excess_y [ c - > start_column + i ] =
c - > border [ TOP ] +
c - > padding [ TOP ] +
c - > height +
c - > padding [ BOTTOM ] +
c - > border [ BOTTOM ] ;
2003-07-07 01:10:12 +04:00
row_span_cell [ c - > start_column + i ] = 0 ;
}
row_span_cell [ c - > start_column ] = c ;
2005-01-11 00:35:34 +03:00
c - > padding [ BOTTOM ] = - border_spacing_v -
2004-12-02 00:48:11 +03:00
c - > border [ TOP ] -
c - > padding [ TOP ] -
2005-01-11 00:35:34 +03:00
c - > height -
2004-12-02 00:48:11 +03:00
c - > border [ BOTTOM ] ;
2003-07-07 01:10:12 +04:00
}
for ( i = 0 ; i ! = columns ; i + + )
2003-07-08 22:49:14 +04:00
if ( row_span [ i ] ! = 0 )
row_span [ i ] - - ;
else
row_span_cell [ i ] = 0 ;
2003-08-30 03:15:54 +04:00
if ( row - > next | | row_group - > next ) {
2004-12-02 00:48:11 +03:00
/* row height is greatest excess of a cell
* which ends in this row */
2003-08-30 03:15:54 +04:00
for ( i = 0 ; i ! = columns ; i + + )
2004-12-02 00:48:11 +03:00
if ( row_span [ i ] = = 0 & & row_height <
excess_y [ i ] )
2003-08-30 03:15:54 +04:00
row_height = excess_y [ i ] ;
} else {
/* except in the last row */
for ( i = 0 ; i ! = columns ; i + + )
if ( row_height < excess_y [ i ] )
row_height = excess_y [ i ] ;
}
2003-07-07 01:10:12 +04:00
for ( i = 0 ; i ! = columns ; i + + ) {
2003-07-08 00:30:51 +04:00
if ( row_height < excess_y [ i ] )
excess_y [ i ] - = row_height ;
else
excess_y [ i ] = 0 ;
2003-07-07 01:10:12 +04:00
if ( row_span_cell [ i ] ! = 0 )
2005-01-13 23:29:24 +03:00
row_span_cell [ i ] - > padding [ BOTTOM ] + =
row_height +
2004-12-02 00:48:11 +03:00
border_spacing_v ;
2002-05-04 23:57:18 +04:00
}
2003-07-07 01:10:12 +04:00
2002-08-18 20:46:45 +04:00
row - > x = 0 ;
row - > y = row_group_height ;
row - > width = table_width ;
row - > height = row_height ;
2004-12-02 00:48:11 +03:00
row_group_height + = row_height + border_spacing_v ;
2002-05-04 23:57:18 +04:00
}
2002-08-18 20:46:45 +04:00
row_group - > x = 0 ;
row_group - > y = table_height ;
row_group - > width = table_width ;
row_group - > height = row_group_height ;
table_height + = row_group_height ;
2002-05-04 23:57:18 +04:00
}
2005-01-11 00:35:34 +03:00
/* perform vertical alignment */
for ( row_group = table - > children ; row_group ; row_group = row_group - > next ) {
for ( row = row_group - > children ; row ; row = row - > next ) {
for ( c = row - > children ; c ; c = c - > next ) {
2005-01-11 17:16:40 +03:00
/* unextended bottom padding is in c->descendant_y1, and unextended
* cell height is in c - > descendant_y0 */
2005-04-14 23:54:24 +04:00
spare_height = ( c - > padding [ BOTTOM ] - c - > descendant_y1 ) +
( c - > height - c - > descendant_y0 ) ;
2005-01-11 00:35:34 +03:00
switch ( c - > style - > vertical_align . type ) {
case CSS_VERTICAL_ALIGN_SUB :
case CSS_VERTICAL_ALIGN_SUPER :
case CSS_VERTICAL_ALIGN_TEXT_TOP :
case CSS_VERTICAL_ALIGN_TEXT_BOTTOM :
case CSS_VERTICAL_ALIGN_LENGTH :
case CSS_VERTICAL_ALIGN_PERCENT :
case CSS_VERTICAL_ALIGN_BASELINE :
/* todo: baseline alignment, for now just use ALIGN_TOP */
case CSS_VERTICAL_ALIGN_TOP :
break ;
case CSS_VERTICAL_ALIGN_MIDDLE :
c - > padding [ TOP ] + = spare_height / 2 ;
c - > padding [ BOTTOM ] - = spare_height / 2 ;
layout_move_children ( c , 0 , spare_height / 2 ) ;
break ;
case CSS_VERTICAL_ALIGN_BOTTOM :
c - > padding [ TOP ] + = spare_height ;
c - > padding [ BOTTOM ] - = spare_height ;
layout_move_children ( c , 0 , spare_height ) ;
break ;
2005-01-11 22:39:49 +03:00
case CSS_VERTICAL_ALIGN_NOT_SET :
2005-01-11 00:35:34 +03:00
case CSS_VERTICAL_ALIGN_INHERIT :
assert ( 0 ) ;
break ;
}
}
}
}
2004-06-03 01:21:13 +04:00
free ( col ) ;
free ( excess_y ) ;
free ( row_span ) ;
free ( row_span_cell ) ;
free ( xs ) ;
2002-06-19 19:17:45 +04:00
2002-05-04 23:57:18 +04:00
table - > width = table_width ;
2002-08-18 20:46:45 +04:00
table - > height = table_height ;
2004-06-03 01:21:13 +04:00
return true ;
2002-05-04 23:57:18 +04:00
}
2002-09-18 23:36:28 +04:00
2005-01-11 00:35:34 +03:00
/**
2005-07-02 22:17:51 +04:00
* Calculate minimum and maximum width of a table .
2004-02-23 01:22:50 +03:00
*
2005-07-02 22:17:51 +04:00
* \ param table box of type TABLE
2005-07-22 01:48:41 +04:00
* \ post table - > min_width and table - > max_width filled in ,
* 0 < = table - > min_width < = table - > max_width
2002-09-18 23:36:28 +04:00
*/
2005-07-02 22:17:51 +04:00
void layout_minmax_table ( struct box * table )
2002-09-18 23:36:28 +04:00
{
2003-09-12 02:02:06 +04:00
unsigned int i , j ;
2005-07-02 22:17:51 +04:00
int border_spacing_h = 0 ;
int table_min = 0 , table_max = 0 ;
int extra_fixed = 0 ;
float extra_frac = 0 ;
struct column * col = table - > col ;
2002-09-18 23:36:28 +04:00
struct box * row_group , * row , * cell ;
2003-08-30 23:20:19 +04:00
/* check if the widths have already been calculated */
2004-02-11 20:15:36 +03:00
if ( table - > max_width ! = UNKNOWN_MAX_WIDTH )
2005-07-02 22:17:51 +04:00
return ;
2003-08-30 23:20:19 +04:00
2005-08-07 02:29:30 +04:00
/* start with 0 except for fixed-width columns */
for ( i = 0 ; i ! = table - > columns ; i + + ) {
if ( col [ i ] . type = = COLUMN_WIDTH_FIXED )
col [ i ] . min = col [ i ] . max = col [ i ] . width ;
else
col [ i ] . min = col [ i ] . max = 0 ;
}
2003-09-09 23:25:28 +04:00
2005-07-02 22:17:51 +04:00
/* border-spacing is used in the separated borders model */
if ( table - > style - > border_collapse = = CSS_BORDER_COLLAPSE_SEPARATE )
border_spacing_h = css_len2px ( & table - > style - >
border_spacing . horz , table - > style ) ;
2005-04-14 23:54:24 +04:00
2003-09-12 02:02:06 +04:00
/* 1st pass: consider cells with colspan 1 only */
2005-07-02 22:17:51 +04:00
for ( row_group = table - > children ; row_group ; row_group = row_group - > next )
for ( row = row_group - > children ; row ; row = row - > next )
for ( cell = row - > children ; cell ; cell = cell - > next ) {
assert ( cell - > type = = BOX_TABLE_CELL ) ;
assert ( cell - > style ) ;
2002-12-27 21:58:03 +03:00
2005-07-02 22:17:51 +04:00
if ( cell - > columns ! = 1 )
continue ;
2003-09-12 02:02:06 +04:00
2005-07-02 22:17:51 +04:00
layout_minmax_block ( cell ) ;
i = cell - > start_column ;
2004-05-28 02:13:20 +04:00
2005-07-02 22:17:51 +04:00
/* update column min, max widths using cell widths */
if ( col [ i ] . min < cell - > min_width )
col [ i ] . min = cell - > min_width ;
if ( col [ i ] . max < cell - > max_width )
col [ i ] . max = cell - > max_width ;
2003-09-12 02:02:06 +04:00
}
2003-04-10 01:57:09 +04:00
2003-09-12 02:02:06 +04:00
/* 2nd pass: cells which span multiple columns */
2005-07-02 22:17:51 +04:00
for ( row_group = table - > children ; row_group ; row_group = row_group - > next )
for ( row = row_group - > children ; row ; row = row - > next )
for ( cell = row - > children ; cell ; cell = cell - > next ) {
unsigned int flexible_columns = 0 ;
int min = 0 , max = 0 , fixed_width = 0 , extra ;
2003-09-12 02:02:06 +04:00
2005-07-02 22:17:51 +04:00
if ( cell - > columns = = 1 )
continue ;
2003-09-12 02:02:06 +04:00
2005-07-02 22:17:51 +04:00
layout_minmax_block ( cell ) ;
i = cell - > start_column ;
2003-09-12 02:02:06 +04:00
2005-07-02 22:17:51 +04:00
/* find min width so far of spanned columns, and count
* number of non - fixed spanned columns and total fixed width */
for ( j = 0 ; j ! = cell - > columns ; j + + ) {
min + = col [ i + j ] . min ;
if ( col [ i + j ] . type = = COLUMN_WIDTH_FIXED )
fixed_width + = col [ i + j ] . width ;
else
flexible_columns + + ;
}
min + = ( cell - > columns - 1 ) * border_spacing_h ;
2003-04-10 01:57:09 +04:00
2005-07-02 22:17:51 +04:00
/* distribute extra min to spanned columns */
if ( min < cell - > min_width ) {
if ( flexible_columns = = 0 ) {
extra = 1 + ( cell - > min_width - min ) /
cell - > columns ;
for ( j = 0 ; j ! = cell - > columns ; j + + ) {
col [ i + j ] . min + = extra ;
if ( col [ i + j ] . max < col [ i + j ] . min )
col [ i + j ] . max = col [ i + j ] . min ;
2003-09-12 02:02:06 +04:00
}
2005-07-02 22:17:51 +04:00
} else {
extra = 1 + ( cell - > min_width - min ) /
flexible_columns ;
for ( j = 0 ; j ! = cell - > columns ; j + + ) {
if ( col [ i + j ] . type ! =
COLUMN_WIDTH_FIXED ) {
col [ i + j ] . min + = extra ;
if ( col [ i + j ] . max <
col [ i + j ] . min )
col [ i + j ] . max =
col [ i + j ] . min ;
2002-12-27 21:58:03 +03:00
}
2003-01-04 01:19:39 +03:00
}
2002-09-18 23:36:28 +04:00
}
}
2005-07-02 22:17:51 +04:00
/* find max width so far of spanned columns */
for ( j = 0 ; j ! = cell - > columns ; j + + )
max + = col [ i + j ] . max ;
max + = ( cell - > columns - 1 ) * border_spacing_h ;
/* distribute extra max to spanned columns */
if ( max < cell - > max_width & & flexible_columns ) {
extra = 1 + ( cell - > max_width - max ) / flexible_columns ;
for ( j = 0 ; j ! = cell - > columns ; j + + )
if ( col [ i + j ] . type ! = COLUMN_WIDTH_FIXED )
col [ i + j ] . max + = extra ;
}
2002-09-18 23:36:28 +04:00
}
2003-01-04 01:19:39 +03:00
2005-07-02 22:17:51 +04:00
for ( i = 0 ; i ! = table - > columns ; i + + ) {
if ( col [ i ] . max < col [ i ] . min ) {
2007-08-20 06:39:49 +04:00
box_dump ( stderr , table , 0 ) ;
2005-07-02 22:17:51 +04:00
assert ( 0 ) ;
}
table_min + = col [ i ] . min ;
table_max + = col [ i ] . max ;
}
2004-06-03 01:21:13 +04:00
2005-07-21 02:25:56 +04:00
/* fixed width takes priority, unless it is too narrow */
if ( table - > style - > width . width = = CSS_WIDTH_LENGTH ) {
int width = css_len2px ( & table - > style - > width . value . length ,
table - > style ) ;
if ( table_min < width )
table_min = width ;
if ( table_max < width )
table_max = width ;
}
2005-07-02 22:17:51 +04:00
/* add margins, border, padding to min, max widths */
2005-07-03 03:37:41 +04:00
calculate_mbp_width ( table - > style , LEFT , & extra_fixed , & extra_frac ) ;
calculate_mbp_width ( table - > style , RIGHT , & extra_fixed , & extra_frac ) ;
2007-03-25 20:20:10 +04:00
if ( extra_fixed < 0 )
extra_fixed = 0 ;
if ( extra_frac < 0 )
extra_frac = 0 ;
2005-07-02 22:17:51 +04:00
if ( 1.0 < = extra_frac )
extra_frac = 0.9 ;
table - > min_width = ( table_min + extra_fixed ) / ( 1.0 - extra_frac ) ;
table - > max_width = ( table_max + extra_fixed ) / ( 1.0 - extra_frac ) ;
table - > min_width + = ( table - > columns + 1 ) * border_spacing_h ;
table - > max_width + = ( table - > columns + 1 ) * border_spacing_h ;
2005-07-22 01:48:41 +04:00
assert ( 0 < = table - > min_width & & table - > min_width < = table - > max_width ) ;
2002-09-18 23:36:28 +04:00
}
2004-08-01 17:08:19 +04:00
2005-04-14 23:54:24 +04:00
/**
2005-07-02 22:17:51 +04:00
* Moves the children of a box by a specified amount
*
* \ param box top of tree of boxes
* \ param x the amount to move children by horizontally
* \ param y the amount to move children by vertically
2005-04-14 23:54:24 +04:00
*/
2005-07-02 22:17:51 +04:00
void layout_move_children ( struct box * box , int x , int y )
2005-04-14 23:54:24 +04:00
{
2005-07-02 22:17:51 +04:00
assert ( box ) ;
2005-04-14 23:54:24 +04:00
2005-07-02 22:17:51 +04:00
for ( box = box - > children ; box ; box = box - > next ) {
box - > x + = x ;
box - > y + = y ;
2005-04-14 23:54:24 +04:00
}
}
/**
2005-07-03 03:37:41 +04:00
* Determine width of margin , borders , and padding on one side of a box .
2005-07-02 22:17:51 +04:00
*
* \ param style style to measure
2005-07-03 03:37:41 +04:00
* \ param size side of box to measure
* \ param fixed increased by sum of fixed margin , border , and padding
* \ param frac increased by sum of fractional margin and padding
2005-04-14 23:54:24 +04:00
*/
2005-07-03 03:37:41 +04:00
void calculate_mbp_width ( struct css_style * style , unsigned int side ,
int * fixed , float * frac )
2005-04-14 23:54:24 +04:00
{
2005-07-02 22:17:51 +04:00
assert ( style ) ;
2005-04-14 23:54:24 +04:00
2005-07-03 03:37:41 +04:00
/* margin */
if ( style - > margin [ side ] . margin = = CSS_MARGIN_LENGTH )
* fixed + = css_len2px ( & style - > margin [ side ] . value . length , style ) ;
else if ( style - > margin [ side ] . margin = = CSS_MARGIN_PERCENT )
* frac + = style - > margin [ side ] . value . percent * 0.01 ;
/* border */
if ( style - > border [ side ] . style ! = CSS_BORDER_STYLE_NONE )
* fixed + = css_len2px ( & style - > border [ side ] . width . value , style ) ;
/* padding */
if ( style - > padding [ side ] . padding = = CSS_PADDING_LENGTH )
* fixed + = css_len2px ( & style - > padding [ side ] . value . length , style ) ;
else if ( style - > padding [ side ] . padding = = CSS_PADDING_PERCENT )
* frac + = style - > padding [ side ] . value . percent * 0.01 ;
2005-04-14 23:54:24 +04:00
}
2006-11-05 15:58:24 +03:00
/**
* Layout list markers .
*/
void layout_lists ( struct box * box )
{
struct box * child ;
struct box * marker ;
for ( child = box - > children ; child ; child = child - > next ) {
if ( child - > list_marker ) {
marker = child - > list_marker ;
2006-11-08 00:49:03 +03:00
if ( marker - > object ) {
marker - > width = marker - > object - > width ;
marker - > x = - marker - > width ;
marker - > height = marker - > object - > height ;
marker - > y = ( line_height ( marker - > style ) -
marker - > height ) / 2 ;
2006-12-27 00:51:08 +03:00
} else if ( marker - > text ) {
2006-11-08 00:49:03 +03:00
if ( marker - > width = = UNKNOWN_WIDTH )
nsfont_width ( marker - > style ,
marker - > text ,
marker - > length ,
& marker - > width ) ;
marker - > x = - marker - > width ;
marker - > y = 0 ;
marker - > height = line_height ( marker - > style ) ;
2006-12-27 00:51:08 +03:00
} else {
marker - > x = 0 ;
marker - > y = 0 ;
marker - > width = 0 ;
marker - > height = 0 ;
2006-11-08 00:49:03 +03:00
}
2006-11-10 17:53:46 +03:00
marker - > x - = 4 ; // Gap between marker and content
2006-11-05 15:58:24 +03:00
}
layout_lists ( child ) ;
}
}
2006-06-26 08:52:34 +04:00
/**
* Adjust positions of relatively positioned boxes .
*/
void layout_position_relative ( struct box * root )
{
struct box * box ;
/**\todo ensure containing box is large enough after moving boxes */
2006-10-11 02:00:10 +04:00
assert ( root ) ;
2006-06-26 08:52:34 +04:00
2006-06-27 02:24:42 +04:00
/* Normal children */
2006-06-26 08:52:34 +04:00
for ( box = root - > children ; box ; box = box - > next ) {
int x , y ;
if ( box - > type = = BOX_TEXT )
continue ;
/* recurse first */
layout_position_relative ( box ) ;
2006-06-27 02:24:42 +04:00
/* Ignore things we're not interested in. */
if ( ! box - > style | | ( box - > style & &
box - > style - > position ! = CSS_POSITION_RELATIVE ) )
continue ;
layout_compute_relative_offset ( box , & x , & y ) ;
box - > x + = x ;
box - > y + = y ;
/* Handle INLINEs - their "children" are in fact
* the sibling boxes between the INLINE and
* INLINE_END boxes */
if ( box - > type = = BOX_INLINE & & box - > inline_end ) {
struct box * b ;
for ( b = box - > next ; b & & b ! = box - > inline_end ;
b = b - > next ) {
b - > x + = x ;
b - > y + = y ;
}
}
}
2006-06-26 08:52:34 +04:00
}
/**
* Compute a box ' s relative offset as per CSS 2.1 9.4 .3
*/
void layout_compute_relative_offset ( struct box * box , int * x , int * y )
{
int left , right , top , bottom ;
assert ( box & & box - > parent & & box - > style & &
box - > style - > position = = CSS_POSITION_RELATIVE ) ;
layout_compute_offsets ( box , box - > parent , & top , & right , & bottom , & left ) ;
2006-06-26 17:22:43 +04:00
2006-06-26 08:52:34 +04:00
if ( left = = AUTO & & right = = AUTO )
left = right = 0 ;
else if ( left = = AUTO )
/* left is auto => computed = -right */
left = - right ;
else if ( right = = AUTO )
/* right is auto => computed = -left */
right = - left ;
else {
/* over constrained => examine direction property
* of containing block */
if ( box - > parent - > style ) {
if ( box - > parent - > style - > direction = =
CSS_DIRECTION_LTR )
/* left wins */
right = - left ;
else if ( box - > parent - > style - > direction = =
CSS_DIRECTION_RTL )
/* right wins */
left = - right ;
}
else {
/* no parent style, so assume LTR */
right = - left ;
}
}
assert ( left = = - right ) ;
if ( top = = AUTO & & bottom = = AUTO )
top = bottom = 0 ;
else if ( top = = AUTO )
top = - bottom ;
else if ( bottom = = AUTO )
bottom = - top ;
else
bottom = - top ;
LOG ( ( " left %i, right %i, top %i, bottom %i " , left , right , top , bottom ) ) ;
* x = left ;
* y = top ;
}
/**
2006-11-04 22:17:11 +03:00
* Recursively layout and position absolutely positioned boxes .
2006-06-26 08:52:34 +04:00
*
2006-11-04 22:17:11 +03:00
* \ param box tree of boxes to layout
* \ param containing_block current containing block
* \ param cx position of box relative to containing_block
* \ param cy position of box relative to containing_block
* \ param content memory pool for any new boxes
2006-06-26 08:52:34 +04:00
* \ return true on success , false on memory exhaustion
*/
2006-10-11 02:00:10 +04:00
bool layout_position_absolute ( struct box * box ,
struct box * containing_block ,
int cx , int cy ,
2006-06-26 08:52:34 +04:00
struct content * content )
{
2006-10-11 02:00:10 +04:00
struct box * c ;
2006-06-26 08:52:34 +04:00
2006-10-11 02:00:10 +04:00
for ( c = box - > children ; c ; c = c - > next ) {
2006-11-04 22:17:11 +03:00
if ( ( c - > type = = BOX_BLOCK | | c - > type = = BOX_TABLE | |
c - > type = = BOX_INLINE_BLOCK ) & &
2006-10-11 02:00:10 +04:00
( c - > style - > position = = CSS_POSITION_ABSOLUTE | |
c - > style - > position = = CSS_POSITION_FIXED ) ) {
if ( ! layout_absolute ( c , containing_block ,
cx , cy , content ) )
return false ;
if ( ! layout_position_absolute ( c , c , 0 , 0 , content ) )
2006-10-09 02:46:25 +04:00
return false ;
2006-10-11 02:00:10 +04:00
} else if ( c - > style & &
c - > style - > position = = CSS_POSITION_RELATIVE ) {
if ( ! layout_position_absolute ( c , c , 0 , 0 , content ) )
return false ;
} else {
if ( ! layout_position_absolute ( c , containing_block ,
cx + c - > x , cy + c - > y , content ) )
2006-10-09 02:46:25 +04:00
return false ;
}
}
2006-06-26 08:52:34 +04:00
return true ;
}
/**
* Layout and position an absolutely positioned box .
*
2006-11-04 22:17:11 +03:00
* \ param box absolute box to layout and position
* \ param containing_block containing block
* \ param cx position of box relative to containing_block
* \ param cy position of box relative to containing_block
* \ param content memory pool for any new boxes
2006-06-26 08:52:34 +04:00
* \ return true on success , false on memory exhaustion
*/
2006-10-11 02:00:10 +04:00
bool layout_absolute ( struct box * box , struct box * containing_block ,
int cx , int cy ,
struct content * content )
2006-06-26 08:52:34 +04:00
{
2006-10-09 02:46:25 +04:00
int static_left , static_top ; /* static position */
2006-06-26 08:52:34 +04:00
int top , right , bottom , left ;
int width , height ;
int * margin = box - > margin ;
int * padding = box - > padding ;
int * border = box - > border ;
2006-06-29 13:55:31 +04:00
int available_width = containing_block - > width ;
2006-06-26 08:52:34 +04:00
int space ;
2006-11-04 22:17:11 +03:00
assert ( box - > type = = BOX_BLOCK | | box - > type = = BOX_TABLE | |
box - > type = = BOX_INLINE_BLOCK ) ;
2006-06-26 08:52:34 +04:00
2006-10-09 02:46:25 +04:00
/* The static position is where the box would be if it was not
* absolutely positioned . The x and y are filled in by
* layout_block_context ( ) . */
static_left = cx + box - > x ;
static_top = cy + box - > y ;
2006-06-29 19:53:17 +04:00
if ( containing_block - > type = = BOX_BLOCK | |
containing_block - > type = = BOX_INLINE_BLOCK | |
containing_block - > type = = BOX_TABLE_CELL ) {
/* Block level container => temporarily increase containing
* block dimensions to include padding ( we restore this
* again at the end ) */
containing_block - > width + = containing_block - > padding [ LEFT ] +
containing_block - > padding [ RIGHT ] ;
containing_block - > height + = containing_block - > padding [ TOP ] +
containing_block - > padding [ BOTTOM ] ;
} else {
/** \todo inline containers */
}
2006-06-26 08:52:34 +04:00
layout_compute_offsets ( box , containing_block ,
& top , & right , & bottom , & left ) ;
2006-06-29 19:53:17 +04:00
layout_find_dimensions ( available_width , box - > style ,
2006-06-26 08:52:34 +04:00
& width , & height , margin , padding , border ) ;
/* 10.3.7 */
LOG ( ( " %i + %i + %i + %i + %i + %i + %i + %i + %i = %i " ,
left , margin [ LEFT ] , border [ LEFT ] , padding [ LEFT ] , width ,
padding [ RIGHT ] , border [ RIGHT ] , margin [ RIGHT ] , right ,
containing_block - > width ) ) ;
if ( left = = AUTO & & width = = AUTO & & right = = AUTO ) {
if ( margin [ LEFT ] = = AUTO )
margin [ LEFT ] = 0 ;
if ( margin [ RIGHT ] = = AUTO )
margin [ RIGHT ] = 0 ;
2006-10-09 02:46:25 +04:00
left = static_left ;
2006-06-29 13:55:31 +04:00
2006-06-26 08:52:34 +04:00
width = min ( max ( box - > min_width , available_width ) , box - > max_width ) ;
2006-06-29 13:55:31 +04:00
width - = box - > margin [ LEFT ] + box - > border [ LEFT ] +
box - > padding [ LEFT ] + box - > padding [ RIGHT ] +
box - > border [ RIGHT ] + box - > margin [ RIGHT ] ;
2006-06-29 13:37:18 +04:00
2006-06-26 08:52:34 +04:00
right = containing_block - > width -
left -
margin [ LEFT ] - border [ LEFT ] - padding [ LEFT ] -
width -
padding [ RIGHT ] - border [ RIGHT ] - margin [ RIGHT ] ;
} else if ( left ! = AUTO & & width ! = AUTO & & right ! = AUTO ) {
if ( margin [ LEFT ] = = AUTO & & margin [ RIGHT ] = = AUTO ) {
space = containing_block - > width -
left -
border [ LEFT ] - padding [ LEFT ] -
width -
padding [ RIGHT ] - border [ RIGHT ] -
right ;
if ( space < 0 ) {
margin [ LEFT ] = 0 ;
margin [ RIGHT ] = space ;
} else {
margin [ LEFT ] = margin [ RIGHT ] = space / 2 ;
}
} else if ( margin [ LEFT ] = = AUTO ) {
margin [ LEFT ] = containing_block - > width -
left -
border [ LEFT ] - padding [ LEFT ] -
width -
padding [ RIGHT ] - border [ RIGHT ] - margin [ RIGHT ] -
right ;
} else if ( margin [ RIGHT ] = = AUTO ) {
margin [ RIGHT ] = containing_block - > width -
left -
2006-06-26 17:22:43 +04:00
margin [ LEFT ] - border [ LEFT ] - padding [ LEFT ] -
2006-06-26 08:52:34 +04:00
width -
2006-06-26 17:22:43 +04:00
padding [ RIGHT ] - border [ RIGHT ] -
2006-06-26 08:52:34 +04:00
right ;
} else {
right = containing_block - > width -
left -
margin [ LEFT ] - border [ LEFT ] - padding [ LEFT ] -
width -
padding [ RIGHT ] - border [ RIGHT ] - margin [ RIGHT ] ;
}
} else {
if ( margin [ LEFT ] = = AUTO )
margin [ LEFT ] = 0 ;
if ( margin [ RIGHT ] = = AUTO )
margin [ RIGHT ] = 0 ;
2006-06-26 17:22:43 +04:00
2006-06-26 08:52:34 +04:00
if ( left = = AUTO & & width = = AUTO & & right ! = AUTO ) {
2006-06-26 17:22:43 +04:00
available_width - = right ;
2006-06-26 08:52:34 +04:00
width = min ( max ( box - > min_width , available_width ) , box - > max_width ) ;
2006-06-29 13:37:18 +04:00
width - = box - > margin [ LEFT ] + box - > border [ LEFT ] +
box - > padding [ LEFT ] + box - > padding [ RIGHT ] +
box - > border [ RIGHT ] + box - > margin [ RIGHT ] ;
2006-06-26 08:52:34 +04:00
left = containing_block - > width -
margin [ LEFT ] - border [ LEFT ] - padding [ LEFT ] -
width -
padding [ RIGHT ] - border [ RIGHT ] - margin [ RIGHT ] -
right ;
} else if ( left = = AUTO & & width ! = AUTO & & right = = AUTO ) {
2006-10-09 02:46:25 +04:00
left = static_left ;
2006-06-26 08:52:34 +04:00
right = containing_block - > width -
left -
margin [ LEFT ] - border [ LEFT ] - padding [ LEFT ] -
width -
padding [ RIGHT ] - border [ RIGHT ] - margin [ RIGHT ] ;
} else if ( left ! = AUTO & & width = = AUTO & & right = = AUTO ) {
2006-06-26 17:22:43 +04:00
available_width - = left ;
2006-06-26 08:52:34 +04:00
width = min ( max ( box - > min_width , available_width ) , box - > max_width ) ;
2006-06-29 13:37:18 +04:00
width - = box - > margin [ LEFT ] + box - > border [ LEFT ] +
box - > padding [ LEFT ] + box - > padding [ RIGHT ] +
box - > border [ RIGHT ] + box - > margin [ RIGHT ] ;
2006-06-26 08:52:34 +04:00
right = containing_block - > width -
left -
margin [ LEFT ] - border [ LEFT ] - padding [ LEFT ] -
width -
padding [ RIGHT ] - border [ RIGHT ] - margin [ RIGHT ] ;
} else if ( left = = AUTO & & width ! = AUTO & & right ! = AUTO ) {
left = containing_block - > width -
margin [ LEFT ] - border [ LEFT ] - padding [ LEFT ] -
width -
padding [ RIGHT ] - border [ RIGHT ] - margin [ RIGHT ] -
right ;
} else if ( left ! = AUTO & & width = = AUTO & & right ! = AUTO ) {
width = containing_block - > width -
left -
margin [ LEFT ] - border [ LEFT ] - padding [ LEFT ] -
padding [ RIGHT ] - border [ RIGHT ] - margin [ RIGHT ] -
right ;
} else if ( left ! = AUTO & & width ! = AUTO & & right = = AUTO ) {
right = containing_block - > width -
left -
margin [ LEFT ] - border [ LEFT ] - padding [ LEFT ] -
width -
padding [ RIGHT ] - border [ RIGHT ] - margin [ RIGHT ] ;
}
}
LOG ( ( " %i + %i + %i + %i + %i + %i + %i + %i + %i = %i " ,
left , margin [ LEFT ] , border [ LEFT ] , padding [ LEFT ] , width ,
padding [ RIGHT ] , border [ RIGHT ] , margin [ RIGHT ] , right ,
containing_block - > width ) ) ;
2006-10-09 02:46:25 +04:00
box - > x = left + margin [ LEFT ] + border [ LEFT ] - cx ;
2006-06-29 15:55:21 +04:00
if ( containing_block - > type = = BOX_BLOCK | |
containing_block - > type = = BOX_INLINE_BLOCK | |
containing_block - > type = = BOX_TABLE_CELL ) {
2006-06-29 19:53:17 +04:00
/* Block-level ancestor => reset container's width */
containing_block - > width - = containing_block - > padding [ LEFT ] +
containing_block - > padding [ RIGHT ] ;
2006-06-29 15:55:21 +04:00
} else {
/** \todo inline ancestors */
}
2006-06-26 08:52:34 +04:00
box - > width = width ;
box - > height = height ;
2006-06-26 17:22:43 +04:00
2006-11-04 22:17:11 +03:00
if ( box - > type = = BOX_BLOCK | | box - > type = = BOX_INLINE_BLOCK | |
box - > object ) {
2006-06-26 08:52:34 +04:00
if ( ! layout_block_context ( box , content ) )
return false ;
} else if ( box - > type = = BOX_TABLE ) {
/* \todo layout_table considers margins etc. again */
if ( ! layout_table ( box , width , content ) )
return false ;
layout_solve_width ( box - > parent - > width , box - > width ,
box - > margin , box - > padding , box - > border ) ;
}
/* 10.6.4 */
LOG ( ( " %i + %i + %i + %i + %i + %i + %i + %i + %i = %i " ,
top , margin [ TOP ] , border [ TOP ] , padding [ TOP ] , height ,
padding [ BOTTOM ] , border [ BOTTOM ] , margin [ BOTTOM ] , bottom ,
containing_block - > height ) ) ;
if ( top = = AUTO & & height = = AUTO & & bottom = = AUTO ) {
2006-10-09 02:46:25 +04:00
top = static_top ;
2006-06-26 08:52:34 +04:00
height = box - > height ;
if ( margin [ TOP ] = = AUTO )
margin [ TOP ] = 0 ;
if ( margin [ BOTTOM ] = = AUTO )
margin [ BOTTOM ] = 0 ;
bottom = containing_block - > height -
top -
margin [ TOP ] - border [ TOP ] - padding [ TOP ] -
height -
padding [ BOTTOM ] - border [ BOTTOM ] - margin [ BOTTOM ] ;
} else if ( top ! = AUTO & & height ! = AUTO & & bottom ! = AUTO ) {
if ( margin [ TOP ] = = AUTO & & margin [ BOTTOM ] = = AUTO ) {
space = containing_block - > height -
top -
border [ TOP ] - padding [ TOP ] -
height -
padding [ BOTTOM ] - border [ BOTTOM ] -
bottom ;
margin [ TOP ] = margin [ BOTTOM ] = space / 2 ;
} else if ( margin [ TOP ] = = AUTO ) {
margin [ TOP ] = containing_block - > height -
top -
border [ TOP ] - padding [ TOP ] -
height -
padding [ BOTTOM ] - border [ BOTTOM ] - margin [ BOTTOM ] -
bottom ;
} else if ( margin [ BOTTOM ] = = AUTO ) {
margin [ BOTTOM ] = containing_block - > height -
top -
margin [ TOP ] - border [ TOP ] - padding [ TOP ] -
height -
padding [ BOTTOM ] - border [ BOTTOM ] -
bottom ;
} else {
bottom = containing_block - > height -
top -
margin [ TOP ] - border [ TOP ] - padding [ TOP ] -
height -
padding [ BOTTOM ] - border [ BOTTOM ] - margin [ BOTTOM ] ;
}
} else {
if ( margin [ TOP ] = = AUTO )
margin [ TOP ] = 0 ;
if ( margin [ BOTTOM ] = = AUTO )
margin [ BOTTOM ] = 0 ;
if ( top = = AUTO & & height = = AUTO & & bottom ! = AUTO ) {
height = box - > height ;
top = containing_block - > height -
margin [ TOP ] - border [ TOP ] - padding [ TOP ] -
height -
padding [ BOTTOM ] - border [ BOTTOM ] - margin [ BOTTOM ] -
bottom ;
} else if ( top = = AUTO & & height ! = AUTO & & bottom = = AUTO ) {
2006-10-09 02:46:25 +04:00
top = static_top ;
2006-06-26 08:52:34 +04:00
bottom = containing_block - > height -
top -
margin [ TOP ] - border [ TOP ] - padding [ TOP ] -
height -
padding [ BOTTOM ] - border [ BOTTOM ] - margin [ BOTTOM ] ;
} else if ( top ! = AUTO & & height = = AUTO & & bottom = = AUTO ) {
height = box - > height ;
bottom = containing_block - > height -
top -
margin [ TOP ] - border [ TOP ] - padding [ TOP ] -
height -
padding [ BOTTOM ] - border [ BOTTOM ] - margin [ BOTTOM ] ;
} else if ( top = = AUTO & & height ! = AUTO & & bottom ! = AUTO ) {
top = containing_block - > height -
margin [ TOP ] - border [ TOP ] - padding [ TOP ] -
height -
padding [ BOTTOM ] - border [ BOTTOM ] - margin [ BOTTOM ] -
bottom ;
} else if ( top ! = AUTO & & height = = AUTO & & bottom ! = AUTO ) {
height = containing_block - > height -
top -
margin [ TOP ] - border [ TOP ] - padding [ TOP ] -
padding [ BOTTOM ] - border [ BOTTOM ] - margin [ BOTTOM ] -
bottom ;
} else if ( top ! = AUTO & & height ! = AUTO & & bottom = = AUTO ) {
bottom = containing_block - > height -
top -
margin [ TOP ] - border [ TOP ] - padding [ TOP ] -
height -
padding [ BOTTOM ] - border [ BOTTOM ] - margin [ BOTTOM ] ;
}
}
LOG ( ( " %i + %i + %i + %i + %i + %i + %i + %i + %i = %i " ,
top , margin [ TOP ] , border [ TOP ] , padding [ TOP ] , height ,
padding [ BOTTOM ] , border [ BOTTOM ] , margin [ BOTTOM ] , bottom ,
containing_block - > height ) ) ;
2006-10-09 02:46:25 +04:00
box - > y = top + margin [ TOP ] + border [ TOP ] - cy ;
2006-06-29 15:55:21 +04:00
if ( containing_block - > type = = BOX_BLOCK | |
containing_block - > type = = BOX_INLINE_BLOCK | |
containing_block - > type = = BOX_TABLE_CELL ) {
2006-06-29 19:53:17 +04:00
/* Block-level ancestor => reset container's height */
containing_block - > height - = containing_block - > padding [ TOP ] +
containing_block - > padding [ BOTTOM ] ;
2006-06-29 15:55:21 +04:00
} else {
/** \todo Inline ancestors */
}
2006-06-26 08:52:34 +04:00
box - > height = height ;
return true ;
}
/**
* Compute box offsets for a relatively or absolutely positioned box with
* respect to a box .
*
* \ param box box to compute offsets for
* \ param containing_block box to compute percentages with respect to
* \ param top updated to top offset , or AUTO
* \ param right updated to right offset , or AUTO
* \ param bottom updated to bottom offset , or AUTO
* \ param left updated to left offset , or AUTO
*
* See CSS 2.1 9.3 .2 . containing_block must have width and height .
*/
void layout_compute_offsets ( struct box * box ,
struct box * containing_block ,
int * top , int * right , int * bottom , int * left )
{
2006-06-30 03:30:06 +04:00
assert ( containing_block - > width ! = UNKNOWN_WIDTH & &
containing_block - > width ! = AUTO & &
containing_block - > height ! = AUTO ) ;
2006-06-26 08:52:34 +04:00
/* left */
if ( box - > style - > pos [ LEFT ] . pos = = CSS_POS_PERCENT )
* left = ( ( box - > style - > pos [ LEFT ] . value . percent *
containing_block - > width ) / 100 ) ;
else if ( box - > style - > pos [ LEFT ] . pos = = CSS_POS_LENGTH )
* left = css_len2px ( & box - > style - > pos [ LEFT ] . value . length ,
box - > style ) ;
else
* left = AUTO ;
/* right */
if ( box - > style - > pos [ RIGHT ] . pos = = CSS_POS_PERCENT )
* right = ( ( box - > style - > pos [ RIGHT ] . value . percent *
containing_block - > width ) / 100 ) ;
else if ( box - > style - > pos [ RIGHT ] . pos = = CSS_POS_LENGTH )
* right = css_len2px ( & box - > style - > pos [ RIGHT ] . value . length ,
box - > style ) ;
else
* right = AUTO ;
/* top */
if ( box - > style - > pos [ TOP ] . pos = = CSS_POS_PERCENT )
* top = ( ( box - > style - > pos [ TOP ] . value . percent *
containing_block - > height ) / 100 ) ;
else if ( box - > style - > pos [ TOP ] . pos = = CSS_POS_LENGTH )
* top = css_len2px ( & box - > style - > pos [ TOP ] . value . length ,
box - > style ) ;
else
* top = AUTO ;
/* bottom */
if ( box - > style - > pos [ BOTTOM ] . pos = = CSS_POS_PERCENT )
* bottom = ( ( box - > style - > pos [ BOTTOM ] . value . percent *
containing_block - > height ) / 100 ) ;
else if ( box - > style - > pos [ BOTTOM ] . pos = = CSS_POS_LENGTH )
* bottom = css_len2px ( & box - > style - > pos [ BOTTOM ] . value . length ,
box - > style ) ;
else
* bottom = AUTO ;
}
2004-08-01 17:08:19 +04:00
/**
* Recursively calculate the descendant_ [ xy ] [ 01 ] values for a laid - out box tree .
*
* \ param box tree of boxes to update
*/
void layout_calculate_descendant_bboxes ( struct box * box )
{
struct box * child ;
2006-12-27 00:51:08 +03:00
if ( box - > width = = UNKNOWN_WIDTH | | box - > height = = AUTO /*||
2005-07-02 22:17:51 +04:00
box - > width < 0 | | box - > height < 0 */ ) {
LOG ( ( " %p has bad width or height " , box ) ) ;
2006-12-27 00:51:08 +03:00
/*while (box->parent)
2005-04-02 15:13:27 +04:00
box = box - > parent ;
2006-12-27 00:51:08 +03:00
box_dump ( box , 0 ) ; */
2005-04-02 15:13:27 +04:00
assert ( 0 ) ;
}
2004-08-01 17:08:19 +04:00
box - > descendant_x0 = - box - > border [ LEFT ] ;
box - > descendant_y0 = - box - > border [ TOP ] ;
box - > descendant_x1 = box - > padding [ LEFT ] + box - > width +
box - > padding [ RIGHT ] + box - > border [ RIGHT ] ;
box - > descendant_y1 = box - > padding [ TOP ] + box - > height +
box - > padding [ BOTTOM ] + box - > border [ BOTTOM ] ;
2005-08-08 23:19:20 +04:00
if ( box - > type = = BOX_INLINE | | box - > type = = BOX_TEXT )
return ;
if ( box - > type = = BOX_INLINE_END ) {
box = box - > inline_end ;
for ( child = box - > next ;
child & & child ! = box - > inline_end ;
child = child - > next ) {
if ( child - > type = = BOX_FLOAT_LEFT | |
child - > type = = BOX_FLOAT_RIGHT )
continue ;
if ( child - > x + child - > descendant_x0 - box - > x <
box - > descendant_x0 )
box - > descendant_x0 = child - > x +
child - > descendant_x0 - box - > x ;
if ( box - > descendant_x1 < child - > x +
child - > descendant_x1 - box - > x )
box - > descendant_x1 = child - > x +
child - > descendant_x1 - box - > x ;
if ( child - > y + child - > descendant_y0 - box - > y <
box - > descendant_y0 )
box - > descendant_y0 = child - > y +
child - > descendant_y0 - box - > y ;
if ( box - > descendant_y1 < child - > y +
child - > descendant_y1 - box - > y )
box - > descendant_y1 = child - > y +
child - > descendant_y1 - box - > y ;
}
return ;
}
2004-08-01 17:08:19 +04:00
for ( child = box - > children ; child ; child = child - > next ) {
if ( child - > type = = BOX_FLOAT_LEFT | |
child - > type = = BOX_FLOAT_RIGHT )
continue ;
layout_calculate_descendant_bboxes ( child ) ;
2007-08-28 04:53:22 +04:00
if ( box - > style & & box - > style - > overflow = = CSS_OVERFLOW_HIDDEN )
2005-08-08 01:28:48 +04:00
continue ;
2004-08-01 17:08:19 +04:00
if ( child - > x + child - > descendant_x0 < box - > descendant_x0 )
box - > descendant_x0 = child - > x + child - > descendant_x0 ;
if ( box - > descendant_x1 < child - > x + child - > descendant_x1 )
box - > descendant_x1 = child - > x + child - > descendant_x1 ;
if ( child - > y + child - > descendant_y0 < box - > descendant_y0 )
box - > descendant_y0 = child - > y + child - > descendant_y0 ;
if ( box - > descendant_y1 < child - > y + child - > descendant_y1 )
box - > descendant_y1 = child - > y + child - > descendant_y1 ;
}
for ( child = box - > float_children ; child ; child = child - > next_float ) {
2006-06-26 08:52:34 +04:00
assert ( child - > type = = BOX_FLOAT_LEFT | |
child - > type = = BOX_FLOAT_RIGHT ) ;
layout_calculate_descendant_bboxes ( child ) ;
if ( child - > x + child - > descendant_x0 < box - > descendant_x0 )
box - > descendant_x0 = child - > x + child - > descendant_x0 ;
if ( box - > descendant_x1 < child - > x + child - > descendant_x1 )
box - > descendant_x1 = child - > x + child - > descendant_x1 ;
if ( child - > y + child - > descendant_y0 < box - > descendant_y0 )
box - > descendant_y0 = child - > y + child - > descendant_y0 ;
if ( box - > descendant_y1 < child - > y + child - > descendant_y1 )
box - > descendant_y1 = child - > y + child - > descendant_y1 ;
}
2006-11-05 15:58:24 +03:00
if ( box - > list_marker ) {
child = box - > list_marker ;
layout_calculate_descendant_bboxes ( child ) ;
if ( child - > x + child - > descendant_x0 < box - > descendant_x0 )
box - > descendant_x0 = child - > x + child - > descendant_x0 ;
if ( box - > descendant_x1 < child - > x + child - > descendant_x1 )
box - > descendant_x1 = child - > x + child - > descendant_x1 ;
if ( child - > y + child - > descendant_y0 < box - > descendant_y0 )
box - > descendant_y0 = child - > y + child - > descendant_y0 ;
if ( box - > descendant_y1 < child - > y + child - > descendant_y1 )
box - > descendant_y1 = child - > y + child - > descendant_y1 ;
}
2004-08-01 17:08:19 +04:00
}