mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-02 18:08:58 +00:00
1890 lines
62 KiB
C
1890 lines
62 KiB
C
/* -*- Mode: C; tab-width: 8; 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.
|
|
*/
|
|
|
|
|
|
/*
|
|
layrelay.c --- reflow of layout elements.
|
|
Created: Nisheeth Ranjan <nisheeth@netscape.com>, 7-Nov-1997.
|
|
*/
|
|
#include "xp.h"
|
|
#include "net.h"
|
|
#include "pa_parse.h"
|
|
#include "layout.h"
|
|
#include "laylayer.h"
|
|
#include "layers.h"
|
|
#include "layrelay.h"
|
|
#include "laytrav.h"
|
|
#ifdef EDITOR
|
|
#include "edt.h"
|
|
#endif
|
|
|
|
#include "libmocha.h"
|
|
#include "libevent.h"
|
|
|
|
extern int MK_OUT_OF_MEMORY;
|
|
|
|
#ifdef PROFILE
|
|
#pragma profile on
|
|
#endif
|
|
|
|
#ifdef TEST_16BIT
|
|
#define XP_WIN16
|
|
#endif /* TEST_16BIT */
|
|
|
|
#ifdef XP_WIN16
|
|
#define SIZE_LIMIT 32000
|
|
#endif /* XP_WIN16 */
|
|
|
|
static lo_DocState *lo_rl_InitDocState( MWContext *context, lo_DocState *state,
|
|
int32 width, int32 height,
|
|
int32 margin_width, int32 margin_height);
|
|
static void lo_rl_PreLayoutElement ( MWContext *context, lo_DocState * state,
|
|
LO_Element *lo_ele );
|
|
static void lo_rl_CopyCellToState( LO_CellStruct *cell, lo_DocState *state );
|
|
static void lo_rl_CopyStateToCell( lo_DocState *state, LO_CellStruct *cell);
|
|
|
|
/* Loops through layout elements and calls their fitting functions */
|
|
static void lo_rl_FitLayoutElements( lo_RelayoutState *relay_state, LO_Element *start_ele );
|
|
|
|
|
|
static lo_DocState *
|
|
lo_rl_InitDocState( MWContext *context, lo_DocState *state, int32 width, int32 height, int32 margin_width, int32 margin_height );
|
|
static void lo_UpdateHeightSpanForBeginRow(lo_TableRec *table);
|
|
static void lo_rl_BeginTableRelayout( MWContext *context, lo_DocState *state, lo_TableRec *table);
|
|
static LO_LinefeedStruct * lo_rl_RecreateElementListsFromCells( lo_DocState *state, LO_TableStruct *table,
|
|
LO_Element **lastElementInLastCell);
|
|
|
|
typedef LO_Element * (*lo_FitFunction)( lo_RelayoutState *relay_state, LO_Element *lo_ele );
|
|
|
|
static LO_Element * lo_rl_FitIgnore( lo_RelayoutState *relay_state, LO_Element *lo_ele );
|
|
static LO_Element * lo_rl_FitError( lo_RelayoutState *relay_state, LO_Element *lo_ele );
|
|
static LO_Element * lo_rl_FitText( lo_RelayoutState *relay_state, LO_Element *lo_ele );
|
|
static LO_Element * lo_rl_FitLineFeed( lo_RelayoutState *relay_state, LO_Element *lo_ele );
|
|
static LO_Element * lo_rl_FitHRule( lo_RelayoutState *relay_state, LO_Element *lo_ele );
|
|
static LO_Element * lo_rl_FitImage( lo_RelayoutState *relay_state, LO_Element *lo_ele );
|
|
static LO_Element * lo_rl_FitBullet( lo_RelayoutState *relay_state, LO_Element *lo_ele );
|
|
static LO_Element * lo_rl_FitFormEle( lo_RelayoutState *relay_state, LO_Element *lo_ele );
|
|
static LO_Element * lo_rl_FitTable( lo_RelayoutState *relay_state, LO_Element *lo_ele );
|
|
static LO_Element * lo_rl_FitCell( lo_RelayoutState *relay_state, LO_Element *lo_ele );
|
|
static LO_Element * lo_rl_FitEmbed( lo_RelayoutState *relay_state, LO_Element *lo_ele );
|
|
static LO_Element * lo_rl_FitBuiltin( lo_RelayoutState *relay_state, LO_Element *lo_ele );
|
|
static LO_Element * lo_rl_FitJava( lo_RelayoutState *relay_state, LO_Element *lo_ele );
|
|
static LO_Element * lo_rl_FitObject( lo_RelayoutState *relay_state, LO_Element *lo_ele );
|
|
static LO_Element * lo_rl_FitParagraph( lo_RelayoutState *relay_state, LO_Element *lo_ele );
|
|
static LO_Element * lo_rl_FitCenter( lo_RelayoutState *relay_state, LO_Element *lo_ele );
|
|
static LO_Element * lo_rl_FitMulticolumn( lo_RelayoutState *relay_state, LO_Element *lo_ele );
|
|
static LO_Element * lo_rl_FitFloat( lo_RelayoutState *relay_state, LO_Element *lo_ele );
|
|
static LO_Element * lo_rl_FitTextBlock( lo_RelayoutState *relay_state, LO_Element *lo_ele );
|
|
static LO_Element * lo_rl_FitList( lo_RelayoutState *relay_state, LO_Element *lo_ele );
|
|
static LO_Element * lo_rl_FitDescTitle( lo_RelayoutState *relay_state, LO_Element *lo_ele );
|
|
static LO_Element * lo_rl_FitDescText( lo_RelayoutState *relay_state, LO_Element *lo_ele );
|
|
static LO_Element * lo_rl_FitBlockQuote( lo_RelayoutState *relay_state, LO_Element *lo_ele );
|
|
static LO_Element * lo_rl_FitLayer( lo_RelayoutState *relay_state, LO_Element *lo_ele );
|
|
static LO_Element * lo_rl_FitHeading( lo_RelayoutState *relay_state, LO_Element *lo_ele );
|
|
static LO_Element * lo_rl_FitSpan( lo_RelayoutState *relay_state, LO_Element *lo_ele );
|
|
static LO_Element * lo_rl_FitDiv( lo_RelayoutState *relay_state, LO_Element *lo_ele );
|
|
static LO_Element * lo_rl_FitSpacer( lo_RelayoutState *relay_state, LO_Element *lo_ele );
|
|
static LO_Element * lo_rl_FitSuper( lo_RelayoutState *relay_state, LO_Element *lo_ele );
|
|
static LO_Element * lo_rl_FitSub( lo_RelayoutState *relay_state, LO_Element *lo_ele );
|
|
|
|
/* The table of fitting functions for each layout element type... */
|
|
static lo_FitFunction lo_rl_FitFunctionTable[] = {
|
|
lo_rl_FitIgnore, /* LO_NONE */
|
|
lo_rl_FitText, /* LO_TEXT */
|
|
lo_rl_FitLineFeed, /* LO_LINEFEED */
|
|
lo_rl_FitHRule, /* LO_HRULE */
|
|
lo_rl_FitImage, /* LO_IMAGE */
|
|
lo_rl_FitBullet, /* LO_BULLET */
|
|
lo_rl_FitFormEle, /* LO_FORM_ELE */
|
|
lo_rl_FitError, /* LO_SUBDOC elements should not occur in line list */
|
|
lo_rl_FitTable, /* LO_TABLE */
|
|
lo_rl_FitCell, /* LO_CELL */
|
|
lo_rl_FitEmbed, /* LO_EMBED */
|
|
lo_rl_FitError, /* LO_EDGE element: Either an error or we should ignore. ??? */
|
|
lo_rl_FitJava, /* LO_JAVA */
|
|
lo_rl_FitError, /* LO_SCRIPT elements should not occur in list of layout elements */
|
|
lo_rl_FitObject, /* LO_OBJECT */
|
|
lo_rl_FitParagraph, /* LO_PARAGRAPH */
|
|
lo_rl_FitCenter, /* LO_CENTER */
|
|
lo_rl_FitMulticolumn, /* LO_MULTICOLUMN */
|
|
lo_rl_FitFloat, /* LO_FLOAT */
|
|
lo_rl_FitTextBlock, /* LO_TEXTBLOCK */
|
|
lo_rl_FitList, /* LO_LIST */
|
|
lo_rl_FitDescTitle, /* LO_DESCTITLE */
|
|
lo_rl_FitDescText, /* LO_DESCTEXT */
|
|
lo_rl_FitBlockQuote, /* LO_BLOCKQUOTE */
|
|
lo_rl_FitLayer, /* LO_LAYER */
|
|
lo_rl_FitHeading, /* LO_HEADING */
|
|
lo_rl_FitSpan, /* LO_SPAN */
|
|
lo_rl_FitDiv, /* LO_DIV */
|
|
lo_rl_FitBuiltin, /* LO_BUILTIN */
|
|
lo_rl_FitSpacer, /* LO_SPACER */
|
|
lo_rl_FitSuper, /* LO_SUPER */
|
|
lo_rl_FitSub /* LO_SUB */
|
|
};
|
|
|
|
|
|
void lo_FillInBuiltinGeometry(lo_DocState *state, LO_BuiltinStruct *builtin,
|
|
Bool relayout);
|
|
void lo_UpdateStateAfterBuiltinLayout (lo_DocState *state, LO_BuiltinStruct *builtin,
|
|
int32 line_inc, int32 baseline_inc);
|
|
static void
|
|
lo_rl_SetLayerDimensions( lo_RelayoutState *relay_state, LO_BlockInitializeStruct *layerParams );
|
|
|
|
/* NRA - 10/3/97: Main Relayout Entry Point
|
|
* This function walks through the layout element list and re-lays out
|
|
* the elements to fit into a window of the specified width and height.
|
|
*
|
|
* It needs to be called on each resize of the window.
|
|
*
|
|
* Issues to be careful about: 1) Synchronization with Javascript that is running concurrently while this
|
|
* re-layout is going on.
|
|
*
|
|
* 2) Keep a copy of elements that change. Will come in handy later to figure out the redraw rectangle.
|
|
* For now, we dirty the entire document
|
|
*
|
|
* 3) FE needs to tell us the position in the current document. We will need to determine the element id
|
|
* at that position and call FE_SetDocPosition to set the document to the saved position after relayout
|
|
*/
|
|
void LO_RelayoutOnResize(MWContext *context, int32 width, int32 height, int32 leftMargin, int32 topMargin)
|
|
{
|
|
lo_RelayoutState *relay_state;
|
|
lo_DocState *state;
|
|
LO_Element *lo_ele;
|
|
int32 docX, docY;
|
|
lo_TopState *top_state;
|
|
|
|
/* check to see if the context we've been passed is a grid context. If so, branch to the grid
|
|
specific resize routine, which will call this one again on its grid cells. */
|
|
top_state = lo_FetchTopState(XP_DOCID(context));
|
|
if (top_state == NULL) {
|
|
return;
|
|
}
|
|
|
|
LO_LockLayout();
|
|
|
|
/* Abort if the document is currently being laid out */
|
|
if (LO_LayingOut( context ))
|
|
{
|
|
LO_UnlockLayout();
|
|
return;
|
|
}
|
|
|
|
if (top_state->the_grid) {
|
|
/* the document doesn't have any elements. It's a grid document */
|
|
lo_RelayoutGridDocumentOnResize(context, top_state, width, height);
|
|
LO_UnlockLayout();
|
|
return;
|
|
}
|
|
|
|
relay_state = lo_rl_CreateRelayoutState();
|
|
if (relay_state == NULL) {
|
|
LO_UnlockLayout();
|
|
return; /* Better error handling later */
|
|
}
|
|
|
|
/* Reset the scoping for any JavaScript to be the top-level layer. */
|
|
/* ET_SetActiveLayer(context, LO_DOCUMENT_LAYER_ID); */
|
|
|
|
/* remember where we are in the document */
|
|
FE_GetDocPosition ( context, FE_VIEW, &docX, &docY );
|
|
|
|
/* shrink the layout document in case we get smaller */
|
|
/* LO_SetDocumentDimensions(context, 0, 0); */
|
|
|
|
if (lo_rl_InitRelayoutState(context, relay_state, width, height, leftMargin, topMargin) != NULL)
|
|
{
|
|
lo_ele = lo_tv_GetFirstLayoutElement(relay_state->doc_state);
|
|
lo_rl_FitLayoutElements(relay_state, lo_ele);
|
|
|
|
/* Flush out any remaining elements on the line list into the line array. */
|
|
lo_rl_AddSoftBreakAndFlushLine(relay_state->context, relay_state->doc_state);
|
|
lo_EndLayoutDuringReflow( relay_state->context, relay_state->doc_state );
|
|
}
|
|
else
|
|
{
|
|
lo_rl_DestroyRelayoutState(relay_state);
|
|
LO_UnlockLayout();
|
|
return;
|
|
}
|
|
|
|
state = relay_state->doc_state;
|
|
|
|
/* Send JS load event. JS will treat it as a resize by looking at the resize_reload param */
|
|
ET_SendLoadEvent(context, EVENT_LOAD, NULL, NULL,
|
|
LO_DOCUMENT_LAYER_ID,
|
|
state->top_state->resize_reload);
|
|
|
|
/* Reset state for force loading images. */
|
|
LO_SetForceLoadImage(NULL, FALSE);
|
|
|
|
/* update the final document dimensions */
|
|
state->y += state->win_bottom;
|
|
LO_SetDocumentDimensions(context, state->max_width, state->y);
|
|
|
|
#if !defined(SMOOTH_PROGRESS)
|
|
if(!state->top_state->is_binary)
|
|
FE_SetProgressBarPercent(context, 100);
|
|
#endif /* !defined(SMOOTH_PRORGESS) */
|
|
|
|
lo_FreeLayoutData(context, state);
|
|
FE_FinishedLayout(context);
|
|
|
|
/* Tell FE to redraw window */
|
|
if (context->compositor)
|
|
{
|
|
CL_Compositor *compositor = context->compositor;
|
|
XP_Rect rect;
|
|
CL_OffscreenMode save_offscreen_mode;
|
|
|
|
rect.left = rect.top = 0;
|
|
rect.right = state->win_width;
|
|
rect.bottom = state->y;
|
|
|
|
CL_UpdateDocumentRect(compositor,
|
|
&rect, (PRBool)FALSE);
|
|
|
|
/* Temporarily force drawing to use the offscreen buffering area to reduce
|
|
flicker when resizing. (If no offscreen store is allocated, this code will
|
|
have no effect, but it will do no harm.) */
|
|
save_offscreen_mode = CL_GetCompositorOffscreenDrawing(compositor);
|
|
CL_SetCompositorOffscreenDrawing(compositor, CL_OFFSCREEN_ENABLED);
|
|
CL_CompositeNow(compositor);
|
|
CL_SetCompositorOffscreenDrawing(compositor, save_offscreen_mode);
|
|
}
|
|
|
|
/* position the document */
|
|
FE_SetDocPosition ( context, FE_VIEW, 0, docY );
|
|
|
|
lo_rl_DestroyRelayoutState(relay_state);
|
|
|
|
LO_UnlockLayout();
|
|
/* Postion is hard-coded to top of document for now.*/
|
|
/* FE_SetDocPosition(context, 0, 0, 0); */
|
|
/* 2nd parameter for FE_ClearView is iView which is ignored. */
|
|
/* FE_ClearView(context, 0); */
|
|
|
|
}
|
|
|
|
/*
|
|
** Relayout a document given a change in one LO_Element*. This is of
|
|
** primary use for plugins (since there is now an API to change the
|
|
** size of a plugin), but could also be used once the LO_Elements are
|
|
** reflected in a DOM and style information affecting the element's
|
|
** size is changed.
|
|
*/
|
|
void
|
|
LO_RelayoutFromElement(MWContext *context, LO_Element *element)
|
|
{
|
|
/* toshok - we don't have all the plumbing in place yet to handle
|
|
something like this, so we punt and make it a wrapper for
|
|
LO_RelayoutOnResize. Given that all drawing is done through a
|
|
compositor, the user shouldn't be aware of everything being
|
|
relayed out anyway. */
|
|
int32 leftMargin, topMargin;
|
|
int32 width, height;
|
|
lo_TopState *top_state = lo_FetchTopState(XP_DOCID(context));
|
|
|
|
if (!top_state)
|
|
return;
|
|
|
|
width = LO_GetLayerScrollWidth(top_state->body_layer);
|
|
height = LO_GetLayerScrollHeight(top_state->body_layer);
|
|
|
|
LO_GetDocumentMargins(context, &leftMargin, &topMargin);
|
|
|
|
LO_RelayoutOnResize(context, width, height, leftMargin, topMargin);
|
|
}
|
|
|
|
/*
|
|
* This function reflows a document from a given element. It's primary function is for the editor.
|
|
* The caller must provide a state record which is correctly initialized to the position the reflow
|
|
* will start.
|
|
*
|
|
* It currently only works for text elements.
|
|
*/
|
|
void LO_Reflow(MWContext *context, lo_DocState * state, LO_Element *startElement, LO_Element *endElement)
|
|
{
|
|
LO_Element *lo_ele;
|
|
lo_TopState *top_state;
|
|
lo_RelayoutState relay_state;
|
|
lo_DocState * save_state;
|
|
LO_TextBlock * block;
|
|
Bool firstElement;
|
|
|
|
#if defined( DEBUG_nisheeth ) || defined( DEBUG_toshok ) || defined( DEBUG_shannon )
|
|
if (context) {
|
|
lo_PrintLayout(context);
|
|
}
|
|
#endif
|
|
|
|
/* check to see if the context we've been passed is a grid context. If so, branch to the grid
|
|
specific resize routine, which will call this one again on its grid cells. */
|
|
top_state = lo_FetchTopState(XP_DOCID(context));
|
|
if (top_state == NULL) {
|
|
return;
|
|
}
|
|
|
|
LO_LockLayout();
|
|
|
|
/* init this by hand as we don't want to create a new state */
|
|
relay_state.context = context;
|
|
relay_state.top_state = top_state; /*lo_FetchTopState(XP_DOCID(context));*/
|
|
relay_state.doc_state = state;
|
|
|
|
firstElement = TRUE;
|
|
lo_ele = startElement;
|
|
|
|
while ( lo_ele != endElement ) {
|
|
lo_rl_PreLayoutElement ( context, state, lo_ele );
|
|
if (state->top_state->out_of_memory)
|
|
{
|
|
LO_UnlockLayout();
|
|
return;
|
|
}
|
|
|
|
state->edit_force_offset = TRUE;
|
|
|
|
save_state = top_state->doc_state;
|
|
top_state->doc_state = state;
|
|
|
|
block = NULL;
|
|
|
|
/*
|
|
* If we get a text element, we also need to retrieve the text block
|
|
*/
|
|
if ( lo_ele->type == LO_TEXT )
|
|
{
|
|
/* I'm pretty sure this ifdef is ok since EDT_GetTextBlock should always return NULL
|
|
if we're not in an editor context. hardts */
|
|
#ifdef EDITOR
|
|
block = EDT_GetTextBlock ( context, lo_ele );
|
|
#endif /* EDITOR */
|
|
}
|
|
|
|
/*
|
|
* if we found a text block, then call the reflow routine with this element, otherwise
|
|
* use the default reflow code. Remember sometimes we get text elements without a text block
|
|
* (such as list elements)
|
|
*/
|
|
if ( block != NULL ) {
|
|
lo_ele = lo_RelayoutTextBlock ( context, state, block, &lo_ele->lo_text );
|
|
}
|
|
else {
|
|
/*
|
|
* HACK: Until I find a better way to deal with this.
|
|
*
|
|
* The above lo_LayoutTag loop will handle setup for things like lists. This is fine
|
|
* when we're inside a list (ie past element 1) as the first thing the reflow will
|
|
* process is the bullet. However, (for a reason I don't entirely understand yet), if
|
|
* we're on the first line of the document and the list is the first element, startElement
|
|
* will point at the LO_LIST element. This means that reflow will reexecute the start list
|
|
* and we'll do the wrong thing.
|
|
*
|
|
* So, for now only, if the first element is a LO_LIST element, then skip it!
|
|
*/
|
|
if ( firstElement && ( lo_ele->type == LO_LIST ) )
|
|
{
|
|
LO_Element * next;
|
|
|
|
next = lo_tv_GetNextLayoutElement ( state, lo_ele, FALSE );
|
|
|
|
lo_ele->lo_any.ele_id = NEXT_ELEMENT;
|
|
lo_ele->lo_any.x = state->x;
|
|
lo_ele->lo_any.y = state->y;
|
|
|
|
state->x += lo_ele->lo_text.width;
|
|
lo_AppendToLineList( context, state, lo_ele, 0);
|
|
|
|
lo_ele = next;
|
|
}
|
|
else
|
|
{
|
|
/* Dispatch the layout element to its fitting routine.
|
|
Fitting routine returns the next layout element to process */
|
|
lo_ele = (*lo_rl_FitFunctionTable[lo_ele->type])( &relay_state, lo_ele);
|
|
}
|
|
}
|
|
|
|
firstElement = FALSE;
|
|
|
|
top_state->doc_state = save_state;
|
|
|
|
if (state->top_state->out_of_memory)
|
|
{
|
|
LO_UnlockLayout();
|
|
return;
|
|
}
|
|
|
|
if ( lo_ele == NULL )
|
|
{
|
|
/* LO_UnlockLayout(); */
|
|
break;
|
|
}
|
|
|
|
state->edit_force_offset = FALSE;
|
|
}
|
|
|
|
#if defined( DEBUG_nisheeth ) || defined( DEBUG_toshok ) || defined( DEBUG_shannon )
|
|
if (context) {
|
|
lo_PrintLayout(context);
|
|
}
|
|
#endif
|
|
|
|
LO_UnlockLayout();
|
|
}
|
|
|
|
/* Selectively cut and pasted from lo_InitDocState(). Should we separate this stuff
|
|
out into a common function rather than duplicating code? */
|
|
static lo_DocState *
|
|
lo_rl_InitDocState( MWContext *context, lo_DocState *state, int32 width, int32 height, int32 margin_width, int32 margin_height )
|
|
{
|
|
lo_TopState *top_state = state->top_state;
|
|
|
|
state->subdoc_tags = NULL;
|
|
state->subdoc_tags_end = NULL;
|
|
|
|
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->max_height = state->win_top + state->win_bottom;
|
|
|
|
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;
|
|
state->left_margin_stack = NULL;
|
|
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;
|
|
|
|
state->line_list = NULL;
|
|
state->end_last_line = NULL;
|
|
|
|
/* XXX - No font information is reset upon entering a layer, nor
|
|
is it restored when the layer ends. Is this the right thing to do ? */
|
|
if (!state->font_stack) {
|
|
state->base_font_size = DEFAULT_BASE_FONT_SIZE;
|
|
state->font_stack = lo_DefaultFont(state, context);
|
|
if (state->font_stack == NULL)
|
|
{
|
|
/*
|
|
XP_FREE_BLOCK(state->line_array);
|
|
#ifdef XP_WIN16
|
|
XP_FREE_BLOCK(state->larray_array);
|
|
#endif
|
|
*/
|
|
return(NULL);
|
|
}
|
|
state->font_stack->text_attr->size = state->base_font_size;
|
|
|
|
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;
|
|
}
|
|
|
|
/* XXXX NRA: Possible memory leak here. What if these guys aren't freed at the end of initial layout?
|
|
* Check before assigning to NULL
|
|
*/
|
|
state->align_stack = NULL;
|
|
state->line_height_stack = NULL;
|
|
state->list_stack = lo_DefaultList(state);
|
|
if (state->list_stack == NULL)
|
|
{
|
|
#if 0
|
|
XP_FREE_BLOCK(state->line_array);
|
|
#ifdef XP_WIN16
|
|
XP_FREE_BLOCK(state->larray_array);
|
|
#endif /* XP_WIN16 */
|
|
|
|
XP_DELETE(state->font_stack);
|
|
#endif
|
|
return(NULL);
|
|
}
|
|
|
|
state->line_buf_size = 0;
|
|
state->line_buf = PA_ALLOC(LINE_BUF_INC * sizeof(char));
|
|
if (state->line_buf == NULL)
|
|
{ /*
|
|
XP_FREE_BLOCK(state->line_array);
|
|
#ifdef XP_WIN16
|
|
XP_FREE_BLOCK(state->larray_array);
|
|
#endif
|
|
/*
|
|
XP_DELETE(state->font_stack);
|
|
*/
|
|
return(NULL);
|
|
}
|
|
state->line_buf_size = LINE_BUF_INC;
|
|
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->hide_content = FALSE;
|
|
|
|
state->old_break = NULL;
|
|
state->old_break_block = NULL;
|
|
state->old_break_pos = -1;
|
|
state->old_break_width = 0;
|
|
|
|
state->current_named_anchor = NULL;
|
|
state->current_anchor = NULL;
|
|
|
|
state->cur_ele_type = LO_NONE;
|
|
state->current_ele = NULL;
|
|
state->current_java = NULL;
|
|
|
|
state->current_table = NULL;
|
|
state->current_grid = NULL;
|
|
state->current_multicol = NULL;
|
|
|
|
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;
|
|
state->selection_layer = NULL;
|
|
|
|
state->in_relayout = FALSE;
|
|
state->tab_stop = DEF_TAB_WIDTH;
|
|
state->beginning_tag_count = top_state->tag_count;
|
|
return(state);
|
|
|
|
}
|
|
|
|
lo_RelayoutState * lo_rl_CreateRelayoutState( void )
|
|
{
|
|
lo_RelayoutState * relay_state = (lo_RelayoutState *) XP_ALLOC(sizeof(lo_RelayoutState));
|
|
return relay_state;
|
|
}
|
|
|
|
void lo_rl_DestroyRelayoutState( lo_RelayoutState *relay_state )
|
|
{
|
|
if (relay_state) {
|
|
XP_FREE(relay_state);
|
|
}
|
|
}
|
|
|
|
lo_RelayoutState *
|
|
lo_rl_InitRelayoutState( MWContext *context, lo_RelayoutState *blank_state, int32 newWidth, int32 newHeight, int32 margin_width, int32 margin_height )
|
|
{
|
|
lo_TopState *top_state;
|
|
lo_DocState *state;
|
|
|
|
if (!context || !blank_state) {
|
|
return NULL;
|
|
}
|
|
|
|
/* Initialize context */
|
|
blank_state->context = context;
|
|
|
|
/* Initialize top state */
|
|
top_state = lo_FetchTopState(XP_DOCID(context));
|
|
if (top_state == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
top_state->element_id = 0;
|
|
|
|
blank_state->top_state = top_state;
|
|
|
|
/* Initialize document state */
|
|
state = top_state->doc_state;
|
|
if (!lo_rl_InitDocState(context, state, newWidth, newHeight, margin_width, margin_height))
|
|
{
|
|
top_state->out_of_memory = TRUE;
|
|
return NULL;
|
|
}
|
|
blank_state->doc_state = state;
|
|
|
|
return blank_state;
|
|
}
|
|
|
|
|
|
static void lo_rl_PreLayoutElement ( MWContext *context, lo_DocState * state, LO_Element *lo_ele )
|
|
{
|
|
/*
|
|
* If we get a non-text tag, and we have some previous text
|
|
* elements we have been merging into state, flush those
|
|
* before processing the new tag.
|
|
*/
|
|
if ( lo_ele->type != LO_TEXTBLOCK )
|
|
{
|
|
lo_FlushLineBuffer(context, state);
|
|
if (state->top_state->out_of_memory)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void lo_rl_FitLayoutElements( lo_RelayoutState *relay_state, LO_Element *start_ele )
|
|
{
|
|
LO_Element *lo_ele = start_ele;
|
|
|
|
/* While not end of layout element list */
|
|
while (lo_ele != NULL) {
|
|
lo_rl_PreLayoutElement ( relay_state->context, relay_state->doc_state, lo_ele );
|
|
if (relay_state->doc_state->top_state->out_of_memory)
|
|
{
|
|
return;
|
|
}
|
|
|
|
/* Dispatch the layout element to its fitting routine.
|
|
Fitting routine returns the next layout element to process */
|
|
lo_ele = (*lo_rl_FitFunctionTable[lo_ele->type])(relay_state, lo_ele);
|
|
if (relay_state->doc_state->top_state->out_of_memory)
|
|
{
|
|
return;
|
|
}
|
|
|
|
} /* End While */
|
|
}
|
|
|
|
static LO_Element *
|
|
lo_rl_FitIgnore( lo_RelayoutState *relay_state, LO_Element *lo_ele )
|
|
{
|
|
XP_TRACE(("lo_rl_FitIgnore called...\n"));
|
|
return lo_tv_GetNextLayoutElement(relay_state->doc_state, lo_ele, FALSE);
|
|
}
|
|
|
|
static LO_Element *
|
|
lo_rl_FitError( lo_RelayoutState *relay_state, LO_Element *lo_ele )
|
|
{
|
|
XP_TRACE(("lo_rl_FitError called...\n"));
|
|
return lo_tv_GetNextLayoutElement(relay_state->doc_state, lo_ele, FALSE);
|
|
}
|
|
|
|
static LO_Element *
|
|
lo_rl_FitText( lo_RelayoutState *relay_state, LO_Element *lo_ele )
|
|
{
|
|
LO_Element *next = lo_tv_GetNextLayoutElement(relay_state->doc_state, lo_ele, FALSE);
|
|
lo_DocState *state = relay_state->doc_state;
|
|
|
|
if (lo_ele->lo_text.bullet_type == BULLET_NONE)
|
|
{
|
|
/* move this element to the correct position and add it to the line list */
|
|
lo_ele->lo_any.ele_id = NEXT_ELEMENT;
|
|
lo_ele->lo_any.x = state->x;
|
|
lo_ele->lo_any.y = state->y;
|
|
|
|
state->x += lo_ele->lo_text.width;
|
|
lo_AppendToLineList(relay_state->context, state, lo_ele, 0);
|
|
}
|
|
else if (lo_ele->lo_text.bullet_type == BULLET_MQUOTE)
|
|
{
|
|
/* Add to recycle list */
|
|
lo_ele->lo_any.prev = NULL;
|
|
lo_ele->lo_any.next = NULL;
|
|
lo_RecycleElements( relay_state->context, relay_state->top_state->doc_state, lo_ele );
|
|
}
|
|
else if (lo_ele->lo_text.bullet_type == WORDBREAK)
|
|
{
|
|
/* Do nothing. Just return the next layout element */
|
|
}
|
|
else /* it's some other form of bullet, most probably resulting from an ordered list. */
|
|
{
|
|
int32 line_height, baseline;
|
|
|
|
/* move this element to the correct position and add it to the line list */
|
|
lo_ele->lo_any.ele_id = NEXT_ELEMENT;
|
|
|
|
lo_FormatBulletStr(relay_state->context, state, (LO_TextStruct*)lo_ele, &line_height, &baseline);
|
|
|
|
lo_AppendToLineList(relay_state->context, state, lo_ele, 0);
|
|
|
|
lo_UpdateStateAfterBulletStr(relay_state->context, state,
|
|
(LO_TextStruct*)lo_ele, line_height, baseline);
|
|
}
|
|
|
|
return next;
|
|
}
|
|
|
|
static LO_Element *
|
|
lo_rl_FitLineFeed( lo_RelayoutState *relay_state, LO_Element *lo_ele )
|
|
{
|
|
LO_Element *next = lo_tv_GetNextLayoutElement( relay_state->doc_state, lo_ele, TRUE);
|
|
|
|
if (lo_ele->lo_linefeed.break_type == LO_LINEFEED_BREAK_SOFT) {
|
|
/* Add linefeed to recycle list */
|
|
lo_ele->lo_any.prev = NULL;
|
|
lo_ele->lo_any.next = NULL;
|
|
lo_RecycleElements( relay_state->context, relay_state->top_state->doc_state, lo_ele );
|
|
}
|
|
else if (lo_ele->lo_linefeed.break_type == LO_LINEFEED_BREAK_HARD) {
|
|
LO_LinefeedStruct *linefeed = (LO_LinefeedStruct*)lo_ele;
|
|
|
|
lo_rl_AppendLinefeedAndFlushLine(relay_state->context, relay_state->doc_state,
|
|
linefeed, linefeed->break_type, linefeed->clear_type, TRUE, FALSE);
|
|
|
|
|
|
switch(linefeed->clear_type)
|
|
{
|
|
case LO_CLEAR_TO_LEFT:
|
|
lo_ClearToLeftMargin(relay_state->context, relay_state->doc_state);
|
|
break;
|
|
case LO_CLEAR_TO_RIGHT:
|
|
lo_ClearToRightMargin(relay_state->context, relay_state->doc_state);
|
|
break;
|
|
case LO_CLEAR_TO_ALL:
|
|
case LO_CLEAR_TO_BOTH:
|
|
lo_ClearToBothMargins(relay_state->context, relay_state->doc_state);
|
|
break;
|
|
case LO_CLEAR_NONE:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Reset the margins properly in case
|
|
* we are inside a list.
|
|
*/
|
|
lo_FindLineMargins(relay_state->context, relay_state->doc_state, TRUE);
|
|
relay_state->doc_state->x = relay_state->doc_state->left_margin;
|
|
}
|
|
else if (lo_ele->lo_linefeed.break_type == LO_LINEFEED_BREAK_PARAGRAPH) {
|
|
LO_LinefeedStruct *linefeed = (LO_LinefeedStruct*)lo_ele;
|
|
|
|
lo_rl_AppendLinefeedAndFlushLine(relay_state->context, relay_state->doc_state,
|
|
linefeed, linefeed->break_type, linefeed->clear_type, TRUE, FALSE);
|
|
}
|
|
|
|
return next;
|
|
}
|
|
|
|
static LO_Element *
|
|
lo_rl_FitHRule( lo_RelayoutState *relay_state, LO_Element *lo_ele )
|
|
{
|
|
LO_Element *next = lo_tv_GetNextLayoutElement(relay_state->doc_state, lo_ele, FALSE);
|
|
|
|
/* need this or the hrule pops up to the previous line. */
|
|
lo_rl_AddSoftBreakAndFlushLine(relay_state->context, relay_state->doc_state);
|
|
|
|
lo_StartHorizontalRuleLayout(relay_state->context, relay_state->doc_state, (LO_HorizRuleStruct*)lo_ele);
|
|
|
|
lo_AppendToLineList(relay_state->context, relay_state->doc_state, lo_ele, 0);
|
|
|
|
lo_UpdateStateAfterHorizontalRule(relay_state->doc_state, (LO_HorizRuleStruct*)lo_ele);
|
|
|
|
lo_rl_AddSoftBreakAndFlushLine(relay_state->context, relay_state->doc_state);
|
|
|
|
lo_FinishHorizontalRuleLayout(relay_state->context, relay_state->doc_state, (LO_HorizRuleStruct*)lo_ele);
|
|
|
|
/* lo_DisplayHR(relay_state->context, (LO_HorizRuleStruct*)lo_ele); */
|
|
|
|
return next;
|
|
}
|
|
|
|
static LO_Element *
|
|
lo_rl_FitImage( lo_RelayoutState *relay_state, LO_Element *lo_ele )
|
|
{
|
|
int32 line_inc, baseline_inc;
|
|
LO_Element *next = lo_tv_GetNextLayoutElement(relay_state->doc_state, lo_ele, FALSE);
|
|
|
|
|
|
lo_FillInImageGeometry( relay_state->doc_state, (LO_ImageStruct *) lo_ele);
|
|
lo_LayoutInflowImage( relay_state->context, relay_state->doc_state, (LO_ImageStruct *) lo_ele, TRUE, &line_inc, &baseline_inc);
|
|
lo_AppendToLineList(relay_state->context, relay_state->doc_state, lo_ele, baseline_inc);
|
|
lo_UpdateStateAfterImageLayout( relay_state->doc_state, (LO_ImageStruct *)lo_ele, line_inc, baseline_inc );
|
|
|
|
return next;
|
|
}
|
|
|
|
static LO_Element *
|
|
lo_rl_FitBullet( lo_RelayoutState *relay_state, LO_Element *lo_ele )
|
|
{
|
|
|
|
LO_Element *next = lo_tv_GetNextLayoutElement(relay_state->doc_state, lo_ele, FALSE);
|
|
int32 line_height, baseline;
|
|
|
|
if (lo_ele->lo_bullet.bullet_type == BULLET_MQUOTE)
|
|
{
|
|
/* Add bullet to recycle list */
|
|
lo_ele->lo_any.prev = NULL;
|
|
lo_ele->lo_any.next = NULL;
|
|
lo_RecycleElements( relay_state->context, relay_state->top_state->doc_state, lo_ele );
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Artificially setting state to 2 here
|
|
* allows us to put headers on list items
|
|
* even if they aren't double spaced.
|
|
*/
|
|
relay_state->doc_state->linefeed_state = 2;
|
|
|
|
lo_FormatBullet(relay_state->context, relay_state->doc_state, (LO_BulletStruct*)lo_ele, &line_height, &baseline);
|
|
|
|
lo_AppendToLineList(relay_state->context, relay_state->doc_state, lo_ele, 0);
|
|
|
|
lo_UpdateStateAfterBullet(relay_state->context, relay_state->doc_state, (LO_BulletStruct*)lo_ele, line_height, baseline);
|
|
|
|
/* lo_DisplayBullet(relay_state->context, (LO_BulletStruct*)lo_ele); */
|
|
|
|
/* XP_ASSERT(0);*/
|
|
}
|
|
|
|
return next;
|
|
}
|
|
|
|
static LO_Element *
|
|
lo_rl_FitList( lo_RelayoutState *relay_state, LO_Element *lo_ele )
|
|
{
|
|
LO_Element *next = lo_tv_GetNextLayoutElement(relay_state->doc_state, lo_ele, FALSE);
|
|
LO_ListStruct *list = (LO_ListStruct*)lo_ele;
|
|
lo_DocState *state = relay_state->doc_state;
|
|
|
|
list->lo_any.ele_id = NEXT_ELEMENT;
|
|
list->lo_any.x = state->x;
|
|
list->lo_any.y = state->y;
|
|
|
|
lo_AppendToLineList(relay_state->context, relay_state->doc_state, lo_ele, 0);
|
|
|
|
if (list->is_end == FALSE)
|
|
lo_SetupStateForList(relay_state->context, relay_state->doc_state,
|
|
list, TRUE);
|
|
else
|
|
lo_UpdateStateAfterList(relay_state->context, relay_state->doc_state,
|
|
list, TRUE);
|
|
|
|
return next;
|
|
}
|
|
|
|
static LO_Element *
|
|
lo_rl_FitDescTitle( lo_RelayoutState *relay_state, LO_Element *lo_ele )
|
|
{
|
|
LO_Element *next = lo_tv_GetNextLayoutElement(relay_state->doc_state, lo_ele, FALSE);
|
|
LO_DescTitleStruct *title = (LO_DescTitleStruct*)lo_ele;
|
|
lo_DocState *state = relay_state->doc_state;
|
|
|
|
title->lo_any.ele_id = NEXT_ELEMENT;
|
|
title->lo_any.x = state->x;
|
|
title->lo_any.y = state->y;
|
|
|
|
lo_AppendToLineList(relay_state->context, relay_state->doc_state, lo_ele, 0);
|
|
|
|
lo_ProcessDescTitleElement(relay_state->context, relay_state->doc_state, title, TRUE);
|
|
|
|
return next;
|
|
}
|
|
|
|
static LO_Element *
|
|
lo_rl_FitDescText( lo_RelayoutState *relay_state, LO_Element *lo_ele )
|
|
{
|
|
LO_Element *next = lo_tv_GetNextLayoutElement(relay_state->doc_state, lo_ele, FALSE);
|
|
LO_DescTextStruct *text = (LO_DescTextStruct*)lo_ele;
|
|
lo_DocState *state = relay_state->doc_state;
|
|
|
|
text->lo_any.ele_id = NEXT_ELEMENT;
|
|
text->lo_any.x = state->x;
|
|
text->lo_any.y = state->y;
|
|
|
|
lo_AppendToLineList(relay_state->context, relay_state->doc_state, lo_ele, 0);
|
|
|
|
lo_ProcessDescTextElement(relay_state->context, relay_state->doc_state, text, TRUE);
|
|
|
|
return next;
|
|
}
|
|
|
|
static LO_Element *
|
|
lo_rl_FitBlockQuote( lo_RelayoutState *relay_state, LO_Element *lo_ele )
|
|
{
|
|
LO_Element *next = lo_tv_GetNextLayoutElement( relay_state->doc_state, lo_ele, TRUE);
|
|
lo_DocState *state = relay_state->doc_state;
|
|
|
|
lo_ele->lo_any.x = state->x;
|
|
lo_ele->lo_any.y = state->y;
|
|
lo_ele->lo_any.ele_id = NEXT_ELEMENT;
|
|
|
|
lo_AppendToLineList(relay_state->context, relay_state->doc_state, lo_ele, 0);
|
|
lo_ProcessBlockQuoteElement(relay_state->context,
|
|
relay_state->doc_state,
|
|
(LO_BlockQuoteStruct*)lo_ele,
|
|
TRUE);
|
|
|
|
return next;
|
|
}
|
|
|
|
static LO_Element *
|
|
lo_rl_FitFormEle( lo_RelayoutState *relay_state, LO_Element *lo_ele )
|
|
{
|
|
LO_Element *next = lo_tv_GetNextLayoutElement(relay_state->doc_state, lo_ele, FALSE);
|
|
LO_FormElementStruct *form = (LO_FormElementStruct*)lo_ele;
|
|
int32 baseline_inc = 0;
|
|
|
|
lo_LayoutInflowFormElement(relay_state->context, relay_state->doc_state, form, &baseline_inc, TRUE);
|
|
|
|
lo_AppendToLineList(relay_state->context, relay_state->doc_state, lo_ele, baseline_inc);
|
|
|
|
lo_UpdateStateAfterFormElement(relay_state->context, relay_state->doc_state, form, baseline_inc);
|
|
|
|
CL_MoveLayer(form->layer,
|
|
form->x + form->x_offset + form->border_horiz_space,
|
|
form->y + form->y_offset + form->border_vert_space);
|
|
|
|
return next;
|
|
}
|
|
|
|
/* Only called during relayout. Sets up current height span struct. */
|
|
static void lo_UpdateHeightSpanForBeginRow(lo_TableRec *table)
|
|
{
|
|
lo_table_span *span_rec;
|
|
|
|
/* Point to current height span struct. */
|
|
if (table->height_span_ptr == NULL)
|
|
{
|
|
table->height_span_ptr = table->height_spans;
|
|
}
|
|
else
|
|
{
|
|
table->height_span_ptr = table->height_span_ptr->next;
|
|
}
|
|
|
|
/* Init. current height span struct */
|
|
span_rec = table->height_span_ptr;
|
|
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;
|
|
}
|
|
|
|
|
|
static LO_Element *
|
|
lo_rl_FitTable( lo_RelayoutState *relay_state, LO_Element *lo_ele )
|
|
{
|
|
int32 cols, i;
|
|
lo_TableRec *table = (lo_TableRec *) lo_ele->lo_table.table;
|
|
MWContext *context = relay_state->context;
|
|
lo_DocState *state = relay_state->doc_state;
|
|
LO_Element *next = lo_tv_GetNextLayoutElement(relay_state->doc_state, lo_ele, TRUE);
|
|
|
|
XP_ASSERT(table != NULL);
|
|
|
|
if (table == NULL)
|
|
return next;
|
|
|
|
#ifndef FAST_TABLES
|
|
/* Skip over top aligned caption element */
|
|
if ((table->caption != NULL) &&
|
|
(table->caption->vert_alignment == LO_ALIGN_TOP))
|
|
{
|
|
next = lo_tv_GetNextLayoutElement(state, next, TRUE);
|
|
}
|
|
|
|
/* Call common functions that set up document state and table state
|
|
for a new table. All these functions are called from lo_BeginTableAttributes()
|
|
also. */
|
|
lo_rl_BeginTableRelayout(context, state, table );
|
|
|
|
/* Reset row ptr to first row */
|
|
table->row_ptr = table->row_list;
|
|
|
|
/* Fit each row */
|
|
do {
|
|
cols = table->row_ptr->cells_in_row;
|
|
lo_UpdateTableStateForBeginRow( table, table->row_ptr );
|
|
lo_UpdateHeightSpanForBeginRow( table );
|
|
/* Fit each cell in the row */
|
|
for (i = 0; i < cols; i++)
|
|
{
|
|
next = lo_rl_FitCell(relay_state, next);
|
|
}
|
|
lo_EndTableRow(context, state, table);
|
|
table->row_ptr = table->row_ptr->next;
|
|
} while (table->row_ptr != NULL);
|
|
|
|
/* Skip over bottom aligned caption element */
|
|
if ((table->caption != NULL) &&
|
|
(table->caption->vert_alignment != LO_ALIGN_TOP))
|
|
{
|
|
next = lo_tv_GetNextLayoutElement(state, next, TRUE);
|
|
}
|
|
|
|
lo_EndTable(context, state, table, TRUE);
|
|
|
|
|
|
#else
|
|
lo_rl_ReHookupCellStructs(table);
|
|
lo_EndTable(context, state, table, TRUE);
|
|
#endif /* FAST_TABLES */
|
|
|
|
return next;
|
|
}
|
|
|
|
static void lo_rl_ReHookupCellStructs(lo_TableRec *table)
|
|
{
|
|
|
|
}
|
|
|
|
static void lo_rl_BeginTableRelayout( MWContext *context, lo_DocState *state, lo_TableRec *table)
|
|
{
|
|
lo_PositionTableElement( state, table->table_ele );
|
|
lo_InitTableRecord( table );
|
|
lo_SetTableDimensions( state, table, state->allow_percent_width, state->allow_percent_height );
|
|
lo_CalcFixedColWidths( context, state, table );
|
|
lo_UpdateStateAfterBeginTable( state, table );
|
|
}
|
|
|
|
static void lo_rl_CopyCellToState( LO_CellStruct *cell, lo_DocState *state )
|
|
{
|
|
LO_Element ** line_array;
|
|
|
|
PA_LOCK(line_array, LO_Element **, state->line_array );
|
|
line_array[0] = cell->cell_list;
|
|
state->float_list = cell->cell_float_list;
|
|
}
|
|
|
|
static void lo_rl_CopyStateToCell( lo_DocState *state, LO_CellStruct *cell)
|
|
{
|
|
LO_Element ** line_array;
|
|
|
|
PA_LOCK(line_array, LO_Element **, state->line_array );
|
|
|
|
cell->cell_list = (LO_Element *) line_array[0];
|
|
/* cell->cell_list_end = state->end_last_line; */
|
|
cell->cell_float_list = state->float_list;
|
|
}
|
|
|
|
LO_Element * lo_rl_FitCell( lo_RelayoutState *relay_state, LO_Element *lo_ele )
|
|
{
|
|
LO_CellStruct *cell = (LO_CellStruct *)lo_ele;
|
|
lo_TableRec *table = (lo_TableRec *) cell->table;
|
|
MWContext *context = relay_state->context;
|
|
lo_DocState *state = relay_state->doc_state;
|
|
LO_Element *first;
|
|
LO_Element *next = lo_tv_GetNextLayoutElement(relay_state->doc_state, lo_ele, TRUE);
|
|
|
|
XP_ASSERT( lo_ele->lo_any.type == LO_CELL );
|
|
|
|
lo_InitForBeginCell((lo_TableRow *)cell->table_row, (lo_TableCell *)cell->table_cell);
|
|
lo_InitSubDocForBeginCell(context, state, table );
|
|
|
|
/* Copy over line lists, float lists to substate */
|
|
lo_rl_CopyCellToState( cell, state->sub_state );
|
|
|
|
/* Replace current doc. state with substate */
|
|
relay_state->doc_state = state->sub_state;
|
|
|
|
/* Fit layout elements on substate */
|
|
first = lo_tv_GetFirstLayoutElement(relay_state->doc_state);
|
|
lo_rl_FitLayoutElements(relay_state, first);
|
|
|
|
/* Dummy Floating elements on a new line at the end of a document were not getting put into
|
|
the line_array. This code should ensure that anything left on the line_list gets flushed
|
|
to the line_array. */
|
|
if (relay_state->doc_state->line_list != NULL)
|
|
lo_AppendLineListToLineArray( relay_state->context, relay_state->doc_state, lo_GetLastElementInList(relay_state->doc_state->line_list) );
|
|
|
|
/* Restore relay state to original state */
|
|
lo_rl_CopyStateToCell( relay_state->doc_state, cell );
|
|
relay_state->doc_state = state;
|
|
|
|
lo_EndTableCell( context, state->sub_state, TRUE );
|
|
|
|
return next;
|
|
}
|
|
|
|
static LO_Element *
|
|
lo_rl_FitEmbed( lo_RelayoutState *relay_state, LO_Element *lo_ele )
|
|
{
|
|
int32 line_inc, baseline_inc;
|
|
LO_Element *next = lo_tv_GetNextLayoutElement(relay_state->doc_state, lo_ele, FALSE);
|
|
LO_EmbedStruct *embed = (LO_EmbedStruct*)lo_ele;
|
|
|
|
lo_FillInEmbedGeometry(relay_state->doc_state, embed, TRUE);
|
|
lo_LayoutInflowEmbed(relay_state->context, relay_state->doc_state, embed, TRUE, &line_inc, &baseline_inc);
|
|
lo_AppendToLineList(relay_state->context, relay_state->doc_state, lo_ele, baseline_inc);
|
|
lo_UpdateStateAfterEmbedLayout(relay_state->doc_state, embed, line_inc, baseline_inc);
|
|
|
|
return next;
|
|
}
|
|
|
|
static LO_Element *
|
|
lo_rl_FitBuiltin( lo_RelayoutState *relay_state, LO_Element *lo_ele )
|
|
{
|
|
int32 line_inc, baseline_inc;
|
|
LO_Element *next = lo_tv_GetNextLayoutElement(relay_state->doc_state, lo_ele, FALSE);
|
|
LO_BuiltinStruct *builtin = (LO_BuiltinStruct*)lo_ele;
|
|
|
|
lo_FillInBuiltinGeometry(relay_state->doc_state, builtin, TRUE);
|
|
lo_LayoutInflowBuiltin(relay_state->context, relay_state->doc_state, builtin, TRUE, &line_inc, &baseline_inc);
|
|
lo_AppendToLineList(relay_state->context, relay_state->doc_state, lo_ele, baseline_inc);
|
|
lo_UpdateStateAfterBuiltinLayout(relay_state->doc_state, builtin, line_inc, baseline_inc);
|
|
|
|
return next;
|
|
}
|
|
|
|
static LO_Element *
|
|
lo_rl_FitJava( lo_RelayoutState *relay_state, LO_Element *lo_ele )
|
|
{
|
|
LO_Element *next = lo_tv_GetNextLayoutElement(relay_state->doc_state, lo_ele, FALSE);
|
|
#ifdef JAVA
|
|
LO_JavaAppStruct *java_app = (LO_JavaAppStruct*)lo_ele;
|
|
|
|
int32 line_inc, baseline_inc;
|
|
|
|
lo_FillInJavaAppGeometry( relay_state->doc_state, java_app, TRUE);
|
|
lo_LayoutInflowJavaApp( relay_state->context, relay_state->doc_state, java_app, TRUE, &line_inc, &baseline_inc);
|
|
lo_AppendToLineList(relay_state->context, relay_state->doc_state, lo_ele, baseline_inc);
|
|
lo_UpdateStateAfterJavaAppLayout( relay_state->doc_state, java_app, line_inc, baseline_inc );
|
|
|
|
CL_MoveLayer(java_app->objTag.layer,
|
|
java_app->objTag.x + java_app->objTag.x_offset + java_app->objTag.border_horiz_space,
|
|
java_app->objTag.y + java_app->objTag.y_offset + java_app->objTag.border_vert_space);
|
|
#endif
|
|
|
|
return next;
|
|
}
|
|
|
|
static LO_Element *
|
|
lo_rl_FitObject( lo_RelayoutState *relay_state, LO_Element *lo_ele )
|
|
{
|
|
XP_ASSERT(0);
|
|
return lo_tv_GetNextLayoutElement(relay_state->doc_state, lo_ele, FALSE);
|
|
}
|
|
|
|
static LO_Element *
|
|
lo_rl_FitParagraph( lo_RelayoutState *relay_state, LO_Element *lo_ele )
|
|
{
|
|
LO_Element *next = lo_tv_GetNextLayoutElement( relay_state->doc_state, lo_ele, TRUE);
|
|
lo_DocState *state = relay_state->doc_state;
|
|
|
|
lo_ele->lo_any.x = state->x;
|
|
lo_ele->lo_any.y = state->y;
|
|
lo_ele->lo_any.ele_id = NEXT_ELEMENT;
|
|
|
|
lo_AppendToLineList(relay_state->context, relay_state->doc_state, lo_ele, 0);
|
|
lo_ProcessParagraphElement(relay_state->context,
|
|
&relay_state->doc_state,
|
|
(LO_ParagraphStruct*)lo_ele, TRUE);
|
|
return next;
|
|
}
|
|
|
|
static LO_Element *
|
|
lo_rl_FitCenter( lo_RelayoutState *relay_state, LO_Element *lo_ele )
|
|
{
|
|
LO_Element *next = lo_tv_GetNextLayoutElement( relay_state->doc_state, lo_ele, TRUE);
|
|
lo_DocState *state = relay_state->doc_state;
|
|
|
|
lo_ele->lo_any.x = state->x;
|
|
lo_ele->lo_any.y = state->y;
|
|
lo_ele->lo_any.ele_id = NEXT_ELEMENT;
|
|
|
|
lo_AppendToLineList(relay_state->context, relay_state->doc_state, lo_ele, 0);
|
|
lo_ProcessCenterElement(relay_state->context,
|
|
&relay_state->doc_state,
|
|
(LO_CenterStruct*)lo_ele,
|
|
TRUE);
|
|
|
|
return next;
|
|
}
|
|
|
|
static LO_Element *
|
|
lo_rl_FitMulticolumn( lo_RelayoutState *relay_state, LO_Element *lo_ele )
|
|
{
|
|
lo_DocState *state = relay_state->doc_state;
|
|
MWContext *context = relay_state->context;
|
|
LO_MulticolumnStruct *multicolElement = (LO_MulticolumnStruct *) lo_ele;
|
|
LO_Element *next = lo_tv_GetNextLayoutElement( state, lo_ele, TRUE );
|
|
|
|
if (multicolElement->is_end == FALSE )
|
|
{
|
|
int32 doc_width;
|
|
|
|
lo_AppendMultiColToLineList(context, state, multicolElement);
|
|
|
|
/* if (line will not be flushed by lo_SetSoftLineBreak) and (there exist some elements on the line list) */
|
|
if (state->linefeed_state >= 2 && state->line_list != NULL)
|
|
{
|
|
/* Append zero width and height line feed to the line list and flush the line list into
|
|
the line array. This forces the layout of elements contained within the MULTICOL tags
|
|
to start on a blank line_list and hence on a new line. lo_EndMultiColumn needs this to
|
|
do its line array hacking properly. */
|
|
lo_AppendZeroWidthAndHeightLF(context, state);
|
|
}
|
|
|
|
lo_SetLineBreakState(context, state, FALSE, LO_LINEFEED_BREAK_SOFT, 2, TRUE);
|
|
if (multicolElement->multicol != NULL)
|
|
{
|
|
LO_LinefeedStruct *linefeedAfterTable = NULL;
|
|
LO_LinefeedStruct *linefeedBeforeTable = NULL;
|
|
LO_Element *lastElementInLastCell;
|
|
LO_CellStruct *lastCellElement;
|
|
|
|
/* Call functions to set up doc state and the multicol structure state that
|
|
get called during initial layout also. */
|
|
lo_StartMultiColInit( state, multicolElement->multicol ) ;
|
|
doc_width = state->right_margin - state->left_margin;
|
|
lo_SetupStateForBeginMulticol( state, multicolElement->multicol, doc_width );
|
|
|
|
/* Traverse all cells in the line list and concatenate their line lists and
|
|
float lists. Return the first element of the first cell's line list to be
|
|
fitted by the lo_rl_FitLayoutElements() loop */
|
|
XP_ASSERT(next->lo_any.type == LO_LINEFEED);
|
|
linefeedBeforeTable = (LO_LinefeedStruct *) next;
|
|
next = next->lo_any.next;
|
|
|
|
XP_ASSERT(next->lo_any.type == LO_TABLE);
|
|
if (next->lo_any.type == LO_TABLE)
|
|
linefeedAfterTable = (LO_LinefeedStruct *) lo_rl_RecreateElementListsFromCells(state, (LO_TableStruct *) next,
|
|
&lastElementInLastCell);
|
|
|
|
/* Trash all the LO_TABLE and LO_CELL elements that were created to hold MULTICOL contents
|
|
for the earlier window size. */
|
|
lastCellElement = (struct LO_CellStruct_struct*) linefeedAfterTable->prev;
|
|
lastCellElement->next = NULL;
|
|
next->lo_any.prev = NULL;
|
|
lo_RecycleElements( context, state, next );
|
|
|
|
|
|
/* Insert the state->linelist constructed above in between the linefeeds before and after
|
|
the table. */
|
|
if (state->line_list) {
|
|
linefeedBeforeTable->next = state->line_list;
|
|
state->line_list->lo_any.prev = (LO_Element *) linefeedBeforeTable;
|
|
lastElementInLastCell->lo_any.next = (LO_Element *) linefeedAfterTable;
|
|
linefeedAfterTable->prev = lastElementInLastCell;
|
|
}
|
|
else {
|
|
/* This means that the MULTICOL tag did not contain anything. So we just
|
|
hook up the linefeeds before and after the table element. */
|
|
linefeedBeforeTable->next = (LO_Element *) linefeedAfterTable;
|
|
linefeedAfterTable->prev = (LO_Element *) linefeedBeforeTable;
|
|
}
|
|
|
|
/* Set the next layout element to be fitted to the linefeed before the table. This
|
|
will fit all the elements that were on the cells of the table */
|
|
next = (LO_Element *) linefeedBeforeTable;
|
|
|
|
/* The linelist should be NULL because we the LO_Elements
|
|
within the multicol tag get laid out on a new line in the line_array */
|
|
state->line_list = NULL;
|
|
}
|
|
}
|
|
else if ( multicolElement->is_end == TRUE )
|
|
{
|
|
if (state->current_multicol != NULL)
|
|
{
|
|
lo_EndMulticolumn(context, state, multicolElement->tag,
|
|
state->current_multicol, TRUE);
|
|
|
|
}
|
|
lo_AppendMultiColToLineList(context, state, multicolElement);
|
|
}
|
|
|
|
return next;
|
|
}
|
|
|
|
static LO_LinefeedStruct * lo_rl_RecreateElementListsFromCells( lo_DocState *state, LO_TableStruct *table,
|
|
LO_Element **lastElementInLastCell)
|
|
{
|
|
LO_Element *lineList = state->line_list;
|
|
LO_Element *floatList = state->float_list;
|
|
LO_Element *ele;
|
|
|
|
/* Point to the first cell element */
|
|
ele = table->next;
|
|
|
|
/* Go to last element on line list and float list */
|
|
lineList = lo_GetLastElementInList(lineList);
|
|
floatList = lo_GetLastElementInList(floatList);
|
|
|
|
/* For all cell elements, keep appending the cell line lists and float lists to the doc state's
|
|
line lists and float lists. Keeps resetting each LO_CELL's line list and float list
|
|
pointers to NULL. */
|
|
for ( ; ele->lo_any.type == LO_CELL; ele = ele->lo_any.next )
|
|
{
|
|
/* Preconditions: 1) lineList points to the element to which the cell list has to be appended,
|
|
2) floatList points to the element to which the cell float list has to be appended */
|
|
if (lineList == NULL)
|
|
{
|
|
lineList = ele->lo_cell.cell_list;
|
|
state->line_list = lineList;
|
|
}
|
|
else
|
|
lineList->lo_any.next = ele->lo_cell.cell_list;
|
|
|
|
ele->lo_cell.cell_list = NULL;
|
|
|
|
if (floatList == NULL)
|
|
{
|
|
floatList = ele->lo_cell.cell_float_list;
|
|
state->float_list = floatList;
|
|
}
|
|
else
|
|
floatList->lo_any.next = ele->lo_cell.cell_float_list;
|
|
|
|
ele->lo_cell.cell_float_list = NULL;
|
|
|
|
/* Go to last element on line list and float list */
|
|
lineList = lo_GetLastElementInList(lineList);
|
|
floatList = lo_GetLastElementInList(floatList);
|
|
}
|
|
|
|
*lastElementInLastCell = lineList;
|
|
|
|
/* ele is the first element after the last cell in the table and should be a linefeed*/
|
|
XP_ASSERT(ele->lo_any.type == LO_LINEFEED);
|
|
return (LO_LinefeedStruct *) ele;
|
|
}
|
|
|
|
|
|
static LO_Element *
|
|
lo_rl_FitFloat( lo_RelayoutState *relay_state, LO_Element *lo_ele )
|
|
{
|
|
LO_Element *next = lo_tv_GetNextLayoutElement( relay_state->doc_state, lo_ele, TRUE);
|
|
int32 x=0, y=0;
|
|
CL_Layer *layer = NULL;
|
|
|
|
if (lo_ele->lo_float.float_ele->lo_any.type == LO_IMAGE) {
|
|
LO_ImageStruct *image = (LO_ImageStruct *)lo_ele->lo_float.float_ele;
|
|
|
|
lo_LayoutFloatImage( relay_state->context, relay_state->doc_state, image, FALSE );
|
|
|
|
/* Determine the new position of the layer. */
|
|
x = image->x + image->x_offset + image->border_width;
|
|
y = image->y + image->y_offset + image->border_width;
|
|
|
|
layer = image->layer;
|
|
}
|
|
#ifdef JAVA
|
|
else if (lo_ele->lo_float.float_ele->lo_any.type == LO_JAVA) {
|
|
LO_JavaAppStruct *java_app = (LO_JavaAppStruct *)lo_ele->lo_float.float_ele;
|
|
|
|
lo_LayoutFloatJavaApp( relay_state->context, relay_state->doc_state, java_app, FALSE );
|
|
|
|
/* Determine the new position of the layer. */
|
|
x = java_app->objTag.x + java_app->objTag.x_offset + java_app->objTag.border_width;
|
|
y = java_app->objTag.y + java_app->objTag.y_offset + java_app->objTag.border_width;
|
|
|
|
layer = java_app->objTag.layer;
|
|
}
|
|
#endif
|
|
else if (lo_ele->lo_float.float_ele->lo_any.type == LO_EMBED) {
|
|
LO_EmbedStruct *embed = (LO_EmbedStruct *)lo_ele->lo_float.float_ele;
|
|
|
|
lo_LayoutFloatEmbed( relay_state->context, relay_state->doc_state, embed, FALSE );
|
|
|
|
/* Determine the new position of the layer. */
|
|
x = embed->objTag.x + embed->objTag.x_offset + embed->objTag.border_width;
|
|
y = embed->objTag.y + embed->objTag.y_offset + embed->objTag.border_width;
|
|
|
|
layer = embed->objTag.layer;
|
|
}
|
|
else if (lo_ele->lo_float.float_ele->lo_any.type == LO_BUILTIN) {
|
|
LO_BuiltinStruct *builtin = (LO_BuiltinStruct *)lo_ele->lo_float.float_ele;
|
|
|
|
lo_LayoutFloatEmbed( relay_state->context, relay_state->doc_state,
|
|
(LO_EmbedStruct *)builtin, FALSE );
|
|
|
|
/* Determine the new position of the layer. */
|
|
x = builtin->x + builtin->x_offset + builtin->border_width;
|
|
y = builtin->y + builtin->y_offset + builtin->border_width;
|
|
|
|
layer = builtin->layer;
|
|
}
|
|
else if (lo_ele->lo_float.float_ele->lo_any.type == LO_TABLE) {
|
|
LO_TableStruct *table_ele = (LO_TableStruct *)lo_ele->lo_float.float_ele;
|
|
lo_DocState *state = relay_state->doc_state;
|
|
LO_Element *save_float_list = state->float_list;
|
|
LO_Element *save_line_list = state->line_list;
|
|
LO_Element *save_elements_after_table = NULL;
|
|
LO_Element *ele = NULL;
|
|
|
|
/* We want to layout the table that is in the float list on the doc state in
|
|
relay_state. So we need to save the float list and non-TABLE and non-CELL
|
|
layout elements on the float list. Then we layout the floating table on
|
|
the doc state. Then we restore the float list. */
|
|
|
|
/* Table elements are followed by CELL elements. The end of the table occurs
|
|
at the first element that is not a CELL. So step through the element list until
|
|
the first non-CELL is encountered */
|
|
LO_Element *prev_ele = (LO_Element *) table_ele;
|
|
for ( ele = table_ele->next; ele->lo_any.type == LO_CELL; ele = ele->lo_any.next )
|
|
{
|
|
prev_ele = ele;
|
|
if (ele->lo_any.next == NULL)
|
|
{
|
|
ele = NULL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ele != NULL)
|
|
{
|
|
/* Temporarily NULL out the last CELL's next pointer. */
|
|
save_elements_after_table = ele;
|
|
prev_ele->lo_any.next = NULL;
|
|
}
|
|
state->float_list = NULL;
|
|
state->line_list = NULL;
|
|
|
|
/* Layout the table onto relay_state->doc_state */
|
|
lo_rl_FitTable( relay_state, (LO_Element *)table_ele );
|
|
|
|
/* Restore line list, float list */
|
|
state->line_list = save_line_list;
|
|
state->float_list = save_float_list;
|
|
if (save_elements_after_table != NULL)
|
|
{
|
|
prev_ele->lo_any.next = save_elements_after_table;
|
|
}
|
|
}
|
|
|
|
/* Reset dummy float element's position and element id before inserting back into the line list */
|
|
lo_ele->lo_any.x = relay_state->doc_state->x;
|
|
lo_ele->lo_any.y = relay_state->doc_state->y;
|
|
lo_ele->lo_any.ele_id = relay_state->top_state->element_id++;
|
|
|
|
lo_AppendToLineList(relay_state->context, relay_state->doc_state, lo_ele, 0);
|
|
|
|
/* Move layer to new position */
|
|
if (layer != NULL)
|
|
{
|
|
CL_MoveLayer(layer, x, y);
|
|
}
|
|
|
|
return next;
|
|
}
|
|
|
|
static LO_Element *
|
|
lo_rl_FitTextBlock( lo_RelayoutState *relay_state, LO_Element *lo_ele )
|
|
{
|
|
LO_Element * next;
|
|
|
|
next = lo_RelayoutTextBlock ( relay_state->context, relay_state->doc_state, &lo_ele->lo_textBlock, NULL );
|
|
return next;
|
|
}
|
|
|
|
static void
|
|
lo_rl_SetLayerDimensions( lo_RelayoutState *relay_state, LO_BlockInitializeStruct *layerParams )
|
|
{
|
|
XP_ASSERT(layerParams != NULL);
|
|
if (layerParams)
|
|
{
|
|
if (layerParams->percent_width > 0)
|
|
{
|
|
int32 parent_width = lo_GetEnclosingLayerWidth(relay_state->doc_state);
|
|
layerParams->width = (parent_width * layerParams->percent_width) / 100;
|
|
}
|
|
|
|
if (layerParams->percent_height > 0)
|
|
{
|
|
int32 parent_height = lo_GetEnclosingLayerHeight(relay_state->doc_state);
|
|
layerParams->height = (parent_height * layerParams->percent_height) / 100;
|
|
}
|
|
}
|
|
}
|
|
|
|
static LO_Element *
|
|
lo_rl_FitLayer( lo_RelayoutState *relay_state, LO_Element *lo_ele )
|
|
{
|
|
LO_LayerStruct *layerEle = (LO_LayerStruct *)lo_ele;
|
|
LO_Element *next = lo_tv_GetNextLayoutElement( relay_state->doc_state, lo_ele, TRUE );
|
|
|
|
if(layerEle && layerEle->is_end == FALSE)
|
|
{
|
|
LO_LayerStruct *endLayer = NULL;
|
|
LO_Element *lastFloat = NULL;
|
|
LO_CellStruct *cell = NULL;
|
|
|
|
lo_AppendToLineList( relay_state->context, relay_state->doc_state, lo_ele, 0 );
|
|
lo_rl_SetLayerDimensions( relay_state, layerEle->initParams );
|
|
lo_BeginLayerReflow( relay_state->context, relay_state->doc_state, layerEle->initParams,
|
|
layerEle->layerDoc );
|
|
|
|
if (next->lo_any.type == LO_CELL)
|
|
{
|
|
/* We are reflowing an ILAYER */
|
|
cell = (LO_CellStruct *) next;
|
|
|
|
/* Set "next" to the layout element following the LO_CELL */
|
|
next = lo_tv_GetNextLayoutElement( relay_state->doc_state, next, TRUE);
|
|
|
|
/* Set the cell's next pointer to null. We've got to fool the end layer
|
|
code into thinking that this cell is the last element on the line list. */
|
|
cell->next = NULL;
|
|
}
|
|
else
|
|
{
|
|
/* We are reflowing a LAYER. So, we get the cell from the lo_LayerDocState structure */
|
|
lo_LayerDocState *layerDoc = (lo_LayerDocState *) layerEle->layerDoc;
|
|
cell = layerDoc->cell;
|
|
}
|
|
|
|
/* Assert that next is a dummy layout element marking the end of the layer */
|
|
XP_ASSERT(next->lo_any.type == LO_LAYER && next->lo_layer.is_end == TRUE);
|
|
endLayer = (LO_LayerStruct *) next;
|
|
|
|
next = cell->cell_list;
|
|
if (next)
|
|
{
|
|
/* The next layout element to be fitted is the first element on the cell list.
|
|
Once the cell list has been fitted we want to end the layer, so we append
|
|
the end layer element to the cell list. */
|
|
XP_ASSERT(cell->cell_list_end && cell->cell_list_end->lo_any.next == NULL);
|
|
cell->cell_list_end->lo_any.next = (LO_Element*) endLayer;
|
|
|
|
/* We also need to append the cell's float list to the state's float list */
|
|
lastFloat = lo_GetLastElementInList(relay_state->doc_state->float_list);
|
|
if (lastFloat)
|
|
lastFloat->lo_any.next = cell->cell_float_list;
|
|
}
|
|
else
|
|
{
|
|
/* There is nothing on the cell's line list to reflow. So, the float list should
|
|
also be null. The next element to be fitted is set to the end layer element. */
|
|
XP_ASSERT(cell->cell_float_list == NULL);
|
|
next = (LO_Element *) endLayer;
|
|
}
|
|
|
|
/* Since the elements inside the layer are going to be reflowed while state->layer_nest_level
|
|
is greater than zero, lo_FlushLineList() will append the layout elements onto the cell's
|
|
line list. So, the cell's line list and float lists need to be initialized to null. */
|
|
if (cell)
|
|
{
|
|
cell->cell_list = NULL;
|
|
cell->cell_float_list = NULL;
|
|
cell->cell_list_end = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lo_EndLayerReflow( relay_state->context, relay_state->doc_state );
|
|
lo_AppendToLineList( relay_state->context, relay_state->doc_state, lo_ele, 0 );
|
|
}
|
|
|
|
return next;
|
|
}
|
|
|
|
|
|
static LO_Element *
|
|
lo_rl_FitHeading( lo_RelayoutState *relay_state, LO_Element *lo_ele )
|
|
{
|
|
LO_Element *next = lo_tv_GetNextLayoutElement( relay_state->doc_state, lo_ele, TRUE);
|
|
LO_HeadingStruct *header = (LO_HeadingStruct*)lo_ele;
|
|
lo_DocState *state = relay_state->doc_state;
|
|
MWContext *context = relay_state->context;
|
|
|
|
/* Put the LO_HEADING element back on the line list */
|
|
header->lo_any.x = state->x;
|
|
header->lo_any.y = state->y;
|
|
header->lo_any.ele_id = NEXT_ELEMENT;
|
|
lo_AppendToLineList(context, state, lo_ele, 0);
|
|
|
|
lo_ProcessHeader(context, state, header, TRUE);
|
|
return next;
|
|
}
|
|
|
|
static LO_Element *
|
|
lo_rl_FitSpacer( lo_RelayoutState *relay_state, LO_Element *lo_ele )
|
|
{
|
|
LO_Element *next = lo_tv_GetNextLayoutElement( relay_state->doc_state, lo_ele, TRUE);
|
|
LO_SpacerStruct *spacer = (LO_SpacerStruct *) lo_ele;
|
|
lo_DocState *state = relay_state->doc_state;
|
|
MWContext *context = relay_state->context;
|
|
|
|
/* Put the LO_SPACER element back on the line list */
|
|
spacer->lo_any.x = state->x;
|
|
spacer->lo_any.y = state->y;
|
|
spacer->lo_any.ele_id = state->top_state->element_id++;
|
|
lo_AppendToLineList(context, state, lo_ele, 0);
|
|
|
|
/* Relayout the SPACER element */
|
|
lo_LayoutSpacerElement(context, state, spacer, TRUE);
|
|
|
|
return next;
|
|
}
|
|
|
|
static LO_Element * lo_rl_FitSuper( lo_RelayoutState *relay_state, LO_Element *lo_ele )
|
|
{
|
|
LO_Element *next = lo_tv_GetNextLayoutElement( relay_state->doc_state, lo_ele, TRUE);
|
|
LO_SuperStruct *super = (LO_SuperStruct *) lo_ele;
|
|
lo_DocState *state = relay_state->doc_state;
|
|
MWContext *context = relay_state->context;
|
|
|
|
/* Put the LO_SUPER element back on the line list */
|
|
super->lo_any.x = state->x;
|
|
super->lo_any.y = state->y;
|
|
super->lo_any.ele_id = state->top_state->element_id++;
|
|
lo_AppendToLineList(context, state, lo_ele, 0);
|
|
|
|
/* Relayout the SUPER element */
|
|
lo_ProcessSuperElement(context, state, super);
|
|
|
|
return next;
|
|
}
|
|
|
|
static LO_Element * lo_rl_FitSub( lo_RelayoutState *relay_state, LO_Element *lo_ele )
|
|
{
|
|
LO_Element *next = lo_tv_GetNextLayoutElement( relay_state->doc_state, lo_ele, TRUE);
|
|
LO_SubStruct *sub = (LO_SubStruct *) lo_ele;
|
|
lo_DocState *state = relay_state->doc_state;
|
|
MWContext *context = relay_state->context;
|
|
|
|
/* Put the LO_SUB element back on the line list */
|
|
sub->lo_any.x = state->x;
|
|
sub->lo_any.y = state->y;
|
|
sub->lo_any.ele_id = state->top_state->element_id++;
|
|
lo_AppendToLineList(context, state, lo_ele, 0);
|
|
|
|
/* Relayout the SUB element */
|
|
lo_ProcessSubElement(context, state, sub);
|
|
|
|
return next;
|
|
}
|
|
|
|
static LO_Element * lo_rl_FitSpan( lo_RelayoutState *relay_state, LO_Element *lo_ele )
|
|
{
|
|
XP_ASSERT(0);
|
|
return lo_tv_GetNextLayoutElement( relay_state->doc_state, lo_ele, TRUE);
|
|
}
|
|
|
|
static LO_Element * lo_rl_FitDiv( lo_RelayoutState *relay_state, LO_Element *lo_ele )
|
|
{
|
|
XP_ASSERT(0);
|
|
return lo_tv_GetNextLayoutElement( relay_state->doc_state, lo_ele, TRUE);
|
|
}
|
|
|
|
/*
|
|
* Adds a soft line break to the end of the line list and adds the line list to the line array. Resets line list to NULL.
|
|
* Should be used during relayout only. It is the relayout version of lo_SetSoftLineBreak().
|
|
*/
|
|
void lo_rl_AddSoftBreakAndFlushLine( MWContext *context, lo_DocState *state )
|
|
{
|
|
lo_rl_AddBreakAndFlushLine( context, state, LO_LINEFEED_BREAK_SOFT, LO_CLEAR_NONE, TRUE);
|
|
}
|
|
|
|
|
|
void lo_rl_AddBreakAndFlushLine( MWContext *context, lo_DocState *state, int32 break_type, uint32 clear_type, Bool breaking)
|
|
{
|
|
LO_LinefeedStruct *linefeed;
|
|
|
|
linefeed = NULL;
|
|
|
|
lo_rl_AppendLinefeedAndFlushLine(context, state, linefeed, break_type, clear_type, breaking, TRUE);
|
|
}
|
|
|
|
void lo_rl_AppendLinefeedAndFlushLine( MWContext *context, lo_DocState *state, LO_LinefeedStruct *linefeed, int32 break_type, uint32 clear_type,
|
|
Bool breaking, Bool createNewLF)
|
|
{
|
|
/* flush any text */
|
|
lo_FlushLineBuffer(context, state);
|
|
|
|
lo_UpdateStateWhileFlushingLine( context, state );
|
|
|
|
if (createNewLF)
|
|
linefeed = lo_NewLinefeed(state, context, break_type, clear_type);
|
|
else
|
|
lo_FillInLineFeed( context, state, break_type, clear_type, linefeed );
|
|
|
|
if (linefeed != NULL)
|
|
{
|
|
lo_AppendLineFeed( context, state, linefeed, breaking, FALSE );
|
|
}
|
|
|
|
lo_UpdateStateAfterFlushingLine( context, state, linefeed, TRUE );
|
|
lo_UpdateStateAfterLineBreak( context, state, FALSE );
|
|
lo_UpdateFEProgressBar(context, state);
|
|
}
|
|
|
|
/* Reflow version of lo_FlushLineList() */
|
|
void lo_rl_FlushLineList( MWContext *context, lo_DocState *state,
|
|
uint32 break_type, uint32 clear_type, Bool breaking )
|
|
{
|
|
LO_LinefeedStruct *linefeed = NULL;
|
|
|
|
lo_UpdateStateWhileFlushingLine( context, state );
|
|
linefeed = lo_NewLinefeed( state, context, break_type, clear_type );
|
|
if (linefeed != NULL)
|
|
{
|
|
lo_AppendLineFeed( context, state, linefeed, breaking, FALSE );
|
|
}
|
|
lo_UpdateStateAfterFlushingLine( context, state, linefeed, TRUE );
|
|
}
|
|
|
|
/*
|
|
* Append a dummy layout element in the line list. When the relayout engine
|
|
* will see this dummy element, it will call lo_LayoutFloat{Image,JavaApp,Embed}()
|
|
*/
|
|
void lo_AppendFloatInLineList(MWContext *context,
|
|
lo_DocState *state, LO_Element *ele, LO_Element *restOfLine)
|
|
{
|
|
LO_Element *eptr;
|
|
LO_FloatStruct *float_dummy = (LO_FloatStruct*)lo_NewElement(context, state,
|
|
LO_FLOAT, NULL, 0);
|
|
float_dummy->float_ele = ele;
|
|
float_dummy->lo_any.type = LO_FLOAT;
|
|
float_dummy->lo_any.ele_id = NEXT_ELEMENT;
|
|
float_dummy->lo_any.x = state->x;
|
|
float_dummy->lo_any.y = state->y;
|
|
float_dummy->lo_any.next = restOfLine;
|
|
float_dummy->lo_any.prev = NULL;
|
|
|
|
if (state->line_list == NULL ) {
|
|
state->line_list = (LO_Element *) float_dummy;
|
|
}
|
|
else {
|
|
for (eptr = state->line_list; eptr->lo_any.next != NULL; eptr = eptr->lo_any.next)
|
|
;
|
|
/* eptr now points to the last element in state->line_list */
|
|
eptr->lo_any.next = (LO_Element *) float_dummy;
|
|
float_dummy->lo_any.prev = eptr;
|
|
}
|
|
}
|
|
|
|
void lo_rl_ReflowCell( MWContext *context, lo_DocState *state, LO_CellStruct *cell )
|
|
{
|
|
lo_RelayoutState *relay_state;
|
|
LO_Element *first;
|
|
|
|
/* Copy over cell line lists, float lists to state */
|
|
lo_rl_CopyCellToState( cell, state );
|
|
|
|
/* Create relayout state */
|
|
relay_state = lo_rl_CreateRelayoutState();
|
|
relay_state->doc_state = state;
|
|
relay_state->context = context;
|
|
relay_state->top_state = state->top_state;
|
|
|
|
/* Fit cell's layout elements */
|
|
first = lo_tv_GetFirstLayoutElement(relay_state->doc_state);
|
|
lo_rl_FitLayoutElements(relay_state, first);
|
|
|
|
/* Restore cell line list and float list */
|
|
lo_rl_CopyStateToCell( relay_state->doc_state, cell );
|
|
|
|
/* Done with relayout. Destroy relayout state. */
|
|
lo_rl_DestroyRelayoutState( relay_state );
|
|
|
|
}
|
|
|
|
void lo_rl_ReflowDocState( MWContext *context, lo_DocState *state )
|
|
{
|
|
lo_RelayoutState *relay_state;
|
|
LO_Element *first;
|
|
|
|
/* Create relayout state */
|
|
relay_state = lo_rl_CreateRelayoutState();
|
|
relay_state->doc_state = state;
|
|
relay_state->context = context;
|
|
relay_state->top_state = state->top_state;
|
|
|
|
/* Fit cell's layout elements */
|
|
first = lo_tv_GetFirstLayoutElement(relay_state->doc_state);
|
|
|
|
lo_rl_FitLayoutElements(relay_state, first);
|
|
|
|
/* Dummy Floating elements on a new line at the end of a document were not getting put into
|
|
the line_array. This code should ensure that anything left on the line_list gets flushed
|
|
to the line_array. */
|
|
/*
|
|
if (state->line_list != NULL)
|
|
lo_AppendLineListToLineArray( context, state, lo_GetLastElementInList(state->line_list) );
|
|
*/
|
|
|
|
/* Done with relayout. Destroy relayout state. */
|
|
lo_rl_DestroyRelayoutState( relay_state );
|
|
}
|
|
|
|
void lo_PrepareElementForReuse( MWContext *context, lo_DocState *state, LO_Element * eptr,
|
|
ED_Element *edit_element, intn edit_offset)
|
|
{
|
|
#ifdef EDITOR
|
|
eptr->lo_any.edit_element = NULL;
|
|
eptr->lo_any.edit_offset = 0;
|
|
|
|
if( EDT_IS_EDITOR(context) )
|
|
{
|
|
if( lo_EditableElement( eptr->type ) )
|
|
{
|
|
if( edit_element == 0 ){
|
|
edit_element = state->edit_current_element;
|
|
edit_offset = state->edit_current_offset;
|
|
}
|
|
EDT_SetLayoutElement( edit_element,
|
|
edit_offset,
|
|
eptr->type,
|
|
eptr );
|
|
} else if( edit_element && (eptr->type == LO_TABLE || eptr->type == LO_CELL) )
|
|
{
|
|
/* _TABLE_EXPERIMENT_ SAVE POINTER TO EDIT ELEMENT IN LO STRUCT */
|
|
eptr->lo_any.edit_element = edit_element;
|
|
|
|
}
|
|
}
|
|
state->edit_force_offset = FALSE;
|
|
#endif
|
|
}
|
|
|