зеркало из https://github.com/mozilla/gecko-dev.git
8091 строка
187 KiB
C
8091 строка
187 KiB
C
/* -*- 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"
|
|
#include "timing.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);
|
|
|
|
static void
|
|
lo_reuse_current_state(MWContext *context, lo_DocState *state,
|
|
int32 width, int32 height, int32 margin_width, int32 margin_height,
|
|
Bool destroyLineLists);
|
|
|
|
static void lo_FreeAllExceptRows( MWContext *context, lo_DocState *state,
|
|
lo_TableRec *table );
|
|
static void lo_FreeTableSpanArray( lo_table_span *spanArray );
|
|
|
|
/*
|
|
********************************************************************************
|
|
* 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 );
|
|
|
|
#ifdef DEBUG_shaver
|
|
extern char *element_names[];
|
|
#endif
|
|
|
|
#ifdef DOM
|
|
void LO_SetTableCellAttributes(MWContext *context, void *cell_v,
|
|
const char *name, const char *value)
|
|
{
|
|
lo_TableCell *cell = (lo_TableCell *)cell_v;
|
|
LO_Element *start = cell->cell->cell_list, *end = cell->cell->cell_list_end;
|
|
lo_DocState *state;
|
|
lo_TopState *top = lo_FetchTopState(context->doc_id);
|
|
if (!top)
|
|
return;
|
|
|
|
state = top->doc_state;
|
|
|
|
if (!start)
|
|
return;
|
|
#ifdef DEBUG_shaver
|
|
fprintf(stderr, "setting %s=%s on <TD>\n", name, value);
|
|
#endif
|
|
|
|
if (!XP_STRCASECMP(name, "bgcolor")) {
|
|
LO_Color rgb;
|
|
LO_Element *iter = start;
|
|
if (!LO_ParseRGB((char *)value, &rgb.red, &rgb.green, &rgb.blue))
|
|
return;
|
|
/* while (iter && iter != end) { */
|
|
#ifdef DEBUG_shaver
|
|
fprintf(stderr, "setting bgcolor of %s to %s\n",
|
|
element_names[iter->type], value);
|
|
#endif
|
|
lo_SetColor(start, &rgb, state, TRUE);
|
|
/* iter = iter->lo_any.next;
|
|
}
|
|
if (iter != start) {
|
|
#ifdef DEBUG_shaver
|
|
fprintf(stderr, "setting bgcolor of %s to %s\n",
|
|
element_names[iter->type], value);
|
|
#endif
|
|
lo_SetColor(start, &rgb, state, TRUE);
|
|
}
|
|
*/
|
|
}
|
|
/* XXX LO_JustRedrawNothingChangedThatsImportant */
|
|
LO_RelayoutFromElement(context, start);
|
|
}
|
|
#endif
|
|
|
|
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;
|
|
|
|
#ifdef DOM
|
|
state->current_span = NULL;
|
|
state->in_span = FALSE;
|
|
#endif
|
|
|
|
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;
|
|
XP_FREE(property);
|
|
}
|
|
}
|
|
}
|
|
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;
|
|
/* ifdef-ed out of service:
|
|
PA_Tag *tag_list; */
|
|
/* Commented and ifdef-ed out of service:
|
|
PA_Tag *tag_ptr; */
|
|
/* Commented out of service:
|
|
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;
|
|
/* ifdef-ed out of service:
|
|
Bool save_diff_state; */
|
|
/* ifdef-ed out of service:
|
|
int32 save_state_pushes; */
|
|
/* ifdef-ed out of service:
|
|
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;
|
|
|
|
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;
|
|
/* Unused:
|
|
PA_Tag *tag_list; */
|
|
/* COmmented out of service:
|
|
PA_Tag *tag_ptr; */
|
|
/* Commented out of service:
|
|
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;
|
|
/* Unused:
|
|
Bool save_diff_state; */
|
|
/* Unused:
|
|
int32 save_state_pushes; */
|
|
/* Unused:
|
|
;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;
|
|
/* Commented out of service:
|
|
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 DOM
|
|
/*
|
|
* Unsafe cast, but code that operates on the Nodes will
|
|
* know that <TD> elements need special care.
|
|
*/
|
|
lo_SetNodeElement(state, (LO_Element *)table_cell);
|
|
#endif
|
|
|
|
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_ZAP(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;
|
|
}
|
|
#if DOM
|
|
/*
|
|
* So this is a little unsafe, on the surface.
|
|
* The code that does the reordering of LO_Elements will have to
|
|
* think important, special-case thoughts about <TR> nodes,
|
|
* but that's OK.
|
|
*/
|
|
lo_SetNodeElement(state, (LO_Element *)table_row);
|
|
#endif
|
|
|
|
/* 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;
|
|
}
|
|
|
|
/* Increment table nesting level (used for passing into lo_CreateCellBackGroundLayer() */
|
|
state->top_state->table_nesting_level++;
|
|
|
|
table_ele = (LO_TableStruct *)lo_NewElement(context, state, LO_TABLE, NULL, 0);
|
|
if (table_ele == NULL)
|
|
{
|
|
state->top_state->out_of_memory = TRUE;
|
|
return;
|
|
}
|
|
|
|
if (state->top_state->table_nesting_level == 1)
|
|
TIMING_STARTCLOCK_OBJECT("lo:blk-tab", table_ele);
|
|
|
|
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;
|
|
|
|
#if DOM
|
|
lo_SetNodeElement(state, (LO_Element *)table_ele);
|
|
#endif
|
|
|
|
/*
|
|
* 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;
|
|
}
|
|
}
|
|
|
|
|
|
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_FreeAllExceptRows( context, state, 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, top_state->table_nesting_level);
|
|
}
|
|
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(context, 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;
|
|
|
|
}
|
|
|
|
/* Decrement table nesting level (used for passing into lo_CreateCellBackGroundLayer() */
|
|
if (!relayout)
|
|
{
|
|
if (state->top_state->table_nesting_level == 1)
|
|
TIMING_STOPCLOCK_OBJECT("lo:blk-tab", table->table_ele, context, "ok");
|
|
|
|
state->top_state->table_nesting_level--;
|
|
}
|
|
|
|
#ifdef XP_WIN16
|
|
_hfree(cell_array);
|
|
#else
|
|
XP_UNLOCK_BLOCK(cell_array_buff);
|
|
XP_FREE_BLOCK(cell_array_buff);
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
* 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);
|
|
|
|
}
|
|
|
|
/* Delete the lo_TableRec data structure associated with the LO_TABLE element.
|
|
Does not free the LO_TABLE element itself. */
|
|
void lo_ScrapeTableElement( MWContext *context, LO_TableStruct *table_ele )
|
|
{
|
|
lo_TableRec *table = (lo_TableRec *) table_ele->table;
|
|
lo_TopState *top_state = lo_FetchTopState(XP_DOCID(context));
|
|
lo_DocState *state = top_state->doc_state;
|
|
|
|
if (table != NULL)
|
|
{
|
|
/* Free the table row list */
|
|
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;
|
|
|
|
/* The lo_TableCell structures will get freed when their peer
|
|
LO_CELL elements get recycled, so just null out the pointers
|
|
to those structures. */
|
|
row->cell_list = NULL;
|
|
row->cell_ptr = NULL;
|
|
|
|
XP_FREEIF(row->backdrop.bg_color);
|
|
XP_FREEIF(row->backdrop.url);
|
|
XP_DELETE(row);
|
|
}
|
|
table->row_list = NULL;
|
|
table->row_ptr = NULL;
|
|
}
|
|
|
|
/* Clean up the line array pointers to the elements contained inside the caption
|
|
cell. Otherwise, the freeing of the caption frees those elements and a double
|
|
free crash occurs when those elements are freed by their peer LO_CELL element */
|
|
if (table->caption && table->caption->subdoc &&
|
|
table->caption->subdoc->state)
|
|
lo_cleanup_old_state( table->caption->subdoc->state );
|
|
|
|
lo_FreeAllExceptRows( context, state, table );
|
|
}
|
|
}
|
|
|
|
|
|
static void lo_FreeAllExceptRows( MWContext *context, lo_DocState *state, lo_TableRec *table )
|
|
{
|
|
/* Free backdrop info */
|
|
XP_FREEIF(table->backdrop.bg_color);
|
|
XP_FREEIF(table->backdrop.url);
|
|
|
|
/* Free width and height span arrays */
|
|
lo_FreeTableSpanArray(table->width_spans);
|
|
table->width_spans = NULL;
|
|
table->width_span_ptr = NULL;
|
|
|
|
lo_FreeTableSpanArray(table->height_spans);
|
|
table->height_spans = NULL;
|
|
table->height_span_ptr = NULL;
|
|
|
|
/* Free caption information. */
|
|
if (table->caption != NULL)
|
|
{
|
|
/* The LO_CELL element associated with the caption will get freed
|
|
when it gets recycled in the line list. So, just null out the
|
|
pointer to it. */
|
|
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;
|
|
}
|
|
|
|
/* Free the subdoc state */
|
|
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);
|
|
}
|
|
|
|
static void lo_FreeTableSpanArray( lo_table_span *spanArray )
|
|
{
|
|
if (spanArray != NULL)
|
|
{
|
|
lo_table_span *span_ptr;
|
|
lo_table_span *span;
|
|
|
|
span_ptr = spanArray;
|
|
while (span_ptr != NULL)
|
|
{
|
|
span = span_ptr;
|
|
span_ptr = span_ptr->next;
|
|
XP_DELETE(span);
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef TEST_16BIT
|
|
#undef XP_WIN16
|
|
#endif /* TEST_16BIT */
|