pjs/lib/layout/laytable.c

8482 строки
194 KiB
C
Исходник Обычный вид История

1998-03-28 05:44:41 +03:00
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "xp.h"
#include "pa_parse.h"
#include "layout.h"
#include "laylayer.h"
#include "np.h"
#include "laystyle.h"
#include "edt.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_BORDER_STYLE BORDER_SOLID
#define TABLE_DEF_VERTICAL_SPACE 0
#define TABLE_DEF_HORIZONTAL_SPACE 0
#define TABLE_MAX_COLSPAN 1000
#define TABLE_MAX_ROWSPAN 10000
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;
LO_SubDocStruct *
lo_EndCellSubDoc(MWContext *context, lo_DocState *state, lo_DocState *old_state,
LO_Element *element, Bool relayout);
LO_SubDocStruct *
lo_RelayoutCaptionSubdoc(MWContext *context, lo_DocState *state, lo_TableCaption *caption,
LO_SubDocStruct *subdoc, int32 width, Bool is_a_header);
LO_CellStruct *
lo_RelayoutCell(MWContext *context, lo_DocState *state,
LO_SubDocStruct *subdoc, lo_TableCell *cell_ptr,
LO_CellStruct *cell, int32 width, Bool is_a_header,
Bool relayout);
void
lo_BeginCaptionSubDoc(MWContext *context, lo_DocState *state,
lo_TableCaption *caption, PA_Tag *tag);
void
lo_BeginCellSubDoc(MWContext *context,
lo_DocState *state,
lo_TableRec *table,
char *bgcolor_attr,
char *background_attr,
lo_TileMode tile_mode,
char *valign_attr,
char *halign_attr,
char *width_attr,
char *height_attr,
Bool is_a_header,
intn draw_borders,
Bool relayout);
Bool
lo_subdoc_has_elements(lo_DocState *sub_state);
Bool
lo_cell_has_elements(LO_CellStruct *cell);
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
lo_align_cell(MWContext *context, lo_DocState *state, lo_TableCell *cell_ptr,
LO_CellStruct *cell, lo_TableRec *table, lo_table_span *row_max);
void
lo_RelayoutTags(MWContext *context, lo_DocState *state, PA_Tag * tag_ptr,
PA_Tag * tag_end_ptr, LO_Element * elem_list);
PA_Tag *
lo_FindReuseableElement(MWContext *context, lo_DocState *state,
LO_Element ** elem_list);
static void
lo_reuse_current_state(MWContext *context, lo_DocState *state,
int32 width, int32 height, int32 margin_width, int32 margin_height,
Bool destroyLineLists);
/*
********************************************************************************
* Some Helper Functions
*/
static int32 lo_CalculateCellPercentWidth( lo_TableRec *table, int32 percent);
static int32 lo_CalculateCellPercentHeight( lo_TableRec *table, lo_TableCell *table_cell);
static int32
lo_ComputeCellEmptySpace(MWContext *context,lo_TableRec *table,
LO_SubDocStruct *subdoc);
static int32
lo_FindDefaultCellWidth(MWContext * context, lo_TableRec *table, lo_TableCell *table_cell,
int32 desired_width, int32 cell_empty_space);
static int32
lo_ComputeInternalTableWidth(MWContext *context, lo_TableRec *table,
lo_DocState *state);
static void
lo_SetDefaultCellWidth(MWContext *context, lo_TableRec *table, LO_SubDocStruct *subdoc,
lo_TableCell *table_cell, int32 cell_width);
static void lo_ResetWidthSpans( lo_TableRec *table );
static void lo_UpdateCaptionCellFromSubDoc( MWContext *context, lo_DocState *state, LO_SubDocStruct *subdoc, LO_CellStruct *cell_ele);
static void lo_FreeCaptionCell( MWContext *context, lo_DocState *state, LO_CellStruct *cell_ele);
static void lo_FreeTableCaption( MWContext *context, lo_DocState *state, lo_TableRec *table );
static int32
lo_ComputeCellEmptySpace(MWContext *context, lo_TableRec *table,
LO_SubDocStruct *subdoc)
{
int32 left_inner_pad;
int32 right_inner_pad;
int32 cell_empty_space;
left_inner_pad = FEUNITS_X(table->inner_left_pad, context);
right_inner_pad = FEUNITS_X(table->inner_right_pad, context);
cell_empty_space = (2 * subdoc->border_width) +
(2 * subdoc->border_horiz_space) +
(left_inner_pad + right_inner_pad);
return cell_empty_space;
}
/*
* Handle Fixed Table Layout. If the table has a COLS attribute
* then the width of this cell may already be specified. The
* trick is to know if this is the first row of the table. If
* so, then this cell can choose it's width.
*/
static int32
lo_FindDefaultCellWidth(MWContext * context, lo_TableRec *table, lo_TableCell *table_cell,
int32 desired_width, int32 cell_empty_space)
{
lo_TableRow * row_ptr;
int32 cell_num;
int32 cell_width;
int32 count;
int32 cell_pad;
cell_pad = FEUNITS_X(table->inter_cell_pad, context);
row_ptr = table->row_ptr;
cell_num = row_ptr->cells;
/* if we don't have a width table or we're out of bounds, bail */
if ( table->fixed_col_widths == NULL ||
((cell_num+table_cell->colspan) > table->fixed_cols) )
{
table->fixed_cols = 0;
table->default_cell_width = 0;
return desired_width;
}
/* does this cell already have a width defined? */
cell_width = table->fixed_col_widths[ cell_num ];
if ( cell_width == 0 )
{
int32 col_width;
/* use it's desired width or the default */
cell_width = desired_width;
if ( cell_width == 0 )
{
/*
* Get our size from the default cell width. We
* may need to clip it to the table width remaining.
*/
cell_width = table->default_cell_width * table_cell->colspan;
/*
* If this is bigger than the width remaining the the table, then
* clip to the remaining space. If the table is already full, then
* we're going for broke and the cell gets all of it.
*/
if ( ( table->fixed_width_remaining > 0 ) &&
( cell_width > table->fixed_width_remaining ) )
{
cell_width = table->fixed_width_remaining;
}
table->fixed_width_remaining -= cell_width;
/*
* Remove any cell spacing so the cell will internally
* layout to the correct size.
*/
cell_width -= cell_empty_space * table_cell->colspan;
}
else
{
/*
* The cell has a specified size. Allocate all of it. If we
* don't have enough space, then we'll keep doing fixed layout,
* but the table may end up larger than expected.
*/
table->fixed_width_remaining -= cell_width + cell_empty_space;
}
/* make sure this stays reasonable */
if ( table->fixed_width_remaining < 0 )
{
table->fixed_width_remaining = 0;
}
/* fill out the apropriate number of col widths */
col_width = cell_width / table_cell->colspan;
for ( count = table_cell->colspan; count > 0 ; --count )
{
table->fixed_col_widths[ cell_num ] = col_width;
cell_num++;
}
/* add any odd amount to the last column */
table->fixed_col_widths[ cell_num-1 ] += (cell_width-
(col_width * table_cell->colspan));
}
else
{
/* add up widths of each column our cell spans */
for ( count = 1; count < table_cell->colspan; ++count )
{
cell_width += table->fixed_col_widths[ cell_num+count ];
}
}
/*
* Add the empty space this cell spans
*/
cell_width += ( table_cell->colspan - 1 ) * ( cell_empty_space + cell_pad );
return cell_width;
}
/*
* For fixed layout, set the cell width for a cell after layout. This is used
* for cases where we don't know how wide a cell is until after it's been layed
* out (for example, when NOWRAP is set).
*
* We will have already chosen a default width for this cell. If our new width
* is larger, then we need to resize the column/s.
*/
static void
lo_SetDefaultCellWidth(MWContext *context, lo_TableRec *table, LO_SubDocStruct *subdoc,
lo_TableCell *table_cell, int32 cell_width)
{
lo_TableRow * row_ptr;
int32 cell_num;
int32 count;
int32 cur_width;
int32 add_width;
int32 cell_empty_space;
int32 cell_pad;
row_ptr = table->row_ptr;
cell_num = row_ptr->cells;
/* if we don't have a width table or we're out of bounds, bail */
if ( table->fixed_col_widths == NULL ||
((cell_num+table_cell->colspan) > table->fixed_cols) )
{
table->fixed_cols = 0;
table->default_cell_width = 0;
return;
}
/*
* Figure out the current width for these cells
*/
cur_width = 0;
for ( count = table_cell->colspan-1; count >= 0 ; --count )
{
cur_width += table->fixed_col_widths[ cell_num+count ];
}
/*
* Add space for the empty space that this cell spans
*/
cell_empty_space = lo_ComputeCellEmptySpace(context, table, subdoc );
cell_pad = FEUNITS_X(table->inter_cell_pad, context);
cur_width += ( table_cell->colspan - 1 ) * ( cell_empty_space + cell_pad );
/*
* If our new width is bigger, we need to grow the default width
*/
if ( cell_width > cur_width )
{
cell_width -= cur_width;
add_width = cell_width / table_cell->colspan;
table->fixed_width_remaining -= add_width;
if ( table->fixed_width_remaining < 0 )
{
table->fixed_width_remaining = 0;
}
for ( count = table_cell->colspan; count > 0 ; --count )
{
table->fixed_col_widths[ cell_num ] += add_width;
cell_width -= add_width;
cell_num++;
}
/* add any odd amount to the last column */
table->fixed_col_widths[ cell_num-1 ] += cell_width;
}
}
static int32
lo_ComputeInternalTableWidth(MWContext *context,lo_TableRec *table,
lo_DocState *state)
{
int32 table_width;
int32 cell_pad;
int32 table_pad;
cell_pad = FEUNITS_X(table->inter_cell_pad, context);
table_width = table->width;
if ( table_width == 0 )
{
/* Compute our starting width as the window width */
table_width = (state->win_width - state->win_left -
state->win_right);
}
/* remove space for the table borders */
table_width -= ( table->table_ele->border_left_width
+ table->table_ele->border_right_width );
if (table->draw_borders == TABLE_BORDERS_OFF)
{
table_pad = FEUNITS_X(TABLE_DEF_CELL_BORDER, context);
table_width -= 2 * table_pad;
}
if ( table->fixed_cols > 0 )
{
table_width -= ( table->fixed_cols + 1 ) * cell_pad;
}
else
{
table_width -= ( table->cols + 1 ) * cell_pad;
}
return table_width;
}
/*
********************************************************************************
* Core Table Layout Code
*/
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->backdrop.bg_color = NULL;
subdoc->backdrop.url = NULL;
subdoc->backdrop.tile_mode = LO_TILE_BOTH;
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(context, 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->type, subdoc->horiz_alignment);
}
state->sub_state = new_state;
state->current_ele = (LO_Element *)subdoc;
/*
* We added a new state.
*/
lo_PushStateLevel ( context );
}
static void
lo_reuse_current_state(MWContext *context, lo_DocState *state,
int32 width, int32 height, int32 margin_width, int32 margin_height,
Bool destroyLineLists)
{
lo_TopState *top_state;
int32 doc_id;
lo_DocLists *doc_lists;
doc_id = XP_DOCID(context);
top_state = lo_FetchTopState(doc_id);
if ((top_state == NULL)||(state == NULL))
{
return;
}
state->subdoc_tags = NULL;
state->subdoc_tags_end = NULL;
state->text_fg.red = lo_master_colors[LO_COLOR_FG].red;
state->text_fg.green = lo_master_colors[LO_COLOR_FG].green;
state->text_fg.blue = lo_master_colors[LO_COLOR_FG].blue;
state->text_bg.red = lo_master_colors[LO_COLOR_BG].red;
state->text_bg.green = lo_master_colors[LO_COLOR_BG].green;
state->text_bg.blue = lo_master_colors[LO_COLOR_BG].blue;
state->anchor_color.red = lo_master_colors[LO_COLOR_LINK].red;
state->anchor_color.green = lo_master_colors[LO_COLOR_LINK].green;
state->anchor_color.blue = lo_master_colors[LO_COLOR_LINK].blue;
state->visited_anchor_color.red = lo_master_colors[LO_COLOR_VLINK].red;
state->visited_anchor_color.green = lo_master_colors[LO_COLOR_VLINK].green;
state->visited_anchor_color.blue = lo_master_colors[LO_COLOR_VLINK].blue;
state->active_anchor_color.red = lo_master_colors[LO_COLOR_ALINK].red;
state->active_anchor_color.green = lo_master_colors[LO_COLOR_ALINK].green;
state->active_anchor_color.blue = lo_master_colors[LO_COLOR_ALINK].blue;
state->win_top = margin_height;
state->win_bottom = margin_height;
state->win_width = width;
state->win_height = height;
state->base_x = 0;
state->base_y = 0;
state->x = 0;
state->y = 0;
state->width = 0;
state->line_num = 1;
state->win_left = margin_width;
state->win_right = margin_width;
state->max_width = state->win_left + state->win_right;
state->x = state->win_left;
state->y = state->win_top;
state->left_margin = state->win_left;
state->right_margin = state->win_width - state->win_right;
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;
}
state->break_holder = state->x;
state->min_width = 0;
state->text_divert = P_UNKNOWN;
state->linefeed_state = 2;
state->delay_align = FALSE;
state->breakable = TRUE;
state->allow_amp_escapes = TRUE;
state->preformatted = PRE_TEXT_NO;
state->preformat_cols = 0;
state->in_paragraph = FALSE;
state->display_blocked = FALSE;
state->display_blocking_element_id = 0;
state->display_blocking_element_y = 0;
if (destroyLineLists == TRUE)
{
if (state->line_list != NULL)
{
lo_FreeElementList(context, state->line_list);
state->line_list = NULL;
}
state->end_last_line = NULL;
if (state->float_list != NULL)
{
lo_FreeElementList(context, state->float_list);
state->float_list = NULL;
}
}
state->base_font_size = DEFAULT_BASE_FONT_SIZE;
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;
}
state->font_stack = lo_DefaultFont(state, context);
state->font_stack->text_attr->size = state->base_font_size;
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;
}
state->list_stack = lo_DefaultList(state);
state->text_info.max_width = 0;
state->text_info.ascent = 0;
state->text_info.descent = 0;
state->text_info.lbearing = 0;
state->text_info.rbearing = 0;
state->line_buf_len = 0;
state->baseline = 0;
state->line_height = 0;
state->break_pos = -1;
state->break_width = 0;
state->last_char_CR = FALSE;
state->trailing_space = FALSE;
state->at_begin_line = TRUE;
state->old_break = NULL;
state->old_break_block = NULL;
state->old_break_pos = -1;
state->old_break_width = 0;
state->current_named_anchor = NULL;
state->current_anchor = NULL;
state->cur_ele_type = LO_NONE;
state->current_ele = NULL;
state->current_java = NULL;
state->current_table = NULL;
state->current_grid = NULL;
state->current_multicol = NULL;
if (state->top_state->doc_state)
doc_lists = lo_GetCurrentDocLists(state->top_state->doc_state);
else
doc_lists = lo_GetCurrentDocLists(state);
/*
* These values are saved into the (sub)doc here
* so that if it gets Relayout() later, we know where
* to reset the from counts to.
*/
if (doc_lists->form_list != NULL)
{
lo_FormData *form_list;
form_list = doc_lists->form_list;
state->form_ele_cnt = form_list->form_ele_cnt;
state->form_id = form_list->id;
}
else
{
state->form_ele_cnt = 0;
state->form_id = 0;
}
state->start_in_form = top_state->in_form;
if (top_state->savedData.FormList != NULL)
{
lo_SavedFormListData *all_form_ele;
all_form_ele = top_state->savedData.FormList;
state->form_data_index = all_form_ele->data_index;
}
else
{
state->form_data_index = 0;
}
/*
* Remember number of embeds we had before beginning this
* (sub)doc. This information is used in laytable.c so
* it can preserve embed indices across a relayout.
*/
state->embed_count_base = top_state->embed_count;
/*
* Ditto for anchors, images, applets and embeds
*/
state->url_count_base = doc_lists->url_list_len;
state->image_list_count_base = doc_lists->image_list_count;
state->applet_list_count_base = doc_lists->applet_list_count;
state->embed_list_count_base = doc_lists->embed_list_count;
state->current_layer_num_base = top_state->current_layer_num;
state->current_layer_num_max = top_state->current_layer_num;
state->must_relayout_subdoc = FALSE;
state->allow_percent_width = TRUE;
state->allow_percent_height = TRUE;
state->is_a_subdoc = SUBDOC_NOT;
state->current_subdoc = 0;
state->sub_documents = NULL;
state->sub_state = NULL;
state->current_cell = NULL;
state->extending_start = FALSE;
state->selection_start = NULL;
state->selection_start_pos = 0;
state->selection_end = NULL;
state->selection_end_pos = 0;
state->selection_new = NULL;
state->selection_new_pos = 0;
#ifdef EDITOR
state->edit_force_offset = FALSE;
state->edit_current_element = 0;
state->edit_current_offset = 0;
state->edit_relayout_display_blocked = FALSE;
#endif
#ifdef MOCHA
state->in_relayout = FALSE;
#endif
state->cur_text_block = NULL;
/* we need min widths during the initial table layout pass */
state->need_min_width = TRUE;
}
static void
lo_reuse_current_subdoc(MWContext *context, LO_SubDocStruct *subdoc)
{
if (subdoc == NULL)
{
return;
}
subdoc->type = LO_SUBDOC;
subdoc->ele_id = 0;
subdoc->x = 0;
subdoc->x_offset = 0;
subdoc->y = 0;
subdoc->y_offset = 0;
subdoc->width = 0;
subdoc->height = 0;
subdoc->next = NULL;
subdoc->prev = NULL;
subdoc->FE_Data = NULL;
/*
* We leave subdoc->state alone as it will get reused later.
*/
XP_FREEIF(subdoc->backdrop.bg_color);
XP_FREEIF(subdoc->backdrop.url);
/*
* These two come from lists of shared pointers, so
* we NULL them but don't free them.
*/
subdoc->anchor_href = NULL;
subdoc->text_attr = NULL;
subdoc->alignment = LO_ALIGN_LEFT;
subdoc->vert_alignment = LO_ALIGN_TOP;
subdoc->horiz_alignment = LO_ALIGN_LEFT;
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;
}
static void
lo_cleanup_old_state(lo_DocState *state)
{
LO_Element **line_array;
if (state == NULL)
{
return;
}
/*
* Clear out the start of the line_list.
*/
#ifdef XP_WIN16
{
XP_Block *larray_array;
XP_LOCK_BLOCK(larray_array, XP_Block *, state->larray_array);
state->line_array = larray_array[0];
XP_UNLOCK_BLOCK(state->larray_array);
}
#endif /* XP_WIN16 */
XP_LOCK_BLOCK(line_array, LO_Element **, state->line_array);
line_array[0] = NULL;
XP_UNLOCK_BLOCK(state->line_array);
state->end_last_line = NULL;
state->float_list = NULL;
}
static int32 lo_CalculateCellPercentWidth( lo_TableRec *table, int32 percent)
{
int32 val = percent;
if ( table->table_width_fixed != FALSE )
{
val = table->width * val / 100;
}
else
{
val = 0;
}
return val;
}
static int32 lo_CalculateCellPercentHeight( lo_TableRec *table, lo_TableCell *table_cell)
{
int32 val;
if ((table->height > 0)&&
(table_cell->percent_height > 0))
{
val = table->height *
table_cell->percent_height / 100;
}
else
{
val = 0;
}
return val;
}
void
lo_BeginCellSubDoc(MWContext *context,
lo_DocState *state,
lo_TableRec *table,
char *bgcolor_attr,
char *background_attr,
lo_TileMode tile_mode,
char *valign_attr,
char *halign_attr,
char *width_attr,
char *height_attr,
Bool is_a_header,
intn draw_borders,
Bool relayout /* Is true during relayout without reload */)
{
LO_SubDocStruct *subdoc;
lo_DocState *new_state;
lo_TableRow *table_row;
lo_TableCell *table_cell;
int32 val;
int32 first_width, first_height;
Bool allow_percent_width;
Bool allow_percent_height;
StyleStruct *style_struct=0;
#ifdef LOCAL_DEBUG
fprintf(stderr, "lo_BeginCellSubDoc called\n");
#endif /* LOCAL_DEBUG */
table_row = table->row_ptr;
table_cell = table_row->cell_ptr;
if (relayout == FALSE)
{
if(state->top_state && state->top_state->style_stack)
style_struct = STYLESTACK_GetStyleByIndex(
state->top_state->style_stack,
0);
}
/*
* Fill in the subdoc structure with default data
*/
lo_reuse_current_subdoc(context, table->current_subdoc);
subdoc = table->current_subdoc;
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->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->backdrop.bg_color = NULL;
subdoc->backdrop.url = NULL;
subdoc->backdrop.tile_mode = LO_TILE_BOTH;
/*
* May inherit a bg_color from your row.
*/
if (table_row->backdrop.bg_color != NULL)
{
subdoc->backdrop.bg_color = XP_NEW(LO_Color);
if (subdoc->backdrop.bg_color != NULL)
*subdoc->backdrop.bg_color = *table_row->backdrop.bg_color;
}
if (relayout == FALSE)
{
subdoc->backdrop.bg_color = NULL;
subdoc->backdrop.url = NULL;
subdoc->backdrop.tile_mode = LO_TILE_BOTH;
/*
* May inherit a bg_color from your row.
*/
if (table_row->backdrop.bg_color != NULL)
{
subdoc->backdrop.bg_color = XP_NEW(LO_Color);
if (subdoc->backdrop.bg_color != NULL)
*subdoc->backdrop.bg_color = *table_row->backdrop.bg_color;
}
/*
* Else may inherit a bg_color from your table.
*/
else if (table->backdrop.bg_color != NULL)
{
subdoc->backdrop.bg_color = XP_NEW(LO_Color);
if (subdoc->backdrop.bg_color != NULL)
*subdoc->backdrop.bg_color = *table->backdrop.bg_color;
}
/*
* 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.backdrop.bg_color != NULL))
{
LO_Color *old_bg;
old_bg = up_state->current_ele->lo_subdoc.backdrop.bg_color;
subdoc->backdrop.bg_color = XP_NEW(LO_Color);
if (subdoc->backdrop.bg_color != NULL)
*subdoc->backdrop.bg_color = *old_bg;
}
}
/* Use backdrop URL, if supplied. */
if (background_attr)
{
subdoc->backdrop.url = XP_STRDUP(background_attr);
subdoc->backdrop.tile_mode = tile_mode;
}
/*
* May inherit a backdrop_url from parent row.
*/
else if (table_row->backdrop.url)
{
subdoc->backdrop.url = XP_STRDUP(table_row->backdrop.url);
subdoc->backdrop.tile_mode = table_row->backdrop.tile_mode;
}
/*
* Else may inherit a backdrop_url from parent table.
*/
else if (table->backdrop.url != NULL)
{
subdoc->backdrop.url = XP_STRDUP(table->backdrop.url);
subdoc->backdrop.tile_mode = table->backdrop.tile_mode;
}
/*
* Else possibly inherit the backdrop_url
* 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.backdrop.url != NULL))
{
lo_Backdrop *src_backdrop = &up_state->current_ele->lo_subdoc.backdrop;
subdoc->backdrop.url = XP_STRDUP(src_backdrop->url);
subdoc->backdrop.tile_mode = src_backdrop->tile_mode;
}
}
/*
* Check for a background color attribute
*/
if (bgcolor_attr)
{
uint8 red, green, blue;
LO_ParseRGB(bgcolor_attr, &red, &green, &blue);
XP_FREEIF(subdoc->backdrop.bg_color);
subdoc->backdrop.bg_color = XP_NEW(LO_Color);
if (subdoc->backdrop.bg_color != NULL)
{
subdoc->backdrop.bg_color->red = red;
subdoc->backdrop.bg_color->green = green;
subdoc->backdrop.bg_color->blue = blue;
}
}
/* check for a style sheet directive for bgcolor */
if(style_struct)
{
char *property = STYLESTRUCT_GetString(style_struct, BG_COLOR_STYLE);
if(property)
{
uint8 red, green, blue;
LO_ParseStyleSheetRGB(property, &red, &green, &blue);
XP_FREEIF(subdoc->backdrop.bg_color);
subdoc->backdrop.bg_color = XP_NEW(LO_Color);
if (subdoc->backdrop.bg_color != NULL)
{
subdoc->backdrop.bg_color->red = red;
subdoc->backdrop.bg_color->green = green;
subdoc->backdrop.bg_color->blue = blue;
}
XP_FREE(property);
}
property = STYLESTRUCT_GetString(style_struct, BG_IMAGE_STYLE);
if(property)
{
if(subdoc->backdrop.url)
XP_FREE(subdoc->backdrop.url);
subdoc->backdrop.url = NULL;
if(strcasecomp(property, "none"))
{
subdoc->backdrop.url = XP_STRDUP(lo_ParseStyleSheetURL(property));
}
XP_FREE(property);
}
property = STYLESTRUCT_GetString(style_struct, BG_REPEAT_STYLE);
if(property)
{
if(!strcasecomp(property, BG_REPEAT_NONE_STYLE))
subdoc->backdrop.tile_mode = LO_NO_TILE;
else if(!strcasecomp(property, BG_REPEAT_X_STYLE))
subdoc->backdrop.tile_mode = LO_TILE_HORIZ;
else if(!strcasecomp(property, BG_REPEAT_Y_STYLE))
subdoc->backdrop.tile_mode = LO_TILE_VERT;
else
subdoc->backdrop.tile_mode = LO_TILE_BOTH;
}
}
}
else /* If relayout is TRUE */
{
/*
subdoc->backdrop.tile_mode = table_cell->cell->backdrop.tile_mode;
if (table_cell->cell->backdrop.bg_color != NULL)
{
subdoc->backdrop.bg_color = XP_NEW(LO_Color);
subdoc->backdrop.bg_color->red = table_cell->cell->backdrop.bg_color->red;
subdoc->backdrop.bg_color->green = table_cell->cell->backdrop.bg_color->green;
subdoc->backdrop.bg_color->blue = table_cell->cell->backdrop.bg_color->blue;
}
if (table_cell->cell->backdrop.url != NULL)
{
subdoc->backdrop.url = XP_STRDUP(table_cell->cell->backdrop.url);
}
*/
subdoc->backdrop = table_cell->cell->backdrop;
}
/*
* Check for a vertical align parameter
*/
if (valign_attr)
{
subdoc->vert_alignment = lo_EvalVAlignParam(valign_attr);
}
if(style_struct)
{
char *property = STYLESTRUCT_GetString(style_struct, VERTICAL_ALIGN_STYLE);
if(property)
{
subdoc->vert_alignment = lo_EvalVAlignParam(property);
XP_FREE(property);
}
}
if (relayout)
{
subdoc->vert_alignment = table_cell->vert_alignment;
}
/*
* Check for a horizontal align parameter
*/
if (halign_attr)
{
subdoc->horiz_alignment = lo_EvalCellAlignParam(halign_attr);
}
if (relayout)
{
subdoc->horiz_alignment = table_cell->horiz_alignment;
}
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.
*/
if (width_attr)
{
Bool is_percent;
val = lo_ValueOrPercent(width_attr, &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 = lo_CalculateCellPercentWidth( table, val );
/* Copied to lo_CalculateCellPercentWidth() */
/*
if ( table->table_width_fixed != FALSE )
{
val = table->width * val / 100;
}
else
{
val = 0;
}
*/
}
else
{
table_cell->percent_width = 0;
val = FEUNITS_X(val, context);
}
if (val < 0)
{
val = 0;
}
subdoc->width = val;
table_cell->specified_width = subdoc->width;
}
/* During relayout without reload, recalculate width of subdoc */
if (relayout)
{
if (table_cell->percent_width > 0)
{
subdoc->width = lo_CalculateCellPercentWidth( table, table_cell->percent_width);
table_cell->specified_width = subdoc->width;
}
else {
subdoc->width = table_cell->specified_width;
if (subdoc->width < 0) {
subdoc->width = 0;
}
}
}
/*
* If we're in the fixed layout case, figure out what our cell
* width should be.
*/
if ( table->fixed_cols > 0 )
{
int32 cell_empty_space;
int32 def_cell_width;
int32 desired_width;
cell_empty_space = lo_ComputeCellEmptySpace ( context, table, subdoc);
desired_width = subdoc->width;
/*
* Obey percentage cell width in fixed columns if we
* already know table width.
*/
if ((table_cell->percent_width > 0)&&(table->width > 0))
{
int32 avail_width;
int32 cell_pad;
/*
* Percentage width is a percentage of the available
* cell space.
*/
cell_pad = FEUNITS_X(table->inter_cell_pad, context);
avail_width = table->width -
((table->fixed_cols + 1) * cell_pad);
avail_width -= (table->table_ele->border_left_width +
table->table_ele->border_right_width);
desired_width = avail_width *
table_cell->percent_width / 100;
/*
* Pecentage width takes into account the
* cell padding/spacing already.
*/
desired_width -= cell_empty_space;
}
def_cell_width = lo_FindDefaultCellWidth (context, table,
table_cell, desired_width, cell_empty_space);
/*
* If NOWRAP is off, we can go ahead and layout to this width. Otherwise
* we want to layout to a dynamic width and then use the bigger of the
* default or computed width for the cell.
*/
if ( table_cell->nowrap == FALSE )
{
subdoc->width = def_cell_width;
}
}
if (height_attr)
{
Bool is_percent;
val = lo_ValueOrPercent(height_attr, &is_percent);
if (is_percent != FALSE)
{
/*
* We can process percentage heights here if
* we have a known table height.
*/
table_cell->percent_height = val;
table->has_percent_height_cells = TRUE;
val = lo_CalculateCellPercentHeight(table, table_cell);
/* Copied to lo_CalculateCellPercentHeight() */
/*
if ((table->height > 0)&&
(table_cell->percent_height > 0))
{
val = table->height *
table_cell->percent_height / 100;
}
else
{
val = 0;
}
*/
}
else
{
table_cell->percent_height = 0;
val = FEUNITS_X(val, context);
}
subdoc->height = val;
if (subdoc->height < 0)
{
subdoc->height = 0;
}
table_cell->specified_height = subdoc->height;
}
/* During relayout without reload, recalculate height of subdoc */
if (relayout)
{
if (table_cell->percent_height > 0)
{
subdoc->height = lo_CalculateCellPercentHeight( table, table_cell);
table_cell->specified_height = subdoc->height;
}
else {
subdoc->height = table_cell->specified_height;
if (subdoc->height < 0) {
subdoc->height = 0;
}
}
}
if (subdoc->width == 0)
{
/*
* Choose a default size that will fit within the current table. If NOWRAP is
* on, we just want to go ahead and choose a big width so that we're sure
* to get the correct nonwrapping text layout.
*/
if ( table_cell->nowrap == FALSE )
{
first_width = lo_ComputeInternalTableWidth ( context, table, state );
first_width -= lo_ComputeCellEmptySpace ( context, table, subdoc);
}
else
{
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;
}
lo_reuse_current_state(context, subdoc->state,
first_width, first_height, 0, 0, TRUE);
new_state = subdoc->state;
subdoc->state = NULL;
if (new_state == NULL)
{
lo_FreeElement(context, (LO_Element *)subdoc, FALSE);
return;
}
new_state->is_a_subdoc = SUBDOC_CELL;
lo_InheritParentState(context, 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, P_TABLE_DATA, 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_DATA, 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);
}
Bool
lo_cell_has_elements(LO_CellStruct *cell)
{
if (cell->cell_list != NULL)
{
return(TRUE);
}
if (cell->cell_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 top_inner_pad;
int32 bottom_inner_pad;
int32 left_inner_pad;
int32 right_inner_pad;
LO_Element **line_array;
top_inner_pad = FEUNITS_X(table->inner_top_pad, context);
bottom_inner_pad = FEUNITS_X(table->inner_bottom_pad, context);
left_inner_pad = FEUNITS_X(table->inner_left_pad, context);
right_inner_pad = FEUNITS_X(table->inner_right_pad, context);
ele_cnt = 0;
/*
* Mess with vertical alignment.
*/
vert_inc = subdoc->height - (2 * subdoc->border_width) -
(top_inner_pad + bottom_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 += left_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) -
(left_inner_pad + right_inner_pad);
side_inc = inside_width -
(c_eptr->lo_linefeed.x +
c_eptr->lo_linefeed.x_offset -
left_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) -
(left_inner_pad + right_inner_pad);
side_inc = inside_width -
(c_eptr->lo_linefeed.x +
c_eptr->lo_linefeed.x_offset -
left_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 + top_inner_pad);
if (eptr->type == LO_CELL)
{
lo_ShiftCell((LO_CellStruct *)eptr, left_inner_pad,
(vert_inc + top_inner_pad));
}
eptr = eptr->lo_any.next;
ele_cnt++;
}
eptr = old_state->float_list;
while (eptr != NULL)
{
eptr->lo_any.x += left_inner_pad;
eptr->lo_any.y += (vert_inc + top_inner_pad);
if (eptr->type == LO_CELL)
{
lo_ShiftCell((LO_CellStruct *)eptr, left_inner_pad,
(vert_inc + top_inner_pad));
}
eptr = eptr->lo_any.next;
ele_cnt++;
}
return(ele_cnt);
}
int32
lo_align_cell(MWContext *context, lo_DocState *state, lo_TableCell *cell_ptr,
LO_CellStruct *cell, lo_TableRec *table, lo_table_span *row_max)
{
int32 ele_cnt;
LO_Element *eptr;
int32 vert_inc;
int32 top_inner_pad;
int32 bottom_inner_pad;
int32 left_inner_pad;
int32 right_inner_pad;
top_inner_pad = FEUNITS_X(table->inner_top_pad, context);
bottom_inner_pad = FEUNITS_X(table->inner_bottom_pad, context);
left_inner_pad = FEUNITS_X(table->inner_left_pad, context);
right_inner_pad = FEUNITS_X(table->inner_right_pad, context);
ele_cnt = 0;
/*
* Mess with vertical alignment.
*/
vert_inc = cell->height - (2 * cell->border_width) -
(top_inner_pad + bottom_inner_pad) - cell_ptr->max_y;
if (vert_inc > 0)
{
if (cell_ptr->vert_alignment == LO_ALIGN_CENTER)
{
vert_inc = vert_inc / 2;
}
else if (cell_ptr->vert_alignment == LO_ALIGN_BOTTOM)
{
/* vert_inc unchanged */
}
else if ((cell_ptr->vert_alignment == LO_ALIGN_BASELINE)&&
(row_max != NULL))
{
int32 baseline;
int32 tmp_val;
baseline = lo_GetCellBaseline(cell);
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 cell.
*/
eptr = cell->cell_list;
while (eptr != NULL)
{
eptr->lo_any.x += left_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 = cell->width -
(2 * cell->border_width) -
(2 * cell->border_horiz_space) -
(left_inner_pad + right_inner_pad);
side_inc = inside_width -
(c_eptr->lo_linefeed.x +
c_eptr->lo_linefeed.x_offset -
left_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 = cell->width -
(2 * cell->border_width) -
(2 * cell->border_horiz_space) -
(left_inner_pad + right_inner_pad);
side_inc = inside_width -
(c_eptr->lo_linefeed.x +
c_eptr->lo_linefeed.x_offset -
left_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 + top_inner_pad);
if (eptr->type == LO_CELL)
{
lo_ShiftCell((LO_CellStruct *)eptr, left_inner_pad,
(vert_inc + top_inner_pad));
}
eptr = eptr->lo_any.next;
ele_cnt++;
}
eptr = cell->cell_float_list;
while (eptr != NULL)
{
eptr->lo_any.x += left_inner_pad;
eptr->lo_any.y += (vert_inc + top_inner_pad);
if (eptr->type == LO_CELL)
{
lo_ShiftCell((LO_CellStruct *)eptr, left_inner_pad,
(vert_inc + top_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, Bool relayout)
{
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 */
/* Close any layers (blocks) that were opened in this cell, in case
the document author forgot to. */
while (old_state->layer_nest_level > 0)
{
lo_EndLayer(context, old_state, PR_TRUE);
}
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);
if (relayout == FALSE)
{
/*
* We don't want to leave any end paragraph linbreaks in the subdoc
* as they give us a really ugly blank line at the bottom of a cell. So,
* if the last element in the list is paragraph break linefeed, then
* we kill it.
*/
eptr = old_state->end_last_line;
if ( (eptr != NULL) && (eptr->type == LO_LINEFEED) &&
(eptr->lo_linefeed.break_type == LO_LINEFEED_BREAK_PARAGRAPH) )
{
LO_Element *prev;
prev = eptr->lo_any.prev;
/*
* Kill this layout element and reset the subdoc height
*/
if ( prev != NULL )
{
prev->lo_any.next = NULL;
old_state->end_last_line = prev;
}
else
{
old_state->line_list = NULL;
old_state->end_last_line = NULL;
}
/* The if condition checks to make sure that the linefeed that we just killed
* was sticking out of the bottom of the cell. This fixes bug 81282.
*/
if (eptr->lo_linefeed.y + eptr->lo_linefeed.line_height >= old_state->y) {
/* shrink the document */
old_state->y -= eptr->lo_linefeed.line_height;
}
lo_RecycleElements ( context, old_state, eptr );
}
}
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;
}
/*
* Add in the size of the subdoc's borders
*/
subdoc->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
* width 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;
}
/*
* Remember: (2 * subdoc->border_width) has already been added to the subdoc
* width above...
*/
subdoc_width = subdoc->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_SoftLineBreak(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)
{
LO_LockLayout();
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);
}
}
LO_UnlockLayout();
}
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_RelayoutCaptionSubdoc(MWContext *context, lo_DocState *state, lo_TableCaption *caption,
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;
int32 original_tag_count;
intn hold_url_list_len;
NET_ReloadMethod save_force;
Bool save_diff_state;
int32 save_state_pushes;
int32 save_state_pops;
lo_DocLists *doc_lists;
int32 hold_image_list_count;
int32 hold_applet_list_count;
int32 hold_embed_list_count;
int32 hold_current_layer_num;
/*
* 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;
doc_lists = lo_GetCurrentDocLists(state);
/*
* If this subdoc contained form elements. We want to reuse
* them without messing 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 (doc_lists->form_list != NULL)
{
lo_FormData *form_list;
lo_FormData *tmp_fptr;
hold_form_id = old_state->form_id;
hold_current_form_num = doc_lists->current_form_num;
form_list = doc_lists->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;
}
doc_lists->form_list = form_list;
doc_lists->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;
/* ditto here for the last comment. We are trying to keep
* a tag count that reflects the order of tags coming in
* on the stream. We need that count to be correct across
* multiple relayout instances so we restore the top state
* count with the saved state
*/
original_tag_count = top_state->tag_count;
top_state->tag_count = state->beginning_tag_count;
/*
* Same goes for anchors and images
*/
hold_url_list_len = doc_lists->url_list_len;
doc_lists->url_list_len = old_state->url_count_base;
hold_image_list_count = doc_lists->image_list_count;
doc_lists->image_list_count = old_state->image_list_count_base;
hold_applet_list_count = doc_lists->applet_list_count;
doc_lists->applet_list_count = old_state->applet_list_count_base;
hold_embed_list_count = doc_lists->embed_list_count;
doc_lists->embed_list_count = old_state->embed_list_count_base;
hold_current_layer_num = top_state->current_layer_num;
top_state->current_layer_num = old_state->current_layer_num_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);
*/
lo_reuse_current_state(context, subdoc->state, width,
first_height, 0, 0, FALSE);
new_state = subdoc->state;
subdoc->state = NULL;
if (new_state == NULL)
{
state->top_state->force_reload = save_force;
return(subdoc);
}
new_state->end_last_line = NULL;
/*
if (old_state->is_a_subdoc == SUBDOC_CAPTION)
{
new_state->is_a_subdoc = SUBDOC_CAPTION;
}
else
{
new_state->is_a_subdoc = SUBDOC_CELL;
}
*/
new_state->is_a_subdoc = SUBDOC_CAPTION;
lo_InheritParentColors(context, 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;
/* we don't need min widths during relayout */
new_state->need_min_width = FALSE;
/* reset line_height stack */
while (new_state->line_height_stack)
lo_PopLineHeight(new_state);
/*
* Initialize the alignment stack for this state
* to match the caption alignment.
*/
if (subdoc->horiz_alignment != LO_ALIGN_LEFT)
{
lo_PushAlignment(new_state, P_TABLE_DATA, 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);
*/
#if 0 /* Doesn't need to happen any more because we do non-destructive reflow
/*
* Save our parent's state levels
*/
save_diff_state = top_state->diff_state;
save_state_pushes = top_state->state_pushes;
save_state_pops = top_state->state_pops;
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;
}
/*
* Reset these so we can tell if anything happened
*/
top_state->diff_state = FALSE;
top_state->state_pushes = 0;
top_state->state_pops = 0;
#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)
{
int32 state_diff;
/* how has our state level changed? */
state_diff = top_state->state_pushes - top_state->state_pops;
/*
* That tag popped us up one state level. If this new
* state is still a subdoc, save the tag there.
*/
if (state_diff == -1)
{
if ((tmp_state->is_a_subdoc == SUBDOC_CELL)||
(tmp_state->is_a_subdoc == SUBDOC_CAPTION))
{
/* if we just popped a table we need to insert
* a dummy end tag to pop the dummy start tag
* we shove on the stack after createing a table
*/
PA_Tag *new_tag = LO_CreateStyleSheetDummyTag(tag);
if(new_tag)
{
lo_SaveSubdocTags(context, tmp_state, new_tag);
}
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 ) &&
( top_state->diff_state != FALSE ) &&
( state_diff == 0 ))
{
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 (( top_state->diff_state == FALSE ) &&
( state_diff == 0 ))
{
lo_SaveSubdocTags(context, sub_state, tag);
}
/*
* Else that tag started a new, nested subdoc.
* Add the starting tag to the parent.
*/
else if (( state_diff == 1 ))
{
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))
{
PA_Tag *new_tag;
tmp_state->subdoc_tags =
sub_state->subdoc_tags_end;
/* add an aditional dummy tag so that style sheets
* can use it to query styles from for this entry
* that created a table
*/
new_tag = LO_CreateStyleSheetDummyTag(tag);
if(new_tag)
{
lo_SaveSubdocTags(context, tmp_state, new_tag);
}
}
}
/*
* This can never happen.
*/
else
{
PA_FreeTag(tag);
}
}
tag_ptr = tag_list;
}
/*
* Restore our parent's state levels
*/
top_state->diff_state = save_diff_state;
top_state->state_pushes = save_state_pushes;
top_state->state_pops = save_state_pops;
#endif
/*
* 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;
}
*/
lo_rl_ReflowDocState( context, state );
/*
* makes sure we are at the bottom
* of everything in the document.
*/
/*
lo_CloseOutLayout(context, state);
*/
lo_EndLayoutDuringReflow( 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 ((doc_lists->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 = doc_lists->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;
}
doc_lists->form_list = form_list;
doc_lists->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;
/* verify that the tag count is still correct */
top_state->tag_count = original_tag_count;
/*
* Likewise for the anchor list.
*/
doc_lists->url_list_len = hold_url_list_len;
doc_lists->image_list_count = hold_image_list_count;
doc_lists->applet_list_count = hold_applet_list_count;
doc_lists->embed_list_count = hold_embed_list_count;
top_state->current_layer_num = hold_current_layer_num;
subdoc = NULL;
if ((state != old_state)&&
(state->current_ele != NULL))
{
subdoc = lo_EndCellSubDoc(context, state,
old_state, state->current_ele, TRUE);
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);
}
LO_CellStruct *
lo_RelayoutCell(MWContext *context, lo_DocState *state,
LO_SubDocStruct *subdoc, lo_TableCell *cell_ptr,
LO_CellStruct *cell, int32 width, Bool is_a_header,
Bool relayout)
{
LO_CellStruct *cell_ele;
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;
int32 original_tag_count;
intn hold_url_list_len;
NET_ReloadMethod save_force;
Bool save_diff_state;
int32 save_state_pushes;
int32 save_state_pops;
lo_DocLists *doc_lists;
int32 hold_image_list_count;
int32 hold_applet_list_count;
int32 hold_embed_list_count;
int32 hold_current_layer_num;
LO_Element * elem_list;
/*
* 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;
top_state = state->top_state;
/*
* We are going to reuse this subdoc element instead
* of allocating a new one.
lo_reuse_current_subdoc(context, subdoc);
subdoc->state = NULL;
*/
subdoc->width = width;
subdoc->height = 0;
subdoc->horiz_alignment = cell_ptr->horiz_alignment;
doc_lists = lo_GetCurrentDocLists(state);
/*
* If this subdoc contained form elements. We want to reuse
* them without messing 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 (doc_lists->form_list != NULL)
{
lo_FormData *form_list;
lo_FormData *tmp_fptr;
hold_form_id = cell_ptr->form_id;
hold_current_form_num = doc_lists->current_form_num;
form_list = doc_lists->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;
}
doc_lists->form_list = form_list;
doc_lists->current_form_num = hold_form_id;
if (form_list != NULL)
{
hold_form_ele_cnt = form_list->form_ele_cnt;
form_list->form_ele_cnt = cell_ptr->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 = cell_ptr->embed_count_base;
/* same for tag count */
original_tag_count = top_state->tag_count;
top_state->tag_count = cell_ptr->beginning_tag_count;
/*
* Same goes for anchors and images
*/
hold_url_list_len = doc_lists->url_list_len;
doc_lists->url_list_len = cell_ptr->url_count_base;
hold_image_list_count = doc_lists->image_list_count;
doc_lists->image_list_count = cell_ptr->image_list_count_base;
hold_applet_list_count = doc_lists->applet_list_count;
doc_lists->applet_list_count = cell_ptr->applet_list_count_base;
hold_embed_list_count = doc_lists->embed_list_count;
doc_lists->embed_list_count = cell_ptr->embed_list_count_base;
hold_current_layer_num = top_state->current_layer_num;
top_state->current_layer_num = cell_ptr->current_layer_num_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 = cell_ptr->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 = cell_ptr->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.
*/
lo_reuse_current_state(context, subdoc->state,
width, first_height, 0, 0, TRUE);
new_state = subdoc->state;
subdoc->state = NULL;
if (new_state == NULL)
{
state->top_state->force_reload = save_force;
return(cell);
}
if (cell_ptr->is_a_subdoc == SUBDOC_CAPTION)
{
new_state->is_a_subdoc = SUBDOC_CAPTION;
}
else
{
new_state->is_a_subdoc = SUBDOC_CELL;
}
lo_InheritParentState(context, 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;
/* we don't need min widths during relayout */
new_state->need_min_width = FALSE;
/* reset line_height stack */
while(new_state->line_height_stack)
lo_PopLineHeight(new_state);
/*
* Initialize the alignment stack for this state
* to match the caption alignment.
*/
if (subdoc->horiz_alignment != LO_ALIGN_LEFT)
{
lo_PushAlignment(new_state, P_TABLE_DATA, 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 = cell_ptr->subdoc_tags;
tag_end_ptr = cell_ptr->subdoc_tags_end;
cell_ptr->subdoc_tags = NULL;
cell_ptr->subdoc_tags_end = NULL;
if (tag_end_ptr != NULL)
{
tag_end_ptr = tag_end_ptr->next;
}
*/
/*
* Copy some cell attribute state from the old cell to the subdoc
* so that we retain the correct state. Make sure that the bg_color
* doesn't get freed.
*/
subdoc->horiz_alignment = cell_ptr->horiz_alignment;
subdoc->vert_alignment = cell_ptr->vert_alignment;
subdoc->backdrop = cell->backdrop;
/*
cell->backdrop.bg_color = NULL;
cell->backdrop.url = NULL;
*/
/*
* Clean up memory used by old cell.
*/
/*
elem_list = cell->cell_list;
cell->next = NULL;
cell->cell_list = NULL;
cell->cell_list_end = NULL;
lo_relayout_recycle(context, state, (LO_Element *)cell);
*/
/*
* Relayout all the goodies
*/
/*
lo_RelayoutTags(context, state, tag_ptr, tag_end_ptr, elem_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_rl_ReflowCell( context, state, cell );
/* Replaced with lo_EndLayoutDuringReflow()
lo_CloseOutLayout(context, state);
*/
lo_EndLayoutDuringReflow( 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 ((doc_lists->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 = doc_lists->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;
}
doc_lists->form_list = form_list;
doc_lists->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;
/* ditto for tag_count */
top_state->tag_count = original_tag_count;
/*
* Likewise for the anchor list and image list.
*/
doc_lists->url_list_len = hold_url_list_len;
doc_lists->image_list_count = hold_image_list_count;
doc_lists->applet_list_count = hold_applet_list_count;
doc_lists->embed_list_count = hold_embed_list_count;
top_state->current_layer_num = hold_current_layer_num;
subdoc = NULL;
cell_ele = NULL;
if ((state != old_state)&&
(state->current_ele != NULL))
{
lo_DocState *subdoc_state;
int32 dx, dy;
int32 base_x, base_y;
subdoc = lo_EndCellSubDoc(context, state,
old_state, state->current_ele, TRUE);
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;
}
}
*/
subdoc_state = (lo_DocState *)(subdoc->state);
cell_ptr->start_in_form = subdoc_state->start_in_form;
cell_ptr->form_id = subdoc_state->form_id;
cell_ptr->form_ele_cnt = subdoc_state->form_ele_cnt;
cell_ptr->form_data_index = subdoc_state->form_data_index;
cell_ptr->embed_count_base = subdoc_state->embed_count_base;
cell_ptr->url_count_base = subdoc_state->url_count_base;
cell_ptr->image_list_count_base = subdoc_state->image_list_count_base;
cell_ptr->applet_list_count_base = subdoc_state->applet_list_count_base;
cell_ptr->embed_list_count_base = subdoc_state->embed_list_count_base;
cell_ptr->current_layer_num_base = subdoc_state->current_layer_num_base;
cell_ptr->must_relayout = subdoc_state->must_relayout_subdoc;
cell_ptr->is_a_subdoc = subdoc_state->is_a_subdoc;
/*
cell_ptr->subdoc_tags = subdoc_state->subdoc_tags;
cell_ptr->subdoc_tags_end = subdoc_state->subdoc_tags_end;
*/
subdoc_state->subdoc_tags = NULL;
subdoc_state->subdoc_tags_end = NULL;
cell_ptr->max_y = subdoc_state->y;
cell_ptr->horiz_alignment = subdoc->horiz_alignment;
cell_ptr->vert_alignment = subdoc->vert_alignment;
/*
cell_ele = lo_SmallSquishSubDocToCell(context, state, subdoc,
&dx, &dy);
*/
cell_ele = cell_ptr->cell;
lo_CreateCellFromSubDoc(context, state, subdoc, cell_ele, &dx, &dy);
lo_cleanup_old_state(subdoc->state);
base_x = cell_ele->x + cell_ele->x_offset + cell_ele->border_width;
base_y = cell_ele->y + cell_ele->y_offset + cell_ele->border_width;
dx -= base_x;
dy -= base_y;
cell_ptr->cell_base_x = dx;
cell_ptr->cell_base_y = dy;
}
XP_ASSERT ( cell_ele != NULL );
old_state->must_relayout_subdoc = FALSE;
state->top_state->force_reload = save_force;
/* pop the style stack once to get rid of the extra dummy tag
* that we added to the stack to force styles on the begin
* subdoc in relayout
*/
if (relayout == FALSE)
{
LO_PopStyleTagByIndex(context, &state, P_TABLE_DATA, 0);
}
return(cell_ele);
}
/*
* if normal borders is TRUE draw cell borders if the rest of
* the table has borders. If FALSE, never draw cell borders
*/
void
lo_BeginTableCellAttributes(MWContext *context,
lo_DocState *state,
lo_TableRec *table,
char * colspan_attr,
char * rowspan_attr,
char * nowrap_attr,
char * bgcolor_attr,
char * background_attr,
lo_TileMode tile_mode,
char * valign_attr,
char * halign_attr,
char * width_attr,
char * height_attr,
Bool is_a_header,
Bool normal_borders)
{
lo_TableRow *table_row;
lo_TableCell *table_cell;
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;
}
if (state->is_a_subdoc != SUBDOC_NOT)
{
table_cell->in_nested_table = TRUE;
}
else
{
table_cell->in_nested_table = FALSE;
}
/* Copied to lo_InitForBeginCell()
table_cell->must_relayout = FALSE;
*/
table_cell->subdoc_tags = NULL;
table_cell->subdoc_tags_end = NULL;
/* Copied to lo_InitForBeginCell()
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->specified_width = 0;
table_cell->specified_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 = NULL;
table_cell->next = NULL;
table_cell->beginning_tag_count = state->top_state->tag_count;
lo_InitForBeginCell( table_row, table_cell );
if (table->current_subdoc == NULL)
{
XP_DELETE(table_cell);
return;
}
if (colspan_attr)
{
val = XP_ATOI(colspan_attr);
if (val < 1)
{
val = 1;
}
/*
* Prevent huge colspan
*/
if (val > TABLE_MAX_COLSPAN)
{
val = TABLE_MAX_COLSPAN;
}
table_cell->colspan = val;
}
if (rowspan_attr)
{
val = XP_ATOI(rowspan_attr);
if (val < 1)
{
val = 1;
}
/*
* Prevent huge rowspan
*/
if (val > TABLE_MAX_ROWSPAN)
{
val = TABLE_MAX_ROWSPAN;
}
table_cell->rowspan = val;
}
if (nowrap_attr)
{
table_cell->nowrap = TRUE;
}
/* Copied to lo_InitForBeginCell()
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,
bgcolor_attr,
background_attr,
tile_mode,
valign_attr,
halign_attr,
width_attr,
height_attr,
is_a_header,
normal_borders ? table->draw_borders : 0,
FALSE);
/*
* We added a new state.
*/
lo_PushStateLevel ( context );
}
void
lo_BeginTableCell(MWContext *context, lo_DocState *state, lo_TableRec *table,
PA_Tag *tag, Bool is_a_header)
{
char *colspan_attr = (char*)lo_FetchParamValue(context, tag, PARAM_COLSPAN);
char *rowspan_attr = (char*)lo_FetchParamValue(context, tag, PARAM_ROWSPAN);
char *nowrap_attr = (char*)lo_FetchParamValue(context, tag, PARAM_NOWRAP);
char *bgcolor_attr = (char*)lo_FetchParamValue(context, tag, PARAM_BGCOLOR);
char *background_attr= (char*)lo_FetchParamValue(context, tag, PARAM_BACKGROUND);
char *valign_attr = (char*)lo_FetchParamValue(context, tag, PARAM_VALIGN);
char *halign_attr = (char*)lo_FetchParamValue(context, tag, PARAM_ALIGN);
char *width_attr = (char*)lo_FetchParamValue(context, tag, PARAM_WIDTH);
char *height_attr = (char*)lo_FetchParamValue(context, tag, PARAM_HEIGHT);
/* remove the PA_LOCK stuff */
lo_BeginTableCellAttributes(context,
state,
table,
colspan_attr,
rowspan_attr,
nowrap_attr,
bgcolor_attr,
background_attr,
LO_TILE_BOTH, /* Default backdrop tile mode */
valign_attr,
halign_attr,
width_attr,
height_attr,
is_a_header,
TRUE);
if(colspan_attr)
PA_FREE(colspan_attr);
if(rowspan_attr)
PA_FREE(rowspan_attr);
if(nowrap_attr)
PA_FREE(nowrap_attr);
if(bgcolor_attr)
PA_FREE(bgcolor_attr);
if(background_attr)
PA_FREE(background_attr);
if(valign_attr)
PA_FREE(valign_attr);
if(halign_attr)
PA_FREE(halign_attr);
if(width_attr)
PA_FREE(width_attr);
if(height_attr)
PA_FREE(height_attr);
}
void
lo_EndTableCell(MWContext *context, lo_DocState *state, Bool relayout )
{
LO_SubDocStruct *subdoc;
LO_CellStruct *cell_ele;
lo_TableRec *table;
lo_TableRow *table_row;
lo_TableCell *table_cell;
lo_table_span *span_rec;
int32 top_inner_pad;
int32 bottom_inner_pad;
int32 left_inner_pad;
int32 right_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.
*/
if (relayout == FALSE)
{
lo_CloseOutLayout(context, state);
}
else
{
lo_EndLayoutDuringReflow( context, state );
}
old_state = state;
/*
* Get the unique document ID, and retrieve 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;
cell_ele = NULL;
if ((state != old_state)&&
(state->current_ele != NULL))
{
subdoc = lo_EndCellSubDoc(context, state,
old_state, state->current_ele, relayout);
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
{
}
}
/*
* We popped a state level.
*/
lo_PopStateLevel ( context );
table = state->current_table;
table_row = table->row_ptr;
table_cell = table_row->cell_ptr;
top_inner_pad = FEUNITS_X(table->inner_top_pad, context);
bottom_inner_pad = FEUNITS_X(table->inner_bottom_pad, context);
left_inner_pad = FEUNITS_X(table->inner_left_pad, context);
right_inner_pad = FEUNITS_X(table->inner_right_pad, context);
if (subdoc != NULL)
{
int32 subdoc_width;
int32 subdoc_height;
int32 min_cellwidth;
int32 base_x, base_y;
int32 dx, dy;
int32 cell_internal_width;
lo_DocState *subdoc_state;
Bool reset_min_width;
reset_min_width = FALSE;
cell_internal_width = old_state->max_width;
/* how big do we think this cell should be? */
min_cellwidth = old_state->min_width;
/*
* If the cell is smaller than this, we need to grow it so that
* any internal elements don't overwrite the cell borders.
*/
if (subdoc->width < min_cellwidth)
{
/*
* We need to lay things out again as we now have more space.
* Do we want to be smart and see if we contain things that
* will change?
* Be sure to add in the width of the borders as later code expects it
*/
subdoc->width = min_cellwidth + (2 * subdoc->border_width);
old_state->must_relayout_subdoc = TRUE;
cell_internal_width = min_cellwidth;
}
subdoc_width = subdoc->width +
(2 * subdoc->border_horiz_space) +
(left_inner_pad + right_inner_pad);
subdoc_height = subdoc->height +
(2 * subdoc->border_vert_space) +
(top_inner_pad + bottom_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) +
(left_inner_pad + right_inner_pad);
/*
* This is some nasty logic. We need to reset the min_width
* of the cell in cases where we're certain about how large
* the cell is.
*/
if ( (table_cell->min_width < table_cell->max_width) )
{
/*
* If we're a fixed width cell and fixed layout (COLS) is on.
* BRAIN DAMAGE: It's arguable that we should always do this - a width for
* the cell was specified, we should respect it. However, certain popular
* sites don't look too good if we do...
*/
if ( (table_cell->specified_width > 0) &&
(table_cell->percent_width == 0) &&
(table->fixed_cols > 0) )
{
reset_min_width = TRUE;
}
else
/*
* If we're in a fixed width table who's width does not
* depend on it's parent and are using fixed layout (COLS).
*/
if ( (table->fixed_cols > 0) &&
(table->table_width_fixed != FALSE) )
{
reset_min_width = TRUE;
}
}
/*
* If nowrap is on or min_width ended up being bigger than
* max_width
*/
if ((table_cell->nowrap != FALSE)||
(table_cell->min_width > table_cell->max_width))
{
reset_min_width = TRUE;
}
if ( reset_min_width != FALSE )
{
table_cell->min_width = table_cell->max_width;
}
/*
* If we're in the fixed layout case, then we may need to grow this
* column to fit this new cell width. This will allow any subsequent
* columns to be layed out to the correct size and not have to be
* relayed out.
*/
if ( table->fixed_cols > 0 )
{
lo_SetDefaultCellWidth( context, table, subdoc, table_cell, cell_internal_width );
}
table_cell->height = subdoc_height;
table_cell->baseline = lo_GetSubDocBaseline(subdoc);
subdoc_state = (lo_DocState *)(subdoc->state);
table_cell->start_in_form = subdoc_state->start_in_form;
table_cell->form_id = subdoc_state->form_id;
table_cell->form_ele_cnt = subdoc_state->form_ele_cnt;
table_cell->form_data_index = subdoc_state->form_data_index;
table_cell->embed_count_base = subdoc_state->embed_count_base;
table_cell->url_count_base = subdoc_state->url_count_base;
table_cell->image_list_count_base = subdoc_state->image_list_count_base;
table_cell->applet_list_count_base = subdoc_state->applet_list_count_base;
table_cell->embed_list_count_base = subdoc_state->embed_list_count_base;
table_cell->current_layer_num_base = subdoc_state->current_layer_num_base;
table_cell->must_relayout = subdoc_state->must_relayout_subdoc;
table_cell->is_a_subdoc = subdoc_state->is_a_subdoc;
if (relayout == FALSE)
{
table_cell->subdoc_tags = subdoc_state->subdoc_tags;
table_cell->subdoc_tags_end = subdoc_state->subdoc_tags_end;
}
subdoc_state->subdoc_tags = NULL;
subdoc_state->subdoc_tags_end = NULL;
table_cell->max_y = subdoc_state->y;
table_cell->horiz_alignment = subdoc->horiz_alignment;
table_cell->vert_alignment = subdoc->vert_alignment;
if (relayout == FALSE)
{
cell_ele = lo_SmallSquishSubDocToCell(context, state, subdoc,
&dx, &dy);
/* Keep ptr. back to table state structs for relayout */
cell_ele->table_cell = table_cell;
cell_ele->table_row = table_row;
cell_ele->table = table;
}
else
{
cell_ele = table_cell->cell;
lo_CreateCellFromSubDoc(context, state, subdoc, cell_ele, &dx, &dy);
}
lo_cleanup_old_state(subdoc->state);
base_x = cell_ele->x + cell_ele->x_offset + cell_ele->border_width;
base_y = cell_ele->y + cell_ele->y_offset + cell_ele->border_width;
dx -= base_x;
dy -= base_y;
table_cell->cell_base_x = dx;
table_cell->cell_base_y = dy;
}
table_cell->cell = cell_ele;
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;
/*
* If the user specified a height for the cell,
* that becomes our min height.
*/
if ((table_cell->specified_height > 0)&&
(table_cell->specified_height > span_rec->min_dim))
{
span_rec->min_dim = table_cell->specified_height;
}
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;
caption->cell_ele = 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 top_inner_pad;
int32 bottom_inner_pad;
int32 left_inner_pad;
int32 right_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, FALSE);
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;
top_inner_pad = FEUNITS_X(table->inner_top_pad, context);
bottom_inner_pad = FEUNITS_X(table->inner_bottom_pad, context);
left_inner_pad = FEUNITS_X(table->inner_left_pad, context);
right_inner_pad = FEUNITS_X(table->inner_right_pad, context);
if (subdoc != NULL)
{
int32 subdoc_width;
int32 subdoc_height;
subdoc_width = subdoc->width +
(2 * subdoc->border_horiz_space) +
(left_inner_pad + right_inner_pad);
subdoc_height = subdoc->height +
(2 * subdoc->border_vert_space) +
(top_inner_pad + bottom_inner_pad);
caption->max_width = subdoc_width;
caption->min_width = old_state->min_width +
(2 * subdoc->border_width) +
(2 * subdoc->border_horiz_space) +
(left_inner_pad + right_inner_pad);
if (caption->min_width > caption->max_width)
{
caption->min_width = caption->max_width;
}
caption->height = subdoc_height;
}
caption->subdoc = subdoc;
/* If the caption is empty, free the memory used by it */
if (lo_subdoc_has_elements(caption->subdoc->state) == FALSE)
{
lo_FreeTableCaption( context, state, table );
}
/*
* We popped a state level.
*/
lo_PopStateLevel ( context );
}
void
lo_BeginTableRowAttributes(MWContext *context,
lo_DocState *state,
lo_TableRec *table,
char *bgcolor_attr,
char *background_attr,
char *valign_attr,
char *halign_attr)
{
lo_TableRow *table_row;
lo_table_span *span_rec;
char *bgcolor_from_style=NULL;
#ifdef LOCAL_DEBUG
fprintf(stderr, "lo_BeginTableRow called\n");
#endif /* LOCAL_DEBUG */
table_row = XP_NEW(lo_TableRow);
if (table_row == NULL)
{
return;
}
/* copied to lo_UpdateTableStateForBeginRow()
table_row->row_done = FALSE;
*/
table_row->has_percent_width_cells = FALSE;
table_row->backdrop.bg_color = NULL;
table_row->backdrop.url = NULL;
table_row->backdrop.tile_mode = LO_TILE_BOTH;
/* copied to lo_UpdateTableStateForBeginRow()
table_row->cells = 0;
*/
table_row->vert_alignment = LO_ALIGN_DEFAULT;
table_row->horiz_alignment = LO_ALIGN_DEFAULT;
/* copied to lo_UpdateTableStateForBeginRow()
table_row->cell_list = NULL;
table_row->cell_ptr = NULL;
*/
table_row->next = NULL;
lo_UpdateTableStateForBeginRow( table, table_row );
/* check for style sheet color and override if necessary */
if(state->top_state && state->top_state->style_stack)
{
StyleStruct *style_struct;
style_struct = STYLESTACK_GetStyleByIndex(
state->top_state->style_stack,
0);
if(style_struct)
{
bgcolor_from_style = STYLESTRUCT_GetString(style_struct, BG_COLOR_STYLE);
if(bgcolor_from_style)
{
bgcolor_attr = bgcolor_from_style;
}
}
}
/*
* Check for a background color attribute
*/
if (bgcolor_attr)
{
uint8 red, green, blue;
XP_Bool rv;
if(bgcolor_from_style)
rv = LO_ParseStyleSheetRGB(bgcolor_attr, &red, &green, &blue);
else
rv = LO_ParseRGB(bgcolor_attr, &red, &green, &blue);
if(rv)
{
table_row->backdrop.bg_color = XP_NEW(LO_Color);
if (table_row->backdrop.bg_color != NULL)
{
table_row->backdrop.bg_color->red = red;
table_row->backdrop.bg_color->green = green;
table_row->backdrop.bg_color->blue = blue;
}
}
}
if (background_attr)
table_row->backdrop.url = XP_STRDUP(background_attr);
XP_FREEIF(bgcolor_from_style);
/*
* Check for a vertical align parameter
*/
if (valign_attr)
{
table_row->vert_alignment = lo_EvalVAlignParam(valign_attr);
}
/*
* Check for a horizontal align parameter
*/
if (halign_attr)
{
table_row->horiz_alignment = lo_EvalCellAlignParam(halign_attr);
}
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;
}
/* copied to lo_UpdateTableStateForBeginRow()
table->width_span_ptr = NULL;
*/
span_rec = XP_NEW(lo_table_span);
if (span_rec == NULL)
{
return;
}
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;
}
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;
}
void
lo_BeginTableRow(MWContext *context, lo_DocState *state, lo_TableRec *table,
PA_Tag *tag)
{
char *bgcolor_attr = (char*)lo_FetchParamValue(context, tag, PARAM_BGCOLOR);
char *background_attr = (char*)lo_FetchParamValue(context, tag, PARAM_BACKGROUND);
char *valign_attr = (char*)lo_FetchParamValue(context, tag, PARAM_VALIGN);
char *halign_attr = (char*)lo_FetchParamValue(context, tag, PARAM_ALIGN);
/* remove the PA_LOCK stuff */
lo_BeginTableRowAttributes(context,
state,
table,
bgcolor_attr,
background_attr,
valign_attr,
halign_attr);
if(bgcolor_attr)
PA_FREE(bgcolor_attr);
if(valign_attr)
PA_FREE(valign_attr);
if(halign_attr)
PA_FREE(halign_attr);
}
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;
}
/*
* We've hit the end of a row, if it's the first row and
* we haven't allocated all columns yet and table width
* is remaining, then set their size now.
*/
if ( table->fixed_width_remaining > 0 )
{
if ( (table_row->cells < table->fixed_cols) && (table->fixed_col_widths != NULL) )
{
int32 count;
int32 colwidth;
int32 cell_extra_space;
int32 left_inner_pad;
int32 right_inner_pad;
/* how much border/pad space do we need per cell */
if (table->draw_borders == TABLE_BORDERS_OFF)
{
cell_extra_space = 2 * TABLE_DEF_CELL_BORDER;
}
else if (table->draw_borders == TABLE_BORDERS_ON)
{
cell_extra_space = 2 * TABLE_DEF_CELL_BORDER;
}
else
{
cell_extra_space = 0;
}
left_inner_pad = FEUNITS_X(table->inner_left_pad, context);
right_inner_pad = FEUNITS_X(table->inner_right_pad, context);
cell_extra_space += left_inner_pad + right_inner_pad;
/* divide space up to the remaining cols */
colwidth = ( table->fixed_width_remaining /
( table->fixed_cols - table_row->cells )) - cell_extra_space;
if ( colwidth < 0 )
{
colwidth = 0;
}
for ( count = table_row->cells; count < table->fixed_cols; ++count )
{
table->fixed_col_widths[ count ] = colwidth;
table->fixed_width_remaining -= colwidth;
}
/* add any leftover space to the last row */
table->fixed_col_widths[ table->fixed_cols - 1 ] +=
table->fixed_width_remaining;
}
table->fixed_width_remaining = 0;
}
}
void
lo_BeginTableAttributes(MWContext *context,
lo_DocState *state,
char *align_attr,
char *border_attr,
char *border_top_attr,
char *border_bottom_attr,
char *border_left_attr,
char *border_right_attr,
char *border_color_attr,
char *border_style_attr,
char *vspace_attr,
char *hspace_attr,
char *bgcolor_attr,
char *background_attr,
char *width_attr,
char *height_attr,
char *cellpad_attr,
char *toppad_attr,
char *bottompad_attr,
char *leftpad_attr,
char *rightpad_attr,
char *cellspace_attr,
char *cols_attr)
{
lo_TableRec *table;
LO_TableStruct *table_ele;
int32 val;
char *bgcolor_from_style = NULL;
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;
/* Copied into lo_PositionTableElement() */
/*
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;
/*
* Default to the current alignment
*/
if ( state->align_stack != NULL )
{
table_ele->alignment = state->align_stack->alignment;
}
else
{
table_ele->alignment = LO_ALIGN_LEFT;
}
table_ele->border_width = TABLE_DEF_BORDER;
table_ele->border_top_width = TABLE_DEF_BORDER;
table_ele->border_bottom_width = TABLE_DEF_BORDER;
table_ele->border_left_width = TABLE_DEF_BORDER;
table_ele->border_right_width = TABLE_DEF_BORDER;
table_ele->border_style = TABLE_DEF_BORDER_STYLE;
table_ele->border_vert_space = TABLE_DEF_VERTICAL_SPACE;
table_ele->border_horiz_space = TABLE_DEF_HORIZONTAL_SPACE;
table_ele->border_color.red = 0;
table_ele->border_color.green = 0;
table_ele->border_color.blue = 0;
table_ele->ele_attrmask = 0;
table_ele->sel_start = -1;
table_ele->sel_end = -1;
/* Copied into lo_PositionTableElement() */
/*
table_ele->next = NULL;
table_ele->prev = NULL;
*/
/*
* Check for an align parameter
*/
if (align_attr)
{
Bool floating;
floating = FALSE;
table_ele->alignment = lo_EvalAlignParam(align_attr, &floating);
/*
* Only allow left and right (floating) and center.
*/
if (floating != FALSE)
{
table_ele->ele_attrmask |= LO_ELE_FLOATING;
}
else
{
/*
* Tables can be left, center, right, justify or char alignment.
* We only do left, center and right. True left and right will
* hit the floating case above. So, we set all alignments to
* be either center or left.
*/
switch ( table_ele->alignment )
{
case LO_ALIGN_LEFT:
case LO_ALIGN_RIGHT:
case LO_ALIGN_CENTER:
break;
case LO_ALIGN_NCSA_CENTER:
table_ele->alignment = LO_ALIGN_CENTER;
break;
default:
table_ele->alignment = LO_ALIGN_LEFT;
break;
}
}
}
lo_PositionTableElement(state, table_ele);
/*
* Push our alignment state if we're not floating
*/
/* Copied into lo_PositionTableElement() */
/*
if ( !(table_ele->ele_attrmask & LO_ELE_FLOATING) )
{
lo_PushAlignment(state, P_TABLE_DATA, table_ele->alignment);
}
*/
/*
* Get the border parameter.
*/
if (border_attr)
{
val = XP_ATOI(border_attr);
if ((val == 0)&&(*border_attr == '0'))
{
val = -1;
}
else if (val < 1)
{
val = 1;
}
table_ele->border_width = val;
table_ele->border_top_width = val;
table_ele->border_bottom_width = val;
table_ele->border_left_width = val;
table_ele->border_right_width = val;
}
table_ele->border_width = FEUNITS_X(table_ele->border_width, context);
/*
* Get the top border parameter.
*/
if (border_top_attr)
{
val = XP_ATOI(border_top_attr);
if ((val == 0)&&(*border_top_attr == '0'))
{
val = -1;
}
else if (val < 1)
{
val = 1;
}
table_ele->border_top_width = val;
}
table_ele->border_top_width = FEUNITS_Y(table_ele->border_top_width, context);
/*
* Get the bottom border parameter.
*/
if (border_bottom_attr)
{
val = XP_ATOI(border_bottom_attr);
if ((val == 0)&&(*border_bottom_attr == '0'))
{
val = -1;
}
else if (val < 1)
{
val = 1;
}
table_ele->border_bottom_width = val;
}
table_ele->border_bottom_width = FEUNITS_Y(table_ele->border_bottom_width, context);
/*
* Get the left border parameter.
*/
if (border_left_attr)
{
val = XP_ATOI(border_left_attr);
if ((val == 0)&&(*border_left_attr == '0'))
{
val = -1;
}
else if (val < 1)
{
val = 1;
}
table_ele->border_left_width = val;
}
table_ele->border_left_width = FEUNITS_X(table_ele->border_left_width, context);
/*
* Get the right border parameter.
*/
if (border_right_attr)
{
val = XP_ATOI(border_right_attr);
if ((val == 0)&&(*border_right_attr == '0'))
{
val = -1;
}
else if (val < 1)
{
val = 1;
}
table_ele->border_right_width = val;
}
table_ele->border_right_width = FEUNITS_X(table_ele->border_right_width, context);
/*
* Get the border style parameter.
*/
if (border_style_attr)
{
int32 border_style;
border_style = BORDER_OUTSET;
if ( pa_TagEqual("none", border_style_attr) )
{
border_style = BORDER_NONE;
}
else if ( pa_TagEqual("dotted", border_style_attr) )
{
border_style = BORDER_DOTTED;
}
else if ( pa_TagEqual("dashed", border_style_attr) )
{
border_style = BORDER_DASHED;
}
else if ( pa_TagEqual("solid", border_style_attr) )
{
border_style = BORDER_SOLID;
}
else if ( pa_TagEqual("double", border_style_attr) )
{
border_style = BORDER_DOUBLE;
}
else if ( pa_TagEqual("groove", border_style_attr) )
{
border_style = BORDER_GROOVE;
}
else if ( pa_TagEqual("ridge", border_style_attr) )
{
border_style = BORDER_RIDGE;
}
else if ( pa_TagEqual("inset", border_style_attr) )
{
border_style = BORDER_INSET;
}
else if ( pa_TagEqual("outset", border_style_attr) )
{
border_style = BORDER_OUTSET;
}
table_ele->border_style = border_style;
}
/*
* Get the border color parameter.
*/
if (border_color_attr)
{
uint8 red, green, blue;
LO_ParseStyleSheetRGB(border_color_attr, &red, &green, &blue);
table_ele->border_color.red = red;
table_ele->border_color.green = green;
table_ele->border_color.blue = blue;
}
/*
* Get the extra vertical space parameter.
*/
if (vspace_attr)
{
val = XP_ATOI(vspace_attr);
if (val < 0)
{
val = 0;
}
table_ele->border_vert_space = val;
}
table_ele->border_vert_space = FEUNITS_Y(table_ele->border_vert_space,
context);
/*
* Get the extra horizontal space parameter.
*/
if (hspace_attr)
{
val = XP_ATOI(hspace_attr);
if (val < 0)
{
val = 0;
}
table_ele->border_horiz_space = val;
}
table_ele->border_horiz_space = FEUNITS_X(table_ele->border_horiz_space,
context);
table = XP_NEW(lo_TableRec);
/* Keep ptr to table state structure. Will be needed during relayout */
table_ele->table = table;
if (table == NULL)
{
return;
}
if(table_ele->border_top_width < 0)
table_ele->border_top_width = 0;
if(table_ele->border_bottom_width < 0)
table_ele->border_bottom_width = 0;
if(table_ele->border_right_width < 0)
table_ele->border_right_width = 0;
if(table_ele->border_left_width < 0)
table_ele->border_left_width = 0;
if(table_ele->border_width < 0)
{
/* backwards compatibility */
table->draw_borders = TABLE_BORDERS_GONE;
table_ele->border_width = 0;
table_ele->border_top_width = 0;
table_ele->border_bottom_width = 0;
table_ele->border_right_width = 0;
table_ele->border_left_width = 0;
}
else if (table_ele->border_top_width == 0
&& table_ele->border_bottom_width == 0
&& table_ele->border_left_width == 0
&& table_ele->border_right_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->backdrop.bg_color = NULL;
table->backdrop.url = NULL;
table->backdrop.tile_mode = LO_TILE_BOTH;
/* Copied to lo_InitTableRecord()
/*
table->rows = 0;
table->cols = 0;
*/
table->width_spans = NULL;
table->width_span_ptr = NULL;
table->height_spans = NULL;
/* Copied to lo_InitTableRecord()
table->height_span_ptr = NULL;
*/
table->caption = NULL;
table->table_ele = table_ele;
table->current_subdoc = NULL;
table->row_list = NULL;
table->row_ptr = NULL;
table->width = 0;
table->height = 0;
lo_InitTableRecord( table );
/*
* Percent width, height added for relayout
*/
table->percent_width = 0;
table->percent_height = 0;
table->inner_top_pad = TABLE_DEF_INNER_CELL_PAD;
table->inner_bottom_pad = TABLE_DEF_INNER_CELL_PAD;
table->inner_left_pad = TABLE_DEF_INNER_CELL_PAD;
table->inner_right_pad = TABLE_DEF_INNER_CELL_PAD;
table->inter_cell_pad = TABLE_DEF_INTER_CELL_PAD;
table->current_subdoc = (LO_SubDocStruct *)lo_NewElement(context, state, LO_SUBDOC, NULL, 0);
table->current_subdoc->type = LO_SUBDOC;
table->current_subdoc->backdrop.bg_color = NULL;
table->current_subdoc->backdrop.url = NULL;
table->current_subdoc->backdrop.tile_mode = LO_TILE_BOTH;
table->current_subdoc->state = lo_NewLayout(context,
state->win_width, state->win_height, 0, 0, NULL);
table->default_cell_width = 0;
table->fixed_width_remaining = 0;
table->fixed_col_widths = NULL;
table->table_width_fixed = FALSE;
table->fixed_cols = 0;
/*
* 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 style sheet color and override if necessary */
if(state->top_state && state->top_state->style_stack)
{
StyleStruct *style_struct;
style_struct = STYLESTACK_GetStyleByIndex(
state->top_state->style_stack,
0);
if(style_struct)
{
bgcolor_from_style = STYLESTRUCT_GetString(style_struct, BG_COLOR_STYLE);
if(bgcolor_from_style)
{
bgcolor_attr = bgcolor_from_style;
}
}
}
/*
* Check for a background color attribute
*/
if (bgcolor_attr)
{
uint8 red, green, blue;
XP_Bool rv;
if(bgcolor_from_style)
rv = LO_ParseStyleSheetRGB(bgcolor_attr, &red, &green, &blue);
else
rv = LO_ParseRGB(bgcolor_attr, &red, &green, &blue);
if(rv)
{
table->backdrop.bg_color = XP_NEW(LO_Color);
if (table->backdrop.bg_color != NULL)
{
table->backdrop.bg_color->red = red;
table->backdrop.bg_color->green = green;
table->backdrop.bg_color->blue = blue;
}
}
}
if (background_attr)
table->backdrop.url = XP_STRDUP(background_attr);
XP_FREEIF(bgcolor_from_style);
/*
* Get the width and height parameters, in absolute or percentage.
* If percentage, make it absolute.
*/
if (width_attr)
{
Bool is_percent;
val = lo_ValueOrPercent(width_attr, &is_percent);
if (is_percent != FALSE)
{
table->percent_width = val;
/*
if (allow_percent_width == FALSE)
{
val = 0;
}
else
{
val = (state->win_width - state->win_left -
state->win_right) * val / 100;
}
*/
}
else
{
table->percent_width = 0;
table->table_width_fixed = TRUE;
val = FEUNITS_X(val, context);
}
if (val < 0)
{
val = 0;
}
table->width = val;
}
if (height_attr)
{
Bool is_percent;
val = lo_ValueOrPercent(height_attr, &is_percent);
if (is_percent != FALSE)
{
table->percent_height = val;
/*
if (allow_percent_height == FALSE)
{
val = 0;
}
else
{
val = (state->win_height - state->win_top -
state->win_bottom) * val / 100;
}
*/
}
else
{
table->percent_height = 0;
val = FEUNITS_X(val, context);
}
if (val < 0)
{
val = 0;
}
table->height = val;
}
lo_SetTableDimensions(state, table, allow_percent_width, allow_percent_height);
if (cellpad_attr)
{
val = XP_ATOI(cellpad_attr);
if (val < 0)
{
val = 0;
}
/* set all our pads to this value */
table->inner_top_pad = val;
table->inner_bottom_pad = val;
table->inner_left_pad = val;
table->inner_right_pad = val;
}
if (toppad_attr)
{
val = XP_ATOI(toppad_attr);
if (val < 0)
{
val = 0;
}
table->inner_top_pad = val;
}
if (bottompad_attr)
{
val = XP_ATOI(bottompad_attr);
if (val < 0)
{
val = 0;
}
table->inner_bottom_pad = val;
}
if (leftpad_attr)
{
val = XP_ATOI(leftpad_attr);
if (val < 0)
{
val = 0;
}
table->inner_left_pad = val;
}
if (rightpad_attr)
{
val = XP_ATOI(rightpad_attr);
if (val < 0)
{
val = 0;
}
table->inner_right_pad = val;
}
if (cellspace_attr)
{
val = XP_ATOI(cellspace_attr);
if (val < 0)
{
val = 0;
}
table->inter_cell_pad = val;
}
/*
* Get the COLS parameter.
*/
if (cols_attr)
{
val = XP_ATOI(cols_attr);
if (val < 0)
{
val = 0;
}
table_ele->border_horiz_space = val;
/*
* If we have a specified number of columns, then
* we first need to make sure we have a real table
* width and then compute our default column width.
*/
table->fixed_cols = val;
if ( val > 0 )
{
/* Copied to lo_CalcFixedColWidths() */
/*
int32 count;
int32 table_width;
table->fixed_cols = val;
table_width = lo_ComputeInternalTableWidth ( context, table, state );
*/
/* Split the space up evenly */
/*
table->default_cell_width = table_width / val;
*/
/* and we have all the table width left to play with */
/*
table->fixed_width_remaining = table_width;
*/
/* allocate and initialize our width array */
table->fixed_col_widths = XP_ALLOC(val * sizeof(int32));
if (table->fixed_col_widths == NULL)
{
state->top_state->out_of_memory = TRUE;
table->fixed_cols = 0;
table->default_cell_width = 0;
return;
}
/*
for ( count = 0; count < val; ++count )
{
table->fixed_col_widths[ count ] = 0;
}
*/
lo_CalcFixedColWidths( context, state, table );
}
}
/* Copied to lo_UpdateStateAfterBeginTable() */
/*
state->current_table = table;
*/
lo_UpdateStateAfterBeginTable( state, table );
}
/*
* Preparse the tag attributes and call the real begin table
*/
void
lo_BeginTable(MWContext *context, lo_DocState *state, PA_Tag *tag)
{
/* style sheets variables */
StyleStruct *style_struct=NULL;
SS_Number *top_padding, *bottom_padding, *left_padding, *right_padding;
char *align_attr = (char*)lo_FetchParamValue(context, tag, PARAM_ALIGN);
char *border_attr = (char*)lo_FetchParamValue(context, tag, PARAM_BORDER);
char *border_top_attr = NULL;
char *border_bottom_attr = NULL;
char *border_left_attr = NULL;
char *border_right_attr = NULL;
char *border_color_attr = (char*)lo_FetchParamValue(context, tag, PARAM_BORDERCOLOR);
char *border_style_attr = NULL;
char *vspace_attr = (char*)lo_FetchParamValue(context, tag, PARAM_VSPACE);
char *hspace_attr = (char*)lo_FetchParamValue(context, tag, PARAM_HSPACE);
char *bgcolor_attr = (char*)lo_FetchParamValue(context, tag, PARAM_BGCOLOR);
char *background_attr = (char*)lo_FetchParamValue(context, tag, PARAM_BACKGROUND);
char *width_attr = (char*)lo_FetchParamValue(context, tag, PARAM_WIDTH);
char *height_attr = (char*)lo_FetchParamValue(context, tag, PARAM_HEIGHT);
char *cellpad_attr = (char*)lo_FetchParamValue(context, tag, PARAM_CELLPAD);
char *toppad_attr = (char*)lo_FetchParamValue(context, tag, PARAM_TOPPAD);
char *bottompad_attr = (char*)lo_FetchParamValue(context, tag, PARAM_BOTTOMPAD);
char *leftpad_attr = (char*)lo_FetchParamValue(context, tag, PARAM_LEFTPAD);
char *rightpad_attr = (char*)lo_FetchParamValue(context, tag, PARAM_RIGHTPAD);
char *cellspace_attr = (char*)lo_FetchParamValue(context, tag, PARAM_CELLSPACE);
char *cols_attr = (char*)lo_FetchParamValue(context, tag, PARAM_COLS);
if(!border_style_attr)
{
border_style_attr = XP_STRDUP("outset");
}
if(!border_color_attr)
{
XP_ASSERT(state);
if(state)
border_color_attr = PR_smprintf("#%2x%2x%2x",
state->text_bg.red,
state->text_bg.green,
state->text_bg.blue);
}
if(state->top_state->style_stack)
style_struct = STYLESTACK_GetStyleByIndex(state->top_state->style_stack, 0);
if(style_struct)
{
left_padding = STYLESTRUCT_GetNumber(style_struct, LEFTPADDING_STYLE);
if(left_padding)
{
LO_AdjustSSUnits(left_padding, LEFTPADDING_STYLE, context, state);
XP_FREEIF(leftpad_attr);
leftpad_attr = PR_smprintf("%ld", (int32)left_padding->value);
}
right_padding = STYLESTRUCT_GetNumber(style_struct, RIGHTPADDING_STYLE);
if(right_padding)
{
LO_AdjustSSUnits(right_padding, RIGHTPADDING_STYLE, context, state);
XP_FREEIF(rightpad_attr);
rightpad_attr = PR_smprintf("%ld", (int32)right_padding->value);
}
top_padding = STYLESTRUCT_GetNumber(style_struct, TOPPADDING_STYLE);
if(top_padding)
{
LO_AdjustSSUnits(top_padding, TOPPADDING_STYLE, context, state);
XP_FREEIF(toppad_attr);
toppad_attr = PR_smprintf("%ld", (int32)top_padding->value);
}
bottom_padding = STYLESTRUCT_GetNumber(style_struct, BOTTOMPADDING_STYLE);
if(bottom_padding)
{
LO_AdjustSSUnits(bottom_padding, BOTTOMPADDING_STYLE, context, state);
XP_FREEIF(bottompad_attr);
bottompad_attr = PR_smprintf("%ld", (int32)bottom_padding->value);
}
}
/* remove the PA_LOCK stuff, it does nothing anyways */
lo_BeginTableAttributes(context,
state,
align_attr,
border_attr,
border_top_attr,
border_bottom_attr,
border_left_attr,
border_right_attr,
border_color_attr,
border_style_attr,
vspace_attr,
hspace_attr,
bgcolor_attr,
background_attr,
width_attr,
height_attr,
cellpad_attr,
toppad_attr,
bottompad_attr,
leftpad_attr,
rightpad_attr,
cellspace_attr,
cols_attr);
if(align_attr)
PA_FREE(align_attr);
if(border_attr)
PA_FREE(border_attr);
if(border_top_attr)
PA_FREE(border_top_attr);
if(border_bottom_attr)
PA_FREE(border_bottom_attr);
if(border_left_attr)
PA_FREE(border_left_attr);
if(border_right_attr)
PA_FREE(border_right_attr);
if(border_color_attr)
PA_FREE(border_color_attr);
if(border_style_attr)
PA_FREE(border_style_attr);
if(vspace_attr)
PA_FREE(vspace_attr);
if(hspace_attr)
PA_FREE(hspace_attr);
if(bgcolor_attr)
PA_FREE(bgcolor_attr);
if(background_attr)
PA_FREE(background_attr);
if(width_attr)
PA_FREE(width_attr);
if(height_attr)
PA_FREE(height_attr);
if(cellpad_attr)
PA_FREE(cellpad_attr);
if(toppad_attr)
PA_FREE(toppad_attr);
if(bottompad_attr)
PA_FREE(bottompad_attr);
if(leftpad_attr)
PA_FREE(leftpad_attr);
if(rightpad_attr)
PA_FREE(rightpad_attr);
if(cellspace_attr)
PA_FREE(cellspace_attr);
if(cols_attr)
PA_FREE(cols_attr);
}
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;
row_ptr->cells_in_row = 0;
while (cell_ptr != NULL)
{
/*
* Also on this pass check if any of the cells
* NEED to be relaid out later.
*/
if (cell_ptr->must_relayout != 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;
}
/*
* If the cell is not an empty cell, count it for this row
*/
/* if (cell_ptr->cell->cell_list != NULL || cell_ptr->cell->cell_float_list != NULL) */
row_ptr->cells_in_row++;
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;
}
/*
* Baseline spacing shouldn't grow the
* max height, except for baseline
* aligned rows as above.
*/
if (row_max->min_dim > row_max->dim)
{
row_max->min_dim = row_max->dim;
}
}
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 *base_table_width, int32 *min_base_table_width)
{
int32 x, y;
int32 indx;
int32 new_table_width;
int32 new_min_table_width;
int32 new_base_table_width;
int32 new_min_base_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;
new_base_table_width = 0;
new_min_base_table_width = 0;
col_max = table->width_spans;
while (col_max != NULL)
{
new_base_table_width += col_max->dim;
new_min_base_table_width += col_max->min_dim;
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 += (table->table_ele->border_left_width +
table->table_ele->border_right_width);
new_min_table_width += cell_pad;
new_min_table_width += (table->table_ele->border_left_width +
table->table_ele->border_right_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;
*base_table_width = new_base_table_width;
*min_base_table_width = new_min_base_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, Bool *rowspan_pass, Bool relayout)
{
int32 x, y;
int32 indx;
lo_table_span *row_max;
lo_table_span *col_max;
lo_TableRow *row_ptr;
lo_TableCell *cell_ptr;
int32 top_inner_pad;
int32 bottom_inner_pad;
int32 left_inner_pad;
int32 right_inner_pad;
top_inner_pad = FEUNITS_X(table->inner_top_pad, context);
bottom_inner_pad = FEUNITS_X(table->inner_bottom_pad, context);
left_inner_pad = FEUNITS_X(table->inner_left_pad, context);
right_inner_pad = FEUNITS_X(table->inner_right_pad, context);
row_ptr = table->row_list;
row_max = table->height_spans;
for (y=0; y < table->rows; y++)
{
Bool max_height_valid;
Bool changed_row_height;
int32 max_row_height;
max_height_valid = FALSE;
changed_row_height = FALSE;
max_row_height = 0;
col_max = table->width_spans;
for (x=0; x < table->cols; x++)
{
LO_CellStruct *cell_struct;
int32 width;
int32 inside_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;
}
cell_struct = cell_ptr->cell;
inside_width = col_max->dim;
width = inside_width;
if (cell_ptr->colspan > 1)
{
int32 i;
lo_table_span *max_ptr;
max_ptr = col_max;
/*
* We need to add some cellpads for the spanned cells
* to our inside width
*/
inside_width += ( cell_ptr->colspan - 1 ) * cell_pad;
for (i=1; i < cell_ptr->colspan; i++)
{
max_ptr = max_ptr->next;
inside_width += max_ptr->dim;
width += cell_pad + max_ptr->dim;
}
}
/*
* We want to relayout the cell if it's been tagged as
* needing it or if it's been layed out to a different size.
*/
if ( (cell_ptr->must_relayout != FALSE) ||
((width != cell_ptr->max_width)) )
{
cell_ptr->must_relayout = FALSE;
inside_width = inside_width -
(2 * cell_struct->border_width) -
(2 * cell_struct->border_horiz_space) -
(left_inner_pad + right_inner_pad);
/*
* Don't relayout documents that have no
* elements, it causes errors.
*/
has_elements = lo_cell_has_elements(cell_ptr->cell);
if ( has_elements == FALSE )
{
/*
* Simply record our new width in this case.
*/
cell_struct->width = inside_width;
}
else
{
cell_struct = lo_RelayoutCell(context, state,
table->current_subdoc, cell_ptr,
cell_struct, inside_width,
cell_ptr->is_a_header, relayout);
if (!cell_struct) /* temporary fix for crash when cell_struct is null */
{
break;
}
cell_ptr->cell = cell_struct;
cell_ptr->baseline = lo_GetCellBaseline(cell_struct);
if (cell_ptr->rowspan == 1)
{
int32 tmp_val;
/*
* We have changed the height of a single row cell, so we may need
* to update the row height later.
*/
changed_row_height = TRUE;
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;
}
/*
* Baseline spacing shouldn't grow the
* max height, except for baseline
* aligned rows as above.
*/
if (row_max->min_dim > row_max->dim)
{
row_max->min_dim = row_max->dim;
}
}
}
else
{
*rowspan_pass = TRUE;
}
}
}
else
{
if (cell_ptr->rowspan > 1)
{
*rowspan_pass = TRUE;
}
}
/*
* If this cell has anything inside it, see if it's height
* is the biggest for the row.
*/
has_elements = lo_cell_has_elements(cell_ptr->cell);
if ( has_elements != FALSE )
{
int32 cell_row_height;
/*
* What row height does this cell want?
*/
cell_row_height = cell_struct->height +
(top_inner_pad + bottom_inner_pad) +
(2 * cell_struct->border_vert_space);
/*
* Munge the height if the row is vertically aligned along
* the baseline and the cell only spans one row.
*/
if (cell_ptr->rowspan == 1)
{
if (row_ptr->vert_alignment == LO_ALIGN_BASELINE)
{
cell_row_height = (cell_row_height -
cell_ptr->baseline) + row_max->min_dim;
}
if ( cell_row_height > max_row_height )
{
/*
* Update to our new maximum and flag that it
* contains valid data.
*/
max_height_valid = TRUE;
max_row_height = cell_row_height;
}
}
}
col_max = col_max->next;
}
/*
* If we did relayout anything on that row which gave us a new
* valid max row height which is different to what we currently
* have, then use that.
*/
if ( max_height_valid != FALSE && changed_row_height != FALSE &&
max_row_height != row_max->dim )
{
/*
* Can't reset height to be smaller than
* the minimum height.
*/
if (max_row_height >= row_max->min_dim)
{
row_max->dim = max_row_height;
}
else
{
row_max->dim = row_max->min_dim;
}
}
row_max = row_max->next;
row_ptr = row_ptr->next;
}
}
static void
lo_cell_rowspan_pass(MWContext *context, lo_TableRec *table, lo_cell_data XP_HUGE *cell_array,
lo_TableCell *blank_cell, int32 cell_pad)
{
int32 x, y;
int32 indx;
lo_table_span *row_max;
lo_table_span *col_max;
lo_TableRow *row_ptr;
lo_TableCell *cell_ptr;
int32 top_inner_pad;
int32 bottom_inner_pad;
top_inner_pad = FEUNITS_X(table->inner_top_pad, context);
bottom_inner_pad = FEUNITS_X(table->inner_bottom_pad, context);
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_CellStruct *cell_struct;
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;
}
cell_struct = cell_ptr->cell;
if (cell_ptr->rowspan > 1)
{
int32 i;
int32 height;
int32 tmp_val;
int32 cell_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;
}
/*
* Baseline spacing shouldn't grow the
* max height, except for baseline
* aligned rows as above.
*/
if (row_max->min_dim > row_max->dim)
{
row_max->min_dim = row_max->dim;
}
}
cell_height = cell_struct->height +
(top_inner_pad + bottom_inner_pad) +
(2 * cell_struct->border_vert_space);
if (height < cell_height)
{
int32 add_height;
int32 add;
lo_table_span *add_ptr;
add_ptr = row_max;
add_height = cell_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->min_dim = add_ptr->dim;
add_ptr = add_ptr->next;
}
add_ptr->dim +=
(add_height - add);
add_ptr->min_dim = add_ptr->dim;
}
}
col_max = col_max->next;
}
row_max = row_max->next;
row_ptr = row_ptr->next;
}
}
static void
lo_free_cell_record(MWContext *context, lo_DocState *state, lo_TableCell *cell)
{
if (cell == NULL)
{
return;
}
/*
* If this table cell is not nested inside another table cell
* or caption, free any re-parse tags stored on this cell.
*/
if ((cell->in_nested_table == FALSE) &&
(cell->subdoc_tags != NULL)&&
(state->is_a_subdoc != SUBDOC_CELL)&&
(state->is_a_subdoc != SUBDOC_CAPTION))
{
PA_Tag *tptr;
PA_Tag *tag;
tptr = cell->subdoc_tags;
while ((tptr != cell->subdoc_tags_end)&&(tptr != NULL))
{
tag = tptr;
tptr = tptr->next;
tag->next = NULL;
PA_FreeTag(tag);
}
if (tptr != NULL)
{
tptr->next = NULL;
PA_FreeTag(tptr);
}
cell->subdoc_tags = NULL;
cell->subdoc_tags_end = NULL;
}
if (cell->cell != NULL) {
cell->cell->table = NULL;
cell->cell->table_row = NULL;
cell->cell->table_cell = NULL;
}
XP_DELETE(cell);
}
static void
lo_free_row_record(MWContext *context, lo_DocState *state,
lo_TableRow *row, Bool partial)
{
lo_TableCell *cell_ptr;
lo_TableCell *cell;
if (row->cell_list != NULL)
{
/*
* These are already freed on a completed table, and
* need to be freed on a partial table.
*/
if (partial != FALSE)
{
cell_ptr = row->cell_list;
while (cell_ptr != NULL)
{
cell = cell_ptr;
cell_ptr = cell_ptr->next;
lo_free_cell_record(context, state, cell);
}
}
row->cell_list = NULL;
row->cell_ptr = NULL;
}
XP_FREEIF(row->backdrop.bg_color);
XP_FREEIF(row->backdrop.url);
XP_DELETE(row);
}
static void lo_FreeTableCaption( MWContext *context, lo_DocState *state, lo_TableRec *table )
{
if (table->caption != NULL)
{
if (table->caption->cell_ele != NULL)
{
lo_FreeCaptionCell( context, state, table->caption->cell_ele );
table->caption->cell_ele = NULL;
}
if ( table->caption->subdoc != NULL )
{
lo_FreePartialSubDoc ( context, state, table->caption->subdoc );
table->caption->subdoc = NULL;
}
XP_DELETE(table->caption);
table->caption = NULL;
}
}
void lo_free_table_record(MWContext *context, lo_DocState *state,
lo_TableRec *table, Bool partial)
{
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;
lo_free_row_record(context, state, row, partial);
}
table->row_list = NULL;
table->row_ptr = NULL;
}
lo_FreeTableCaption( context, state, table );
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;
}
XP_FREEIF(table->backdrop.bg_color);
XP_FREEIF(table->backdrop.url);
/*
* Whether the partial flag is set or not, we always
* want to eliminate this subdoc and all its contents
* when the table is done.
*/
if (table->current_subdoc != NULL)
{
lo_FreePartialSubDoc(context, state, table->current_subdoc);
table->current_subdoc = NULL;
}
if ( table->fixed_col_widths != NULL )
{
XP_FREE(table->fixed_col_widths);
}
/*
* Reset back pointer in table layout element
*/
if (table->table_ele != NULL) {
table->table_ele->table = NULL;
}
XP_DELETE(table);
}
void
lo_FreePartialTable(MWContext *context, lo_DocState *state, lo_TableRec *table)
{
lo_TableRow *row_ptr;
lo_TableCell *cell_ptr;
LO_SubDocStruct *subdoc;
LO_CellStruct *cell_struct;
if (table == NULL)
{
return;
}
row_ptr = table->row_list;
while (row_ptr != NULL)
{
cell_ptr = row_ptr->cell_list;
while (cell_ptr != NULL)
{
cell_struct = cell_ptr->cell;
lo_FreePartialCell(context, state, cell_struct);
cell_ptr->cell = 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, state, table, TRUE);
}
void
lo_EndTable(MWContext *context, lo_DocState *state, lo_TableRec *table, Bool relayout)
{
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 base_table_width, min_base_table_width;
int32 table_height;
int32 min_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 top_inner_pad;
int32 bottom_inner_pad;
int32 left_inner_pad;
int32 right_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);
table_pad = FEUNITS_X(TABLE_DEF_CELL_BORDER, context);
top_inner_pad = FEUNITS_X(table->inner_top_pad, context);
bottom_inner_pad = FEUNITS_X(table->inner_bottom_pad, context);
left_inner_pad = FEUNITS_X(table->inner_left_pad, context);
right_inner_pad = FEUNITS_X(table->inner_right_pad, 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;
/*
* Don't wanna free table record any more because this information
* is used during relayout.
*/
/*
if (table != NULL)
{
lo_free_table_record(context, state, table, FALSE);
}
*/
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;
base_table_width = 0;
min_base_table_width = 0;
col_max = table->width_spans;
while (col_max != NULL)
{
base_table_width += col_max->dim;
min_base_table_width += col_max->min_dim;
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;
min_table_width += cell_pad;
table_width += (table->table_ele->border_left_width +
table->table_ele->border_right_width);
min_table_width += (table->table_ele->border_left_width +
table->table_ele->border_right_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 unless we're in
* a fixed layout table (has the COLS attribute) in which case
* the cell widths are already set.
*/
if ((table->has_percent_width_cells != FALSE) &&
(table->fixed_cols == 0))
{
lo_percent_width_cells(table, cell_array, &blank_cell,
cell_pad, table_pad, &table_width, &min_table_width,
&base_table_width, &min_base_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 we're in a fixed layout table, then we never
* want to cut to "window width"
*/
if ( table->fixed_cols > 0 )
{
cut_to_window_width = FALSE;
}
/*
* If the table is too small, we always need to relayout.
*/
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 minimum
* width then we grow the sucker.
*/
if ((table->width > 0)&&(width_limit > table_width))
{
int32 add_width;
int32 add;
int32 newWidth;
int32 min_add_width;
int32 min_add;
lo_table_span *add_ptr;
/* relayout to fill all the space we're adding */
relayout_pass = TRUE;
add_ptr = table->width_spans;
add_width = width_limit - table_width;
if ( add_width < 0 )
{
add_width = 0;
}
add = 0;
min_add_width = width_limit - min_table_width;
min_add = 0;
while ((add_ptr != NULL)&&(add_ptr->next != NULL))
{
newWidth = add_width * add_ptr->dim / base_table_width;
add_ptr->dim += newWidth;
add += newWidth;
/*
* We only want to resize the min_dim's of the spans
* if we're a fixed width table.
*/
if ( table->table_width_fixed )
{
newWidth = min_add_width * add_ptr->min_dim / min_base_table_width;
add_ptr->min_dim += newWidth;
min_add += newWidth;
}
add_ptr = add_ptr->next;
}
if ( table->table_width_fixed )
{
add_ptr->min_dim += (min_add_width - min_add);
}
add_ptr->dim += (add_width - add);
}
rowspan_pass = FALSE;
if ((state->top_state->doc_state == state) ||
(state->top_state->in_cell_relayout == TRUE))
{
if (state->top_state->doc_state == state)
{
state->top_state->in_cell_relayout = TRUE;
}
if (relayout_pass != FALSE)
{
lo_cell_relayout_pass(context, state, table, cell_array,
&blank_cell, cell_pad, &rowspan_pass, relayout);
}
if (rowspan_pass != FALSE)
{
lo_cell_rowspan_pass(context, table, cell_array, &blank_cell,
cell_pad);
}
if (state->top_state->doc_state == state)
{
state->top_state->in_cell_relayout = FALSE;
}
}
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 += (table->table_ele->border_left_width +
table->table_ele->border_right_width);
min_table_width += cell_pad;
min_table_width += (table->table_ele->border_left_width +
table->table_ele->border_right_width);
table_height = 0;
min_table_height = 0;
row_max = table->height_spans;
while (row_max != NULL)
{
table_height = table_height + cell_pad + row_max->dim;
min_table_height = min_table_height + cell_pad + row_max->min_dim;
row_max = row_max->next;
}
table_height += cell_pad;
min_table_height += cell_pad;
table_height += (table->table_ele->border_top_width +
table->table_ele->border_bottom_width);
min_table_height += (table->table_ele->border_top_width +
table->table_ele->border_bottom_width);
if (table->draw_borders == TABLE_BORDERS_OFF)
{
table_width += (2 * table_pad);
min_table_width += (2 * table_pad);
table_height += (2 * table_pad);
min_table_height += (2 * table_pad);
}
/*
* If the user specified a taller table than the min
* height we need to adjust the heights of all the rows.
*/
if ((table->height > 0)&&(table->height > min_table_height))
{
int32 add_height;
int32 add;
lo_table_span *add_ptr;
int32 newHeight;
int32 min_add_height;
int32 min_add;
add_ptr = table->height_spans;
add_height = table->height - table_height;
if ( add_height < 0 )
{
add_height = 0;
}
min_add_height = table->height - min_table_height;
add = 0;
min_add = 0;
while((add_ptr != NULL) && (add_ptr->next != NULL))
{
newHeight = add_height * add_ptr->dim / table_height;
add_ptr->dim += newHeight;
add += newHeight;
newHeight = min_add_height * add_ptr->min_dim / table_height;
add_ptr->min_dim += newHeight;
min_add += newHeight;
add_ptr = add_ptr->next;
}
add_ptr->dim += (add_height - add);
add_ptr->min_dim += (min_add_height - min_add);
/*
* We can't make the height be less than the sum
* of the row heights.
*/
if (table_height < table->height)
{
table_height = table->height;
}
min_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_SetSoftLineBreakState(context, state, FALSE, 1);
*/
lo_SetLineBreakState ( context, state, FALSE, LO_LINEFEED_BREAK_SOFT, 1, relayout );
}
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;
/*cmanske - Save spacing param for drawing table selection in Composer */
table->table_ele->inter_cell_space = table->inter_cell_pad;
lo_AppendToLineList(context, state,
(LO_Element *)table->table_ele, 0);
#ifdef EDITOR
/*cmanske - build list of tables we are laying out
* so Editor can readjust it's data after all is finished
*/
EDT_AddToRelayoutTables(context, table->table_ele);
#endif
state->x += (cell_pad + table->table_ele->border_left_width);
state->y += (cell_pad + table->table_ele->border_top_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) -
(left_inner_pad + right_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) -
(left_inner_pad + right_inner_pad);
table->caption->subdoc = lo_RelayoutCaptionSubdoc(context,
state, table->caption, subdoc, inside_width, FALSE);
subdoc = table->caption->subdoc;
table->caption->height = subdoc->height +
(2 * subdoc->border_vert_space) +
(top_inner_pad + bottom_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;
if (relayout == FALSE)
{
/*
cell_ele = lo_SquishSubDocToCell(context, state,
subdoc, TRUE);
*/
cell_ele = lo_SquishSubDocToCell(context, state,
subdoc, FALSE);
cell_ele->isCaption = TRUE;
table->caption->cell_ele = cell_ele;
}
else
{
cell_ele = table->caption->cell_ele;
lo_UpdateCaptionCellFromSubDoc(context, state, subdoc, cell_ele);
}
/* table->caption->subdoc = NULL; */
if (cell_ele == NULL)
{
lo_AppendToLineList(context, state,
(LO_Element *)subdoc, 0);
}
else
{
/*cmanske - Save spacing param for drawing cell selection by FEs */
/* should we use cell_pad (converted to FE units) instead? */
cell_ele->inter_cell_space = table->inter_cell_pad;
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_top_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, TRUE);
table->caption->subdoc = NULL;
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_CellStruct *cell_struct;
int32 new_x, new_y;
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;
}
cell_struct = cell_ptr->cell;
/*
cell_struct->x = cell_x;
cell_struct->y = cell_y;
cell_struct->x_offset = (int16)cell_struct->border_horiz_space;
cell_struct->y_offset = (int32)cell_struct->border_vert_space;
*/
new_x = cell_x + (int16)cell_struct->border_horiz_space + cell_struct->border_width;
new_y = cell_y + (int32)cell_struct->border_vert_space + cell_struct->border_width;
cell_struct->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;
cell_struct->width = cell_struct->width +
cell_pad + max_ptr->dim;
}
}
cell_struct->width = cell_struct->width -
(2 * cell_struct->border_horiz_space);
cell_struct->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;
cell_struct->height = cell_struct->height +
cell_pad + max_ptr->dim;
}
}
cell_struct->height = cell_struct->height -
(2 * cell_struct->border_vert_space);
lo_ShiftCell(cell_struct,
cell_ptr->cell_base_x, cell_ptr->cell_base_y);
cell_ptr->cell_base_x = 0;
cell_ptr->cell_base_y = 0;
ele_cnt = lo_align_cell(context, state, cell_ptr,
cell_struct, table, row_max);
/*
if (ele_cnt > 0)
*/
{
LO_CellStruct *cell_ele;
int32 shift_x, shift_y;
shift_x = new_x - cell_struct->x -
cell_struct->x_offset -
cell_struct->border_width;
shift_y = new_y - cell_struct->y -
cell_struct->y_offset -
cell_struct->border_width;
cell_struct->x = cell_x;
cell_struct->y = cell_y;
cell_struct->x_offset = (int16)cell_struct->border_horiz_space;
cell_struct->y_offset = (int32)cell_struct->border_vert_space;
cell_ele = cell_struct;
/*
lo_ShiftCell(cell_ele, shift_x, shift_y);
*/
lo_ShiftCell(cell_ele, new_x, new_y);
/*
* Keep element ids sequential.
*/
if (cell_ele != NULL)
{
cell_ele->ele_id = NEXT_ELEMENT;
lo_RenumberCell(state, cell_ele);
}
if (cell_ele == NULL)
{
lo_AppendToLineList(context, state,
(LO_Element *)cell_struct, 0);
}
else
{
/*cmanske - Save spacing param for drawing cell selection by FEs */
cell_ele->inter_cell_space = table->inter_cell_pad;
lo_AppendToLineList(context, state,
(LO_Element *)cell_ele, 0);
}
if ( relayout == FALSE )
{
/*
* Cell backgrounds now sit in their own layer. This is needed
* for selection to work correctly.
* Cell backgrounds can exist in the main _BODY layer,
* so we need to special case the parent layer of the
* cell background,
*/
if (context->compositor &&
(cell_ele->backdrop.bg_color || cell_ele->backdrop.url))
{
lo_TopState *top_state = state->top_state;
CL_Layer *parent_layer = lo_CurrentLayer(state);
if (parent_layer == top_state->doc_layer)
parent_layer = top_state->body_layer;
cell_ele->cell_bg_layer =
lo_CreateCellBackgroundLayer(context, cell_ele,
parent_layer);
}
else
{
cell_ele->cell_bg_layer = NULL;
}
}
}
/*
else
{
*/
/*
LO_CellStruct *cell_ele;
*/
/*
* Free up the useless cell
*/
/*
cell_ele = cell_struct;
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_left_width;
cell_y = cell_y + table->table_ele->border_top_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;
if (relayout == FALSE)
{
/*
cell_ele = lo_SquishSubDocToCell(context, state,
subdoc, TRUE);
*/
cell_ele = lo_SquishSubDocToCell(context, state,
subdoc, FALSE);
cell_ele->isCaption = TRUE;
table->caption->cell_ele = cell_ele;
}
else
{
cell_ele = table->caption->cell_ele;
lo_UpdateCaptionCellFromSubDoc(context, state, subdoc, cell_ele);
}
/* table->caption->subdoc = NULL; */
if (cell_ele == NULL)
{
lo_AppendToLineList(context, state,
(LO_Element *)subdoc, 0);
}
else
{
/*cmanske - Save spacing param for drawing cell selection by FEs */
cell_ele->inter_cell_space = table->inter_cell_pad;
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, TRUE);
table->caption->subdoc = NULL;
if (cell_ele != NULL)
{
lo_FreeElement(context,
(LO_Element *)cell_ele, TRUE);
}
}
}
/*
* This table may have contained named anchors.
* This will correct their positions in the name_list,
* and unblock us if we were blocked on them.
*/
lo_CheckNameList(context, state, table->table_ele->ele_id);
/*
* The usual stuff for a table.
*/
if (floating == FALSE)
{
lo_AlignStack *aptr;
int32 indent;
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;
/*
* Find how far the table might be indented from
* being inside a list.
*/
indent = state->list_stack->old_left_margin - state->win_left;
if (indent < 0)
{
indent = 0;
}
save_doc_min_width = state->min_width;
if (relayout == FALSE)
{
lo_SoftLineBreak(context, state, FALSE);
}
else
{
lo_rl_AddBreakAndFlushLine( context, state, LO_LINEFEED_BREAK_SOFT, LO_CLEAR_NONE, FALSE );
}
if ((min_table_width + indent) > save_doc_min_width)
{
save_doc_min_width = min_table_width + indent;
}
state->min_width = save_doc_min_width;
/*
* Pop the table's alignment.
*/
aptr = lo_PopAlignment(state);
if (aptr != NULL)
{
XP_DELETE(aptr);
}
}
/*
* 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;
}
if (relayout == FALSE)
{
lo_AppendFloatInLineList(state, (LO_Element *)table->table_ele, save_line_list );
}
else
{
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_left_width +
table->table_ele->border_right_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, (! relayout));
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;
}
/* Now cell records get freed when the LO_TABLE element in the line list gets recycled
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))
{
lo_free_cell_record(context, state, cell_ptr);
}
}
}
*/
#ifdef XP_WIN16
_hfree(cell_array);
#else
XP_UNLOCK_BLOCK(cell_array_buff);
XP_FREE_BLOCK(cell_array_buff);
#endif
/*
* Don't wanna free the table record any more because this information
* is used during relayout.
*/
/*
lo_free_table_record(context, state, table, FALSE);
*/
}
/*
* This function relaysout the tags in a table cell. It knows how to handle
* certain types of elements that can be resused directly rather than thrown
* away and relayedout from scratch (the default case).
*/
void
lo_RelayoutTags(MWContext *context, lo_DocState *state, PA_Tag * tag_ptr,
PA_Tag * tag_end_ptr, LO_Element * elem_list)
{
PA_Tag * next_tag;
Bool save_diff_state;
int32 save_state_pushes;
int32 save_state_pops;
lo_TopState *top_state;
PA_Tag *tag_list;
next_tag = NULL;
top_state = state->top_state;
/*
* Save our parent's state levels
*/
save_diff_state = top_state->diff_state;
save_state_pushes = top_state->state_pushes;
save_state_pops = top_state->state_pops;
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;
}
/*
* Reset these so we can tell if anything happened
*/
top_state->diff_state = FALSE;
top_state->state_pushes = 0;
top_state->state_pops = 0;
#ifdef MOCHA
sub_state->in_relayout = TRUE;
#endif
/*
* If we're not currently searching for a tag, then find the next
* one to look for.
*/
if ( next_tag == NULL && elem_list != NULL )
{
next_tag = lo_FindReuseableElement ( context, state, &elem_list );
}
/*
* Can we reuse this current element?
*/
if ( (tag == next_tag) && (elem_list != NULL) )
{
LO_Element *eptr;
LO_Element *enext;
/*
* Yup, remove it from the list and call the object layout code to
* do the relayout.
*/
eptr = elem_list;
enext = eptr->lo_any.next;
elem_list = enext;
if ( enext != NULL )
{
enext->lo_any.prev = NULL;
}
eptr->lo_any.next = 0L;
eptr->lo_any.prev = 0L;
switch ( eptr->type )
{
case LO_EMBED:
lo_RelayoutEmbed ( context, sub_state, &eptr->lo_embed, tag );
break;
#ifdef JAVA
case LO_JAVA:
lo_RelayoutJavaApp ( context, sub_state, tag, &eptr->lo_java );
break;
#endif /* JAVA */
default:
/*
* We goofed and got something we don't know how to relayout
*/
lo_relayout_recycle ( context, state, eptr );
lo_LayoutTag(context, sub_state, tag);
break;
}
/*
* Force us to look for the next reusable element.
*/
next_tag = NULL;
}
else
{
/*
* Nope, call the standard layout code.
*/
lo_LayoutTag(context, sub_state, tag);
}
tmp_state = lo_CurrentSubState(state);
#ifdef MOCHA
if (tmp_state == sub_state)
{
sub_state->in_relayout = FALSE;
}
#endif
tmp_state = lo_CurrentSubState(state);
#ifdef MOCHA
if (tmp_state == sub_state)
{
sub_state->in_relayout = FALSE;
}
#endif
if (may_save != FALSE)
{
int32 state_diff;
/* how has our state level changed? */
state_diff = top_state->state_pushes - top_state->state_pops;
/*
* That tag popped us up one state level. If this new
* state is still a subdoc, save the tag there.
*/
if (state_diff == -1)
{
if ((tmp_state->is_a_subdoc == SUBDOC_CELL)||
(tmp_state->is_a_subdoc == SUBDOC_CAPTION))
{
/* if we just popped a table we need to insert
* a dummy end tag to pop the dummy start tag
* we shove on the stack after createing a table
*/
PA_Tag *new_tag = LO_CreateStyleSheetDummyTag(tag);
if(new_tag)
{
lo_SaveSubdocTags(context, tmp_state, new_tag);
}
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 ) &&
( top_state->diff_state != FALSE ) &&
( state_diff == 0 ))
{
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 (( top_state->diff_state == FALSE ) &&
( state_diff == 0 ))
{
lo_SaveSubdocTags(context, sub_state, tag);
}
/*
* Else that tag started a new, nested subdoc.
* Add the starting tag to the parent.
*/
else if (( state_diff == 1 ))
{
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))
{
PA_Tag *new_tag;
tmp_state->subdoc_tags =
sub_state->subdoc_tags_end;
/* add an aditional dummy tag so that style sheets
* can use it to query styles from for this entry
* that created a table
*/
new_tag = LO_CreateStyleSheetDummyTag(tag);
if(new_tag)
{
lo_SaveSubdocTags(context, tmp_state, new_tag);
}
}
}
/*
* This can never happen.
*/
else
{
PA_FreeTag(tag);
}
}
tag_ptr = tag_list;
}
/*
* Restore our parent's state levels
*/
top_state->diff_state = save_diff_state;
top_state->state_pushes = save_state_pushes;
top_state->state_pops = save_state_pops;
}
/*
* Walk the element list, throwing them away until we find one
* that can be reused.
*/
PA_Tag *
lo_FindReuseableElement(MWContext *context, lo_DocState *state, LO_Element ** elem_list)
{
LO_Element * eptr;
LO_Element * enext;
PA_Tag * tag;
tag = NULL;
eptr = *elem_list;
enext = NULL;
/*
* Keep going until we've gone through all the elements
* or found one that we can reuse.
*/
while ( (eptr != NULL) && (tag == NULL) )
{
enext = eptr->lo_any.next;
/*
* Any element found by this switch statement will attempt to be relayed out
* using the same element structure. DO NOT put anything in here that can
* have atributes set by style sheets until the lo_PreLayoutTag function
* can correctly handle stylesheets.
*/
switch ( eptr->type )
{
case LO_EMBED:
tag = eptr->lo_embed.tag;
break;
#ifdef JAVA
case LO_JAVA:
tag = eptr->lo_java.tag;
break;
#endif /* JAVA */
}
/*
* If we didn't find a tag from that element, then dispose of it and
* keep looking.
*/
if ( tag == NULL )
{
/*
* We dunno how to reuse this type of element, so throw
* it away and someone else will relay it out from scratch.
*/
eptr->lo_any.prev = NULL;
eptr->lo_any.next = NULL;
lo_relayout_recycle ( context, state, eptr );
if ( enext != NULL )
{
enext->lo_any.prev = NULL;
}
eptr = enext;
}
}
/*
* Advance the element list to the new head
*/
*elem_list = eptr;
return tag;
}
/*
* Functions separated out of lo_BeginTableAttributes
*/
void lo_PositionTableElement(lo_DocState *state, LO_TableStruct *table_ele)
{
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->next = NULL;
table_ele->prev = NULL;
/*
* Push our alignment state if we're not floating
*/
if ( !(table_ele->ele_attrmask & LO_ELE_FLOATING) )
{
lo_PushAlignment(state, P_TABLE_DATA, table_ele->alignment);
}
}
void lo_InitTableRecord( lo_TableRec *table )
{
/* Reset row and col counters */
table->rows = 0;
table->cols = 0;
/* Reset width span array */
lo_ResetWidthSpans(table);
table->height_span_ptr = NULL;
}
static void lo_ResetWidthSpans( lo_TableRec *table )
{
lo_table_span *span = table->width_spans;
while (span != NULL)
{
span->dim = 1;
span->min_dim = 1;
span->span = 0;
span = span->next;
}
}
void lo_SetTableDimensions( lo_DocState *state, lo_TableRec *table, int32 allow_percent_width, int32 allow_percent_height)
{
int32 val;
if (table->percent_width > 0)
{
val = table->percent_width;
if (allow_percent_width == FALSE)
{
val = 0;
}
else
{
val = (state->win_width - state->win_left -
state->win_right) * val / 100;
}
if (val < 0)
{
val = 0;
}
table->width = val;
}
if (table->percent_height > 0)
{
val = table->percent_height;
if (allow_percent_height == FALSE)
{
val = 0;
}
else
{
val = (state->win_height - state->win_top -
state->win_bottom) * val / 100;
}
if (val < 0)
{
val = 0;
}
table->height = val;
}
}
void lo_CalcFixedColWidths( MWContext *context, lo_DocState *state, lo_TableRec *table)
{
int32 cols = table->fixed_cols;
if (cols > 0) {
int32 count;
int32 table_width;
table_width = lo_ComputeInternalTableWidth ( context, table, state );
/* Split the space up evenly */
table->default_cell_width = table_width / cols;
/* and we have all the table width left to play with */
table->fixed_width_remaining = table_width;
/* Initialize our width array */
for ( count = 0; count < cols; ++count )
{
table->fixed_col_widths[ count ] = 0;
}
}
}
void lo_UpdateStateAfterBeginTable( lo_DocState *state, lo_TableRec *table)
{
state->current_table = table;
}
/* Relayout version of lo_BeginTableRowAttributes() */
void lo_UpdateTableStateForBeginRow(lo_TableRec *table, lo_TableRow *table_row)
{
table_row->row_done = FALSE;
table_row->cells = 0;
table_row->cell_list = NULL;
table_row->cell_ptr = NULL;
/* table_row->next = NULL;
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;
}
/*
* Functions for breaking up lo_BeginTableCellAttributes()
*/
void lo_InitForBeginCell(lo_TableRow *table_row, lo_TableCell *table_cell)
{
table_cell->must_relayout = FALSE;
table_cell->cell_done = FALSE;
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;
}
}
void lo_InitSubDocForBeginCell( MWContext *context, lo_DocState *state, lo_TableRec *table )
{
lo_TableCell *table_cell = table->row_ptr->cell_ptr;
lo_BeginCellSubDoc(context,
state,
table,
NULL,
NULL,
LO_TILE_BOTH,
NULL,
NULL,
NULL,
NULL,
table_cell->is_a_header,
table->draw_borders,
TRUE);
/*
* We added a new state.
*/
lo_PushStateLevel ( context );
}
static void lo_UpdateCaptionCellFromSubDoc( MWContext *context, lo_DocState *state, LO_SubDocStruct *subdoc, LO_CellStruct *cell_ele)
{
int32 dx = 0;
int32 dy = 0;
lo_CreateCellFromSubDoc(context, state, subdoc, cell_ele, &dx, &dy);
lo_ShiftCell(cell_ele, dx, dy);
lo_RenumberCell(state, cell_ele);
}
/* Only deletes the cell itself. Assumes that stuff the cell points to will get deleted
elsewhere */
static void lo_FreeCaptionCell( MWContext *context, lo_DocState *state, LO_CellStruct *cell_ele)
{
cell_ele->next = NULL;
cell_ele->prev = NULL;
cell_ele->cell_list = NULL;
cell_ele->cell_list_end = NULL;
cell_ele->cell_float_list = NULL;
cell_ele->table_cell = NULL;
cell_ele->table_row = NULL;
cell_ele->table = NULL;
lo_FreeElement(context, (LO_Element *)cell_ele, TRUE);
}
#ifdef TEST_16BIT
#undef XP_WIN16
#endif /* TEST_16BIT */