netscape-revival
lib/layout/laysub.c
#include "xp.h"
#include "pa_parse.h"
#include "layout.h"
#ifdef TEST_16BIT
#define XP_WIN16
#endif /* TEST_16BIT */
#define SUBDOC_DEF_ANCHOR_BORDER 1
#define SUBDOC_DEF_VERTICAL_SPACE 5
#define SUBDOC_DEF_HORIZONTAL_SPACE 5
#define CELL_LINE_INC 10
void
lo_InheritParentState(lo_DocState *child_state, lo_DocState *parent_state)
{
/*
* Instead of the default of a new doc assuming 100 lines,
* we will start assuming a cell is 10 lines.
* This save lots of memory in table processing.
*/
if ((child_state->is_a_subdoc == SUBDOC_CELL)||
(child_state->is_a_subdoc == SUBDOC_CAPTION))
{
XP_Block line_array_block;
LO_Element **line_array;
line_array_block = XP_ALLOC_BLOCK(CELL_LINE_INC *
sizeof(LO_Element *));
if (line_array_block != NULL)
{
XP_FREE_BLOCK(child_state->line_array);
child_state->line_array = line_array_block;
XP_LOCK_BLOCK(line_array, LO_Element **,
child_state->line_array);
line_array[0] = NULL;
XP_UNLOCK_BLOCK(child_state->line_array);
child_state->line_array_size = CELL_LINE_INC;
#ifdef XP_WIN16
{
XP_Block *larray_array;
XP_LOCK_BLOCK(larray_array, XP_Block *,
child_state->larray_array);
larray_array[0] = child_state->line_array;
XP_UNLOCK_BLOCK(child_state->larray_array);
}
#endif /* XP_WIN16 */
}
}
if (((child_state->is_a_subdoc == SUBDOC_CELL)||
(child_state->is_a_subdoc == SUBDOC_CAPTION))&&
((parent_state->is_a_subdoc == SUBDOC_CELL)||
(parent_state->is_a_subdoc == SUBDOC_CAPTION)))
{
child_state->subdoc_tags = parent_state->subdoc_tags_end;
child_state->subdoc_tags_end = NULL;
}
child_state->text_fg.red = STATE_DEFAULT_FG_RED(parent_state);
child_state->text_fg.green = STATE_DEFAULT_FG_GREEN(parent_state);
child_state->text_fg.blue = STATE_DEFAULT_FG_BLUE(parent_state);
child_state->text_bg.red = STATE_DEFAULT_BG_RED(parent_state);
child_state->text_bg.green = STATE_DEFAULT_BG_GREEN(parent_state);
child_state->text_bg.blue = STATE_DEFAULT_BG_BLUE(parent_state);
lo_RecolorText(child_state);
child_state->anchor_color.red =
STATE_UNVISITED_ANCHOR_RED(parent_state);
child_state->anchor_color.green =
STATE_UNVISITED_ANCHOR_GREEN(parent_state);
child_state->anchor_color.blue =
STATE_UNVISITED_ANCHOR_BLUE(parent_state);
child_state->visited_anchor_color.red =
STATE_VISITED_ANCHOR_RED(parent_state);
child_state->visited_anchor_color.green =
STATE_VISITED_ANCHOR_GREEN(parent_state);
child_state->visited_anchor_color.blue =
STATE_VISITED_ANCHOR_BLUE(parent_state);
child_state->active_anchor_color.red =
STATE_SELECTED_ANCHOR_RED(parent_state);
child_state->active_anchor_color.green =
STATE_SELECTED_ANCHOR_GREEN(parent_state);
child_state->active_anchor_color.blue =
STATE_SELECTED_ANCHOR_BLUE(parent_state);
}
int32
lo_GetSubDocBaseline(LO_SubDocStruct *subdoc)
{
LO_Element **line_array;
LO_Element *eptr;
lo_DocState *subdoc_state;
subdoc_state = (lo_DocState *)subdoc->state;
if (subdoc_state == NULL)
{
return(0);
}
/*
* Make eptr point to the start of the element chain
* for this subdoc.
*/
#ifdef XP_WIN16
{
XP_Block *larray_array;
if (subdoc_state->larray_array == NULL)
{
return(0);
}
XP_LOCK_BLOCK(larray_array, XP_Block *, subdoc_state->larray_array);
subdoc_state->line_array = larray_array[0];
XP_UNLOCK_BLOCK(subdoc_state->larray_array);
}
#endif /* XP_WIN16 */
if (subdoc_state->line_array == NULL)
{
return(0);
}
XP_LOCK_BLOCK(line_array, LO_Element **, subdoc_state->line_array);
eptr = line_array[0];
XP_UNLOCK_BLOCK(subdoc_state->line_array);
while (eptr != NULL)
{
if (eptr->type == LO_LINEFEED)
{
break;
}
eptr = eptr->lo_any.next;
}
if (eptr == NULL)
{
return(0);
}
return(eptr->lo_linefeed.baseline);
}
void
lo_BeginSubDoc(MWContext *context, lo_DocState *state, PA_Tag *tag)
{
LO_SubDocStruct *subdoc;
lo_DocState *new_state;
PA_Block buff;
char *str;
int32 val;
int32 first_width, first_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->state = NULL;
subdoc->vert_alignment = LO_ALIGN_TOP;
subdoc->alignment = LO_ALIGN_LEFT;
subdoc->border_width = SUBDOC_DEF_ANCHOR_BORDER;
subdoc->border_vert_space = SUBDOC_DEF_VERTICAL_SPACE;
subdoc->border_horiz_space = SUBDOC_DEF_HORIZONTAL_SPACE;
subdoc->ele_attrmask = 0;
subdoc->sel_start = -1;
subdoc->sel_end = -1;
/*
* Check for an align parameter
*/
subdoc->alignment = LO_ALIGN_LEFT;
subdoc->ele_attrmask |= LO_ELE_FLOATING;
buff = lo_FetchParamValue(context, tag, PARAM_ALIGN);
if (buff != NULL)
{
Bool floating;
floating = TRUE;
PA_LOCK(str, char *, buff);
subdoc->alignment = lo_EvalAlignParam(str, &floating);
if (floating == FALSE)
{
subdoc->ele_attrmask &= (~(LO_ELE_FLOATING));
}
PA_UNLOCK(buff);
}
/*
* Check for a vertical align parameter
*/
buff = lo_FetchParamValue(context, tag, PARAM_VALIGN);
if (buff != NULL)
{
PA_LOCK(str, char *, buff);
subdoc->vert_alignment = lo_EvalVAlignParam(str);
PA_UNLOCK(buff);
}
/*
* Get the width parameter, in absolute or percentage.
* If percentage, make it absolute.
*/
buff = lo_FetchParamValue(context, tag, PARAM_WIDTH);
if (buff != NULL)
{
Bool is_percent;
PA_LOCK(str, char *, buff);
val = lo_ValueOrPercent(str, &is_percent);
if (is_percent != FALSE)
{
val = state->win_width * val / 100;
}
else
{
val = FEUNITS_X(val, context);
}
subdoc->width = val;
if (subdoc->width < 1)
{
subdoc->width = 1;
}
PA_UNLOCK(buff);
}
/*
* Get the height parameter, in absolute or percentage.
* If percentage, make it absolute.
*/
buff = lo_FetchParamValue(context, tag, PARAM_HEIGHT);
if (buff != NULL)
{
Bool is_percent;
PA_LOCK(str, char *, buff);
val = lo_ValueOrPercent(str, &is_percent);
if (is_percent != FALSE)
{
val = state->win_height * val / 100;
}
else
{
val = FEUNITS_Y(val, context);
}
subdoc->height = val;
if (subdoc->height < 1)
{
subdoc->height = 1;
}
PA_UNLOCK(buff);
}
/*
* Get the border parameter.
*/
buff = lo_FetchParamValue(context, tag, PARAM_BORDER);
if (buff != NULL)
{
PA_LOCK(str, char *, buff);
val = XP_ATOI(str);
if (val < 0)
{
val = 0;
}
subdoc->border_width = val;
PA_UNLOCK(buff);
}
subdoc->border_width = FEUNITS_X(subdoc->border_width, context);
/*
* Get the extra vertical space parameter.
*/
buff = lo_FetchParamValue(context, tag, PARAM_VSPACE);
if (buff != NULL)
{
PA_LOCK(str, char *, buff);
val = XP_ATOI(str);
if (val < 0)
{
val = 0;
}
subdoc->border_vert_space = val;
PA_UNLOCK(buff);
}
subdoc->border_vert_space = FEUNITS_Y(subdoc->border_vert_space,
context);
/*
* Get the extra horizontal space parameter.
*/
buff = lo_FetchParamValue(context, tag, PARAM_HSPACE);
if (buff != NULL)
{
PA_LOCK(str, char *, buff);
val = XP_ATOI(str);
if (val < 0)
{
val = 0;
}
subdoc->border_horiz_space = val;
PA_UNLOCK(buff);
}
subdoc->border_horiz_space = FEUNITS_X(subdoc->border_horiz_space,
context);
if (subdoc->width == 0)
{
first_width = FEUNITS_X(5000, context);
}
else
{
first_width = subdoc->width;
}
if (subdoc->height == 0)
{
first_height = FEUNITS_Y(10000, context);
}
else
{
first_height = subdoc->height;
}
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_IS;
lo_InheritParentState(new_state, state);
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;
state->sub_state = new_state;
state->current_ele = (LO_Element *)subdoc;
}
void
lo_EndSubDoc(MWContext *context, lo_DocState *state, lo_DocState *old_state,
LO_Element *element)
{
LO_Element *eptr;
LO_SubDocStruct *subdoc;
PA_Block buff;
char *str;
Bool line_break;
int32 vert_inc;
int32 baseline_inc;
int32 line_inc;
int32 subdoc_height, subdoc_width;
LO_TextStruct tmp_text;
LO_TextInfo text_info;
LO_Element **line_array;
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;
}
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 (subdoc->width == 0)
{
subdoc->width = old_state->max_width +
(2 * subdoc->border_width);
}
if (subdoc->height == 0)
{
subdoc->height = old_state->y + (2 * subdoc->border_width);
}
/*
* Mess with vertical alignment.
*/
vert_inc = subdoc->height - (old_state->y + (2 * subdoc->border_width));
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
{
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)
{
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)) -
(c_eptr->lo_linefeed.x +
c_eptr->lo_linefeed.x_offset);
side_inc = side_inc / 2;
if (side_inc > 0)
{
c_eptr->lo_linefeed.width -= side_inc;
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;
default:
break;
}
eptr->lo_any.y += vert_inc;
eptr = eptr->lo_any.next;
}
subdoc_width = subdoc->width + (2 * subdoc->border_width) +
(2 * subdoc->border_horiz_space);
subdoc_height = subdoc->height + (2 * subdoc->border_width) +
(2 * subdoc->border_vert_space);
/*
* SEVERE FLOW BREAK! This may be a floating subdoc,
* which means at this point we go do something completely
* different.
*/
if (subdoc->ele_attrmask & LO_ELE_FLOATING)
{
if (subdoc->alignment == LO_ALIGN_RIGHT)
{
subdoc->x = state->right_margin - subdoc_width;
if (subdoc->x < 0)
{
subdoc->x = 0;
}
}
else
{
subdoc->x = state->left_margin;
}
subdoc->y = -1;
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;
if (subdoc->y < 0)
{
old_state->base_y = subdoc->y;
}
else
{
old_state->base_y = subdoc->y + subdoc->y_offset +
subdoc->border_width;
}
lo_AddMarginStack(state, subdoc->x, subdoc->y,
subdoc->width, subdoc->height,
subdoc->border_width,
subdoc->border_vert_space, subdoc->border_horiz_space,
(intn)subdoc->alignment);
/*
* Insert this element into the float list.
*/
subdoc->next = state->float_list;
state->float_list = (LO_Element *)subdoc;
if (state->at_begin_line != FALSE)
{
lo_FindLineMargins(context, state);
state->x = state->left_margin;
if (state->display_blocked == FALSE)
{
subdoc->x += state->base_x;
subdoc->y += state->base_y;
lo_DisplaySubDoc(context, FE_VIEW, subdoc);
subdoc->x -= state->base_x;
subdoc->y -= state->base_y;
}
}
else
{
}
return;
}
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 unwrapped preformatted 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.
*/
if (line_break != FALSE)
{
/*
* We need to make the elements sequential, linefeed
* before image.
*/
state->top_state->element_id = subdoc->ele_id;
lo_HardLineBreak(context, state, TRUE);
subdoc->x = state->x;
subdoc->y = state->y;
subdoc->ele_id = NEXT_ELEMENT;
}
/*
* 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;
lo_AppendToLineList(context, state,
(LO_Element *)subdoc, baseline_inc);
state->baseline += (intn) baseline_inc;
state->line_height += (intn) (baseline_inc + line_inc);
/*
* 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;
}
#ifdef TEST_16BIT
#undef XP_WIN16
#endif /* TEST_16BIT */