netscape-revival
lib/layout/laytable.c
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t -*-
*/
#include "xp.h"
#include "pa_parse.h"
#include "layout.h"
#include "np.h"
#ifdef TEST_16BIT
#define XP_WIN16
#endif /* TEST_16BIT */
#define TABLE_BORDERS_ON 1
#define TABLE_BORDERS_OFF 0
#define TABLE_BORDERS_GONE -1
#define TABLE_DEF_INNER_CELL_PAD 1
#define TABLE_DEF_INTER_CELL_PAD 2
#define TABLE_DEF_CELL_BORDER 1
#define TABLE_DEF_BORDER 0
#define TABLE_DEF_VERTICAL_SPACE 0
#define TABLE_DEF_HORIZONTAL_SPACE 0
typedef struct lo_cell_data_struct {
#ifdef XP_WIN16
/*
* This struct must be a power of 2 if we are going to allocate an
* array of more than 128K
*/
unsigned width, height;
#else
int32 width, height;
#endif
lo_TableCell *cell;
} lo_cell_data;
void
lo_BeginCaptionSubDoc(MWContext *context, lo_DocState *state,
lo_TableCaption *caption, PA_Tag *tag)
{
LO_SubDocStruct *subdoc;
lo_DocState *new_state;
int32 first_width, first_height;
Bool allow_percent_width;
Bool allow_percent_height;
/*
* Fill in the subdoc structure with default data
*/
subdoc = (LO_SubDocStruct *)lo_NewElement(context, state, LO_SUBDOC, NULL, 0);
if (subdoc == NULL)
{
return;
}
subdoc->type = LO_SUBDOC;
subdoc->ele_id = NEXT_ELEMENT;
subdoc->x = state->x;
subdoc->x_offset = 0;
subdoc->y = state->y;
subdoc->y_offset = 0;
subdoc->width = 0;
subdoc->height = 0;
subdoc->next = NULL;
subdoc->prev = NULL;
subdoc->anchor_href = state->current_anchor;
if (state->font_stack == NULL)
{
subdoc->text_attr = NULL;
}
else
{
subdoc->text_attr = state->font_stack->text_attr;
}
subdoc->FE_Data = NULL;
subdoc->bg_color = NULL;
subdoc->state = NULL;
subdoc->vert_alignment = LO_ALIGN_CENTER;
subdoc->horiz_alignment = caption->horiz_alignment;
subdoc->alignment = LO_ALIGN_BOTTOM;
subdoc->border_width = 0;
subdoc->border_vert_space = 0;
subdoc->border_horiz_space = 0;
subdoc->ele_attrmask = 0;
subdoc->sel_start = -1;
subdoc->sel_end = -1;
subdoc->border_width = FEUNITS_X(subdoc->border_width, context);
if (subdoc->width == 0)
{
first_width = FEUNITS_X(5000, context);
allow_percent_width = FALSE;
}
else
{
first_width = subdoc->width;
allow_percent_width = TRUE;
}
if (subdoc->height == 0)
{
first_height = FEUNITS_Y(10000, context);
allow_percent_height = FALSE;
}
else
{
first_height = subdoc->height;
allow_percent_height = TRUE;
}
new_state = lo_NewLayout(context, first_width, first_height, 0, 0, NULL);
if (new_state == NULL)
{
lo_FreeElement(context, (LO_Element *)subdoc, FALSE);
return;
}
new_state->is_a_subdoc = SUBDOC_CAPTION;
lo_InheritParentState(new_state, state);
new_state->allow_percent_width = allow_percent_width;
new_state->allow_percent_height = allow_percent_height;
new_state->base_x = 0;
new_state->base_y = 0;
new_state->display_blocked = TRUE;
if (subdoc->width == 0)
{
new_state->delay_align = TRUE;
}
new_state->win_left = 0;
new_state->win_right = 0;
new_state->x = new_state->win_left;
new_state->y = 0;
new_state->max_width = new_state->x + 1;
new_state->left_margin = new_state->win_left;
new_state->right_margin = new_state->win_width - new_state->win_right;
new_state->list_stack->old_left_margin = new_state->left_margin;
new_state->list_stack->old_right_margin = new_state->right_margin;
/*
* Initialize the alignment stack for this state
* to match the caption alignment.
*/
if (subdoc->horiz_alignment != LO_ALIGN_LEFT)
{
lo_PushAlignment(new_state, tag, subdoc->horiz_alignment);
}
state->sub_state = new_state;
state->current_ele = (LO_Element *)subdoc;
}
void
lo_BeginCellSubDoc(MWContext *context, lo_DocState *state,
lo_TableRec *table, PA_Tag *tag,
Bool is_a_header, intn draw_borders)
{
LO_SubDocStruct *subdoc;
lo_DocState *new_state;
lo_TableRow *table_row;
lo_TableCell *table_cell;
PA_Block buff;
char *str;
int32 val;
int32 first_width, first_height;
Bool allow_percent_width;
Bool allow_percent_height;
#ifdef LOCAL_DEBUG
fprintf(stderr, "lo_BeginCellSubDoc called\n");
#endif /* LOCAL_DEBUG */
table_row = table->row_ptr;
table_cell = table_row->cell_ptr;
/*
* Fill in the subdoc structure with default data
*/
subdoc = (LO_SubDocStruct *)lo_NewElement(context, state, LO_SUBDOC, NULL, 0);
if (subdoc == NULL)
{
return;
}
subdoc->type = LO_SUBDOC;
subdoc->ele_id = NEXT_ELEMENT;
subdoc->x = state->x;
subdoc->x_offset = 0;
subdoc->y = state->y;
subdoc->y_offset = 0;
subdoc->width = 0;
subdoc->height = 0;
subdoc->next = NULL;
subdoc->prev = NULL;
subdoc->anchor_href = state->current_anchor;
if (state->font_stack == NULL)
{
subdoc->text_attr = NULL;
}
else
{
subdoc->text_attr = state->font_stack->text_attr;
}
subdoc->FE_Data = NULL;
subdoc->state = NULL;
subdoc->vert_alignment = table_row->vert_alignment;
if (subdoc->vert_alignment == LO_ALIGN_DEFAULT)
{
subdoc->vert_alignment = LO_ALIGN_CENTER;
}
subdoc->horiz_alignment = table_row->horiz_alignment;
if (subdoc->horiz_alignment == LO_ALIGN_DEFAULT)
{
if (is_a_header == FALSE)
{
subdoc->horiz_alignment = LO_ALIGN_LEFT;
}
else
{
subdoc->horiz_alignment = LO_ALIGN_CENTER;
}
}
subdoc->alignment = LO_ALIGN_BOTTOM;
if (draw_borders == TABLE_BORDERS_OFF)
{
subdoc->border_width = 0;
subdoc->border_vert_space = TABLE_DEF_CELL_BORDER;
subdoc->border_horiz_space = TABLE_DEF_CELL_BORDER;
}
else if (draw_borders == TABLE_BORDERS_ON)
{
subdoc->border_width = TABLE_DEF_CELL_BORDER;
subdoc->border_vert_space = 0;
subdoc->border_horiz_space = 0;
}
else
{
subdoc->border_width = 0;
subdoc->border_vert_space = 0;
subdoc->border_horiz_space = 0;
}
subdoc->ele_attrmask = 0;
subdoc->sel_start = -1;
subdoc->sel_end = -1;
subdoc->bg_color = NULL;
/*
* May inherit a bg_color from your row.
*/
if (table_row->bg_color != NULL)
{
subdoc->bg_color = XP_NEW(LO_Color);
if (subdoc->bg_color != NULL)
{
subdoc->bg_color->red = table_row->bg_color->red;
subdoc->bg_color->green = table_row->bg_color->green;
subdoc->bg_color->blue = table_row->bg_color->blue;
}
}
/*
* Else may inherit a bg_color from your table.
*/
else if (table->bg_color != NULL)
{
subdoc->bg_color = XP_NEW(LO_Color);
if (subdoc->bg_color != NULL)
{
subdoc->bg_color->red = table->bg_color->red;
subdoc->bg_color->green = table->bg_color->green;
subdoc->bg_color->blue = table->bg_color->blue;
}
}
/*
* Else possibly inherit the background color attribute
* of a parent table cell.
*/
else if (state->is_a_subdoc == SUBDOC_CELL)
{
lo_DocState *up_state;
/*
* Find the parent subdoc's state.
*/
up_state = state->top_state->doc_state;
while ((up_state->sub_state != NULL)&&
(up_state->sub_state != state))
{
up_state = up_state->sub_state;
}
if ((up_state->sub_state != NULL)&&
(up_state->current_ele != NULL)&&
(up_state->current_ele->type == LO_SUBDOC)&&
(up_state->current_ele->lo_subdoc.bg_color != NULL))
{
LO_Color *old_bg;
old_bg = up_state->current_ele->lo_subdoc.bg_color;
subdoc->bg_color = XP_NEW(LO_Color);
if (subdoc->bg_color != NULL)
{
subdoc->bg_color->red = old_bg->red;
subdoc->bg_color->green = old_bg->green;
subdoc->bg_color->blue = old_bg->blue;
}
}
}
/*
* Check for a background color attribute
*/
buff = lo_FetchParamValue(context, tag, PARAM_BGCOLOR);
if (buff != NULL)
{
uint8 red, green, blue;
PA_LOCK(str, char *, buff);
LO_ParseRGB(str, &red, &green, &blue);
PA_UNLOCK(buff);
PA_FREE(buff);
subdoc->bg_color = XP_NEW(LO_Color);
if (subdoc->bg_color != NULL)
{
subdoc->bg_color->red = red;
subdoc->bg_color->green = green;
subdoc->bg_color->blue = blue;
}
}
/*
* Check for a vertical align parameter
*/
buff = lo_FetchParamValue(context, tag, PARAM_VALIGN);
if (buff != NULL)
{
PA_LOCK(str, char *, buff);
subdoc->vert_alignment = lo_EvalVAlignParam(str);
PA_UNLOCK(buff);
PA_FREE(buff);
}
/*
* Check for a horizontal align parameter
*/
buff = lo_FetchParamValue(context, tag, PARAM_ALIGN);
if (buff != NULL)
{
PA_LOCK(str, char *, buff);
subdoc->horiz_alignment = lo_EvalCellAlignParam(str);
PA_UNLOCK(buff);
PA_FREE(buff);
}
subdoc->border_width = FEUNITS_X(subdoc->border_width, context);
subdoc->border_vert_space =
FEUNITS_Y(subdoc->border_vert_space, context);
subdoc->border_horiz_space =
FEUNITS_X(subdoc->border_horiz_space, context);
/*
* Allow individual setting of cell
* width and height.
*/
buff = lo_FetchParamValue(context, tag, PARAM_WIDTH);
if (buff != NULL)
{
Bool is_percent;
PA_LOCK(str, char *, buff);
val = lo_ValueOrPercent(str, &is_percent);
if (is_percent != FALSE)
{
/*
* Percentage width cells must be handled
* later after at least the whole row is
* processed.
*/
table_cell->percent_width = val;
table_row->has_percent_width_cells = TRUE;
table->has_percent_width_cells = TRUE;
val = 0;
}
else
{
val = FEUNITS_X(val, context);
}
subdoc->width = val;
if (subdoc->width < 0)
{
subdoc->width = 0;
}
PA_UNLOCK(buff);
PA_FREE(buff);
}
buff = lo_FetchParamValue(context, tag, PARAM_HEIGHT);
if (buff != NULL)
{
Bool is_percent;
PA_LOCK(str, char *, buff);
val = lo_ValueOrPercent(str, &is_percent);
if (is_percent != FALSE)
{
/*
* Percentage width cells must be handled
* later after at least the whole row is
* processed.
*/
val = 0;
table_cell->percent_height = val;
table->has_percent_height_cells = TRUE;
}
else
{
val = FEUNITS_X(val, context);
}
subdoc->height = val;
if (subdoc->height < 0)
{
subdoc->height = 0;
}
PA_UNLOCK(buff);
PA_FREE(buff);
}
if (subdoc->width == 0)
{
first_width = FEUNITS_X(5000, context);
allow_percent_width = FALSE;
}
else
{
first_width = subdoc->width;
allow_percent_width = TRUE;
}
if (subdoc->height == 0)
{
first_height = FEUNITS_Y(10000, context);
allow_percent_height = FALSE;
}
else
{
first_height = subdoc->height;
allow_percent_height = TRUE;
}
new_state = lo_NewLayout(context, first_width, first_height, 0, 0, state);
if (new_state == NULL)
{
lo_FreeElement(context, (LO_Element *)subdoc, FALSE);
return;
}
new_state->is_a_subdoc = SUBDOC_CELL;
lo_InheritParentState(new_state, state);
new_state->allow_percent_width = allow_percent_width;
new_state->allow_percent_height = allow_percent_height;
new_state->base_x = 0;
new_state->base_y = 0;
new_state->display_blocked = TRUE;
if (subdoc->width == 0)
{
new_state->delay_align = TRUE;
}
new_state->win_left = 0;
new_state->win_right = 0;
new_state->x = new_state->win_left;
new_state->y = 0;
new_state->max_width = new_state->x + 1;
new_state->left_margin = new_state->win_left;
new_state->right_margin = new_state->win_width - new_state->win_right;
new_state->list_stack->old_left_margin = new_state->left_margin;
new_state->list_stack->old_right_margin = new_state->right_margin;
/*
* Initialize the alignment stack for this state
* to match the caption alignment.
*/
if (subdoc->horiz_alignment != LO_ALIGN_LEFT)
{
lo_PushAlignment(new_state, tag, subdoc->horiz_alignment);
}
state->sub_state = new_state;
state->current_ele = (LO_Element *)subdoc;
if (is_a_header != FALSE)
{
LO_TextAttr *old_attr;
LO_TextAttr *attr;
LO_TextAttr tmp_attr;
old_attr = new_state->font_stack->text_attr;
lo_CopyTextAttr(old_attr, &tmp_attr);
tmp_attr.fontmask |= LO_FONT_BOLD;
attr = lo_FetchTextAttr(new_state, &tmp_attr);
lo_PushFont(new_state, tag->type, attr);
}
}
Bool
lo_subdoc_has_elements(lo_DocState *sub_state)
{
if (sub_state->end_last_line != NULL)
{
return(TRUE);
}
if (sub_state->float_list != NULL)
{
return(TRUE);
}
return(FALSE);
}
int32
lo_align_subdoc(MWContext *context, lo_DocState *state, lo_DocState *old_state,
LO_SubDocStruct *subdoc, lo_TableRec *table, lo_table_span *row_max)
{
int32 ele_cnt;
LO_Element *eptr;
int32 vert_inc;
int32 inner_pad;
LO_Element **line_array;
inner_pad = FEUNITS_X(table->inner_cell_pad, context);
ele_cnt = 0;
/*
* Mess with vertical alignment.
*/
vert_inc = subdoc->height - (2 * subdoc->border_width) -
(2 * inner_pad) - old_state->y;
if (vert_inc > 0)
{
if (subdoc->vert_alignment == LO_ALIGN_CENTER)
{
vert_inc = vert_inc / 2;
}
else if (subdoc->vert_alignment == LO_ALIGN_BOTTOM)
{
/* vert_inc unchanged */
}
else if ((subdoc->vert_alignment == LO_ALIGN_BASELINE)&&
(row_max != NULL))
{
int32 baseline;
int32 tmp_val;
baseline = lo_GetSubDocBaseline(subdoc);
tmp_val = row_max->min_dim - baseline;
if (tmp_val > vert_inc)
{
tmp_val = vert_inc;
}
if (tmp_val > 0)
{
vert_inc = tmp_val;
}
else
{
vert_inc = 0;
}
}
else
{
vert_inc = 0;
}
}
else
{
vert_inc = 0;
}
/*
* Make eptr point to the start of the element chain
* for this subdoc.
*/
#ifdef XP_WIN16
{
XP_Block *larray_array;
XP_LOCK_BLOCK(larray_array, XP_Block *, old_state->larray_array);
old_state->line_array = larray_array[0];
XP_UNLOCK_BLOCK(old_state->larray_array);
}
#endif /* XP_WIN16 */
XP_LOCK_BLOCK(line_array, LO_Element **, old_state->line_array);
eptr = line_array[0];
XP_UNLOCK_BLOCK(old_state->line_array);
while (eptr != NULL)
{
eptr->lo_any.x += inner_pad;
switch (eptr->type)
{
case LO_LINEFEED:
if (eptr->lo_linefeed.ele_attrmask &
LO_ELE_DELAY_ALIGNED)
{
if (eptr->lo_linefeed.ele_attrmask &
LO_ELE_DELAY_CENTER)
{
int32 side_inc;
int32 inside_width;
LO_Element *c_eptr;
c_eptr = eptr;
inside_width = subdoc->width -
(2 * subdoc->border_width) -
(2 * subdoc->border_horiz_space) -
(2 * inner_pad);
side_inc = inside_width -
(c_eptr->lo_linefeed.x +
c_eptr->lo_linefeed.x_offset -
inner_pad);
side_inc = side_inc / 2;
if (side_inc > 0)
{
c_eptr->lo_linefeed.width -= side_inc;
if (c_eptr->lo_linefeed.width < 0)
{
c_eptr->lo_linefeed.width = 0;
}
while ((c_eptr->lo_any.prev != NULL)&&
(c_eptr->lo_any.prev->type !=
LO_LINEFEED))
{
c_eptr->lo_any.x += side_inc;
if (c_eptr->type == LO_CELL)
{
lo_ShiftCell(
(LO_CellStruct *)c_eptr,
side_inc, 0);
}
c_eptr = c_eptr->lo_any.prev;
}
c_eptr->lo_any.x += side_inc;
if (c_eptr->type == LO_CELL)
{
lo_ShiftCell(
(LO_CellStruct *)c_eptr,
side_inc, 0);
}
}
}
else if (eptr->lo_linefeed.ele_attrmask &
LO_ELE_DELAY_RIGHT)
{
int32 side_inc;
int32 inside_width;
LO_Element *c_eptr;
c_eptr = eptr;
inside_width = subdoc->width -
(2 * subdoc->border_width) -
(2 * subdoc->border_horiz_space) -
(2 * inner_pad);
side_inc = inside_width -
(c_eptr->lo_linefeed.x +
c_eptr->lo_linefeed.x_offset -
inner_pad);
if (side_inc > 0)
{
c_eptr->lo_linefeed.width -= side_inc;
if (c_eptr->lo_linefeed.width < 0)
{
c_eptr->lo_linefeed.width = 0;
}
while ((c_eptr->lo_any.prev != NULL)&&
(c_eptr->lo_any.prev->type !=
LO_LINEFEED))
{
c_eptr->lo_any.x += side_inc;
if (c_eptr->type == LO_CELL)
{
lo_ShiftCell(
(LO_CellStruct *)c_eptr,
side_inc, 0);
}
c_eptr = c_eptr->lo_any.prev;
}
c_eptr->lo_any.x += side_inc;
if (c_eptr->type == LO_CELL)
{
lo_ShiftCell(
(LO_CellStruct *)c_eptr,
side_inc, 0);
}
}
}
eptr->lo_linefeed.ele_attrmask &=
(~(LO_ELE_DELAY_ALIGNED));
}
break;
default:
break;
}
eptr->lo_any.y += (vert_inc + inner_pad);
if (eptr->type == LO_CELL)
{
lo_ShiftCell((LO_CellStruct *)eptr, inner_pad,
(vert_inc + inner_pad));
}
eptr = eptr->lo_any.next;
ele_cnt++;
}
eptr = old_state->float_list;
while (eptr != NULL)
{
eptr->lo_any.x += inner_pad;
eptr->lo_any.y += (vert_inc + inner_pad);
if (eptr->type == LO_CELL)
{
lo_ShiftCell((LO_CellStruct *)eptr, inner_pad,
(vert_inc + inner_pad));
}
eptr = eptr->lo_any.next;
ele_cnt++;
}
return(ele_cnt);
}
LO_SubDocStruct *
lo_EndCellSubDoc(MWContext *context, lo_DocState *state, lo_DocState *old_state,
LO_Element *element)
{
LO_Element *eptr;
LO_SubDocStruct *subdoc;
PA_Block buff;
char *str;
Bool line_break;
int32 baseline_inc;
int32 line_inc;
int32 subdoc_height, subdoc_width;
int32 doc_height;
LO_TextStruct tmp_text;
LO_TextInfo text_info;
LO_Element **line_array;
Bool dynamic_width;
Bool dynamic_height;
#ifdef LOCAL_DEBUG
fprintf(stderr, "lo_EndCellSubDoc called\n");
#endif /* LOCAL_DEBUG */
subdoc = (LO_SubDocStruct *)element;
subdoc->state = (void *)old_state;
/*
* All this work is to get the text_info filled in for the current
* font in the font stack. Yuck, there must be a better way.
*/
memset (&tmp_text, 0, sizeof (tmp_text));
buff = PA_ALLOC(1);
if (buff == NULL)
{
state->top_state->out_of_memory = TRUE;
return(NULL);
}
PA_LOCK(str, char *, buff);
str[0] = ' ';
PA_UNLOCK(buff);
tmp_text.text = buff;
tmp_text.text_len = 1;
tmp_text.text_attr =
state->font_stack->text_attr;
FE_GetTextInfo(context, &tmp_text, &text_info);
PA_FREE(buff);
dynamic_width = FALSE;
dynamic_height = FALSE;
if (subdoc->width == 0)
{
dynamic_width = TRUE;
/*
* Subdocs that were dynamically widthed, and which
* contained right aligned items, must be relaid out
* once their width is determined.
*/
eptr = old_state->float_list;
while (eptr != NULL)
{
if ((eptr->type == LO_IMAGE)&&
(eptr->lo_image.image_attr->alignment == LO_ALIGN_RIGHT))
{
old_state->must_relayout_subdoc = TRUE;
break;
}
else if ((eptr->type == LO_SUBDOC)&&
(eptr->lo_subdoc.alignment == LO_ALIGN_RIGHT))
{
old_state->must_relayout_subdoc = TRUE;
break;
}
eptr = eptr->lo_any.next;
}
subdoc->width = old_state->max_width +
(2 * subdoc->border_width);
}
/*
* Figure the height the subdoc laid out in.
* Use this if we were passed no height, or if it is greater
* than the passed height.
*/
doc_height = old_state->y + (2 * subdoc->border_width);
if (subdoc->height == 0)
{
dynamic_height = TRUE;
subdoc->height = doc_height;
}
else if (subdoc->height < doc_height)
{
subdoc->height = doc_height;
}
/*
* Make eptr point to the start of the element chain
* for this subdoc.
*/
#ifdef XP_WIN16
{
XP_Block *larray_array;
XP_LOCK_BLOCK(larray_array, XP_Block *, old_state->larray_array);
old_state->line_array = larray_array[0];
XP_UNLOCK_BLOCK(old_state->larray_array);
}
#endif /* XP_WIN16 */
XP_LOCK_BLOCK(line_array, LO_Element **, old_state->line_array);
eptr = line_array[0];
XP_UNLOCK_BLOCK(old_state->line_array);
while (eptr != NULL)
{
switch (eptr->type)
{
case LO_LINEFEED:
if ((eptr->lo_linefeed.x + eptr->lo_linefeed.x_offset +
eptr->lo_linefeed.width) >= (subdoc->width - 1 -
(2 * subdoc->border_width)))
{
eptr->lo_linefeed.width = (subdoc->width - 1 -
(2 * subdoc->border_width)) -
(eptr->lo_linefeed.x +
eptr->lo_linefeed.x_offset);
if (eptr->lo_linefeed.width < 0)
{
eptr->lo_linefeed.width = 0;
}
}
#ifdef OLD_DELAY_CENTERED
if (eptr->lo_linefeed.ele_attrmask &
LO_ELE_DELAY_CENTERED)
{
int32 side_inc;
LO_Element *c_eptr;
c_eptr = eptr;
side_inc = subdoc->width - 1 -
(2 * subdoc->border_width) -
(eptr->lo_linefeed.x +
eptr->lo_linefeed.x_offset);
side_inc = side_inc / 2;
if (side_inc > 0)
{
c_eptr->lo_linefeed.width -= side_inc;
if (c_eptr->lo_linefeed.width < 0)
{
c_eptr->lo_linefeed.width = 0;
}
while ((c_eptr->lo_any.prev != NULL)&&
(c_eptr->lo_any.prev->type !=
LO_LINEFEED))
{
c_eptr->lo_any.x += side_inc;
if (c_eptr->type == LO_CELL)
{
lo_ShiftCell(
(LO_CellStruct *)c_eptr,
side_inc, 0);
}
c_eptr = c_eptr->lo_any.prev;
}
c_eptr->lo_any.x += side_inc;
if (c_eptr->type == LO_CELL)
{
lo_ShiftCell(
(LO_CellStruct *)c_eptr,
side_inc, 0);
}
}
eptr->lo_linefeed.ele_attrmask &=
(~(LO_ELE_DELAY_CENTERED));
}
#endif /* OLD_DELAY_CENTERED */
break;
/*
* This is awful, but any dynamically dimenstioned
* subdoc that contains one of these elements
* must be relayed out to take care of window
* widht and height dependencies.
*/
case LO_HRULE:
case LO_SUBDOC:
case LO_TABLE:
old_state->must_relayout_subdoc = TRUE;
break;
case LO_IMAGE:
/* WILL NEED THIS LATER FOR PERCENT WIDTH IMAGES
if ((old_state->allow_percent_width == FALSE)||
(old_state->allow_percent_height == FALSE))
{
old_state->must_relayout_subdoc = TRUE;
}
*/
break;
default:
break;
}
eptr = eptr->lo_any.next;
}
subdoc_width = subdoc->width + (2 * subdoc->border_width) +
(2 * subdoc->border_horiz_space);
subdoc_height = subdoc->height + (2 * subdoc->border_width) +
(2 * subdoc->border_vert_space);
if (old_state->display_blocked != FALSE)
{
old_state->display_blocked = FALSE;
}
/*
* Will this subdoc make the line too wide.
*/
if ((state->x + subdoc_width) > state->right_margin)
{
line_break = TRUE;
}
else
{
line_break = FALSE;
}
/*
* if we are at the beginning of the line. There is
* no point in breaking, we are just too wide.
* Also don't break in unwrappedpreformatted text.
* Also can't break inside a NOBR section.
*/
if ((state->at_begin_line != FALSE)||
(state->preformatted == PRE_TEXT_YES)||
(state->breakable == FALSE))
{
line_break = FALSE;
}
/*
* break on the subdoc if we have
* a break.
*/
/* DOn't break in cell
if (line_break != FALSE)
{
lo_HardLineBreak(context, state, TRUE);
subdoc->x = state->x;
subdoc->y = state->y;
}
*/
/*
* Figure out how to align this subdoc.
* baseline_inc is how much to increase the baseline
* of previous element of this line. line_inc is how
* much to increase the line height below the baseline.
*/
baseline_inc = 0;
line_inc = 0;
/*
* If we are at the beginning of a line, with no baseline,
* we first set baseline and line_height based on the current
* font, then place the subdoc.
*/
if (state->baseline == 0)
{
state->baseline = 0;
}
lo_CalcAlignOffsets(state, &text_info, (intn)subdoc->alignment,
subdoc_width, subdoc_height,
&subdoc->x_offset, &subdoc->y_offset, &line_inc, &baseline_inc);
subdoc->x_offset += (int16)subdoc->border_horiz_space;
subdoc->y_offset += (int32)subdoc->border_vert_space;
old_state->base_x = subdoc->x + subdoc->x_offset +
subdoc->border_width;
old_state->base_y = subdoc->y + subdoc->y_offset +
subdoc->border_width;
/*
* Clean up state
state->x = state->x + subdoc->x_offset +
subdoc_width - subdoc->border_horiz_space;
state->linefeed_state = 0;
state->at_begin_line = FALSE;
state->trailing_space = FALSE;
state->cur_ele_type = LO_SUBDOC;
*/
return(subdoc);
}
void
lo_relayout_recycle(MWContext *context, lo_DocState *state, LO_Element *elist)
{
while (elist != NULL)
{
LO_Element *eptr;
eptr = elist;
elist = elist->lo_any.next;
eptr->lo_any.next = NULL;
if (eptr->type == LO_IMAGE)
{
eptr->lo_any.next = state->top_state->trash;
state->top_state->trash = eptr;
}
else if (eptr->type == LO_CELL)
{
if (eptr->lo_cell.cell_list != NULL)
{
if (eptr->lo_cell.cell_list_end != NULL)
{
eptr->lo_cell.cell_list_end->lo_any.next = NULL;
}
lo_relayout_recycle(context, state,
eptr->lo_cell.cell_list);
eptr->lo_cell.cell_list = NULL;
eptr->lo_cell.cell_list_end = NULL;
}
if (eptr->lo_cell.cell_float_list != NULL)
{
lo_relayout_recycle(context, state,
eptr->lo_cell.cell_float_list);
eptr->lo_cell.cell_float_list = NULL;
}
lo_RecycleElements(context, state, eptr);
}
else
{
/*
* If this is an embed, tell it that it should
* recycle rather than delete itself.
*/
if (eptr->type == LO_EMBED)
NPL_SameElement((LO_EmbedStruct*)eptr);
lo_RecycleElements(context, state, eptr);
}
}
}
static void
lo_cleanup_state(MWContext *context, lo_DocState *state)
{
LO_Element **line_array;
if (state == NULL)
{
return;
}
if (state->left_margin_stack != NULL)
{
lo_MarginStack *mptr;
lo_MarginStack *margin;
mptr = state->left_margin_stack;
while (mptr != NULL)
{
margin = mptr;
mptr = mptr->next;
XP_DELETE(margin);
}
state->left_margin_stack = NULL;
}
if (state->right_margin_stack != NULL)
{
lo_MarginStack *mptr;
lo_MarginStack *margin;
mptr = state->right_margin_stack;
while (mptr != NULL)
{
margin = mptr;
mptr = mptr->next;
XP_DELETE(margin);
}
state->right_margin_stack = NULL;
}
if (state->line_list != NULL)
{
lo_relayout_recycle(context, state, state->line_list);
state->line_list = NULL;
}
if (state->font_stack != NULL)
{
lo_FontStack *fstack;
lo_FontStack *fptr;
fptr = state->font_stack;
while (fptr != NULL)
{
fstack = fptr;
fptr = fptr->next;
XP_DELETE(fstack);
}
state->font_stack = NULL;
}
if (state->align_stack != NULL)
{
lo_AlignStack *aptr;
lo_AlignStack *align;
aptr = state->align_stack;
while (aptr != NULL)
{
align = aptr;
aptr = aptr->next;
XP_DELETE(align);
}
state->align_stack = NULL;
}
if (state->list_stack != NULL)
{
lo_ListStack *lptr;
lo_ListStack *list;
lptr = state->list_stack;
while (lptr != NULL)
{
list = lptr;
lptr = lptr->next;
XP_DELETE(list);
}
state->list_stack = NULL;
}
if (state->line_buf != NULL)
{
PA_FREE(state->line_buf);
state->line_buf = NULL;
}
if (state->float_list != NULL)
{
lo_relayout_recycle(context, state, state->float_list);
state->float_list = NULL;
}
if (state->line_array != NULL)
{
LO_Element *eptr;
#ifdef XP_WIN16
{
XP_Block *larray_array;
intn cnt;
XP_LOCK_BLOCK(larray_array, XP_Block *, state->larray_array);
cnt = state->larray_array_size - 1;
while (cnt > 0)
{
XP_FREE_BLOCK(larray_array[cnt]);
cnt--;
}
state->line_array = larray_array[0];
XP_UNLOCK_BLOCK(state->larray_array);
XP_FREE_BLOCK(state->larray_array);
}
#endif /* XP_WIN16 */
eptr = NULL;
XP_LOCK_BLOCK(line_array, LO_Element **, state->line_array);
eptr = line_array[0];
if (eptr != NULL)
{
lo_relayout_recycle(context, state, eptr);
}
XP_UNLOCK_BLOCK(state->line_array);
XP_FREE_BLOCK(state->line_array);
}
XP_DELETE(state);
}
static lo_FormData *
lo_merge_form_data(lo_FormData *new_form_list, lo_FormData *hold_form_list)
{
intn i;
LO_FormElementStruct **new_ele_list;
LO_FormElementStruct **hold_ele_list;
PA_LOCK(new_ele_list, LO_FormElementStruct **,
new_form_list->form_elements);
PA_LOCK(hold_ele_list, LO_FormElementStruct **,
hold_form_list->form_elements);
for (i=0; i<new_form_list->form_ele_cnt; i++)
{
if (hold_ele_list[i] != new_ele_list[i])
{
#ifdef MOCHA
if (new_ele_list[i]->mocha_object == NULL)
{
new_ele_list[i]->mocha_object
= hold_ele_list[i]->mocha_object;
}
#endif
hold_ele_list[i] = new_ele_list[i];
}
}
PA_UNLOCK(hold_form_list->form_elements);
PA_UNLOCK(new_form_list->form_elements);
#ifdef MOCHA
/* XXX sometimes the second pass does not reflect a form object! */
if (new_form_list->mocha_object != NULL)
{
hold_form_list->mocha_object = new_form_list->mocha_object;
}
#endif
return(hold_form_list);
}
/*
* Serious table magic. Given a table cell subdoc,
* redo the layout to the new width from the stored tag list,
* and create a whole new subdoc, which is returned.
*/
LO_SubDocStruct *
lo_RelayoutSubdoc(MWContext *context, lo_DocState *state,
LO_SubDocStruct *subdoc, int32 width, Bool is_a_header)
{
int32 first_height;
lo_TopState *top_state;
lo_DocState *old_state;
lo_DocState *new_state;
PA_Tag *tag_list;
PA_Tag *tag_ptr;
PA_Tag *tag_end_ptr;
int32 doc_id;
Bool allow_percent_width;
Bool allow_percent_height;
int32 hold_form_ele_cnt;
int32 hold_form_data_index;
intn hold_form_id;
intn hold_current_form_num;
Bool hold_in_form;
lo_FormData *hold_form_list;
int32 hold_embed_global_index;
intn hold_url_list_len;
NET_ReloadMethod save_force;
/*
* Relayout is NOT allowed to block on images, so never
* have the forced reload flag set.
*/
save_force = state->top_state->force_reload;
state->top_state->force_reload = NET_CACHE_ONLY_RELOAD;
#ifdef LOCAL_DEBUG
fprintf(stderr, "lo_RelayoutSubdoc called\n");
#endif /* LOCAL_DEBUG */
top_state = state->top_state;
old_state = (lo_DocState *) subdoc->state;
/*
* We are going to reuse this subdoc element instead
* of allocating a new one.
*/
subdoc->state = NULL;
subdoc->width = width;
subdoc->height = 0;
/*
* If this subdoc contained form elements. We want to reuse
* them without screwing up the order of later form elements in
* other subdocs.
*
* We assume that relaying out the doc will create the exact
* same number of form elements in the same order as the first time.
* so we reset global form counters to before this subdoc
* was ever laid out, saving the current counts to restore later.
*/
if (top_state->form_list != NULL)
{
lo_FormData *form_list;
lo_FormData *tmp_fptr;
hold_form_id = old_state->form_id;
hold_current_form_num = top_state->current_form_num;
form_list = top_state->form_list;
hold_form_list = NULL;
while ((form_list != NULL)&&
(form_list->id > hold_form_id))
{
tmp_fptr = form_list;
form_list = form_list->next;
tmp_fptr->next = hold_form_list;
hold_form_list = tmp_fptr;
}
top_state->form_list = form_list;
top_state->current_form_num = hold_form_id;
if (form_list != NULL)
{
hold_form_ele_cnt = form_list->form_ele_cnt;
form_list->form_ele_cnt = old_state->form_ele_cnt;
}
else
{
hold_form_ele_cnt = 0;
}
}
else
{
hold_form_id = 0;
hold_form_ele_cnt = 0;
hold_form_list = NULL;
hold_current_form_num = 0;
}
/*
* We're going to be deleting and then recreating the contents
* of this subdoc. We want the newly-created embeds to have
* the same embed indices as their recycled counterparts, so
* we reset the master embed index in the top_state to be the
* value it held at the time the old subdoc was created. When
* we're finished creating the new subdoc, the master index
* should be back to its original value (but just in case we
* save that value in a local variable here).
*/
hold_embed_global_index = top_state->embed_count;
top_state->embed_count = old_state->embed_count_base;
/*
* Same goes for anchors.
*/
hold_url_list_len = top_state->url_list_len;
top_state->url_list_len = old_state->url_count_base;
/*
* Save whether we are in a form or not, and restore
* to what we were when the subdoc was started.
*/
hold_in_form = top_state->in_form;
top_state->in_form = old_state->start_in_form;
if (top_state->savedData.FormList != NULL)
{
lo_SavedFormListData *all_form_ele;
all_form_ele = top_state->savedData.FormList;
hold_form_data_index = all_form_ele->data_index;
all_form_ele->data_index = old_state->form_data_index;
}
else
{
hold_form_data_index = 0;
}
/*
* Still variable height, but we know the width now.
*/
first_height = FEUNITS_Y(10000, context);
allow_percent_height = FALSE;
allow_percent_width = TRUE;
/*
* Get a new sub-state to create the new subdoc in.
*/
new_state = lo_NewLayout(context, width, first_height, 0, 0, NULL);
if (new_state == NULL)
{
state->top_state->force_reload = save_force;
return(subdoc);
}
if (old_state->is_a_subdoc == SUBDOC_CAPTION)
{
new_state->is_a_subdoc = SUBDOC_CAPTION;
}
else
{
new_state->is_a_subdoc = SUBDOC_CELL;
}
lo_InheritParentState(new_state, state);
new_state->allow_percent_width = allow_percent_width;
new_state->allow_percent_height = allow_percent_height;
/*
* In relaying out subdocs, we NEVER link back up subdoc tags
*/
new_state->subdoc_tags = NULL;
new_state->subdoc_tags_end = NULL;
/*
* Initialize other new state sundries.
*/
new_state->base_x = 0;
new_state->base_y = 0;
new_state->display_blocked = TRUE;
if (subdoc->width == 0)
{
new_state->delay_align = TRUE;
}
new_state->win_left = 0;
new_state->win_right = 0;
new_state->x = new_state->win_left;
new_state->y = 0;
new_state->max_width = new_state->x + 1;
new_state->left_margin = new_state->win_left;
new_state->right_margin = new_state->win_width - new_state->win_right;
new_state->list_stack->old_left_margin = new_state->left_margin;
new_state->list_stack->old_right_margin = new_state->right_margin;
/*
* Initialize the alignment stack for this state
* to match the caption alignment.
*/
if (subdoc->horiz_alignment != LO_ALIGN_LEFT)
{
PA_Tag tmp_tag;
tmp_tag.type = P_TABLE_DATA;
lo_PushAlignment(new_state, &tmp_tag, subdoc->horiz_alignment);
}
state->sub_state = new_state;
state->current_ele = (LO_Element *)subdoc;
if (is_a_header != FALSE)
{
LO_TextAttr *old_attr;
LO_TextAttr *attr;
LO_TextAttr tmp_attr;
old_attr = new_state->font_stack->text_attr;
lo_CopyTextAttr(old_attr, &tmp_attr);
tmp_attr.fontmask |= LO_FONT_BOLD;
attr = lo_FetchTextAttr(new_state, &tmp_attr);
lo_PushFont(new_state, P_TABLE_HEADER, attr);
}
/*
* Move our current state down into the new sub-state.
* Fetch the tag list from the old subdoc's state in preparation
* for relayout.
*/
state = new_state;
tag_ptr = old_state->subdoc_tags;
tag_end_ptr = old_state->subdoc_tags_end;
old_state->subdoc_tags = NULL;
old_state->subdoc_tags_end = NULL;
if (tag_end_ptr != NULL)
{
tag_end_ptr = tag_end_ptr->next;
}
/*
* Clean up memory used by old subdoc state.
*/
lo_cleanup_state(context, old_state);
while (tag_ptr != tag_end_ptr)
{
PA_Tag *tag;
lo_DocState *sub_state;
lo_DocState *up_state;
lo_DocState *tmp_state;
Bool may_save;
tag = tag_ptr;
tag_ptr = tag_ptr->next;
tag->next = NULL;
tag_list = tag_ptr;
up_state = NULL;
sub_state = state;
while (sub_state->sub_state != NULL)
{
up_state = sub_state;
sub_state = sub_state->sub_state;
}
if ((sub_state->is_a_subdoc == SUBDOC_CELL)||
(sub_state->is_a_subdoc == SUBDOC_CAPTION))
{
may_save = TRUE;
}
else
{
may_save = FALSE;
}
#ifdef MOCHA
sub_state->in_relayout = TRUE;
#endif
lo_LayoutTag(context, sub_state, tag);
tmp_state = lo_CurrentSubState(state);
#ifdef MOCHA
if (tmp_state == sub_state)
{
sub_state->in_relayout = FALSE;
}
#endif
if (may_save != FALSE)
{
/*
* That tag popped us up one state level. If this new
* state is still a subdoc, save the tag there.
*/
if (tmp_state == up_state)
{
if ((tmp_state->is_a_subdoc == SUBDOC_CELL)||
(tmp_state->is_a_subdoc == SUBDOC_CAPTION))
{
lo_SaveSubdocTags(context, tmp_state, tag);
}
else
{
PA_FreeTag(tag);
}
}
/*
* Else that tag put us in a new subdoc on the same
* level. It needs to be saved one level up,
* if the parent is also a subdoc.
*/
else if ((up_state != NULL)&&
(tmp_state == up_state->sub_state)&&
(tmp_state != sub_state))
{
if ((up_state->is_a_subdoc == SUBDOC_CELL)||
(up_state->is_a_subdoc == SUBDOC_CAPTION))
{
lo_SaveSubdocTags(context, up_state, tag);
}
else
{
PA_FreeTag(tag);
}
}
/*
* Else we are still in the same subdoc
*/
else if (tmp_state == sub_state)
{
lo_SaveSubdocTags(context, sub_state, tag);
}
/*
* Else that tag started a new, nested subdoc.
* Add the starting tag to the parent.
*/
else if (tmp_state == sub_state->sub_state)
{
lo_SaveSubdocTags(context, sub_state, tag);
/*
* Since we have extended the parent chain,
* we need to reset the child to the new
* parent end-chain.
*/
if ((tmp_state->is_a_subdoc == SUBDOC_CELL)||
(tmp_state->is_a_subdoc == SUBDOC_CAPTION))
{
tmp_state->subdoc_tags =
sub_state->subdoc_tags_end;
}
}
/*
* This can never happen.
*/
else
{
PA_FreeTag(tag);
}
}
tag_ptr = tag_list;
}
/*
* Link the end of this subdoc's tag chain back to
* its parent. The beginning should have never been
* unlinked from the parent.
*/
if (state->subdoc_tags_end != NULL)
{
state->subdoc_tags_end->next = tag_end_ptr;
}
/*
* makes sure we are at the bottom
* of everything in the document.
*/
lo_CloseOutLayout(context, state);
old_state = state;
/*
* Get the unique document ID, and retreive this
* documents layout state.
*/
doc_id = XP_DOCID(context);
top_state = lo_FetchTopState(doc_id);
state = top_state->doc_state;
while ((state->sub_state != NULL)&&
(state->sub_state != old_state))
{
state = state->sub_state;
}
/*
* Ok, now reset the global form element counters
* to their original values.
*/
if ((top_state->form_list != NULL)||(hold_form_list != NULL))
{
lo_FormData *form_list;
lo_FormData *new_form_list;
lo_FormData *tmp_fptr;
/*
* Remove any new forms created in this subdocs to a
* separate list.
*/
form_list = top_state->form_list;
new_form_list = NULL;
while ((form_list != NULL)&&
(form_list->id > hold_form_id))
{
tmp_fptr = form_list;
form_list = form_list->next;
tmp_fptr->next = new_form_list;
new_form_list = tmp_fptr;
}
/*
* Restore the element count in the form we started in
* because the subdoc may have left it half finished.
*/
if (form_list != NULL)
{
form_list->form_ele_cnt = hold_form_ele_cnt;
}
/*
* Merge the newly created forms with the old ones
* since the new ones may have partially complete
* data.
*/
while ((new_form_list != NULL)&&(hold_form_list != NULL))
{
tmp_fptr = lo_merge_form_data(new_form_list,
hold_form_list);
new_form_list = new_form_list->next;
hold_form_list = hold_form_list->next;
tmp_fptr->next = form_list;
form_list = tmp_fptr;
}
/*
* Add back on forms that are from later subdocs.
*/
while (hold_form_list != NULL)
{
tmp_fptr = hold_form_list;
hold_form_list = hold_form_list->next;
tmp_fptr->next = form_list;
form_list = tmp_fptr;
}
top_state->form_list = form_list;
top_state->current_form_num = hold_current_form_num;
}
/*
* Restore in form status to what is
* was before this relayout.
*/
top_state->in_form = hold_in_form;
if (top_state->savedData.FormList != NULL)
{
lo_SavedFormListData *all_form_ele;
all_form_ele = top_state->savedData.FormList;
all_form_ele->data_index = hold_form_data_index;
}
/*
* The master embed index is typically now be back
* to its original value, but might not be if we
* only had to relayout some (not all) of the embeds
* in this subdoc. So, make sure it's set back to
* its original value here.
*/
top_state->embed_count = hold_embed_global_index;
/*
* Likewise for the anchor list.
*/
top_state->url_list_len = hold_url_list_len;
subdoc = NULL;
if ((state != old_state)&&
(state->current_ele != NULL))
{
subdoc = lo_EndCellSubDoc(context, state,
old_state, state->current_ele);
state->sub_state = NULL;
state->current_ele = NULL;
/*
if ((state->is_a_subdoc == SUBDOC_CELL)||
(state->is_a_subdoc == SUBDOC_CAPTION))
{
if (old_state->subdoc_tags_end != NULL)
{
state->subdoc_tags_end =
old_state->subdoc_tags_end;
}
}
*/
}
old_state->must_relayout_subdoc = FALSE;
state->top_state->force_reload = save_force;
return(subdoc);
}
void
lo_BeginTableCell(MWContext *context, lo_DocState *state, lo_TableRec *table,
PA_Tag *tag, Bool is_a_header)
{
lo_TableRow *table_row;
lo_TableCell *table_cell;
PA_Block buff;
char *str;
int32 val;
#ifdef LOCAL_DEBUG
fprintf(stderr, "lo_BeginTableCell called\n");
#endif /* LOCAL_DEBUG */
table_row = table->row_ptr;
table_cell = XP_NEW(lo_TableCell);
if (table_cell == NULL)
{
return;
}
table_cell->cell_done = FALSE;
table_cell->nowrap = FALSE;
table_cell->is_a_header = is_a_header;
table_cell->percent_width = 0;
table_cell->percent_height = 0;
table_cell->min_width = 0;
table_cell->max_width = 0;
table_cell->height = 0;
table_cell->baseline = 0;
table_cell->rowspan = 1;
table_cell->colspan = 1;
table_cell->cell_subdoc = NULL;
table_cell->next = NULL;
buff = lo_FetchParamValue(context, tag, PARAM_COLSPAN);
if (buff != NULL)
{
PA_LOCK(str, char *, buff);
val = XP_ATOI(str);
if (val < 1)
{
val = 1;
}
table_cell->colspan = val;
PA_UNLOCK(buff);
PA_FREE(buff);
}
buff = lo_FetchParamValue(context, tag, PARAM_ROWSPAN);
if (buff != NULL)
{
PA_LOCK(str, char *, buff);
val = XP_ATOI(str);
if (val < 1)
{
val = 1;
}
table_cell->rowspan = val;
PA_UNLOCK(buff);
PA_FREE(buff);
}
buff = lo_FetchParamValue(context, tag, PARAM_NOWRAP);
if (buff != NULL)
{
table_cell->nowrap = TRUE;
PA_FREE(buff);
}
if (table_row->cell_list == NULL)
{
table_row->cell_list = table_cell;
table_row->cell_ptr = table_cell;
}
else
{
table_row->cell_ptr->next = table_cell;
table_row->cell_ptr = table_cell;
}
lo_BeginCellSubDoc(context, state, table, tag,
is_a_header, table->draw_borders);
}
void
lo_EndTableCell(MWContext *context, lo_DocState *state)
{
LO_SubDocStruct *subdoc;
lo_TableRec *table;
lo_TableRow *table_row;
lo_TableCell *table_cell;
lo_table_span *span_rec;
int32 inner_pad;
int32 i;
lo_TopState *top_state;
lo_DocState *old_state;
int32 doc_id;
#ifdef LOCAL_DEBUG
fprintf(stderr, "lo_EndTableCell called\n");
#endif /* LOCAL_DEBUG */
/*
* makes sure we are at the bottom
* of everything in the document.
*/
lo_CloseOutLayout(context, state);
old_state = state;
/*
* Get the unique document ID, and retreive this
* documents layout state.
*/
doc_id = XP_DOCID(context);
top_state = lo_FetchTopState(doc_id);
state = top_state->doc_state;
while ((state->sub_state != NULL)&&
(state->sub_state != old_state))
{
state = state->sub_state;
}
subdoc = NULL;
if ((state != old_state)&&
(state->current_ele != NULL))
{
subdoc = lo_EndCellSubDoc(context, state,
old_state, state->current_ele);
state->sub_state = NULL;
state->current_ele = NULL;
if ((state->is_a_subdoc == SUBDOC_CELL)||
(state->is_a_subdoc == SUBDOC_CAPTION))
{
if (old_state->subdoc_tags_end != NULL)
{
state->subdoc_tags_end =
old_state->subdoc_tags_end;
}
}
else
{
}
}
table = state->current_table;
table_row = table->row_ptr;
table_cell = table_row->cell_ptr;
inner_pad = FEUNITS_X(table->inner_cell_pad, context);
if (subdoc != NULL)
{
int32 subdoc_width;
int32 subdoc_height;
subdoc_width = subdoc->width +
(2 * subdoc->border_horiz_space) +
(2 * inner_pad);
subdoc_height = subdoc->height +
(2 * subdoc->border_vert_space) +
(2 * inner_pad);
table_cell->max_width = subdoc_width;
table_cell->min_width = old_state->min_width +
(2 * subdoc->border_width) +
(2 * subdoc->border_horiz_space) +
(2 * inner_pad);
if ((table_cell->nowrap != FALSE)||
(table_cell->min_width > table_cell->max_width))
{
table_cell->min_width = table_cell->max_width;
}
table_cell->height = subdoc_height;
table_cell->baseline = lo_GetSubDocBaseline(subdoc);
}
table_cell->cell_subdoc = subdoc;
table_cell->cell_done = TRUE;
i = 0;
while (i < table_cell->colspan)
{
if ((table->width_spans == NULL)||
((table->width_span_ptr != NULL)&&
(table->width_span_ptr->next == NULL)))
{
span_rec = XP_NEW(lo_table_span);
if (span_rec == NULL)
{
return;
}
span_rec->dim = 1;
span_rec->min_dim = 1;
span_rec->span = 0;
span_rec->next = NULL;
if (table->width_spans == NULL)
{
table->width_spans = span_rec;
table->width_span_ptr = span_rec;
}
else
{
table->width_span_ptr->next = span_rec;
table->width_span_ptr = span_rec;
}
}
else
{
if (table->width_span_ptr == NULL)
{
table->width_span_ptr = table->width_spans;
}
else
{
table->width_span_ptr =
table->width_span_ptr->next;
}
span_rec = table->width_span_ptr;
}
if (span_rec->span > 0)
{
span_rec->span--;
table_row->cells++;
/*
* This only happens if a colspan on this
* row overlaps a rowspan from a previous row.
*/
if (i > 0)
{
int32 new_span;
new_span = table_cell->rowspan - 1;
if (new_span > span_rec->span)
{
span_rec->span = new_span;
}
i++;
/*
* Don't count this cell twice.
*/
table_row->cells--;
}
continue;
}
else
{
span_rec->span = table_cell->rowspan - 1;
i++;
if (table_cell->colspan == 1)
{
if (table_cell->max_width > span_rec->dim)
{
span_rec->dim = table_cell->max_width;
}
if (table_cell->min_width > span_rec->min_dim)
{
span_rec->min_dim = table_cell->min_width;
}
}
}
}
span_rec = table->height_span_ptr;
if (table_cell->rowspan == 1)
{
int32 tmp_val;
tmp_val = table_cell->baseline - span_rec->min_dim;
if (tmp_val > 0)
{
span_rec->min_dim += tmp_val;
if (table_row->vert_alignment == LO_ALIGN_BASELINE)
{
span_rec->dim += tmp_val;
}
}
if (table_row->vert_alignment == LO_ALIGN_BASELINE)
{
tmp_val = (table_cell->height - table_cell->baseline) -
(span_rec->dim - span_rec->min_dim);
if (tmp_val > 0)
{
span_rec->dim += tmp_val;
}
}
else
{
if (table_cell->height > span_rec->dim)
{
span_rec->dim = table_cell->height;
}
}
}
table_row->cells += table_cell->colspan;
}
void
lo_BeginTableCaption(MWContext *context, lo_DocState *state, lo_TableRec *table,
PA_Tag *tag)
{
lo_TableCaption *caption;
PA_Block buff;
char *str;
caption = XP_NEW(lo_TableCaption);
if (caption == NULL)
{
return;
}
caption->vert_alignment = LO_ALIGN_TOP;
caption->horiz_alignment = LO_ALIGN_CENTER;
caption->min_width = 0;
caption->max_width = 0;
caption->height = 0;
caption->subdoc = NULL;
/*
* Check for an align parameter
*/
buff = lo_FetchParamValue(context, tag, PARAM_ALIGN);
if (buff != NULL)
{
PA_LOCK(str, char *, buff);
if (pa_TagEqual("bottom", str))
{
caption->vert_alignment = LO_ALIGN_BOTTOM;
}
PA_UNLOCK(buff);
PA_FREE(buff);
}
table->caption = caption;
lo_BeginCaptionSubDoc(context, state, caption, tag);
}
void
lo_EndTableCaption(MWContext *context, lo_DocState *state)
{
LO_SubDocStruct *subdoc;
lo_TableRec *table;
lo_TableCaption *caption;
lo_TopState *top_state;
lo_DocState *old_state;
int32 doc_id;
int32 inner_pad;
/*
* makes sure we are at the bottom
* of everything in the document.
*/
lo_CloseOutLayout(context, state);
old_state = state;
/*
* Get the unique document ID, and retreive this
* documents layout state.
*/
doc_id = XP_DOCID(context);
top_state = lo_FetchTopState(doc_id);
state = top_state->doc_state;
while ((state->sub_state != NULL)&&
(state->sub_state != old_state))
{
state = state->sub_state;
}
subdoc = NULL;
if ((state != old_state)&&
(state->current_ele != NULL))
{
subdoc = lo_EndCellSubDoc(context, state,
old_state, state->current_ele);
state->sub_state = NULL;
state->current_ele = NULL;
if ((state->is_a_subdoc == SUBDOC_CELL)||
(state->is_a_subdoc == SUBDOC_CAPTION))
{
if (old_state->subdoc_tags_end != NULL)
{
state->subdoc_tags_end =
old_state->subdoc_tags_end;
}
}
}
table = state->current_table;
caption = table->caption;
inner_pad = FEUNITS_X(table->inner_cell_pad, context);
if (subdoc != NULL)
{
int32 subdoc_width;
int32 subdoc_height;
subdoc_width = subdoc->width +
(2 * subdoc->border_horiz_space) +
(2 * inner_pad);
subdoc_height = subdoc->height +
(2 * subdoc->border_vert_space) +
(2 * inner_pad);
caption->max_width = subdoc_width;
caption->min_width = old_state->min_width +
(2 * subdoc->border_width) +
(2 * subdoc->border_horiz_space) +
(2 * inner_pad);
if (caption->min_width > caption->max_width)
{
caption->min_width = caption->max_width;
}
caption->height = subdoc_height;
}
caption->subdoc = subdoc;
}
void
lo_BeginTableRow(MWContext *context, lo_DocState *state, lo_TableRec *table,
PA_Tag *tag)
{
lo_TableRow *table_row;
lo_table_span *span_rec;
PA_Block buff;
char *str;
#ifdef LOCAL_DEBUG
fprintf(stderr, "lo_BeginTableRow called\n");
#endif /* LOCAL_DEBUG */
table_row = XP_NEW(lo_TableRow);
if (table_row == NULL)
{
return;
}
table_row->row_done = FALSE;
table_row->has_percent_width_cells = FALSE;
table_row->bg_color = NULL;
table_row->cells = 0;
table_row->vert_alignment = LO_ALIGN_DEFAULT;
table_row->horiz_alignment = LO_ALIGN_DEFAULT;
table_row->cell_list = NULL;
table_row->cell_ptr = NULL;
table_row->next = NULL;
/*
* Check for a background color attribute
*/
buff = lo_FetchParamValue(context, tag, PARAM_BGCOLOR);
if (buff != NULL)
{
uint8 red, green, blue;
PA_LOCK(str, char *, buff);
LO_ParseRGB(str, &red, &green, &blue);
PA_UNLOCK(buff);
PA_FREE(buff);
table_row->bg_color = XP_NEW(LO_Color);
if (table_row->bg_color != NULL)
{
table_row->bg_color->red = red;
table_row->bg_color->green = green;
table_row->bg_color->blue = blue;
}
}
/*
* Check for a vertical align parameter
*/
buff = lo_FetchParamValue(context, tag, PARAM_VALIGN);
if (buff != NULL)
{
PA_LOCK(str, char *, buff);
table_row->vert_alignment = lo_EvalVAlignParam(str);
PA_UNLOCK(buff);
PA_FREE(buff);
}
/*
* Check for a horizontal align parameter
*/
buff = lo_FetchParamValue(context, tag, PARAM_ALIGN);
if (buff != NULL)
{
PA_LOCK(str, char *, buff);
table_row->horiz_alignment = lo_EvalCellAlignParam(str);
PA_UNLOCK(buff);
PA_FREE(buff);
}
if (table->row_list == NULL)
{
table->row_list = table_row;
table->row_ptr = table_row;
}
else
{
table->row_ptr->next = table_row;
table->row_ptr = table_row;
}
table->width_span_ptr = NULL;
span_rec = XP_NEW(lo_table_span);
if (span_rec == NULL)
{
return;
}
span_rec->dim = 1;
/*
* Since min_dim on the heights is never used.
* I am appropriating it to do baseline aligning. It will
* start as 0, and eventually be the amount of baseline needed
* to align all these cells in this row
* by their baselines.
*/
span_rec->min_dim = 0;
span_rec->span = 0;
span_rec->next = NULL;
if (table->height_spans == NULL)
{
table->height_spans = span_rec;
table->height_span_ptr = span_rec;
}
else
{
table->height_span_ptr->next = span_rec;
table->height_span_ptr = span_rec;
}
}
void
lo_EndTableRow(MWContext *context, lo_DocState *state, lo_TableRec *table)
{
lo_TableRow *table_row;
#ifdef LOCAL_DEBUG
fprintf(stderr, "lo_EndTableRow called\n");
#endif /* LOCAL_DEBUG */
table_row = table->row_ptr;
table_row->row_done = TRUE;
table->rows++;
while (table->width_span_ptr != NULL)
{
table->width_span_ptr = table->width_span_ptr->next;
if (table->width_span_ptr != NULL)
{
table->width_span_ptr->span--;
table_row->cells++;
}
}
if (table_row->cells > table->cols)
{
table->cols = table_row->cells;
}
}
void
lo_BeginTable(MWContext *context, lo_DocState *state, PA_Tag *tag)
{
lo_TableRec *table;
LO_TableStruct *table_ele;
PA_Block buff;
char *str;
int32 val;
Bool allow_percent_width;
Bool allow_percent_height;
#ifdef LOCAL_DEBUG
fprintf(stderr, "lo_BeginTable called\n");
#endif /* LOCAL_DEBUG */
if (state == NULL)
{
return;
}
table_ele = (LO_TableStruct *)lo_NewElement(context, state, LO_TABLE, NULL, 0);
if (table_ele == NULL)
{
state->top_state->out_of_memory = TRUE;
return;
}
table_ele->type = LO_TABLE;
table_ele->ele_id = NEXT_ELEMENT;
table_ele->x = state->x;
table_ele->x_offset = 0;
table_ele->y = state->y;
table_ele->y_offset = 0;
table_ele->width = 0;
table_ele->height = 0;
table_ele->line_height = 0;
table_ele->FE_Data = NULL;
table_ele->anchor_href = state->current_anchor;
table_ele->alignment = LO_ALIGN_CENTER;
table_ele->border_width = TABLE_DEF_BORDER;
table_ele->border_vert_space = TABLE_DEF_VERTICAL_SPACE;
table_ele->border_horiz_space = TABLE_DEF_HORIZONTAL_SPACE;
table_ele->ele_attrmask = 0;
table_ele->sel_start = -1;
table_ele->sel_end = -1;
table_ele->next = NULL;
table_ele->prev = NULL;
/*
* Check for an align parameter
*/
buff = lo_FetchParamValue(context, tag, PARAM_ALIGN);
if (buff != NULL)
{
Bool floating;
floating = FALSE;
PA_LOCK(str, char *, buff);
table_ele->alignment = lo_EvalAlignParam(str, &floating);
/*
* Only allow left and right (floating) and center.
*/
if (floating != FALSE)
{
table_ele->ele_attrmask |= LO_ELE_FLOATING;
}
else
{
table_ele->alignment = LO_ALIGN_CENTER;
}
PA_UNLOCK(buff);
PA_FREE(buff);
}
/*
* Get the border parameter.
*/
buff = lo_FetchParamValue(context, tag, PARAM_BORDER);
if (buff != NULL)
{
PA_LOCK(str, char *, buff);
val = XP_ATOI(str);
if ((val == 0)&&(*str == '0'))
{
val = -1;
}
else if (val < 1)
{
val = 1;
}
table_ele->border_width = val;
PA_UNLOCK(buff);
PA_FREE(buff);
}
table_ele->border_width = FEUNITS_X(table_ele->border_width, context);
/*
* Get the extra vertical space parameter.
*/
buff = lo_FetchParamValue(context, tag, PARAM_VSPACE);
if (buff != NULL)
{
PA_LOCK(str, char *, buff);
val = XP_ATOI(str);
if (val < 0)
{
val = 0;
}
table_ele->border_vert_space = val;
PA_UNLOCK(buff);
PA_FREE(buff);
}
table_ele->border_vert_space = FEUNITS_Y(table_ele->border_vert_space,
context);
/*
* Get the extra horizontal space parameter.
*/
buff = lo_FetchParamValue(context, tag, PARAM_HSPACE);
if (buff != NULL)
{
PA_LOCK(str, char *, buff);
val = XP_ATOI(str);
if (val < 0)
{
val = 0;
}
table_ele->border_horiz_space = val;
PA_UNLOCK(buff);
PA_FREE(buff);
}
table_ele->border_horiz_space = FEUNITS_X(table_ele->border_horiz_space,
context);
table = XP_NEW(lo_TableRec);
if (table == NULL)
{
return;
}
if (table_ele->border_width < 0)
{
table->draw_borders = TABLE_BORDERS_GONE;
table_ele->border_width = 0;
}
else if (table_ele->border_width == 0)
{
table->draw_borders = TABLE_BORDERS_OFF;
}
else
{
table->draw_borders = TABLE_BORDERS_ON;
}
table->has_percent_width_cells = FALSE;
table->has_percent_height_cells = FALSE;
table->bg_color = NULL;
table->rows = 0;
table->cols = 0;
table->width_spans = NULL;
table->width_span_ptr = NULL;
table->height_spans = NULL;
table->height_span_ptr = NULL;
table->caption = NULL;
table->table_ele = table_ele;
table->row_list = NULL;
table->row_ptr = NULL;
table->width = 0;
table->height = 0;
table->inner_cell_pad = TABLE_DEF_INNER_CELL_PAD;
table->inter_cell_pad = TABLE_DEF_INTER_CELL_PAD;
/*
* You can't do percentage widths if the parent's
* width is still undecided.
*/
allow_percent_width = TRUE;
allow_percent_height = TRUE;
if ((state->is_a_subdoc == SUBDOC_CELL)||
(state->is_a_subdoc == SUBDOC_CAPTION))
{
lo_TopState *top_state;
lo_DocState *new_state;
int32 doc_id;
/*
* Get the unique document ID, and retreive this
* documents layout state.
*/
doc_id = XP_DOCID(context);
top_state = lo_FetchTopState(doc_id);
new_state = top_state->doc_state;
while ((new_state->sub_state != NULL)&&
(new_state->sub_state != state))
{
new_state = new_state->sub_state;
}
if ((new_state->sub_state == state)&&
(new_state->current_ele != NULL))
{
LO_SubDocStruct *subdoc;
subdoc = (LO_SubDocStruct *)new_state->current_ele;
if (subdoc->width == 0)
{
allow_percent_width = FALSE;
#ifdef LOCAL_DEBUG
fprintf(stderr, "Percent width not allowed in this subdoc!\n");
#endif /* LOCAL_DEBUG */
}
else
{
#ifdef LOCAL_DEBUG
fprintf(stderr, "Percent width IS allowed in this subdoc!\n");
#endif /* LOCAL_DEBUG */
}
if (subdoc->height == 0)
{
allow_percent_height = FALSE;
}
}
}
/*
* Check for a background color attribute
*/
buff = lo_FetchParamValue(context, tag, PARAM_BGCOLOR);
if (buff != NULL)
{
uint8 red, green, blue;
PA_LOCK(str, char *, buff);
LO_ParseRGB(str, &red, &green, &blue);
PA_UNLOCK(buff);
PA_FREE(buff);
table->bg_color = XP_NEW(LO_Color);
if (table->bg_color != NULL)
{
table->bg_color->red = red;
table->bg_color->green = green;
table->bg_color->blue = blue;
}
}
/*
* Get the width and height parameters, in absolute or percentage.
* If percentage, make it absolute.
*/
buff = lo_FetchParamValue(context, tag, PARAM_WIDTH);
if (buff != NULL)
{
Bool is_percent;
PA_LOCK(str, char *, buff);
val = lo_ValueOrPercent(str, &is_percent);
if (is_percent != FALSE)
{
if (allow_percent_width == FALSE)
{
val = 0;
}
else
{
val = (state->win_width - state->win_left -
state->win_right) * val / 100;
}
}
else
{
val = FEUNITS_X(val, context);
}
table->width = val;
if (table->width < 0)
{
table->width = 0;
}
PA_UNLOCK(buff);
PA_FREE(buff);
}
buff = lo_FetchParamValue(context, tag, PARAM_HEIGHT);
if (buff != NULL)
{
Bool is_percent;
PA_LOCK(str, char *, buff);
val = lo_ValueOrPercent(str, &is_percent);
if (is_percent != FALSE)
{
if (allow_percent_height == FALSE)
{
val = 0;
}
else
{
val = (state->win_height - state->win_top -
state->win_bottom) * val / 100;
}
}
else
{
val = FEUNITS_X(val, context);
}
table->height = val;
if (table->height < 0)
{
table->height = 0;
}
PA_UNLOCK(buff);
PA_FREE(buff);
}
buff = lo_FetchParamValue(context, tag, PARAM_CELLPAD);
if (buff != NULL)
{
PA_LOCK(str, char *, buff);
val = XP_ATOI(str);
if (val < 0)
{
val = 0;
}
table->inner_cell_pad = val;
PA_UNLOCK(buff);
PA_FREE(buff);
}
buff = lo_FetchParamValue(context, tag, PARAM_CELLSPACE);
if (buff != NULL)
{
PA_LOCK(str, char *, buff);
val = XP_ATOI(str);
if (val < 0)
{
val = 0;
}
table->inter_cell_pad = val;
PA_UNLOCK(buff);
PA_FREE(buff);
}
state->current_table = table;
}
static void
lo_fill_cell_array(lo_TableRec *table, lo_cell_data XP_HUGE *cell_array,
lo_TableCell *blank_cell, int32 cell_pad, Bool *relayout_pass)
{
int32 x, y;
int32 indx;
lo_table_span *row_max;
lo_table_span *col_max;
lo_TableRow *row_ptr;
lo_TableCell *cell_ptr;
row_max = table->height_spans;
row_ptr = table->row_list;
for (y = 0; y < table->rows; y++)
{
x = 0;
col_max = table->width_spans;
cell_ptr = row_ptr->cell_list;
while (cell_ptr != NULL)
{
lo_DocState *subdoc_state;
/*
* Also on this pass check if any of the cells
* NEED to be relaid out later.
*/
subdoc_state =
(lo_DocState *)cell_ptr->cell_subdoc->state;
if (subdoc_state->must_relayout_subdoc != FALSE)
{
*relayout_pass = TRUE;
}
/*
* "fix" up badly specified row spans.
*/
if ((y + cell_ptr->rowspan) > table->rows)
{
cell_ptr->rowspan = table->rows - y;
if (cell_ptr->rowspan == 1)
{
if (cell_ptr->height > row_max->dim)
{
row_max->dim = cell_ptr->height;
}
}
}
indx = (y * table->cols) + x;
if (cell_array[indx].cell == blank_cell)
{
x++;
col_max = col_max->next;
continue;
}
cell_array[indx].cell = cell_ptr;
cell_array[indx].width = cell_ptr->max_width;
cell_array[indx].height = cell_ptr->height;
if (cell_ptr->colspan > 1)
{
int32 i;
int32 width, min_width;
lo_table_span *max_ptr;
max_ptr = col_max;
width = max_ptr->dim;
min_width = max_ptr->min_dim;
for (i=1; i < cell_ptr->colspan; i++)
{
cell_array[indx + i].cell = blank_cell;
max_ptr = max_ptr->next;
width = width + cell_pad + max_ptr->dim;
min_width = min_width + cell_pad +
max_ptr->min_dim;
}
if (width < cell_ptr->max_width)
{
int32 add_width;
int32 add;
lo_table_span *add_ptr;
add_ptr = col_max;
add_width = cell_ptr->max_width -
width;
add = 0;
while (add_ptr != max_ptr)
{
int32 newWidth;
newWidth = add_width *
add_ptr->dim / width;
add_ptr->dim += newWidth;
add += newWidth;
add_ptr = add_ptr->next;
}
add_ptr->dim += (add_width - add);
}
if (min_width < cell_ptr->min_width)
{
int32 add_width;
int32 add;
lo_table_span *add_ptr;
add_ptr = col_max;
add_width = cell_ptr->min_width -
min_width;
add = 0;
while (add_ptr != max_ptr)
{
int32 newWidth;
newWidth = add_width *
add_ptr->min_dim /
min_width;
/*
* We are not allowed to add
* enough to put min_dim > dim.
*/
if ((add_ptr->min_dim +
newWidth) > add_ptr->dim)
{
newWidth = add_ptr->dim -
add_ptr->min_dim;
/*
* don't let newWidth become
* negative.
*/
if (newWidth < 0)
{
newWidth = 0;
}
}
add_ptr->min_dim += newWidth;
add += newWidth;
add_ptr = add_ptr->next;
}
add_ptr->min_dim += (add_width - add);
}
col_max = max_ptr;
}
if (cell_ptr->rowspan > 1)
{
int32 i;
int32 height;
int32 tmp_val;
lo_table_span *max_ptr;
max_ptr = row_max;
height = max_ptr->dim;
for (i=1; i < cell_ptr->rowspan; i++)
{
cell_array[indx + (i * table->cols)].cell =
blank_cell;
if (cell_ptr->colspan > 1)
{
int32 j;
for (j=1; j < cell_ptr->colspan; j++)
{
cell_array[indx +
(i * table->cols) + j].cell =
blank_cell;
}
}
max_ptr = max_ptr->next;
height = height + cell_pad + max_ptr->dim;
}
tmp_val = cell_ptr->baseline - row_max->min_dim;
if (tmp_val > 0)
{
row_max->min_dim += tmp_val;
if (row_ptr->vert_alignment ==
LO_ALIGN_BASELINE)
{
row_max->dim += tmp_val;
height += tmp_val;
}
}
if (height < cell_ptr->height)
{
int32 add_height;
int32 add;
lo_table_span *add_ptr;
add_ptr = row_max;
add_height = cell_ptr->height -
height;
add = 0;
while (add_ptr != max_ptr)
{
int32 newHeight;
newHeight = add_height *
add_ptr->dim / height;
add_ptr->dim += newHeight;
add += newHeight;
add_ptr = add_ptr->next;
}
add_ptr->dim += (add_height - add);
}
}
x += cell_ptr->colspan;
col_max = col_max->next;
cell_ptr = cell_ptr->next;
cell_array[indx].cell->next = NULL;
}
row_ptr = row_ptr->next;
row_max = row_max->next;
}
}
static void
lo_percent_width_cells(lo_TableRec *table, lo_cell_data XP_HUGE *cell_array,
lo_TableCell *blank_cell, int32 cell_pad, int32 table_pad,
int32 *table_width, int32 *min_table_width)
{
int32 x, y;
int32 indx;
int32 new_table_width;
int32 new_min_table_width;
Bool need_pass_two;
lo_table_span *row_max;
lo_table_span *col_max;
lo_TableRow *row_ptr;
lo_TableCell *cell_ptr;
new_table_width = 0;
row_ptr = table->row_list;
row_max = table->height_spans;
for (y=0; y < table->rows; y++)
{
if (row_ptr->has_percent_width_cells != FALSE)
{
int32 reserve;
int32 unknown, unknown_base;
unknown = 0;
unknown_base = 0;
reserve = 100 - table->cols;
col_max = table->width_spans;
for (x=0; x < table->cols; x++)
{
indx = (y * table->cols) + x;
cell_ptr = cell_array[indx].cell;
if ((cell_ptr == blank_cell)||
(cell_ptr == NULL))
{
col_max = col_max->next;
continue;
}
if (cell_ptr->percent_width > 0)
{
int32 width;
reserve += cell_ptr->colspan;
if (cell_ptr->percent_width > reserve)
{
cell_ptr->percent_width = reserve;
reserve = 0;
}
else
{
reserve -= cell_ptr->percent_width;
}
width = cell_ptr->max_width * 100 /
cell_ptr->percent_width;
if (width > new_table_width)
{
new_table_width = width;
}
}
else
{
unknown++;
unknown_base += cell_ptr->max_width;
}
col_max = col_max->next;
}
if (unknown)
{
col_max = table->width_spans;
for (x=0; x < table->cols; x++)
{
indx = (y * table->cols) + x;
cell_ptr = cell_array[indx].cell;
if ((cell_ptr == blank_cell)||
(cell_ptr == NULL))
{
col_max = col_max->next;
continue;
}
if (cell_ptr->percent_width == 0)
{
int32 width;
int32 percent;
if (unknown == 1)
{
percent = reserve;
}
else
{
percent = reserve *
cell_ptr->max_width /
unknown_base;
}
reserve -= percent;
if (reserve < 0)
{
reserve = 0;
}
percent += cell_ptr->colspan;
cell_ptr->percent_width = percent;
width = cell_ptr->max_width * 100 /
cell_ptr->percent_width;
if (width > new_table_width)
{
new_table_width = width;
}
unknown--;
}
col_max = col_max->next;
}
}
}
else
{
int32 width;
width = 0;
col_max = table->width_spans;
for (x=0; x < table->cols; x++)
{
indx = (y * table->cols) + x;
cell_ptr = cell_array[indx].cell;
if ((cell_ptr == blank_cell)||
(cell_ptr == NULL))
{
col_max = col_max->next;
continue;
}
width += cell_ptr->max_width;
col_max = col_max->next;
}
if (width > new_table_width)
{
new_table_width = width;
}
}
row_ptr = row_ptr->next;
row_max = row_max->next;
}
if (*table_width > new_table_width)
{
new_table_width = *table_width;
}
/*
* If we already know how wide this table must be
* Use that width when calculate percentage cell widths.
*/
if ((table->width > 0)&&(table->width >= *min_table_width))
{
new_table_width = table->width;
}
need_pass_two = FALSE;
col_max = table->width_spans;
for (x=0; x < table->cols; x++)
{
int32 current_max;
current_max = col_max->dim;
col_max->dim = 1;
row_max = table->height_spans;
for (y=0; y < table->rows; y++)
{
indx = (y * table->cols) + x;
cell_ptr = cell_array[indx].cell;
if ((cell_ptr == blank_cell)||
(cell_ptr == NULL))
{
row_max = row_max->next;
continue;
}
if ((cell_ptr->percent_width > 0)&&
(cell_ptr->colspan == 1))
{
int32 p_width;
p_width = new_table_width *
cell_ptr->percent_width / 100;
if (p_width < cell_ptr->min_width)
{
p_width = cell_ptr->min_width;
}
if (p_width > col_max->dim)
{
col_max->dim = p_width;
}
}
else if (cell_ptr->colspan > 1)
{
need_pass_two = TRUE;
}
else
{
if (cell_ptr->max_width > col_max->dim)
{
col_max->dim =
cell_ptr->max_width;
}
}
row_max = row_max->next;
}
if (col_max->dim < col_max->min_dim)
{
col_max->dim = col_max->min_dim;
}
col_max = col_max->next;
}
/*
* Take care of spanning columns if any
*/
if (need_pass_two != FALSE)
{
row_max = table->height_spans;
for (y=0; y < table->rows; y++)
{
col_max = table->width_spans;
for (x=0; x < table->cols; x++)
{
indx = (y * table->cols) + x;
cell_ptr = cell_array[indx].cell;
if ((cell_ptr == blank_cell)||
(cell_ptr == NULL))
{
col_max = col_max->next;
continue;
}
if (cell_ptr->colspan > 1)
{
int32 i;
int32 width;
lo_table_span *max_ptr;
int32 p_width;
int32 new_width;
new_width = cell_ptr->max_width;
if (cell_ptr->percent_width > 0)
{
p_width = new_table_width *
cell_ptr->percent_width / 100;
if (p_width >= cell_ptr->min_width)
{
new_width = p_width;
}
}
max_ptr = col_max;
width = max_ptr->dim;
for (i=1; i < cell_ptr->colspan; i++)
{
max_ptr = max_ptr->next;
width = width + cell_pad +
max_ptr->dim;
}
if (width < new_width)
{
int32 add_width;
int32 add;
lo_table_span *add_ptr;
add_ptr = col_max;
add_width = new_width - width;
add = 0;
while (add_ptr != max_ptr)
{
int32 newWidth;
newWidth = add_width *
add_ptr->dim /
width;
add_ptr->dim +=newWidth;
add += newWidth;
add_ptr = add_ptr->next;
}
add_ptr->dim += (add_width -
add);
}
}
col_max = col_max->next;
}
row_max = row_max->next;
}
}
new_table_width = 0;
new_min_table_width = 0;
col_max = table->width_spans;
while (col_max != NULL)
{
new_table_width = new_table_width + cell_pad +
col_max->dim;
new_min_table_width = new_min_table_width + cell_pad +
col_max->min_dim;
col_max = col_max->next;
}
new_table_width += cell_pad;
new_table_width += (2 * table->table_ele->border_width);
new_min_table_width += cell_pad;
new_min_table_width += (2 * table->table_ele->border_width);
if (table->draw_borders == TABLE_BORDERS_OFF)
{
new_table_width += (2 * table_pad);
new_min_table_width += (2 * table_pad);
}
*table_width = new_table_width;
*min_table_width = new_min_table_width;
}
static void
lo_cell_relayout_pass(MWContext *context, lo_DocState *state,
lo_TableRec *table, lo_cell_data XP_HUGE *cell_array, lo_TableCell *blank_cell,
int32 cell_pad, int32 inner_pad, Bool *rowspan_pass)
{
int32 x, y;
int32 indx;
lo_table_span *row_max;
lo_table_span *col_max;
lo_TableRow *row_ptr;
lo_TableCell *cell_ptr;
row_ptr = table->row_list;
row_max = table->height_spans;
for (y=0; y < table->rows; y++)
{
col_max = table->width_spans;
for (x=0; x < table->cols; x++)
{
lo_DocState *subdoc_state;
LO_SubDocStruct *subdoc;
int32 width;
Bool has_elements;
indx = (y * table->cols) + x;
cell_ptr = cell_array[indx].cell;
if ((cell_ptr == blank_cell)||
(cell_ptr == NULL))
{
col_max = col_max->next;
continue;
}
subdoc = cell_ptr->cell_subdoc;
subdoc_state = (lo_DocState *)subdoc->state;
width = col_max->dim;
if (cell_ptr->colspan > 1)
{
int32 i;
lo_table_span *max_ptr;
max_ptr = col_max;
for (i=1; i < cell_ptr->colspan; i++)
{
max_ptr = max_ptr->next;
width = width + cell_pad +
max_ptr->dim;
}
}
/*
* Don't relayout documents that have no
* elements, it causes errors.
*/
has_elements = lo_subdoc_has_elements(subdoc_state);
if ((width < cell_ptr->max_width)&&
(has_elements == FALSE))
{
int32 inside_width;
inside_width = width -
(2 * subdoc->border_width) -
(2 * subdoc->border_horiz_space) -
(2 * inner_pad);
subdoc->width = inside_width;
}
else if (width < cell_ptr->max_width)
{
int32 inside_width;
inside_width = width -
(2 * subdoc->border_width) -
(2 * subdoc->border_horiz_space) -
(2 * inner_pad);
cell_ptr->cell_subdoc =
lo_RelayoutSubdoc(context,
state, subdoc, inside_width,
cell_ptr->is_a_header);
subdoc = cell_ptr->cell_subdoc;
cell_ptr->baseline =
lo_GetSubDocBaseline(subdoc);
if (cell_ptr->rowspan == 1)
{
int32 subdoc_height;
int32 tmp_val;
subdoc_height = subdoc->height +
(2 * inner_pad) +
(2 * subdoc->border_vert_space);
tmp_val = cell_ptr->baseline -
row_max->min_dim;
if (tmp_val > 0)
{
row_max->min_dim += tmp_val;
if (row_ptr->vert_alignment ==
LO_ALIGN_BASELINE)
{
row_max->dim += tmp_val;
}
}
if (row_ptr->vert_alignment ==
LO_ALIGN_BASELINE)
{
tmp_val = (subdoc_height -
cell_ptr->baseline) -
(row_max->dim -
row_max->min_dim);
if (tmp_val > 0)
{
row_max->dim += tmp_val;
}
}
else
{
if (subdoc_height >
row_max->dim)
{
row_max->dim =
subdoc_height;
}
}
}
else
{
*rowspan_pass = TRUE;
}
}
else if ((subdoc_state->must_relayout_subdoc != FALSE)&&
(has_elements == FALSE))
{
int32 inside_width;
inside_width = width -
(2 * subdoc->border_width) -
(2 * subdoc->border_horiz_space) -
(2 * inner_pad);
subdoc->width = inside_width;
subdoc_state->must_relayout_subdoc = FALSE;
}
else if (subdoc_state->must_relayout_subdoc !=
FALSE)
{
int32 inside_width;
inside_width = width -
(2 * subdoc->border_width) -
(2 * subdoc->border_horiz_space) -
(2 * inner_pad);
cell_ptr->cell_subdoc =
lo_RelayoutSubdoc(context,
state, subdoc, inside_width,
cell_ptr->is_a_header);
subdoc = cell_ptr->cell_subdoc;
cell_ptr->baseline =
lo_GetSubDocBaseline(subdoc);
if (cell_ptr->rowspan == 1)
{
int32 subdoc_height;
int32 tmp_val;
subdoc_height = subdoc->height +
(2 * inner_pad) +
(2 * subdoc->border_vert_space);
tmp_val = cell_ptr->baseline -
row_max->min_dim;
if (tmp_val > 0)
{
row_max->min_dim += tmp_val;
if (row_ptr->vert_alignment ==
LO_ALIGN_BASELINE)
{
row_max->dim += tmp_val;
}
}
if (row_ptr->vert_alignment ==
LO_ALIGN_BASELINE)
{
tmp_val = (subdoc_height -
cell_ptr->baseline) -
(row_max->dim -
row_max->min_dim);
if (tmp_val > 0)
{
row_max->dim += tmp_val;
}
}
else
{
if (subdoc_height >
row_max->dim)
{
row_max->dim =
subdoc_height;
}
}
}
else
{
*rowspan_pass = TRUE;
}
}
col_max = col_max->next;
}
row_max = row_max->next;
row_ptr = row_ptr->next;
}
}
static void
lo_cell_rowspan_pass(lo_TableRec *table, lo_cell_data XP_HUGE *cell_array,
lo_TableCell *blank_cell, int32 cell_pad, int32 inner_pad)
{
int32 x, y;
int32 indx;
lo_table_span *row_max;
lo_table_span *col_max;
lo_TableRow *row_ptr;
lo_TableCell *cell_ptr;
row_max = table->height_spans;
row_ptr = table->row_list;
for (y=0; y < table->rows; y++)
{
col_max = table->width_spans;
for (x=0; x < table->cols; x++)
{
LO_SubDocStruct *subdoc;
indx = (y * table->cols) + x;
cell_ptr = cell_array[indx].cell;
if ((cell_ptr == blank_cell)||
(cell_ptr == NULL))
{
col_max = col_max->next;
continue;
}
subdoc = cell_ptr->cell_subdoc;
if (cell_ptr->rowspan > 1)
{
int32 i;
int32 height;
int32 tmp_val;
int32 subdoc_height;
lo_table_span *max_ptr;
max_ptr = row_max;
height = max_ptr->dim;
for (i=1; i < cell_ptr->rowspan; i++)
{
max_ptr = max_ptr->next;
height = height + cell_pad +
max_ptr->dim;
}
tmp_val = cell_ptr->baseline -
row_max->min_dim;
if (tmp_val > 0)
{
row_max->min_dim += tmp_val;
if (row_ptr->vert_alignment ==
LO_ALIGN_BASELINE)
{
row_max->dim += tmp_val;
height += tmp_val;
}
}
subdoc_height = subdoc->height +
(2 * inner_pad) +
(2 * subdoc->border_vert_space);
if (height < subdoc_height)
{
int32 add_height;
int32 add;
lo_table_span *add_ptr;
add_ptr = row_max;
add_height = subdoc_height -
height;
add = 0;
while (add_ptr != max_ptr)
{
int32 newHeight;
newHeight = add_height *
add_ptr->dim /
height;
add_ptr->dim +=
newHeight;
add += newHeight;
add_ptr = add_ptr->next;
}
add_ptr->dim +=
(add_height - add);
}
}
col_max = col_max->next;
}
row_max = row_max->next;
row_ptr = row_ptr->next;
}
}
static void
#ifdef SCARY_LEAK_FIX
lo_free_row_record(lo_TableRow *row, Bool partial)
#else
lo_free_row_record(lo_TableRow *row)
#endif /* SCARY_LEAK_FIX */
{
#ifdef SCARY_LEAK_FIX
lo_TableCell *cell_ptr;
lo_TableCell *cell;
#endif /* SCARY_LEAK_FIX */
if (row->cell_list != NULL)
{
/*
* These are already freed on a completed table, and
* need to be freed on a partial table.
*/
#ifdef SCARY_LEAK_FIX
if (partial != FALSE)
{
cell_ptr = row->cell_list;
while (cell_ptr != NULL)
{
cell = cell_ptr;
cell_ptr = cell_ptr->next;
XP_DELETE(cell);
}
}
#endif /* SCARY_LEAK_FIX */
row->cell_list = NULL;
row->cell_ptr = NULL;
}
if (row->bg_color != NULL)
{
XP_DELETE(row->bg_color);
}
XP_DELETE(row);
}
static void
#ifdef SCARY_LEAK_FIX
lo_free_table_record(MWContext *context, lo_TableRec *table, Bool partial)
#else
lo_free_table_record(MWContext *context, lo_TableRec *table)
#endif /* SCARY_LEAK_FIX */
{
if (table->row_list != NULL)
{
lo_TableRow *row_ptr;
lo_TableRow *row;
row_ptr = table->row_list;
while (row_ptr != NULL)
{
row = row_ptr;
row_ptr = row_ptr->next;
#ifdef SCARY_LEAK_FIX
lo_free_row_record(row, partial);
#else
lo_free_row_record(row);
#endif /* SCARY_LEAK_FIX */
}
table->row_list = NULL;
table->row_ptr = NULL;
}
if (table->caption != NULL)
{
XP_DELETE(table->caption);
table->caption = NULL;
}
if (table->width_spans != NULL)
{
lo_table_span *span_ptr;
lo_table_span *span;
span_ptr = table->width_spans;
while (span_ptr != NULL)
{
span = span_ptr;
span_ptr = span_ptr->next;
XP_DELETE(span);
}
table->width_spans = NULL;
table->width_span_ptr = NULL;
}
if (table->height_spans != NULL)
{
lo_table_span *span_ptr;
lo_table_span *span;
span_ptr = table->height_spans;
while (span_ptr != NULL)
{
span = span_ptr;
span_ptr = span_ptr->next;
XP_DELETE(span);
}
table->height_spans = NULL;
table->height_span_ptr = NULL;
}
if (table->bg_color != NULL)
{
XP_DELETE(table->bg_color);
}
XP_DELETE(table);
}
#ifdef SCARY_LEAK_FIX
void
lo_FreePartialTable(MWContext *context, lo_DocState *state, lo_TableRec *table)
{
lo_TableRow *row_ptr;
lo_TableCell *cell_ptr;
LO_SubDocStruct *subdoc;
if (table == NULL)
{
return;
}
row_ptr = table->row_list;
while (row_ptr != NULL)
{
cell_ptr = row_ptr->cell_list;
while (cell_ptr != NULL)
{
subdoc = cell_ptr->cell_subdoc;
lo_FreePartialSubDoc(context, state, subdoc);
cell_ptr->cell_subdoc = NULL;
cell_ptr = cell_ptr->next;
}
row_ptr = row_ptr->next;
}
if (table->caption != NULL)
{
subdoc = table->caption->subdoc;
lo_FreePartialSubDoc(context, state, subdoc);
table->caption->subdoc = NULL;
}
lo_free_table_record(context, table, TRUE);
}
#endif /* SCARY_LEAK_FIX */
void
lo_EndTable(MWContext *context, lo_DocState *state, lo_TableRec *table)
{
int32 save_doc_min_width;
int32 x, y;
int32 cell_x, cell_y;
int32 indx;
int32 cell_cnt;
int32 ele_cnt;
int32 table_width, min_table_width;
int32 table_height;
int32 width_limit;
Bool relayout_pass;
Bool rowspan_pass;
Bool cut_to_window_width;
lo_TableCell blank_cell;
lo_cell_data XP_HUGE *cell_array;
XP_Block cell_array_buff;
lo_table_span *row_max;
lo_table_span *col_max;
lo_TableCell *cell_ptr;
int32 cell_pad;
int32 inner_pad;
int32 table_pad;
Bool floating;
int32 save_state_x, save_state_y;
LO_Element *save_line_list;
#ifdef LOCAL_DEBUG
fprintf(stderr, "lo_EndTable called\n");
#endif /* LOCAL_DEBUG */
cell_pad = FEUNITS_X(table->inter_cell_pad, context);
inner_pad = FEUNITS_X(table->inner_cell_pad, context);
table_pad = FEUNITS_X(TABLE_DEF_CELL_BORDER, context);
relayout_pass = FALSE;
cut_to_window_width = TRUE;
floating = FALSE;
/*
* So gcc won't complain
*/
save_state_x = 0;
save_state_y = 0;
save_line_list = NULL;
/*
state->current_table = NULL;
*/
cell_cnt = table->rows * table->cols;
/*
* Empty tables are completely ignored!
*/
if (cell_cnt <= 0)
{
/*
* Clear table state, and free up this structure.
*/
state->current_table = NULL;
if (table != NULL)
{
#ifdef SCARY_LEAK_FIX
lo_free_table_record(context, table, FALSE);
#else
lo_free_table_record(context, table);
#endif /* SCARY_LEAK_FIX */
}
return;
}
#ifdef XP_WIN16
/*
* It had better be the case that the size of the struct is a
* power of 2
*/
XP_ASSERT(sizeof(lo_cell_data) == 8);
cell_array = (lo_cell_data XP_HUGE *)_halloc(cell_cnt, sizeof(lo_cell_data));
/*
* There isn't a runtime routine that can initialize a huge array
*/
if (cell_cnt * sizeof(lo_cell_data) <= 0xFFFFL)
memset(cell_array, 0, (cell_cnt * sizeof(lo_cell_data)));
else {
BYTE XP_HUGE *tmp = (BYTE XP_HUGE *)cell_array;
for (indx = 0; indx < cell_cnt * sizeof(lo_cell_data); indx++)
tmp[indx] = 0;
}
#else
cell_array_buff = XP_ALLOC_BLOCK(cell_cnt * sizeof(lo_cell_data));
XP_LOCK_BLOCK(cell_array, lo_cell_data *, cell_array_buff);
memset(cell_array, 0, (cell_cnt * sizeof(lo_cell_data)));
#endif
lo_fill_cell_array(table, cell_array, &blank_cell, cell_pad,
&relayout_pass);
table_width = 0;
min_table_width = 0;
col_max = table->width_spans;
while (col_max != NULL)
{
table_width = table_width + cell_pad + col_max->dim;
min_table_width = min_table_width + cell_pad + col_max->min_dim;
col_max = col_max->next;
}
table_width += cell_pad;
table_width += (2 * table->table_ele->border_width);
min_table_width += cell_pad;
min_table_width += (2 * table->table_ele->border_width);
if (table->draw_borders == TABLE_BORDERS_OFF)
{
table_width += (2 * table_pad);
min_table_width += (2 * table_pad);
}
/*
* Take care of cells with percentage widths
*/
if (table->has_percent_width_cells != FALSE)
{
lo_percent_width_cells(table, cell_array, &blank_cell,
cell_pad, table_pad, &table_width, &min_table_width);
relayout_pass = TRUE;
}
/*
* Use state->left_margin here instead of state->win_left to take
* indent from lists into account.
*/
width_limit = (state->win_width - state->left_margin -state->win_right);
if (table->width > 0)
{
width_limit = table->width;
}
/*
* Else, if we are a nested table in an infinite width
* layout space, we don't want to cut to "window width"
*/
else if (state->allow_percent_width == FALSE)
{
cut_to_window_width = FALSE;
}
if (min_table_width >= width_limit)
{
lo_table_span *sub_ptr;
relayout_pass = TRUE;
sub_ptr = table->width_spans;
while (sub_ptr != NULL)
{
sub_ptr->dim = sub_ptr->min_dim;
sub_ptr = sub_ptr->next;
}
}
else if ((table_width > width_limit)&&(cut_to_window_width != FALSE))
{
intn pass;
Bool expand_failed;
int32 add_width;
int32 div_width;
int32 div_width_next;
int32 add;
int32 total_to_add;
lo_table_span *add_ptr;
relayout_pass = TRUE;
expand_failed = TRUE;
pass = 0;
total_to_add = width_limit - min_table_width;
div_width = table_width;
while ((total_to_add > 0)&&(pass < 10)&&(expand_failed !=FALSE))
{
int32 extra;
int32 min_extra;
expand_failed = FALSE;
add_ptr = table->width_spans;
add_width = total_to_add;
total_to_add = 0;
div_width_next = (table->cols + 1) * cell_pad;
add = 0;
while (add_ptr->next != NULL)
{
if ((pass > 0)&&
(add_ptr->min_dim == add_ptr->dim))
{
add_ptr = add_ptr->next;
continue;
}
extra = add_width * add_ptr->dim /
div_width;
if ((add_ptr->min_dim + extra) > add_ptr->dim)
{
expand_failed = TRUE;
min_extra = add_ptr->dim -
add_ptr->min_dim;
extra = min_extra;
}
add_ptr->min_dim += extra;
if (add_ptr->min_dim < add_ptr->dim)
{
div_width_next += add_ptr->dim;
}
add += extra;
add_ptr = add_ptr->next;
}
if ((pass == 0)||(add_ptr->min_dim < add_ptr->dim))
{
if (expand_failed == FALSE)
{
extra = add_width - add;
}
else
{
extra = add_width * add_ptr->dim /
div_width;
}
if ((add_ptr->min_dim + extra) > add_ptr->dim)
{
expand_failed = TRUE;
min_extra = add_ptr->dim -
add_ptr->min_dim;
extra = min_extra;
}
add_ptr->min_dim += extra;
if (add_ptr->min_dim < add_ptr->dim)
{
div_width_next += add_ptr->dim;
}
add += extra;
}
total_to_add = add_width - add;
div_width = div_width_next;
pass++;
}
if (total_to_add > 0)
{
add = 0;
add_ptr = table->width_spans;
while ((add_ptr->next != NULL)&&(total_to_add > 0))
{
if ((add_ptr->min_dim + total_to_add) >
add_ptr->dim)
{
add = add_ptr->dim - add_ptr->min_dim;
total_to_add = total_to_add - add;
add_ptr->min_dim += add;
}
else
{
add_ptr->min_dim += total_to_add;
total_to_add = 0;
}
add_ptr = add_ptr->next;
}
add_ptr->min_dim += total_to_add;
}
add_ptr = table->width_spans;
while (add_ptr != NULL)
{
add_ptr->dim = add_ptr->min_dim;
add_ptr = add_ptr->next;
}
}
/*
* If the user specified a wider width than the optimal
* width. Make it so.
*/
if ((table->width > 0)&&(width_limit > table_width))
{
int32 add_width;
int32 add;
int32 newWidth;
lo_table_span *add_ptr;
add_ptr = table->width_spans;
add_width = width_limit - table_width;
add = 0;
while ((add_ptr != NULL)&&(add_ptr->next != NULL))
{
newWidth = add_width * add_ptr->dim / table_width;
add_ptr->dim += newWidth;
add += newWidth;
add_ptr = add_ptr->next;
}
add_ptr->dim += (add_width - add);
}
rowspan_pass = FALSE;
if (relayout_pass != FALSE)
{
lo_cell_relayout_pass(context, state, table, cell_array,
&blank_cell, cell_pad, inner_pad, &rowspan_pass);
}
if (rowspan_pass != FALSE)
{
lo_cell_rowspan_pass(table, cell_array, &blank_cell,
cell_pad, inner_pad);
}
table_width = 0;
min_table_width = 0;
col_max = table->width_spans;
while (col_max != NULL)
{
table_width = table_width + cell_pad + col_max->dim;
min_table_width = min_table_width + cell_pad + col_max->min_dim;
col_max = col_max->next;
}
table_width += cell_pad;
table_width += (2 * table->table_ele->border_width);
min_table_width += cell_pad;
min_table_width += (2 * table->table_ele->border_width);
table_height = 0;
row_max = table->height_spans;
while (row_max != NULL)
{
table_height = table_height + cell_pad + row_max->dim;
row_max = row_max->next;
}
table_height += cell_pad;
table_height += (2 * table->table_ele->border_width);
if (table->draw_borders == TABLE_BORDERS_OFF)
{
table_width += (2 * table_pad);
min_table_width += (2 * table_pad);
table_height += (2 * table_pad);
}
/*
* If the user specified a taller table than the optimal
* height. Make it so.
*/
if ((table->height > 0)&&(table->height > table_height))
{
int32 add_height;
int32 add;
lo_table_span *add_ptr;
int32 newHeight;
add_ptr = table->height_spans;
add_height = table->height - table_height;
add = 0;
while((add_ptr != NULL) && (add_ptr->next != NULL))
{
newHeight = add_height * add_ptr->dim / table_height;
add_ptr->dim += newHeight;
add += newHeight;
add_ptr = add_ptr->next;
}
add_ptr->dim += (add_height - add);
table_height = table->height;
}
table->table_ele->width = table_width;
table->table_ele->height = table_height;
/*
* Here, if we are floating we don't do the linebreak.
* We do save some state info and then "fake" a linebreak
* so we can use common code to place the rest of the table.
*/
if (table->table_ele->ele_attrmask & LO_ELE_FLOATING)
{
save_line_list = state->line_list;
save_state_x = state->x;
save_state_y = state->y;
floating = TRUE;
state->x = state->left_margin;
state->y = state->y + state->line_height;
state->line_list = NULL;
}
else
{
lo_SoftLineBreak(context, state, FALSE, 1);
}
table->table_ele->x = state->x;
table->table_ele->y = state->y;
/* Keep the element IDs in order */
table->table_ele->ele_id = NEXT_ELEMENT;
lo_AppendToLineList(context, state,
(LO_Element *)table->table_ele, 0);
state->x += (cell_pad + table->table_ele->border_width);
state->y += (cell_pad + table->table_ele->border_width);
if (table->draw_borders == TABLE_BORDERS_OFF)
{
state->x += table_pad;
state->y += table_pad;
}
if (table->caption != NULL)
{
int32 new_width;
LO_SubDocStruct *subdoc;
Bool has_elements;
subdoc = table->caption->subdoc;
col_max = table->width_spans;
new_width = col_max->dim;
while (col_max->next != NULL)
{
col_max = col_max->next;
new_width = new_width + cell_pad + col_max->dim;
}
/*
* Don't relayout documents that have no
* elements, it causes errors.
*/
has_elements = lo_subdoc_has_elements(subdoc->state);
if ((new_width < table->caption->max_width)&&
(has_elements == FALSE))
{
int32 inside_width;
inside_width = new_width -
(2 * subdoc->border_width) -
(2 * subdoc->border_horiz_space) -
(2 * inner_pad);
subdoc->width = inside_width;
}
else if (new_width < table->caption->max_width)
{
int32 inside_width;
inside_width = new_width -
(2 * subdoc->border_width) -
(2 * subdoc->border_horiz_space) -
(2 * inner_pad);
table->caption->subdoc = lo_RelayoutSubdoc(context,
state, subdoc, inside_width, FALSE);
subdoc = table->caption->subdoc;
table->caption->height = subdoc->height +
(2 * subdoc->border_vert_space) +
(2 * inner_pad);
table->caption->max_width = new_width;
}
else
{
table->caption->max_width = new_width;
}
}
state->current_table = NULL;
cell_x = state->x;
cell_y = state->y;
if ((table->caption != NULL)&&
(table->caption->vert_alignment == LO_ALIGN_TOP))
{
LO_SubDocStruct *subdoc;
cell_x = state->x;
subdoc = table->caption->subdoc;
subdoc->x = cell_x;
subdoc->y = table->table_ele->y;
subdoc->x_offset = (int16)subdoc->border_horiz_space;
subdoc->y_offset = (int32)subdoc->border_vert_space;
subdoc->width = table->caption->max_width -
(2 * subdoc->border_horiz_space);
subdoc->height = table->caption->height -
(2 * subdoc->border_vert_space);
ele_cnt = lo_align_subdoc(context, state,
(lo_DocState *)subdoc->state, subdoc, table, NULL);
if (ele_cnt > 0)
{
LO_CellStruct *cell_ele;
cell_ele = lo_SquishSubDocToCell(context, state,
subdoc);
if (cell_ele == NULL)
{
lo_AppendToLineList(context, state,
(LO_Element *)subdoc, 0);
}
else
{
lo_AppendToLineList(context, state,
(LO_Element *)cell_ele, 0);
}
cell_x = state->x;
cell_y = cell_y + table->caption->height + cell_pad;
table->table_ele->y_offset = cell_y -
table->table_ele->y;
cell_y += (cell_pad + table->table_ele->border_width);
if (table->draw_borders == TABLE_BORDERS_OFF)
{
cell_y += table_pad;
}
}
else
{
LO_CellStruct *cell_ele;
/*
* Free up the useless subdoc
*/
cell_ele = lo_SquishSubDocToCell(context, state,
subdoc);
if (cell_ele != NULL)
{
lo_FreeElement(context,
(LO_Element *)cell_ele, TRUE);
}
}
}
row_max = table->height_spans;
for (y=0; y < table->rows; y++)
{
cell_x = state->x;
col_max = table->width_spans;
for (x=0; x < table->cols; x++)
{
LO_SubDocStruct *subdoc;
indx = (y * table->cols) + x;
cell_ptr = cell_array[indx].cell;
if ((cell_ptr == &blank_cell)||(cell_ptr == NULL))
{
cell_x = cell_x + col_max->dim + cell_pad;
col_max = col_max->next;
continue;
}
subdoc = cell_ptr->cell_subdoc;
subdoc->x = cell_x;
subdoc->y = cell_y;
subdoc->x_offset = (int16)subdoc->border_horiz_space;
subdoc->y_offset = (int32)subdoc->border_vert_space;
subdoc->width = col_max->dim;
if (cell_ptr->colspan > 1)
{
int32 i;
lo_table_span *max_ptr;
max_ptr = col_max;
for (i=1; i < cell_ptr->colspan; i++)
{
max_ptr = max_ptr->next;
subdoc->width = subdoc->width +
cell_pad + max_ptr->dim;
}
}
subdoc->width = subdoc->width -
(2 * subdoc->border_horiz_space);
subdoc->height = row_max->dim;
if (cell_ptr->rowspan > 1)
{
int32 i;
lo_table_span *max_ptr;
max_ptr = row_max;
for (i=1; i < cell_ptr->rowspan; i++)
{
max_ptr = max_ptr->next;
subdoc->height = subdoc->height +
cell_pad + max_ptr->dim;
}
}
subdoc->height = subdoc->height -
(2 * subdoc->border_vert_space);
ele_cnt = lo_align_subdoc(context, state,
(lo_DocState *)subdoc->state, subdoc,
table, row_max);
if (ele_cnt > 0)
{
LO_CellStruct *cell_ele;
cell_ele = lo_SquishSubDocToCell(context, state,
subdoc);
if (cell_ele == NULL)
{
lo_AppendToLineList(context, state,
(LO_Element *)subdoc, 0);
}
else
{
lo_AppendToLineList(context, state,
(LO_Element *)cell_ele, 0);
}
}
else
{
LO_CellStruct *cell_ele;
/*
* Free up the useless subdoc
*/
cell_ele = lo_SquishSubDocToCell(context, state,
subdoc);
if (cell_ele != NULL)
{
lo_FreeElement(context,
(LO_Element *)cell_ele, TRUE);
}
}
cell_x = cell_x + col_max->dim + cell_pad;
col_max = col_max->next;
}
cell_y = cell_y + row_max->dim + cell_pad;
row_max = row_max->next;
}
cell_x = cell_x + table->table_ele->border_width;
cell_y = cell_y + table->table_ele->border_width;
if (table->draw_borders == TABLE_BORDERS_OFF)
{
cell_x += table_pad;
cell_y += table_pad;
}
if ((table->caption != NULL)&&
(table->caption->vert_alignment != LO_ALIGN_TOP))
{
LO_SubDocStruct *subdoc;
subdoc = table->caption->subdoc;
subdoc->x = state->x;
subdoc->y = cell_y;
subdoc->x_offset = (int16)subdoc->border_horiz_space;
subdoc->y_offset = (int32)subdoc->border_vert_space;
subdoc->width = table->caption->max_width -
(2 * subdoc->border_horiz_space);
subdoc->height = table->caption->height -
(2 * subdoc->border_vert_space);
ele_cnt = lo_align_subdoc(context, state,
(lo_DocState *)subdoc->state, subdoc, table, NULL);
if (ele_cnt > 0)
{
LO_CellStruct *cell_ele;
cell_ele = lo_SquishSubDocToCell(context, state,
subdoc);
if (cell_ele == NULL)
{
lo_AppendToLineList(context, state,
(LO_Element *)subdoc, 0);
}
else
{
lo_AppendToLineList(context, state,
(LO_Element *)cell_ele, 0);
}
cell_y = cell_y + table->caption->height + cell_pad;
}
else
{
LO_CellStruct *cell_ele;
/*
* Free up the useless subdoc
*/
cell_ele = lo_SquishSubDocToCell(context, state,
subdoc);
if (cell_ele != NULL)
{
lo_FreeElement(context,
(LO_Element *)cell_ele, TRUE);
}
}
}
/*
* The usual stuff for a table.
*/
if (floating == FALSE)
{
state->x = cell_x;
state->baseline = 0;
state->line_height = cell_y - state->y;
state->linefeed_state = 0;
state->at_begin_line = FALSE;
state->trailing_space = FALSE;
state->cur_ele_type = LO_SUBDOC;
table->table_ele->line_height = state->line_height;
save_doc_min_width = state->min_width;
lo_HardLineBreak(context, state, FALSE);
if (min_table_width > save_doc_min_width)
{
save_doc_min_width = min_table_width;
}
state->min_width = save_doc_min_width;
}
/*
* Else this is a floating table, rip it out of the "faked"
* line list, stuff itin the margin, and restore our state
* to where we left off.
*/
else
{
int32 push_right;
int32 line_height;
LO_Element *tptr;
LO_Element *last;
line_height = cell_y - state->y;
push_right = 0;
if (table->table_ele->alignment == LO_ALIGN_RIGHT)
{
push_right = state->right_margin - cell_x;
}
table->table_ele->x_offset +=
(int16)table->table_ele->border_horiz_space;
table->table_ele->y_offset +=
(int32)table->table_ele->border_vert_space;
last = NULL;
tptr = state->line_list;
while (tptr != NULL)
{
tptr->lo_any.x += push_right;
if (tptr->type == LO_CELL)
{
tptr->lo_any.x +=
table->table_ele->border_horiz_space;
tptr->lo_any.y +=
table->table_ele->border_vert_space;
lo_ShiftCell((LO_CellStruct *)tptr,
(push_right +
table->table_ele->border_horiz_space),
table->table_ele->border_vert_space);
}
last = tptr;
tptr->lo_any.line_height = line_height;
tptr = tptr->lo_any.next;
}
/*
* Stuff the whole line list into the float list, and
* restore the line list to its pre-table state.
*/
if (state->line_list != NULL)
{
last->lo_any.next = state->float_list;
state->float_list = state->line_list;
state->line_list = NULL;
}
state->line_list = save_line_list;
table->table_ele->line_height = line_height;
table->table_ele->expected_y = table->table_ele->y;
table->table_ele->y = -1;
lo_AddMarginStack(state,
table->table_ele->x, table->table_ele->y,
table->table_ele->width, table->table_ele->line_height,
table->table_ele->border_width,
table->table_ele->border_vert_space,
table->table_ele->border_horiz_space,
(intn)table->table_ele->alignment);
/*
* Restore state to pre-table values.
*/
state->x = save_state_x;
state->y = save_state_y;
/*
* All the doc_min_width stuff makes state->min_width
* be correct for tables nested inside tables.
*/
save_doc_min_width = state->min_width;
/*
* Standard float stuff, if we happen to be at the start
* of a line, place the table now.
*/
if (state->at_begin_line != FALSE)
{
lo_FindLineMargins(context, state);
state->x = state->left_margin;
}
if (min_table_width > save_doc_min_width)
{
save_doc_min_width = min_table_width;
}
state->min_width = save_doc_min_width;
}
for (y=0; y < table->rows; y++)
{
for (x=0; x < table->cols; x++)
{
indx = (y * table->cols) + x;
cell_ptr = cell_array[indx].cell;
if ((cell_ptr != &blank_cell)&&(cell_ptr != NULL))
{
XP_DELETE(cell_ptr);
}
}
}
#ifdef XP_WIN16
_hfree(cell_array);
#else
XP_UNLOCK_BLOCK(cell_array_buff);
XP_FREE_BLOCK(cell_array_buff);
#endif
#ifdef SCARY_LEAK_FIX
lo_free_table_record(context, table, FALSE);
#else
lo_free_table_record(context, table);
#endif /* SCARY_LEAK_FIX */
}
#ifdef TEST_16BIT
#undef XP_WIN16
#endif /* TEST_16BIT */