home *** CD-ROM | disk | FTP | other *** search
- /* -*- 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 "pa_tags.h"
- #include "layout.h"
- #include "laylayer.h"
- #include "laystyle.h"
- #include "libmocha.h"
- #include "libevent.h"
- #include "layers.h"
- #include "intl_csi.h"
-
- extern Bool lo_IsEmptyTag(TagType type);
-
- /* This struct is used during the processing of a <LAYER> or <ILAYER>
- * tag, but discarded after the tag is closed. It is used to store the
- * current document state while process the tag and channel everything
- * into the layer.
- */
- struct lo_Block {
- MWContext *context;
-
- /* Saved document state, restored after block is layed out */
- lo_DocState *saved_state;
-
- int32 start_x, start_y; /* Initial upper-left corner of block,
- in parent layer coord system */
- char *old_base_url;
- uint8 old_body_attr;
-
- char * name; /* Identifier for this layer */
- char * above; /* Name of layer above this layer or NULL */
- char * below; /* Name of layer below this layer or NULL */
- int32 z_order; /* Z-order if above/below unspecified */
-
- int32 x_offset, y_offset; /* Layer coordinate translation
- (for in-flow layers) */
- PRPackedBool is_inflow; /* Is this an out-of-flow or in-flow layer ? */
- PRPackedBool is_inline; /* Is this inline or SRCed */
- PRPackedBool is_dynamic; /* Has the SRC been dynamically changed? */
- PRPackedBool uses_ss_positioning; /* Created using style-sheet 'position'
- property instead of tag ? */
- int clip_expansion_policy; /* Expand clip to contain layer content ? */
-
- CL_Layer *layer;
- LO_CellStruct *cell;
-
- lo_LayerDocState *old_layer_state; /* Used during table relayout */
- char *match_code; /* Value of layer tag's MATCH parameter */
- char *source_url;
- };
-
- static int lo_AppendLayerElement(MWContext *context, lo_DocState *state, int32 is_end);
-
- #ifdef XP_MAC
- PRIVATE
- #endif
- lo_LayerDocState *
- lo_GetLayerStateFromId(MWContext *context, int32 layer_id)
- {
- int32 doc_id;
- lo_TopState *top_state;
- lo_LayerDocState *layer_state;
-
- doc_id = XP_DOCID(context);
- top_state = lo_FetchTopState(doc_id);
- XP_ASSERT(top_state);
- if (!top_state)
- return NULL;
-
- XP_ASSERT(layer_id <= top_state->max_layer_num);
- if (layer_id > top_state->max_layer_num)
- return NULL;
- layer_state = top_state->layers[layer_id];
- /* XP_ASSERT(layer_state); */
- return layer_state;
- }
-
- void *
- LO_GetLayerMochaObjectFromId(MWContext *context, int32 layer_id)
- {
- lo_LayerDocState *layer_state = lo_GetLayerStateFromId(context, layer_id);
- if (!layer_state)
- return NULL;
- return layer_state->mocha_object;
- }
-
- void *
- LO_GetLayerMochaObjectFromLayer(MWContext *context, CL_Layer *layer)
- {
- lo_LayerDocState *layer_state = lo_GetLayerState(layer);
- if (!layer_state)
- return NULL;
- return layer_state->mocha_object;
- }
-
- void
- LO_SetLayerMochaObject(MWContext *context, int32 layer_id, void *mocha_object)
- {
- lo_LayerDocState *layer_state = lo_GetLayerStateFromId(context, layer_id);
- if (!layer_state)
- return;
- layer_state->mocha_object = mocha_object;
- }
-
- CL_Layer *
- LO_GetLayerFromId(MWContext *context, int32 layer_id)
- {
- lo_LayerDocState *layer_state = lo_GetLayerStateFromId(context, layer_id);
- if (!layer_state)
- return NULL;
- return layer_state->layer;
- }
-
- int32
- LO_GetIdFromLayer(MWContext *context, CL_Layer *layer)
- {
- lo_LayerDocState *layer_state = lo_GetLayerState(layer);
- XP_ASSERT(layer_state);
- if (!layer_state)
- return 0;
- return layer_state->id;
- }
-
- int32
- LO_GetNumberOfLayers(MWContext *context)
- {
- int32 doc_id;
- lo_TopState *top_state;
-
- doc_id = XP_DOCID(context);
- top_state = lo_FetchTopState(doc_id);
- if (!top_state)
- return 0;
-
- return (top_state->max_layer_num);
- }
-
- PRBool
- lo_IsCurrentLayerDynamic(lo_DocState *state)
- {
- lo_LayerDocState *layer_state = lo_CurrentLayerState(state);
- lo_Block *block = layer_state->temp_block;
-
- if (layer_state->id == LO_DOCUMENT_LAYER_ID)
- return PR_FALSE;
-
- XP_ASSERT(block);
- if (!block)
- return PR_FALSE;
-
- return (PRBool)block->is_dynamic;
- }
-
- PRBool
- lo_IsAnyCurrentAncestorSourced(lo_DocState *state)
- {
- lo_LayerStack *lptr;
- lo_TopState *top_state = state->top_state;
-
- if (top_state->layer_stack == NULL)
- return PR_FALSE;
-
- lptr = top_state->layer_stack;
- while (lptr && lptr->layer_state &&
- (lptr->layer_state->id != LO_DOCUMENT_LAYER_ID)) {
- lo_Block *block = lptr->layer_state->temp_block;
- if (block && !block->is_inline)
- return PR_TRUE;
-
- lptr = lptr->next;
- }
-
- return PR_FALSE;
- }
-
- PRBool
- lo_IsTagInSourcedLayer(lo_DocState *state, PA_Tag *tag)
- {
- PRBool ancestor_sourced = PR_FALSE;
- PRBool current_layer_sourced = PR_FALSE;
- lo_LayerStack *lptr;
- lo_TopState *top_state = state->top_state;
-
- if (top_state->layer_stack == NULL)
- return PR_FALSE;
-
- lptr = top_state->layer_stack;
- while (lptr && lptr->layer_state &&
- (lptr->layer_state->id != LO_DOCUMENT_LAYER_ID)) {
- lo_Block *block = lptr->layer_state->temp_block;
- if (block && !block->is_inline) {
- if (top_state->layer_stack == lptr)
- current_layer_sourced = PR_TRUE;
- else {
- ancestor_sourced = PR_TRUE;
- break;
- }
- }
- lptr = lptr->next;
- }
-
- /*
- * If we're not dealing with a </LAYER> or </ILAYER> tag,
- * then we just return whether any current layer ancestor
- * has a SRC attribute.
- */
- if (((tag->type != P_LAYER) && (tag->type != P_ILAYER)) ||
- (tag->is_end == FALSE) ||
- (top_state->ignore_layer_nest_level != 0))
- return (PRBool)(ancestor_sourced || current_layer_sourced);
- /*
- * Otherwise, it may be possible that the current close tag
- * actually closes out the sourced layer and isn't actually
- * part of the content of the sourced layer.
- */
- else
- return ancestor_sourced;
- }
-
-
- /*
- * Are there any dynamic layers on the current layer_stack?
- */
- PRBool
- lo_IsAnyCurrentAncestorDynamic(lo_DocState *state)
- {
- lo_LayerStack *lptr;
- lo_TopState *top_state = state->top_state;
-
- if (top_state->layer_stack == NULL)
- return PR_FALSE;
-
- lptr = top_state->layer_stack;
- while (lptr && lptr->layer_state &&
- (lptr->layer_state->id != LO_DOCUMENT_LAYER_ID)) {
- lo_Block *block = lptr->layer_state->temp_block;
- if (block && block->is_dynamic)
- return PR_TRUE;
-
- lptr = lptr->next;
- }
-
- return PR_FALSE;
- }
-
- static void
- lo_init_block_cell(MWContext *context, lo_DocState *state, lo_Block *block)
- {
- LO_CellStruct *cell;
-
- if ((block == NULL)||(block->cell == NULL))
- {
- return;
- }
-
- cell = block->cell;
-
- cell->type = LO_CELL;
- cell->ele_id = NEXT_ELEMENT;
- cell->x = state->x;
- cell->x_offset = 0;
- cell->y = state->y;
- cell->y_offset = 0;
- cell->width = 0;
- cell->height = 0;
- cell->line_height = state->line_height;
- cell->next = NULL;
- cell->prev = NULL;
- cell->FE_Data = NULL;
- cell->cell_float_list = NULL;
- cell->backdrop.bg_color = NULL;
- cell->backdrop.url = NULL;
- cell->border_width = 0;
- cell->border_vert_space = 0;
- cell->border_horiz_space = 0;
- cell->ele_attrmask = 0;
- cell->sel_start = -1;
- cell->sel_end = -1;
- cell->cell_list = NULL;
- cell->cell_list_end = NULL;
- cell->cell_float_list = NULL;
- cell->cell_inflow_layer = NULL;
- cell->cell_bg_layer = NULL;
- cell->table_cell = NULL;
- cell->table_row = NULL;
- cell->table = NULL;
- }
-
- lo_LayerDocState *
- lo_NewLayerState(MWContext *context)
- {
- lo_LayerDocState *layer_state;
- XP_Rect everything = CL_MAX_RECT;
-
- layer_state = XP_NEW_ZAP(lo_LayerDocState);
- if (layer_state == NULL)
- return NULL;
-
- layer_state->id = 0; /* This will be filled in later */
- layer_state->cell = NULL;
- layer_state->viewRect = everything;
- layer_state->doc_lists = XP_NEW_ZAP(lo_DocLists);
- if (!layer_state->doc_lists) {
- XP_FREE(layer_state);
- return NULL;
- }
- if (!lo_InitDocLists(context, layer_state->doc_lists)) {
- XP_FREE(layer_state->doc_lists);
- XP_FREE(layer_state);
- return NULL;
- }
-
- return layer_state;
- }
-
- #ifdef XP_MAC
- PRIVATE
- #endif
- void
- lo_DeleteBlock(lo_Block* block)
- {
- XP_FREEIF(block->name);
- XP_FREEIF(block->above);
- XP_FREEIF(block->below);
- XP_FREEIF(block->saved_state);
- XP_FREEIF(block->match_code);
- XP_FREEIF(block->source_url);
- XP_FREE(block);
- }
-
- void
- lo_DeleteLayerState(MWContext *context, lo_DocState *state,
- lo_LayerDocState *layer_state)
- {
- /* Get rid of the layer_state's contents */
- if (layer_state->cell)
- lo_RecycleElements(context, state, (LO_Element *)layer_state->cell);
-
- /* Get rid of the layer_state's layer */
- if (layer_state->layer) {
- CL_Layer *parent_layer = CL_GetLayerParent(layer_state->layer);
- if (parent_layer)
- CL_RemoveChild(parent_layer, layer_state->layer);
- LO_LockLayout();
- CL_DestroyLayerTree(layer_state->layer);
- LO_UnlockLayout();
- }
-
- lo_DeleteDocLists(context, layer_state->doc_lists);
- if (layer_state->id != LO_DOCUMENT_LAYER_ID)
- XP_FREE(layer_state->doc_lists);
- if (layer_state->temp_block)
- lo_DeleteBlock(layer_state->temp_block);
- XP_FREE(layer_state);
- }
-
- /* Number of entries to grow layers array when it is too small */
- #define LAYER_ARRAY_GROW_SIZE 50
-
- /*
- * Adds the layer_state to the layer list. If one with the same
- * id already exists (because of table relayout), we replace
- * it with the new one. The old layer_state is returned, so that
- * it may be discarded when the new layer is done loading.
- */
- lo_LayerDocState *
- lo_append_to_layer_array(MWContext *context, lo_TopState *top_state,
- lo_DocState *state,
- lo_LayerDocState *layer_state)
- {
- int32 id;
-
- XP_ASSERT(top_state);
- if (!top_state)
- return NULL;
-
- id = ++top_state->current_layer_num;
- layer_state->id = id;
-
- if (state)
- state->current_layer_num_max = id;
-
- /*
- * If we're doing table relayout, we find the corresponding layer in
- * the layer list from a previous pass and replace it with the current
- * layer.
- */
- if (state && state->in_relayout) {
- lo_LayerDocState **old_layer_statep = &top_state->layers[id];
- lo_LayerDocState *old_layer_state = *old_layer_statep;
-
- XP_ASSERT(old_layer_state);
- XP_ASSERT(old_layer_state->id == id);
-
- /*
- * Copy over the mocha object, since the reflection might
- * already have happened.
- */
- layer_state->mocha_object = old_layer_state->mocha_object;
-
- /* Out with the old and in with the new */
- *old_layer_statep = layer_state;
- return old_layer_state;
- }
-
- /* Extend the layers array if it's full */
- if (id >= top_state->num_layers_allocated) {
- int32 new_count = top_state->num_layers_allocated + LAYER_ARRAY_GROW_SIZE;
- int32 nsize = new_count * sizeof(lo_LayerDocState*);
- lo_LayerDocState **new_layers;
-
- if (top_state->num_layers_allocated == 0)
- new_layers = (lo_LayerDocState**)XP_ALLOC(nsize);
- else
- new_layers = (lo_LayerDocState**)XP_REALLOC(top_state->layers, nsize);
-
- XP_ASSERT(new_layers);
- if (!new_layers)
- return NULL;
- top_state->layers = new_layers;
- top_state->num_layers_allocated = new_count;
- }
-
- top_state->layers[id] = layer_state;
-
- if (id > top_state->max_layer_num)
- top_state->max_layer_num = id;
- return NULL;
- }
-
- static void
- lo_block_src_exit_fn(URL_Struct *url_struct, int status, MWContext *context)
- {
- int32 doc_id;
- lo_TopState *top_state;
- lo_DocState *state;
-
- /* XXX need state to be subdoc state? */
- doc_id = XP_DOCID(context);
- top_state = lo_FetchTopState(doc_id);
- if ((top_state == NULL) ||
- ((state = top_state->doc_state) == NULL)) {
- return;
- }
-
- /* Flush tags blocked by this <LAYER SRC="URL"> tag. We treat
- the special case of an interrupted stream as normal completion,
- as this is the resulting error code when we do
- <LAYER SRC=some.gif> and some.gif is in the image cache. */
- if (status >= 0 || status == MK_INTERRUPTED) {
- top_state->layout_blocking_element = NULL;
- lo_FlushBlockage(context, state, state);
- }
- /* XXX What's the right thing to do when we fail???
- * Presumably we don't want to flush the blockage and
- * continue as if nothing happened. But in some cases,
- * we do want to recover in some way.
- */
- NET_FreeURLStruct(url_struct);
- }
-
- static void
- lo_free_stream(MWContext *context, NET_StreamClass *stream)
- {
- XP_DELETE(stream);
- }
-
- int32
- lo_GetEnclosingLayerWidth(lo_DocState *state)
- {
- lo_LayerDocState *layer_state = lo_CurrentLayerState(state);
-
- /* Special case 100% value for top-level document so that
- it doesn't include window margins. */
- if (layer_state->id == LO_DOCUMENT_LAYER_ID)
- return state->win_left + state->win_width + state->win_right;
-
- return state->right_margin - state->left_margin;
- }
-
- /* Convert a string containing a horizontal dimension into layout coordinates,
- handling percentages if necessary. */
- static int32
- lo_parse_horizontal_param(char *value, lo_DocState *state, MWContext *context)
- {
- int32 parent_width = lo_GetEnclosingLayerWidth(state);
- XP_Bool is_percent;
- int32 ival;
-
- ival = lo_ValueOrPercent(value, &is_percent);
- if (is_percent)
- {
- if (state->allow_percent_width == FALSE)
- {
- ival = 0;
- }
- else
- {
- ival = (parent_width * ival) / 100;
- }
- }
- else
- {
- ival = FEUNITS_X(ival, context);
- }
- return ival;
- }
-
- int32
- lo_GetEnclosingLayerHeight(lo_DocState *state)
- {
- lo_LayerDocState *layer_state = lo_CurrentLayerState(state);
- return layer_state->height;
- }
-
- /* Convert a string containing a vertical dimension into layout coordinates,
- handling percentages if necessary. */
- static int32
- lo_parse_vertical_param(char *value, lo_DocState *state, MWContext *context)
- {
- XP_Bool is_percent;
- int32 ival;
- int32 parent_height = lo_GetEnclosingLayerHeight(state);
-
- ival = lo_ValueOrPercent(value, &is_percent);
- if (is_percent)
- ival = (parent_height * ival) / 100;
- else
- ival = FEUNITS_Y(ival, context);
- return ival;
- }
-
- #ifdef XP_MAC
- PRIVATE
- #endif
- int
- lo_parse_clip(char *str, XP_Rect *clip,
- lo_DocState *state, MWContext *context)
- {
- int32 coord, coords[4];
- int coord_count;
- int clip_expansion_policy = LO_AUTO_EXPAND_NONE;
- for (coord_count = 0; coord_count <= 3; coord_count++) {
-
- /* Skip leading whitespace and commas */
- while (XP_IS_SPACE(*str) || (*str == ','))
- str++;
-
- if (!*str)
- break;
-
- /* Parse distinguished "auto" value */
- if (!XP_STRNCASECMP(str, "auto", 4)) {
- str += 4;
- clip_expansion_policy |= 1;
- coords[coord_count] = 0;
- } else {
- if (coord_count & 1)
- coord = lo_parse_vertical_param(str, state, context);
- else
- coord = lo_parse_horizontal_param(str, state, context);
- coords[coord_count] = coord;
-
- /* Skip over the number and percentage sign */
- while (*str && !XP_IS_SPACE(*str) && !(*str == ','))
- str++;
- }
- clip_expansion_policy <<= 1;
- }
- clip_expansion_policy >>= 1;
-
- if (coord_count == 2) {
- clip->right = coords[0];
- clip->bottom = coords[1];
- return clip_expansion_policy;
- } else if (coord_count >= 4) {
- clip->left = coords[0];
- clip->top = coords[1];
- clip->right = coords[2];
- clip->bottom = coords[3];
- return clip_expansion_policy;
- }
-
- /* Error - don't clip at all */
- return LO_AUTO_EXPAND_CLIP;
- }
-
- extern XP_Bool
- lo_BeginLayer(MWContext *context,
- lo_DocState *state,
- LO_BlockInitializeStruct *param,
- XP_Bool is_inflow);
-
- #ifdef XP_MAC
- PRIVATE
- #endif
- void
- lo_FreeBlockInitializeStruct(LO_BlockInitializeStruct *param)
- {
- if(param)
- {
- XP_FREEIF(param->clip);
- XP_FREEIF(param->overflow);
- XP_FREEIF(param->name);
- XP_FREEIF(param->id);
- XP_FREEIF(param->above);
- XP_FREEIF(param->below);
- XP_FREEIF(param->visibility);
- XP_FREEIF(param->bgcolor);
- XP_FREEIF(param->bgimage);
- XP_FREEIF(param->src);
-
- XP_FREE(param);
- }
- }
-
- /* Start a <LAYER> or an <ILAYER>. */
- void
- lo_BeginLayerTag(MWContext *context, lo_DocState *state, PA_Tag *tag)
- {
- INTL_CharSetInfo c = LO_GetDocumentCharacterSetInfo(context);
- int16 win_csid = INTL_GetCSIWinCSID(c);
- LO_BlockInitializeStruct *param;
- char *val;
- lo_LayerDocState *layer_state;
- CL_Layer *parent_layer;
-
-
- if (!context->compositor)
- return;
-
- layer_state = lo_CurrentLayerState(state);
- parent_layer = layer_state->layer;
-
- param = XP_NEW_ZAP(LO_BlockInitializeStruct);
-
- if(!param)
- {
- state->top_state->out_of_memory = TRUE;
- return;
- }
-
- /*
- * Get the horizontal position of the block
- */
- val = (char*) lo_FetchParamValue(context, tag, PARAM_LEFT);
- if(val)
- {
- param->has_left = TRUE;
- param->left = lo_parse_horizontal_param(val, state, context);
- XP_FREE(val);
- } else {
- /* No LEFT attribute. Is there an X attribute ? */
- val = (char*) lo_FetchParamValue(context, tag, PARAM_PAGEX);
- if(val)
- {
- param->has_left = TRUE;
- param->left = (int32)XP_ATOI(val);
-
- /* Convert from absolute coordinates to layer-relative coordinates */
- param->left -= CL_GetLayerXOrigin(parent_layer);
- XP_FREE(val);
- }
- }
-
- /*
- * Get the vertical position of the block
- */
- val = (char*)lo_FetchParamValue(context, tag, PARAM_TOP);
- if (val)
- {
- param->has_top = TRUE;
- param->top = lo_parse_vertical_param(val, state, context);
- XP_FREE(val);
- } else {
- /* No TOP attribute. Is there a Y attribute ? */
- val = (char*) lo_FetchParamValue(context, tag, PARAM_PAGEY);
- if(val)
- {
- param->has_top = TRUE;
- param->top = (int32)XP_ATOI(val);
-
- /* Convert from absolute coordinates to layer-relative coordinates */
- param->top -= CL_GetLayerYOrigin(parent_layer);
- XP_FREE(val);
- }
- }
-
- /*
- * Parse the comma separated coordinate list into an
- * array of integers.
- */
- val = (char*)lo_FetchParamValue(context, tag, PARAM_CLIP);
- if(val)
- {
- param->clip = XP_NEW_ZAP(XP_Rect);
-
- if(param->clip)
- {
- XP_BZERO(param->clip, sizeof(XP_Rect));
- param->clip_expansion_policy =
- lo_parse_clip(val, param->clip, state, context);
- }
- }
- else
- param->clip_expansion_policy = LO_AUTO_EXPAND_CLIP;
-
- /*
- * Get the width parameter, in absolute or percentage.
- * If percentage, make it absolute.
- */
- val = (char*)lo_FetchParamValue(context, tag, PARAM_WIDTH);
- if(val)
- {
- param->has_width = TRUE;
- param->width = lo_parse_horizontal_param(val, state, context);
- XP_FREE(val);
- }
-
- /*
- * Get the height parameter, in absolute or percentage.
- * If percentage, make it absolute.
- */
- val = (char*)lo_FetchParamValue(context, tag, PARAM_HEIGHT);
- if(val)
- {
- param->has_height = TRUE;
- param->height = lo_parse_vertical_param(val, state, context);
- XP_FREE(val);
- }
-
- /* Get the OVERFLOW attribute. */
- param->overflow = (char*)lo_FetchParamValue(context, tag, PARAM_OVERFLOW);
-
- /*
- * Get the optional name for this layer.
- */
- param->name = (char*)PA_FetchParamValue(tag, PARAM_NAME, win_csid);
-
- /* Use either NAME or ID, since we will probably be switching to
- the latter */
- param->id = (char*)PA_FetchParamValue(tag, PARAM_ID, win_csid);
-
- /*
- * Get the optional "above" name for the layer we are above.
- */
- param->above = (char*)PA_FetchParamValue(tag, PARAM_ABOVE, win_csid);
-
- /*
- * Get the optional "below" name for the layer we are below.
- */
- param->below = (char*)PA_FetchParamValue(tag, PARAM_BELOW, win_csid);
-
- /*
- * Get the Z-order of the block
- */
- val = (char*)lo_FetchParamValue(context, tag, PARAM_ZINDEX);
- if (val) {
- param->zindex = XP_ATOI(val);
- param->has_zindex = TRUE;
- XP_FREE(val);
- }
- else
- param->has_zindex = FALSE;
-
- /* Get the VISIBILITY parameter to know if this layer starts hidden. */
- param->visibility = (char*)PA_FetchParamValue(tag, PARAM_VISIBILITY, win_csid);
-
- /* Process background color (BGCOLOR) attribute, if present. */
- param->bgcolor = (char*)PA_FetchParamValue(tag, PARAM_BGCOLOR, win_csid);
-
- /* Process backdrop (BACKGROUND) image attribute, if present. */
- param->bgimage = lo_ParseBackgroundAttribute(context,
- state,
- tag, FALSE);
-
- param->src = (char*)PA_FetchParamValue(tag, PARAM_SRC, win_csid);
-
- param->tag = tag;
- param->ss_tag = NULL;
-
- if (lo_BeginLayer(context, state, param, tag->type == P_ILAYER))
- lo_FreeBlockInitializeStruct(param);
- }
-
- static int lo_AppendLayerElement(MWContext *context, lo_DocState *state, int32 is_end)
- {
- LO_LayerStruct *layer;
- layer = (LO_LayerStruct*)lo_NewElement(context, state, LO_LAYER, NULL, 0);
-
- XP_ASSERT(layer);
- if (!layer)
- return FALSE;
-
- layer->lo_any.type = LO_LAYER;
- layer->lo_any.x = state->x;
- layer->lo_any.y = state->y;
- layer->lo_any.x_offset = 0;
- layer->lo_any.y_offset = 0;
- layer->lo_any.width = 0;
- layer->lo_any.height = 0;
- layer->lo_any.line_height = 0;
- layer->lo_any.ele_id = NEXT_ELEMENT;
-
- layer->is_end = is_end;
- layer->initParams = NULL; /* Not keeping params for now. Just trying to fix ILAYER crash. */
-
- lo_AppendToLineList(context, state, (LO_Element*)layer, 0);
-
- return TRUE;
- }
-
- /* parse a comma separated list of 2 or 4 values
- *
- * Format is "rect(top, right, bottom, left)"
- * or "rect(right, bottom)"
- * or degenerate case of "top,right,bottom,left" with no rect()
- */
- #ifdef XP_MAC
- PRIVATE
- #endif
- XP_Rect *
- lo_ParseStyleCoords(MWContext *context,
- lo_DocState *state,
- StyleStruct *style_struct,
- char *coord_string)
- {
-
- XP_Rect *coords = XP_NEW_ZAP(XP_Rect);
- int32 val[4];
- int index=0;
- char *value;
- SS_Number *ss_num;
-
- if(!coords)
- return(NULL);
-
- coord_string = XP_StripLine(coord_string);
-
- /* go past "rect(" and kill ")" character */
- #define _RECT "rect"
- if(!strncasecomp(coord_string, _RECT, sizeof(_RECT)-1)) {
- char *t;
-
- /* go past "rect" */
- coord_string += sizeof(_RECT)-1;
-
- /* go past spaces */
- while(XP_IS_SPACE(*coord_string)) coord_string++;
-
- /* go past '(' */
- if(*coord_string == '(')
- coord_string++;
-
- /* kill any more spaces */
- while(XP_IS_SPACE(*coord_string)) coord_string++;
-
- /* Kill the ending ')' */
- t = XP_STRCHR(coord_string, ')');
- if (t)
- *t = '\0';
- }
-
- value = XP_STRTOK(coord_string, ", ");
-
- while(value && index < 4)
- {
- ss_num = STYLESTRUCT_StringToSSNumber(style_struct, value);
-
- /* First and third args are heights. Note that we use
- LAYER_WIDTH_STYLE instead of WIDTH_STYLE, since the two are
- subtly different. (For the top-level DOCUMENT layer, 100%
- WIDTH is the distance between the margins and 100%
- LAYER_WIDTH is the width of the window.) */
- if(index & 1)
- LO_AdjustSSUnits(ss_num, LAYER_WIDTH_STYLE, context, state);
- else
- LO_AdjustSSUnits(ss_num, HEIGHT_STYLE, context, state);
-
- val[index++] = (int32)ss_num->value;
-
- value = XP_STRTOK(NULL, ",) ");
- }
-
- if (index == 2)
- {
- coords->right = FEUNITS_X(val[0], context);
- coords->bottom = FEUNITS_Y(val[1], context);
- }
- else if (index == 4)
- {
- coords->top = FEUNITS_Y(val[0], context);
- coords->right = FEUNITS_X(val[1], context);
- coords->bottom = FEUNITS_Y(val[2], context);
- coords->left = FEUNITS_X(val[3], context);
- }
- else
- {
- XP_FREE(coords);
- return NULL;
- }
-
- return coords;
- }
-
- void
- lo_SetStyleSheetLayerProperties(MWContext *context,
- lo_DocState *state,
- StyleStruct *style_struct,
- PA_Tag *tag)
- {
- LO_BlockInitializeStruct *param;
- char *prop;
- char *src_prop;
- XP_Bool is_inflow;
- SS_Number *ss_num;
-
- if(!style_struct)
- return;
-
- prop = STYLESTRUCT_GetString(style_struct, POSITION_STYLE);
- src_prop = STYLESTRUCT_GetString(style_struct, LAYER_SRC_STYLE);
-
- if(!prop && !src_prop)
- return;
-
- if(lo_IsEmptyTag(tag->type))
- {
- /* setting positioning on an empty tag will
- * cause things to not work because of blocked image
- * problems, so don't allow it.
- */
- return;
- }
-
- if(prop && !strcasecomp(prop, ABSOLUTE_STYLE))
- {
- is_inflow = FALSE;
- }
- else if(prop && !strcasecomp(prop, RELATIVE_STYLE))
- {
- is_inflow = TRUE;
- }
- else if(src_prop)
- {
- /* not positioned, but an include src attribute */
- is_inflow = TRUE;
- }
- else
- {
- XP_FREEIF(prop);
- return; /* don't do layers */
- }
-
- XP_FREEIF(prop);
-
- param = XP_NEW_ZAP(LO_BlockInitializeStruct);
-
- if(!param)
- return;
-
- param->name = (char*)lo_FetchParamValue(context, tag, PARAM_NAME);
- param->id = (char*)lo_FetchParamValue(context, tag, PARAM_ID);
-
- ss_num = STYLESTRUCT_GetNumber(style_struct, LEFT_STYLE);
- if(ss_num)
- {
- LO_AdjustSSUnits(ss_num, LEFT_STYLE, context, state);
- param->left = FEUNITS_X((int32)ss_num->value, context);
- param->has_left = TRUE;
- STYLESTRUCT_FreeSSNumber(style_struct, ss_num);
- }
-
- ss_num = STYLESTRUCT_GetNumber(style_struct, TOP_STYLE);
- if(ss_num)
- {
- LO_AdjustSSUnits(ss_num, TOP_STYLE, context, state);
- param->top = FEUNITS_Y((int32)ss_num->value, context);
- param->has_top = TRUE;
- STYLESTRUCT_FreeSSNumber(style_struct, ss_num);
- }
-
- ss_num = STYLESTRUCT_GetNumber(style_struct, HEIGHT_STYLE);
- if(ss_num)
- {
- LO_AdjustSSUnits(ss_num, HEIGHT_STYLE, context, state);
- param->height = FEUNITS_Y((int32)ss_num->value, context);
- param->has_height = TRUE;
- STYLESTRUCT_FreeSSNumber(style_struct, ss_num);
- }
-
- /* don't set width. normal style sheets will handle it */
-
- prop = STYLESTRUCT_GetString(style_struct, CLIP_STYLE);
-
- if(prop) {
- param->clip = lo_ParseStyleCoords(context, state, style_struct, prop);
- param->clip_expansion_policy = LO_AUTO_EXPAND_NONE;
- }
-
- param->above = NULL;
- param->below = NULL;
- ss_num = STYLESTRUCT_GetNumber(style_struct, ZINDEX_STYLE);
- if (ss_num) {
- param->zindex = (int32)ss_num->value;
- param->has_zindex = TRUE;
- STYLESTRUCT_FreeSSNumber(style_struct, ss_num);
- }
- else
- param->has_zindex = FALSE;
-
- param->visibility = STYLESTRUCT_GetString(style_struct, VISIBILITY_STYLE);
-
- param->src = src_prop;
- if(param->src)
- {
- char *tmp = param->src;
-
- param->src = lo_ParseStyleSheetURL(param->src);
- param->src = NET_MakeAbsoluteURL(state->top_state->base_url, param->src);
- XP_FREE(tmp);
- }
-
- param->overflow = STYLESTRUCT_GetString(style_struct, OVERFLOW_STYLE);
-
- param->bgcolor = STYLESTRUCT_GetString(style_struct, LAYER_BG_COLOR_STYLE);
- param->is_style_bgcolor = TRUE;
- param->bgimage = STYLESTRUCT_GetString(style_struct, LAYER_BG_IMAGE_STYLE);
- if(param->bgimage)
- {
- char *tmp = param->bgimage;
- if(!strcasecomp(param->bgimage, "none"))
- {
- param->bgimage = NULL;
- }
- else
- {
- param->bgimage = lo_ParseStyleSheetURL(param->bgimage);
- param->bgimage = NET_MakeAbsoluteURL(state->top_state->base_url, param->bgimage);
- }
- XP_FREE(tmp);
- }
-
- STYLESTRUCT_SetString(style_struct, STYLE_NEED_TO_POP_LAYER, "1", 0);
-
- param->tag = NULL;
- param->ss_tag = tag;
-
- if (lo_BeginLayer(context, state, param, is_inflow))
- lo_FreeBlockInitializeStruct(param);
- }
-
- static void
- lo_expand_parent_bbox(CL_Layer *layer); /* Forward declaration */
-
-
- /* Save a copy of the document state, so that we can restore it later. */
- static PRBool
- lo_SaveDocState(lo_Block *block, lo_DocState *state)
- {
- lo_DocState *saved_state;
-
- block->start_x = state->x;
- block->start_y = state->y;
-
- saved_state = XP_NEW(lo_DocState);
- if (!saved_state)
- return PR_FALSE;
-
- block->saved_state = saved_state;
- XP_BCOPY(state, saved_state, sizeof *saved_state);
- if (!block->is_inflow) {
- state->top_state->in_head = TRUE;
- state->top_state->in_body = FALSE;
- }
- block->old_body_attr = state->top_state->body_attr;
- state->top_state->body_attr = 0;
- return PR_TRUE;
- }
-
- static void
- lo_RestoreDocState(lo_Block *block, lo_DocState *state)
- {
- lo_DocState *saved = block->saved_state;
- lo_FontStack *font_stack;
- PA_Tag *subdoc_tags_end, *subdoc_tags;
- LO_TextInfo text_info;
- intn layer_nest_level;
- int32 layer_num_max;
-
- /*
- * If there was a BODY tag with a TEXT attribute in this layer,
- * then we pop the font that was pushed to enable layer-specific
- * text coloring.
- */
- if (state->top_state->body_attr & BODY_ATTR_TEXT) {
- lo_PopFont(state, P_BODY);
- }
- state->top_state->body_attr = block->old_body_attr;
-
- lo_SetBaseUrl(state->top_state, block->old_base_url, FALSE);
-
- if (block->is_inflow) {
- state->line_num = saved->line_num;
- state->float_list = saved->float_list;
- state->line_list = saved->line_list;
- state->end_last_line = saved->end_last_line;
-
- /* Push the cell representing the inflow layer onto the line
- list, so that it appears like any other (non-layer)
- element. */
- if (state->line_list == NULL) {
- state->line_list = (LO_Element*)block->cell;
- } else {
- LO_Element *eptr = state->line_list;
- while (eptr->lo_any.next != NULL)
- eptr = eptr->lo_any.next;
- eptr->lo_any.next = (LO_Element*)block->cell;
- block->cell->prev = eptr;
- }
-
- if (state->end_last_line != NULL)
- state->end_last_line->lo_any.next = NULL;
- state->linefeed_state = 0;
- state->text_fg = saved->text_fg;
- state->text_bg = saved->text_bg;
- state->anchor_color = saved->anchor_color;
- state->visited_anchor_color = saved->visited_anchor_color;
- state->active_anchor_color = saved->active_anchor_color;
- return;
- }
-
- state->top_state->in_head = FALSE;
- state->top_state->in_body = TRUE;
-
- /* Save a few special state variables that we *don't* restore.
- See lo_InitDocState(). */
-
- /* XXX - Right now, font info is not reset when entering and
- exiting layers. Is that right ? */
- font_stack = state->font_stack;
- text_info = state->text_info;
- layer_nest_level = state->layer_nest_level;
- layer_num_max = state->current_layer_num_max;
- subdoc_tags_end = state->subdoc_tags_end;
- subdoc_tags = state->subdoc_tags;
-
- /* First, free up the pieces of the document state that we're
- about to overwrite with their restored values. This gets rid of
- default values or values left on the stack because the document
- author didn't properly close tags inside the layer. */
- state->font_stack = NULL; /* But, don't free the font stack */
- lo_free_layout_state_data(block->context, state);
-
- /* Restore the entire document state ... */
- XP_BCOPY(saved, state, sizeof *state);
-
- /* ...except for these variables which are retained across LAYERs */
- state->font_stack = font_stack;
- state->text_info = text_info;
- state->layer_nest_level = layer_nest_level;
- state->current_layer_num_max = layer_num_max;
- state->subdoc_tags_end = subdoc_tags_end;
- state->subdoc_tags = subdoc_tags;
-
- if (state->end_last_line != NULL)
- state->end_last_line->lo_any.next = NULL;
-
- XP_FREE(block->saved_state);
- block->saved_state = NULL;
- }
-
- static PRBool
- lo_SetupDocStateForLayer(lo_DocState *state,
- lo_LayerDocState *layer_state,
- int32 width,
- int32 height,
- PRBool is_inflow)
- {
- lo_Block *block = layer_state->temp_block;
- MWContext *context = block->context;
- lo_DocState *saved_state;
-
- block->is_inflow = is_inflow;
-
- /* Save old document state so that we can selectively restore
- parts of it after the layer is closed. */
- if (!lo_SaveDocState(block, state))
- return PR_FALSE;
-
- state->float_list = NULL;
- state->line_list = NULL;
-
- if (state->top_state->base_url)
- block->old_base_url = XP_STRDUP(state->top_state->base_url);
-
- if (is_inflow)
- return PR_TRUE;
-
- /*
- * XXX This doesn't seem right. We're saving some of the doc's
- * layout state and resetting all of it while the block
- * is laid out. This layout state will be restored once the block
- * is completed. However, things like the float_list are part of the
- * incremental layout state as well as a representation of the final
- * document. So, if we're asked to redraw while the block is being laid
- * out, we will probably do the wrong thing for floating elements.
- */
-
- /* Unspecified height won't change state's height property. */
- if (height == 0)
- height = state->win_height;
-
- state = lo_InitDocState(state, context,
- width, height,
- 0, 0, /* margin_width, margin_height */
- NULL, /* clone_state */
- layer_state->doc_lists, PR_TRUE);
-
- if (!state)
- return PR_FALSE;
-
- /* Though most state variables are reset to their virgin state (in
- lo_InitDocState, above), there are a few state variables
- related to table layout that are preserved when a layer tag is
- opened. */
- saved_state = block->saved_state;
- state->is_a_subdoc = saved_state->is_a_subdoc;
- state->in_relayout = saved_state->in_relayout;
- state->subdoc_tags = saved_state->subdoc_tags;
- state->subdoc_tags_end = saved_state->subdoc_tags_end;
-
- state->text_fg = saved_state->text_fg;
- state->text_bg = saved_state->text_bg;
- state->anchor_color = saved_state->anchor_color;
- state->visited_anchor_color = saved_state->visited_anchor_color;
- state->active_anchor_color = saved_state->active_anchor_color;
-
- return PR_TRUE;
- }
-
- static char layer_end_tag[] = "</" PT_LAYER ">";
- static char layer_suppress_tag[] = "<" PT_LAYER " suppress>";
- static char display_none_style[] = PARAM_STYLE "='display:none'>";
-
- #ifdef XP_MAC
- PRIVATE
- #endif
- void
- lo_insert_suppress_tags(MWContext *context, lo_TopState *top_state,
- LO_BlockInitializeStruct *param)
- {
- PA_Tag *end_tag;
- int32 i;
-
- /*
- * Since we're adding tags to the blocked tags list without going through
- * lo_BlockTag, we need to see if this is a flushed to block transition
- * and, if so, add to the doc_data's ref count. We don't want to do this
- * if we're in the process of flushing blockage - in that case, the count
- * has already been incremented.
- */
- if (top_state->tags == NULL && top_state->flushing_blockage == FALSE)
- PA_HoldDocData(top_state->doc_data);
-
- /* If we can here through a LAYER or ILAYER tag */
- if (param->tag) {
- /*
- * Shove in a </LAYER><LAYER suppress> sequence into the
- * tag stream so that all inline content of this layer is
- * suppressed. The sourced content comes in before the
- * first end tag, the inline conent comes in after the
- * <LAYER suppress> tag.
- */
- end_tag = pa_CreateMDLTag(top_state->doc_data,
- layer_end_tag,
- sizeof layer_end_tag - 1);
-
- if (end_tag) {
- end_tag->newline_count = LO_IGNORE_TAG_MARKER;
- end_tag->next = pa_CreateMDLTag(top_state->doc_data,
- layer_suppress_tag,
- sizeof layer_suppress_tag - 1);
- if (end_tag->next) {
- end_tag->next->newline_count = LO_IGNORE_TAG_MARKER;
- if (top_state->tags == NULL)
- top_state->tags_end = &end_tag->next->next;
- else
- end_tag->next->next = top_state->tags;
- top_state->tags = end_tag;
-
- /*
- * If there are any other input_write_levels on the stack
- * that correspond to the front of the tag list, move them
- * to account for the newly inserted tags.
- */
- for (i = 0; i < top_state->input_write_level; i++)
- if (top_state->input_write_point[i] == &top_state->tags)
- top_state->input_write_point[i] = &end_tag->next->next;
- }
- else {
- top_state->out_of_memory = TRUE;
- PA_FreeTag(end_tag);
- }
- }
- else
- top_state->out_of_memory = TRUE;
- }
- /*
- * If we came here through the include-source style and
- * the tag is a container tag
- */
- else if (param->ss_tag && !lo_IsEmptyTag(param->ss_tag->type)) {
- /*
- * Shove in a </Foo><Foo STYLE="display:none"> sequence into
- * the tag stream. The sourced content comes in before the
- * first end tag, the inline conent comes in after the
- * display:none tag and is ignored.
- */
- end_tag = (PA_Tag *)XP_NEW_ZAP(PA_Tag);
-
- if (end_tag) {
- end_tag->type = param->ss_tag->type;
- end_tag->is_end = TRUE;
- end_tag->newline_count = LO_IGNORE_TAG_MARKER;
-
- end_tag->next = PA_CloneMDLTag(param->ss_tag);
- if (end_tag->next) {
- PA_Tag *begin_tag = end_tag->next;
-
- begin_tag->newline_count = LO_IGNORE_TAG_MARKER;
- if (begin_tag->data)
- PA_FREE(begin_tag->data);
- /* Can't do a strdup because it's parser memory */
- begin_tag->data_len = XP_STRLEN(display_none_style);
- begin_tag->true_len = begin_tag->data_len;
- begin_tag->data = PA_ALLOC(begin_tag->data_len + 1);
- if (begin_tag->data) {
- char *buff;
-
- /* Copy over the new tag data */
- PA_LOCK(buff, char *, begin_tag->data);
- XP_BCOPY(display_none_style, buff, begin_tag->data_len);
- buff[begin_tag->data_len] = '\0';
- PA_UNLOCK(buff);
-
- if (top_state->tags == NULL)
- top_state->tags_end = &begin_tag->next;
- else
- begin_tag->next = top_state->tags;
- top_state->tags = end_tag;
- }
- else {
- top_state->out_of_memory = TRUE;
- PA_FreeTag(begin_tag);
- PA_FreeTag(end_tag);
- }
- }
- else {
- top_state->out_of_memory = TRUE;
- PA_FreeTag(end_tag);
- }
- }
- else
- top_state->out_of_memory = TRUE;
- }
- }
-
-
- /* Start a <LAYER> or an <ILAYER>. */
- #ifdef XP_MAC
- PRIVATE
- #endif
- void
- lo_begin_layer_internal(MWContext *context,
- lo_DocState *state,
- LO_BlockInitializeStruct *param,
- XP_Bool is_inflow)
- {
- INTL_CharSetInfo c = LO_GetDocumentCharacterSetInfo(context);
- int16 win_csid = INTL_GetCSIWinCSID(c);
- lo_Block *block;
- lo_LayerDocState *layer_state, *parent_layer_state;
- char *str, *layer_name;
- int32 block_wrap_width, x_parent_offset, y_parent_offset;
- int32 block_x, block_y;
- lo_TopState *top_state;
- XP_Rect bbox;
- PRBool hidden, inherit_visibility;
- CL_Layer *layer, *parent_layer;
- char *backdrop_image_url = NULL;
- LO_Color rgb, *bg_color = NULL;
- char *url = NULL;
-
- if (!context->compositor || !param)
- return;
-
- /*
- * If this is a nested inflow layer, then flush the line list into our parent
- * (without introducing a line break). This ensures that whatever line changes
- * (specifically shifting of cell origin) that occur while laying out this ilayer
- * are reflected in our parent.
- */
- if (lo_InsideInflowLayer(state) && is_inflow)
- {
- lo_FlushLineList(context, state, LO_LINEFEED_BREAK_SOFT, LO_CLEAR_NONE, FALSE);
- }
-
- top_state = state->top_state;
- block = XP_NEW_ZAP(lo_Block);
- if (block == NULL)
- {
- state->top_state->out_of_memory = TRUE;
- return;
- }
- block->context = context;
- layer_state = lo_NewLayerState(context);
- if (layer_state == NULL) {
- state->top_state->out_of_memory = TRUE;
- lo_DeleteBlock(block);
- return;
- }
- layer_state->temp_block = block;
-
- /* Retain MATCH attribute for use in comparison of attribute of
- same name in matching closing layer tag. */
- block->match_code = NULL;
- if (param->tag) {
- char *match =
- (char*)PA_FetchParamValue(param->tag, PARAM_MATCH, win_csid);
- if (match) {
- block->match_code = XP_STRDUP(match);
- PA_FREE(match);
- }
- }
-
- block->name = NULL;
- block->above = NULL;
- block->below = NULL;
- hidden = PR_FALSE;
- inherit_visibility = PR_TRUE;
- block->z_order = -1;
- block->old_layer_state = NULL;
-
- /* If there is no tag associated with this layer, then it was
- created as a result of a style sheet. */
- block->uses_ss_positioning = (param->tag == NULL);
-
- block->is_inflow = is_inflow;
-
- /* In-flow layers use coordinates that are relative to their
- "natural", in-flow position. */
- if (block->is_inflow) {
- block->x_offset = state->x;
- block->y_offset = state->y;
- } else {
- block->x_offset = 0;
- block->y_offset = 0;
- }
-
-
- x_parent_offset = y_parent_offset = 0;
- parent_layer_state = lo_CurrentLayerState(state);
- parent_layer = parent_layer_state->layer;
- if (parent_layer) /* Paranoia */
- lo_GetLayerXYShift(parent_layer, &x_parent_offset, &y_parent_offset);
-
- /*
- * Get the X position of the block
- */
- if (param->has_left)
- {
- block_x = param->left;
- } else {
- if (block->is_inflow) {
- block_x = 0;
- } else {
- block_x = state->x - x_parent_offset;
- }
- }
-
- /*
- * Get the Y position of the block
- */
- if (param->has_top)
- {
- block_y = param->top;
- } else {
- if (block->is_inflow) {
- block_y = 0;
- } else {
- block_y = state->y - y_parent_offset;
- }
- }
-
- XP_BZERO(&bbox, sizeof(bbox));
-
- /*
- * Get the width parameter, in absolute or percentage.
- * If percentage, make it absolute.
- */
- if (param->has_width)
- block_wrap_width = param->width;
- else if (param->has_left)
- block_wrap_width = state->right_margin - param->left;
- else
- block_wrap_width = state->right_margin - state->x;
-
- /*
- * Parse the comma separated coordinate list into an
- * array of integers.
- */
- if (param->clip)
- {
- bbox = *param->clip;
-
- /* Don't allow the layer's clip to expand */
- block->clip_expansion_policy = param->clip_expansion_policy;
- } else {
- /* Allow the clip to expand to include the layer's contents. */
- block->clip_expansion_policy = LO_AUTO_EXPAND_CLIP;
- if (param->has_width)
- bbox.right = block_wrap_width;
- }
-
- if (param->has_height) {
- layer_state->height = param->height;
- /* If no CLIP set, set initial bottom edge of layer clip to be
- the same as HEIGHT. */
- if (block->clip_expansion_policy & LO_AUTO_EXPAND_CLIP_BOTTOM)
- bbox.bottom = param->height;
- }
-
- /* Treat any value of OVERFLOW, except "hidden" to be the same as
- "visible". For compatibility with the older CSS positioning
- spec, we also treat "none" specially. Can't set OVERFLOW
- unless HEIGHT is provided. */
- if (param->has_height &&
- param->overflow &&
- XP_STRCASECMP(param->overflow, "none") &&
- XP_STRCASECMP(param->overflow, "visible")) {
-
- /* Constrain all drawing to {0, 0, width, height} box */
- XP_Rect *viewRect = &layer_state->viewRect;
- viewRect->left = 0;
- viewRect->top = 0;
- viewRect->right = block_wrap_width;
- viewRect->bottom = param->height;
- }
-
- /*
- * Get the optional name for this layer.
- */
- layer_name = NULL;
- if(param->name)
- layer_name = param->name;
- else if(param->id)
- layer_name = param->id;
-
- /* Don't allow layer names that start with a number or underscore */
- if (layer_name && ((layer_name[0] < '0') || (layer_name[0] > '9')) &&
- (layer_name[0] != '_'))
- block->name = XP_STRDUP(layer_name);
-
- /*
- * Get the optional "above" name for the layer we are above.
- */
- if(param->above)
- block->above = XP_STRDUP(param->above);
-
- /*
- * Get the optional "below" name for the layer we are below.
- */
- if (!block->above)
- {
- if(param->below)
- block->below = XP_STRDUP(param->below);
-
- if (!block->below)
- {
- /*
- * Get the Z-order of the block
- */
- if (param->has_zindex)
- {
- block->z_order = param->zindex;
- }
- }
- }
-
- /* Get the VISIBILITY parameter to know if this layer starts hidden. */
- if (param->visibility)
- {
- /* Handle "HIDE", "HIDDEN", etc. */
- hidden = (PRBool)!XP_STRNCASECMP(param->visibility, "hid", 3);
- inherit_visibility = (PRBool)!XP_STRCASECMP(param->visibility, "inherit");
- }
-
- if (is_inflow)
- {
- /* Add a new LO_LAYER dummy layout element to the line list. Relayout will step through
- the line list and reflow the layer when the LO_LAYER element is encountered. */
- if (!lo_AppendLayerElement(context, state, FALSE))
- return;
- }
-
- /* Reset document layout state, saving old state to be restored
- after we lay out this layer. */
- if (!lo_SetupDocStateForLayer(state, layer_state,
- block_wrap_width, layer_state->height,
- (PRBool)is_inflow)) {
- state->top_state->out_of_memory = TRUE;
- lo_DeleteLayerState(context, state, layer_state);
- return;
- }
-
- block->cell = layer_state->cell =
- (LO_CellStruct *)lo_NewElement(context, state,
- LO_CELL, NULL, 0);
- if (block->cell == NULL)
- {
- state->top_state->out_of_memory = TRUE;
- lo_DeleteLayerState(context, state, layer_state);
- return;
- }
- lo_init_block_cell(context, state, block);
-
- /* Create the layer that corresponds to this block, initially invisible
- and with empty clip and [0,0] origin. */
- PA_LOCK(str, char *, block->name);
- layer = lo_CreateBlockLayer(context,
- str,
- (PRBool)block->is_inflow,
- block->x_offset,
- block->y_offset,
- block_wrap_width,
- layer_state, state);
- PA_UNLOCK(block->name);
- if (!layer) {
- state->top_state->out_of_memory = TRUE;
- lo_DeleteLayerState(context, state, layer_state);
- return;
- }
- block->layer = layer_state->layer = layer;
- if (block->is_inflow)
- block->cell->cell_inflow_layer = layer;
-
- /* Indicate that this layer's contents were not obtained as a
- result of setting the JavaScript 'src' property of the layer. */
- block->is_dynamic = FALSE;
- block->is_inline = TRUE;
-
- /*
- * Attach the layer doc_state to the layer list. The return
- * value is the old layer_state if we're in table relayout.
- * We need to wait till we're done processing this layer tag
- * before we actually get rid of the layer_state and its
- * contents.
- */
- block->old_layer_state = lo_append_to_layer_array(context, state->top_state,
- state,
- layer_state);
-
- /* Attach the layer into the layer tree */
- lo_AttachHTMLLayer(context, layer, parent_layer,
- block->above, block->below, block->z_order);
-
- /* Reflect the layer into JavaScript */
- ET_ReflectObject(context, NULL, param->tag,
- parent_layer_state->id,
- layer_state->id, LM_LAYERS);
-
- /* Process background color (BGCOLOR) attribute, if present. */
- if (param->bgcolor) {
-
- XP_Bool rv;
- if(param->is_style_bgcolor)
- rv = LO_ParseStyleSheetRGB(param->bgcolor, &rgb.red, &rgb.green, &rgb.blue);
- else
- rv = LO_ParseRGB(param->bgcolor, &rgb.red, &rgb.green, &rgb.blue);
- if(rv)
- bg_color = &rgb;
- }
- if (bg_color)
- LO_SetLayerBgColor(layer, bg_color);
-
- /* Process backdrop (BACKGROUND) image attribute, if present. */
- if(param->bgimage)
- backdrop_image_url = XP_STRDUP(param->bgimage);
-
- if (!bg_color && !backdrop_image_url) {
- /* This is a transparent block, so let's go offscreen */
- CL_ChangeLayerFlag(layer, CL_PREFER_DRAW_OFFSCREEN, PR_TRUE);
- }
- if (backdrop_image_url) {
- LO_SetLayerBackdropURL(layer, backdrop_image_url);
- XP_FREE(backdrop_image_url);
- }
-
- lo_SetLayerClipExpansionPolicy(layer, block->clip_expansion_policy);
-
- /* Move layer into position. Set clip dimensions and initial visibility. */
- LO_MoveLayer(layer, block_x, block_y);
- LO_SetLayerBbox(layer, &bbox);
- lo_expand_parent_bbox(layer);
- CL_ChangeLayerFlag(layer, CL_HIDDEN, hidden);
- #ifdef XP_MAC
- CL_ChangeLayerFlag(layer, CL_OVERRIDE_INHERIT_VISIBILITY,
- (PRBool)!inherit_visibility);
- #else
- CL_ChangeLayerFlag(layer, CL_OVERRIDE_INHERIT_VISIBILITY,
- (int32)!inherit_visibility);
- #endif
-
- /* Push this layer on the layer stack */
- lo_PushLayerState(state->top_state, layer_state);
- #ifdef MOCHA
- ET_SetActiveLayer(context, layer_state->id);
- #endif /* MOCHA */
- state->layer_nest_level++;
-
- if (param->src) {
- url = NET_MakeAbsoluteURL(top_state->base_url, param->src);
- if (url == NULL) {
- top_state->out_of_memory = TRUE;
- return;
- }
- }
-
- if ((url != NULL) && (top_state->doc_data != NULL)) {
- URL_Struct *url_struct;
- int status;
-
- block->source_url = XP_STRDUP(url);
- block->is_inline = FALSE;
- url_struct = NET_CreateURLStruct(url, top_state->force_reload);
- if (block->source_url == NULL || url_struct == NULL) {
- top_state->out_of_memory = TRUE;
- if (url_struct != NULL)
- NET_FreeURLStruct(url_struct);
- }
- else {
- char *referer;
- lo_LayerStack *lptr;
-
- /*
- * The referer for this SRC="url" fetch will be the base document
- * url if there are no enclosing out-of-line or dynamic layer tags,
- * otherwise it will be the nearest enclosing layer block's source
- * url (set via a previous SRC= or by LO_PrepareLayerForWriting).
- */
- referer = top_state->base_url;
- lptr = top_state->layer_stack->next;
- while (lptr && lptr->layer_state &&
- (lptr->layer_state->id != LO_DOCUMENT_LAYER_ID)) {
- lo_Block *temp_block;
-
- temp_block = lptr->layer_state->temp_block;
- if (temp_block &&
- (!temp_block->is_inline || temp_block->is_dynamic)) {
- referer = temp_block->source_url;
- break;
- }
- lptr = lptr->next;
- }
-
- url_struct->referer = XP_STRDUP(referer);
- if (url_struct->referer == NULL) {
- top_state->out_of_memory = TRUE;
- NET_FreeURLStruct(url_struct);
- return;
- }
-
- /*
- * We're blocking on the current element till we
- * read in the new stream.
- */
- top_state->layout_blocking_element = (LO_Element *)block->cell;
-
- lo_insert_suppress_tags(context, top_state, param);
-
- /*
- * New tags will be inserted at the start of the
- * blocked tags list.
- */
- top_state->input_write_point[top_state->input_write_level] =
- &top_state->tags;
-
- lo_SetBaseUrl(state->top_state, url, FALSE);
- XP_FREEIF(top_state->inline_stream_blocked_base_url);
-
- status = NET_GetURL(url_struct, FO_CACHE_AND_PRESENT_INLINE, context,
- lo_block_src_exit_fn);
-
- if (status < 0)
- top_state->layout_blocking_element = NULL;
-
- }
- XP_FREE(url);
- }
- }
-
- static Bool
- lo_create_layer_blockage(MWContext *context, lo_DocState *state)
- {
- lo_TopState *top_state;
- top_state = state->top_state;
-
- top_state->layout_blocking_element
- = lo_NewElement(context, state, LO_CELL, NULL, 0);
- if (top_state->layout_blocking_element == NULL) {
- top_state->out_of_memory = TRUE;
- } else {
- top_state->layout_blocking_element->type = LO_CELL;
- top_state->layout_blocking_element->lo_any.ele_id = NEXT_ELEMENT;
- top_state->layout_blocking_element->lo_cell.cell_list = NULL;
- top_state->layout_blocking_element->lo_cell.cell_list_end = NULL;
- top_state->layout_blocking_element->lo_cell.cell_float_list = NULL;
- top_state->layout_blocking_element->lo_cell.cell_bg_layer = NULL;
- top_state->layout_blocking_element->lo_cell.backdrop.bg_color = NULL;
- }
-
- return(top_state->layout_blocking_element != NULL);
- }
-
- typedef struct
- {
- MWContext *context;
- lo_DocState *state;
- XP_Bool is_inflow;
- int32 doc_id;
- } lo_RestoreLayerClosure;
-
- static void
- lo_RestoreLayerExitFn(void *myclosure,
- LO_BlockInitializeStruct *param)
- {
- lo_RestoreLayerClosure *closure = (lo_RestoreLayerClosure *)myclosure;
- MWContext *context = closure->context;
- lo_DocState *state = closure->state;
- lo_TopState *top_state;
- int32 doc_id = closure->doc_id;
- PRBool flushp = (PRBool)(param->src == NULL);
- LO_Element *blocking_element;
-
- if (doc_id == XP_DOCID(context)) {
- top_state = state->top_state;
- /*
- * We check that we're still blocking, since it's possible that
- * something's come along and changed things under us e.g. if
- * the context is interrupted while we were out to mocha.
- */
- blocking_element = top_state->layout_blocking_element;
- if (blocking_element)
- lo_begin_layer_internal(context, state, param, closure->is_inflow);
- }
-
- XP_FREE(closure);
-
- /* Get rid of the cloned tag */
- if(param->tag) {
- PA_FreeTag(param->tag);
- }
- else if (param->ss_tag) {
- PA_FreeTag(param->ss_tag);
- }
-
- lo_FreeBlockInitializeStruct(param);
-
- /* Get rid of the fake layout blocking element */
- if ((doc_id == XP_DOCID(context)) &&
- (blocking_element)) {
- lo_FreeElement(context, blocking_element, FALSE);
-
- /*
- * If there was a SRC attribute in the param list, then
- * the block layout will have created a new blocking element.
- * Otherwise, flush the blocked list and carry on as if
- * nothing happened.
- */
- if (flushp) {
- top_state->layout_blocking_element = NULL;
- lo_FlushBlockage(context, state, state->top_state->doc_state);
- }
- }
- }
-
- XP_Bool
- lo_BeginLayer(MWContext *context,
- lo_DocState *state,
- LO_BlockInitializeStruct *param,
- XP_Bool is_inflow)
- {
- if (!context->compositor || !param)
- return TRUE;
-
- if (state->top_state->resize_reload && !state->in_relayout &&
- !lo_IsAnyCurrentAncestorDynamic(state) && LM_CanDoJS(context)) {
- lo_RestoreLayerClosure *closure;
- PA_Tag *new_tag;
-
- /* I guess this whole section can go away, now that we have resize
- without reload a la Mariner??? */
-
- closure = XP_NEW_ZAP(lo_RestoreLayerClosure);
- if (!closure)
- return TRUE;
-
- closure->context = context;
- closure->state = state;
- closure->is_inflow = is_inflow;
- closure->doc_id = XP_DOCID(context);
-
- /*
- * Block layout and send an event mocha to restore the layer
- * state from the preserved mocha object.
- */
- lo_create_layer_blockage(context, state);
- lo_BlockLayerTag(context, state, NULL);
-
- if (param->tag) {
- new_tag = PA_CloneMDLTag(param->tag);
- if (!new_tag) {
- state->top_state->out_of_memory = TRUE;
- return TRUE;
- }
- param->tag = new_tag;
- }
- else if (param->ss_tag) {
- new_tag = PA_CloneMDLTag(param->ss_tag);
- if (!new_tag) {
- state->top_state->out_of_memory = TRUE;
- return TRUE;
- }
- param->ss_tag = new_tag;
- }
-
- ET_RestoreLayerState(context, state->top_state->current_layer_num + 1,
- param, lo_RestoreLayerExitFn, closure);
- return FALSE;
- }
- else {
- lo_begin_layer_internal(context, state, param, is_inflow);
- return TRUE;
- }
- }
-
- void
- lo_BlockLayerTag(MWContext *context, lo_DocState *state, PA_Tag *tag)
- {
- lo_TopState *top_state;
- pa_DocData *doc_data;
-
- top_state = state->top_state;
- doc_data = top_state->doc_data;
- XP_ASSERT(doc_data != NULL && doc_data->url_struct != NULL);
- if (doc_data == NULL || doc_data->url_struct == NULL) /* Paranoia */
- return;
- }
-
- void
- lo_UnblockLayerTag(lo_DocState *state)
- {
- /*
- * I guess we don't really need this anymore, since we're not
- * maintaining a blocked_tag count.
- */
- }
-
- static void
- lo_set_layer_bbox(CL_Layer *layer, XP_Rect *bbox, PRBool grow_parent);
-
- /* A layer has expanded in order to contain its content. Expand it's
- parent also.*/
- static void
- lo_expand_parent_bbox(CL_Layer *layer)
- {
- XP_Rect parent_bbox, child_bbox;
- CL_Compositor *compositor = CL_GetLayerCompositor(layer);
-
- /* Get the parent's and child's bbox */
- CL_Layer *parent_layer = CL_GetLayerParent(layer);
-
- if (! parent_layer)
- return;
-
- CL_GetLayerBbox(parent_layer, &parent_bbox);
- CL_GetLayerBbox(layer, &child_bbox);
-
- /* Convert the child and parent to the same coordinate system. */
- CL_LayerToWindowRect(compositor, parent_layer, &parent_bbox);
- CL_LayerToWindowRect(compositor, layer, &child_bbox);
-
- /* Expand the parent's bbox to encompass the child layer. */
- XP_RectsBbox(&child_bbox, &parent_bbox, &parent_bbox);
- CL_WindowToLayerRect(compositor, parent_layer, &parent_bbox);
- lo_set_layer_bbox(parent_layer, &parent_bbox, PR_TRUE);
-
- lo_expand_parent_bbox(parent_layer);
- }
-
- /* Set the clipping bounds of a layer, but don't override any
- explicit clip set by the user with the CLIP attribute. */
- static void
- lo_set_layer_bbox(CL_Layer *layer, XP_Rect *bbox, PRBool grow_parent)
- {
- XP_Rect new_bbox, old_bbox;
-
- int clip_expansion_policy = lo_GetLayerClipExpansionPolicy(layer);
-
- CL_GetLayerBbox(layer, &old_bbox);
- XP_CopyRect(&old_bbox, &new_bbox);
-
- if (clip_expansion_policy & LO_AUTO_EXPAND_CLIP_LEFT)
- new_bbox.left = bbox->left;
-
- if (clip_expansion_policy & LO_AUTO_EXPAND_CLIP_RIGHT)
- new_bbox.right = bbox->right;
-
- if (clip_expansion_policy & LO_AUTO_EXPAND_CLIP_TOP)
- new_bbox.top = bbox->top;
-
- if (clip_expansion_policy & LO_AUTO_EXPAND_CLIP_BOTTOM)
- new_bbox.bottom = bbox->bottom;
-
- /* If the layer's clip didn't change, there's nothing to do */
- if (XP_EqualRect(&old_bbox, &new_bbox))
- return;
-
- LO_SetLayerBbox(layer, &new_bbox);
-
- /* Expand the parent layer's bbox to contain this child's bbox */
- if (grow_parent)
- lo_expand_parent_bbox(layer);
- }
-
- /* Expand the layer associated with an HTML block in case the block
- has grown. Don't expand the layer's width if the width is fixed
- and don't expand the layer's height if the height is fixed. */
- static void
- lo_block_grown(lo_Block *block)
- {
- CL_Layer *layer = block->layer;
- lo_LayerDocState *layer_state;
- LO_CellStruct *cell = block->cell;
-
- XP_Rect clip, existing_clip;
-
- clip.left = cell->x;
- clip.top = cell->y;
- clip.right = cell->x + cell->width;
- clip.bottom = cell->y + cell->height;
-
- layer_state = lo_GetLayerState(layer);
- layer_state->contentWidth = cell->width;
- layer_state->contentHeight = cell->height;
-
- /* The coordinates of elements inside in-flow layers is with respect
- to the containing layer. */
- if (block->is_inflow)
- XP_OffsetRect(&clip, -block->start_x, -block->start_y);
-
- /* Don't allow a layer's clip to shrink. */
- CL_GetLayerBbox(layer, &existing_clip);
- XP_RectsBbox(&existing_clip, &clip, &clip);
-
- lo_set_layer_bbox(layer, &clip, (PRBool)!block->is_dynamic);
- }
-
- static LO_CellStruct *
- lo_compose_block(MWContext *context, lo_DocState *state, lo_Block *block)
- {
- int32 shift;
- XP_Rect update_rect, ele_bbox;
- LO_Element *tptr;
- LO_CellStruct *cell;
-
- cell = block->cell;
-
- XP_BZERO(&update_rect, sizeof(XP_Rect));
-
- /* Expands the dimensions of the cell to encompass any floating
- * elements that are outside its bounds.
- */
- tptr = state->float_list;
- while (tptr != NULL) {
- lo_GetElementBbox(tptr, &ele_bbox);
-
- shift = cell->x - ele_bbox.left;
- if (shift > 0) {
- cell->x -= shift;
- cell->width += shift;
- }
- shift = ele_bbox.right - (cell->x + cell->width);
- if (shift > 0)
- cell->width += shift;
- shift = cell->y - ele_bbox.top;
- if (shift > 0) {
- cell->y -= shift;
- cell->height += shift;
- }
- shift = ele_bbox.bottom - (cell->y + cell->height);
- if (shift > 0)
- cell->height += shift;
-
- XP_RectsBbox(&ele_bbox, &update_rect, &update_rect);
-
- tptr = tptr->lo_any.next;
- }
- tptr = state->float_list;
- cell->cell_float_list = tptr;
-
- if (context->compositor) {
- /* Expand the block layer. */
- lo_block_grown(block);
-
- if (block->is_inflow)
- XP_OffsetRect(&update_rect, -block->start_x, -block->start_y);
-
- /* Update the area occupied by the floating elements. */
- CL_UpdateLayerRect(context->compositor, block->layer, &update_rect,
- PR_FALSE);
- }
-
- return(cell);
- }
-
- /* Process a </LAYER> or </ILAYER> tag. */
- void
- lo_EndLayerTag(MWContext *context,
- lo_DocState *state,
- PA_Tag *tag)
- {
- INTL_CharSetInfo c = LO_GetDocumentCharacterSetInfo(context);
- int16 win_csid = INTL_GetCSIWinCSID(c);
- lo_LayerDocState *layer_state = lo_CurrentLayerState(state);
- lo_Block *block = layer_state->temp_block;
-
- if (! block)
- return;
-
- /* If opening layer tag had a MATCH attribute. The value of the
- MATCH attribute in the closing tag must be identical or we
- refuse to really close the layer. This capability is used by
- libmime to prevent renegade mail messages from escaping the
- bounds of their layer-enforced encapsulation using extra layer
- end tags in the message. */
- if (block->match_code) {
- char *attempted_match =
- (char*)PA_FetchParamValue(tag, PARAM_MATCH, win_csid);
- if (!attempted_match)
- return;
- if (XP_STRCMP(attempted_match, block->match_code)) {
- XP_TRACE(("Failed attempt to circumvent mail message security"));
- XP_ASSERT(0);
- PA_FREE(attempted_match);
- return;
- }
- PA_FREE(attempted_match);
- }
-
- lo_EndLayer(context, state, PR_TRUE);
- }
-
- static PRBool
- lo_destroy_ancillary_child_layers(CL_Layer *layer, void *unused)
- {
- LO_LayerType type;
- type = LO_GetLayerType(layer);
- if (type == LO_GROUP_LAYER)
- return PR_TRUE;
- CL_DestroyLayer(layer);
- return PR_TRUE;
- }
-
- void
- lo_EndLayer(MWContext *context,
- lo_DocState *state,
- PRBool send_load_event)
- {
- int32 right_edge;
- LO_CellStruct *cell;
- lo_LayerDocState *enclosing_layer_state;
- lo_LayerDocState *layer_state = lo_CurrentLayerState(state);
- lo_Block *block = layer_state->temp_block;
-
- /* During destruction, the compositor can disappear out from underneath us. */
- if (!context->compositor)
- return;
-
- /*
- * Protect from bad params.
- */
- if (! block) {
- return;
- }
-
- if (! block->is_inflow) {
- lo_CloseOutLayout(context, state);
- }
- else {
- /*
- * Flush out the last line of the block, without
- * introducing a line break.
- * BUGBUG In reality, calling lo_FlushLineList
- * also introduces a linefeed. We've set it up
- * so that linefeeds within blocks are of 0
- * size, so the linefeed is effectively ignored.
- * The 0 linefeed stuff is a hack!
- */
- lo_FlushLineList(context, state, LO_LINEFEED_BREAK_SOFT, LO_CLEAR_NONE, FALSE);
- }
-
- cell = lo_compose_block(context, state, block);
-
- /* For an in-flow layer, expand the enclosing cell's size on the
- right and bottom edges to contain any descendant
- layers. However, we only do this for ILAYER tags, not for
- layers created as a result of 'position:relative' applied to
- style-sheet elements. */
- if (block->is_inflow && !block->uses_ss_positioning) {
- int32 grow_width, grow_height;
- XP_Rect bbox;
-
- CL_GetLayerBbox(block->layer, &bbox);
- grow_width = (bbox.right - cell->width);
- grow_height = (bbox.bottom - cell->height);
-
- /* Position of right-edge of cell containing layer */
- right_edge = state->x;
-
- /* If the inflow layer is caused to grow vertically, force a
- line break. */
- if (grow_height > 0) {
- lo_SetSoftLineBreakState(context, state, FALSE, 1);
- cell->height = bbox.bottom;
- state->y += grow_height;
- }
-
- /* Compute new position of cell's right edge. */
- if (grow_width > 0) {
- right_edge += grow_width;
- cell->width = bbox.right;
- }
-
- /* Set minimum and maximum possible layout widths so that any
- enclosing table cells will be dimensioned properly. */
- if (right_edge + state->win_right > state->max_width)
- state->max_width = right_edge + state->win_right;
- if (right_edge + state->win_right > state->min_width)
- state->min_width = right_edge + state->win_right;
- }
-
- /* Restore document layout state, if necessary */
- lo_RestoreDocState(block, state);
-
- if (block->is_inflow)
- {
- /* Mark the </LAYER> tag by appending a LO_LAYER element to the line list. */
- if (!lo_AppendLayerElement(context, state, TRUE))
- return;
- }
-
- if (cell != NULL && !block->is_inflow)
- {
- int32 max_y;
-
- cell->next = NULL;
- cell->ele_id = NEXT_ELEMENT;
- lo_RenumberCell(state, cell);
-
- /* XXX - Do we really want to expand the document size to
- include the layer ? */
- max_y = cell->y + cell->y_offset + cell->height;
- if (max_y > state->max_height)
- {
- state->max_height = max_y;
- }
- }
-
- /*
- * If we're in table relayout, we can now safely delete the
- * layer from a previous layout pass.
- */
- if (state->in_relayout && block->old_layer_state) {
- /* Get rid of child image layers, cell background layers, embedded window layers and blink layers */
- CL_ForEachChildOfLayer(block->old_layer_state->layer,
- lo_destroy_ancillary_child_layers,
- (void *)block->old_layer_state->layer);
- CL_DestroyLayer(block->old_layer_state->layer);
- }
-
- state->layer_nest_level--;
- lo_PopLayerState(state);
- #ifdef MOCHA
- enclosing_layer_state = lo_CurrentLayerState(state);
- ET_SetActiveLayer(context, enclosing_layer_state->id);
- #endif /* MOCHA */
-
- if (block->is_dynamic) {
- lo_TopState * top_state;
-
- top_state = state->top_state;
- top_state->nurl = NULL;
- top_state->layout_status = PA_COMPLETE;
-
- lo_CloseMochaWriteStream(top_state, EVENT_LOAD);
-
- lo_FreeLayoutData(context, state);
-
- /*
- * We force a composite so that the layer is drawn, even
- * if it is immediately changed again (as is sometimes the
- * case when we're dynamically resizing layers.
- */
- if (context->compositor) {
- XP_Rect bbox;
-
- CL_GetLayerBbox(block->layer, &bbox);
- CL_UpdateLayerRect(context->compositor, block->layer,
- &bbox, PR_TRUE);
- }
- }
-
- #ifdef MOCHA
- if (send_load_event)
- ET_SendLoadEvent(context, EVENT_LOAD, NULL, NULL, layer_state->id,
- state->top_state->resize_reload);
- #endif
-
- lo_DeleteBlock(block);
- layer_state->temp_block = NULL;
- }
-
- void
- lo_AddLineListToLayer(MWContext *context,
- lo_DocState *state,
- LO_Element *line_list_end)
- {
- int32 max_y, max_x, min_x, height, width;
- LO_Element *line_list;
- LO_CellStruct *cell;
- lo_LayerDocState *layer_state = lo_CurrentLayerState(state);
- lo_Block *block = layer_state->temp_block;
-
- line_list = state->line_list;
- if (line_list == NULL)
- return;
-
- cell = block->cell;
-
- /*
- * For dynamic src changing, we just refresh the area occupied by
- * the old layer. For the autoexpanding case, we reset the size
- * of the layer to zero.
- */
- if ((cell->cell_list == NULL) && (cell->cell_float_list == NULL)) {
-
- /* If no page background color is specified, we must
- commit to one as soon as any layout element is
- displayed in order to avoid the excessive flashing that
- would occur had we created the background later. */
- if (state->top_state->nothing_displayed != FALSE) {
- lo_use_default_doc_background(context, state);
- state->top_state->nothing_displayed = FALSE;
- }
-
- if (block->is_dynamic) {
- XP_Rect bbox;
-
- CL_GetLayerBbox(block->layer, &bbox);
- CL_UpdateLayerRect(context->compositor, block->layer, &bbox, PR_FALSE);
-
- if (block->clip_expansion_policy == LO_AUTO_EXPAND_CLIP)
- {
- XP_Rect empty_bbox = {0, 0, 0, 0};
-
- CL_SetLayerBbox(block->layer, &empty_bbox);
- }
- }
- }
-
- if (cell->cell_list_end == NULL)
- {
- line_list->lo_any.prev = NULL;
- cell->cell_list = line_list;
- line_list_end->lo_any.next = NULL;
- cell->cell_list_end = line_list_end;
- }
- else
- {
- cell->cell_list_end->lo_any.next = line_list;
- line_list->lo_any.prev = cell->cell_list_end;
- line_list_end->lo_any.next = NULL;
- cell->cell_list_end = line_list_end;
- }
-
- max_y = line_list_end->lo_any.y + line_list_end->lo_any.y_offset +
- line_list_end->lo_any.height;
-
- if (block->is_inflow)
- height = max_y - cell->y;
- else
- height = max_y;
- if (height > cell->height)
- cell->height = height;
-
- /*
- * If the new line extends past the previous bounds of the
- * cell, extend the bounds of the cell.
- */
- max_x = line_list_end->lo_any.x + line_list_end->lo_any.x_offset +
- line_list_end->lo_any.width;
-
- if (block->is_inflow)
- width = max_x - cell->x;
- else
- width = max_x;
- if (width > cell->width)
- cell->width = width;
-
- /*
- * This deals with the case where the new line laid out
- * has a start position to the left of the start of the
- * block. This can happen if the layer (with no absolute
- * positioning starts to the right of an element that
- * been aligned left and then its contents flow to the
- * left of the start position below the aligned element i.e.
- *
- * *******
- * ******* -----
- * ******* -----
- * ******* -----
- * -------------
- * -------------
- *
- * where * represents the element aligned left (an image
- * for instance) and - represents the contents of the layer.
- * The layer is shifted left (to the start position of
- * the new line and expanded) i.e.
- *
- * *******
- * ####### -----
- * ####### -----
- * ####### -----
- * -------------
- * -------------
- *
- * where # represents the (transparent) part of the layer
- * overlapping the aligned element.
- */
- min_x = line_list->lo_any.x + line_list->lo_any.x_offset;
- if (min_x < cell->x) {
- cell->width += cell->x - min_x;
- cell->x = min_x;
- }
-
- if (context->compositor && (block->layer != NULL)) {
- int32 min_y;
- XP_Rect update_rect;
-
- /* Expand the block layer. */
- lo_block_grown(block);
-
- /* Update the area of the line we just added. */
- min_y = max_y - state->line_height;
- update_rect.left = min_x;
- update_rect.top = min_y;
- update_rect.right = max_x;
- update_rect.bottom = max_y;
-
- if (block->is_inflow)
- XP_OffsetRect(&update_rect, -block->start_x, -block->start_y);
-
- CL_UpdateLayerRect(context->compositor, block->layer, &update_rect,
- PR_FALSE);
- }
- }
-
-
- void
- lo_FinishLayerLayout(MWContext *context, lo_DocState *state, int mocha_event)
- {
- lo_TopState *top_state = state->top_state;
- PA_Tag *tag;
-
- /* End the current block if we're done processing all tags */
- if ((top_state->layout_blocking_element == NULL) &&
- (top_state->tags == NULL))
- lo_EndLayer(context, state, PR_TRUE);
- /* We're still blocked on something, so
- * create a fake </LAYER> tag and add it to the end of the
- * blocked list. Processing this tag will eventually close
- * out layout.
- */
- else
- {
- tag = pa_CreateMDLTag(top_state->doc_data,
- layer_end_tag,
- sizeof layer_end_tag - 1);
-
- if (tag != NULL) {
- /* Put it at the end of the tag list */
- if (top_state->tags == NULL)
- top_state->tags = tag;
- else
- *top_state->tags_end = tag;
- top_state->tags_end = &tag->next;
- }
- else
- top_state->out_of_memory = TRUE;
- }
- }
-
- static void
- lo_block_src_setter_exit_fn(URL_Struct *url_struct,
- int status,
- MWContext *context)
- {
- NET_FreeURLStruct(url_struct);
- }
-
- static lo_Block *
- lo_init_block(MWContext *context, lo_DocState *state,
- lo_LayerDocState *layer_state, int32 block_x, int32 block_y,
- int32 width)
- {
- lo_Block *block;
-
- /* Create a new block and initialize it */
- block = XP_NEW_ZAP(lo_Block);
- if (block == NULL)
- return NULL;
- block->context = context;
-
- layer_state->temp_block = block;
-
- if (!lo_SetupDocStateForLayer(state, layer_state,
- width, layer_state->height, PR_FALSE)) {
- lo_DeleteBlock(block);
- layer_state->temp_block = NULL;
- return NULL;
- }
-
- return block;
- }
-
- static PRBool
- lo_remove_extra_layers(CL_Layer *child, void *closure)
- {
- LO_LayerType type;
- CL_Layer *parent = (CL_Layer *)closure;
-
- type = LO_GetLayerType(child);
- if ((type == LO_HTML_BLOCK_LAYER) || (type == LO_HTML_BACKGROUND_LAYER))
- return PR_TRUE;
- CL_RemoveChild(parent, child);
- LO_LockLayout();
- CL_DestroyLayerTree(child);
- LO_UnlockLayout();
- return PR_TRUE;
- }
-
- Bool
- LO_PrepareLayerForWriting(MWContext *context, int32 layer_id,
- const char *referer, int32 width)
- {
- int32 doc_id;
- lo_TopState *top_state;
- lo_DocState *state;
- CL_Layer *layer;
- lo_LayerDocState *layer_state;
- lo_Block *block;
- int32 block_x, block_y;
-
- /* Get the top state of the document */
- doc_id = XP_DOCID(context);
- top_state = lo_FetchTopState(doc_id);
- if ((top_state == NULL)||(top_state->doc_state == NULL))
- {
- return FALSE;
- }
- state = top_state->doc_state;
-
- /*
- * XXX For now, if we're still loading, we can't
- * change the src of a layer. Is this the right
- * thing to check that we're done with the original
- * HTML stream?
- */
- if ((top_state->doc_data != NULL) || lo_InsideLayer(state))
- return FALSE;
-
- layer_state = lo_GetLayerStateFromId(context, layer_id);
- if (!layer_state)
- return FALSE;
- layer = layer_state->layer;
-
- /* Delete the contents of the old layer */
- lo_SaveFormElementStateInFormList(context,
- layer_state->doc_lists->form_list,
- TRUE);
- if (layer_state->cell)
- lo_RecycleElements(context, state, (LO_Element *)layer_state->cell);
- lo_DeleteDocLists(context, layer_state->doc_lists);
-
- /*
- * Get rid of all "extra" layers associated (blink, cell_bg, images, etc.)
- * associated with this layer and its content. Get rid of all group
- * layer descendants, too.
- */
- CL_ForEachChildOfLayer(layer,
- lo_remove_extra_layers,
- (void *)layer);
- /*
- * XXX We're assuming that FinishLayout has already been called and
- * some of the doc_state has been trashed. Here we reset some of the
- * state so that new tags can be parsed.
- */
- state->base_font_size = DEFAULT_BASE_FONT_SIZE;
- state->font_stack = lo_DefaultFont(state, context);
- state->line_buf = PA_ALLOC(LINE_BUF_INC * sizeof(char));
- if (state->line_buf == NULL) {
- state->top_state->out_of_memory = TRUE;
- return FALSE;
- }
- state->line_buf_size = LINE_BUF_INC;
- state->line_buf_len = 0;
-
- /*
- * We reset the script_tag_count so that we'll reset the
- * mocha decoder stream.
- */
- top_state->script_tag_count = 0;
-
- block_x = CL_GetLayerXOffset(layer);
- block_y = CL_GetLayerYOffset(layer);
-
- if (!lo_InitDocLists(context, layer_state->doc_lists)) {
- state->top_state->out_of_memory = FALSE;
- return FALSE;
- }
-
- block = lo_init_block(context, state, layer_state, block_x, block_y,
- width);
- if (block)
- block->cell = (LO_CellStruct *)lo_NewElement(context, state,
- LO_CELL, NULL, 0);
-
- if ((block == NULL) || (block->cell == NULL))
- {
- state->top_state->out_of_memory = TRUE;
- if (block) {
- lo_DeleteBlock(block);
- layer_state->temp_block = NULL;
- }
-
- return FALSE;
- }
-
- layer_state->cell = block->cell;
-
- lo_init_block_cell(context, state, block);
-
- block->layer = layer;
- block->is_dynamic = TRUE;
- block->is_inline = TRUE;
- block->source_url = referer ? XP_STRDUP(referer) : NULL;
-
- state->layer_nest_level++;
- /* Push this layer on the layer stack */
- lo_PushLayerState(state->top_state, layer_state);
- #ifdef MOCHA
- ET_SetActiveLayer(context, layer_state->id);
- #endif /* MOCHA */
-
- block->clip_expansion_policy = lo_GetLayerClipExpansionPolicy(layer);
-
- return TRUE;
- }
-
-
- Bool
- LO_SetLayerSrc(MWContext *context, int32 layer_id, char *str,
- const char *referer, int32 width)
- {
- int32 doc_id;
- lo_TopState *top_state;
- lo_DocState *state;
- char *url;
- URL_Struct *url_struct;
- int status;
- lo_LayerDocState *layer_state;
-
- /* Get the top state of the document */
- doc_id = XP_DOCID(context);
- top_state = lo_FetchTopState(doc_id);
- if ((top_state == NULL)||(top_state->doc_state == NULL))
- {
- return FALSE;
- }
- state = top_state->doc_state;
-
- if (!LO_PrepareLayerForWriting(context, layer_id, referer, width))
- return FALSE;
-
- layer_state = lo_CurrentLayerState(state);
- if (layer_state && layer_state->temp_block)
- layer_state->temp_block->is_inline = FALSE;
-
- /* Ask netlib to start loading the new URL */
- url = NET_MakeAbsoluteURL(top_state->base_url, str);
- if (url == NULL) {
- /*lo_Block *block;*/
-
- top_state->out_of_memory = TRUE;
- /* XXX block = state->current_block;
- if (block) {
- lo_RecycleElements(context, state, (LO_Element *)block->cell);
- XP_DELETE(block);
- }
- state->current_block = NULL; */
- return FALSE;
- }
-
- url_struct = NET_CreateURLStruct(url, top_state->force_reload);
- if (url_struct == NULL)
- top_state->out_of_memory = TRUE;
- else {
- url_struct->referer = XP_STRDUP(referer);
- if (!url_struct->referer) {
- top_state->out_of_memory = TRUE;
- NET_FreeURLStruct(url_struct);
- XP_FREE(url);
- return FALSE;
- }
-
- lo_SetBaseUrl(state->top_state, url, FALSE);
- XP_FREEIF(top_state->inline_stream_blocked_base_url);
-
- status = NET_GetURL(url_struct, FO_CACHE_AND_PRESENT_INLINE, context,
- lo_block_src_setter_exit_fn);
- }
-
- XP_FREE(url);
- return TRUE;
- }
-
- /* Create an anonymous layer, not tied to the HTML source.
- Returns -1 on error, 0 if unable to create a new layer because the parser
- stream is still active. */
- int32
- LO_CreateNewLayer(MWContext *context, int32 wrap_width, int32 parent_layer_id)
- {
- int32 doc_id, layer_id;
- LO_BlockInitializeStruct *param;
- CL_Layer *parent_layer;
- lo_TopState *top_state;
- lo_DocState *state;
- lo_LayerDocState *layer_state;
- CL_Layer *layer;
-
- doc_id = XP_DOCID(context);
- top_state = lo_FetchTopState(doc_id);
- if (!top_state)
- return 0;
-
- /*
- * XXX For now, if we're still loading, we can't
- * change the src of a layer. Is this the right
- * thing to check that we're done with the original
- * HTML stream?
- */
- state = top_state->doc_state;
- if ((top_state->doc_data != NULL) || lo_InsideLayer(state))
- return 0;
-
- param = XP_NEW_ZAP(LO_BlockInitializeStruct);
- if(!param)
- return -1;
-
- param->has_width = PR_TRUE;
- param->width = wrap_width;
- param->has_left = PR_TRUE;
- param->left = 0;
- param->has_top = PR_TRUE;
- param->top = 0;
- param->visibility = "hide";
- param->clip_expansion_policy = LO_AUTO_EXPAND_CLIP;
-
- layer_id = top_state->max_layer_num;
-
- /* Create a fake layer and append it to the document */
- lo_begin_layer_internal(context, state, param, FALSE);
- lo_EndLayer(context, state, PR_FALSE);
- XP_FREE(param);
-
- /* The only way we know if we succeeded is to see if the
- top_state->layers array has grown. */
- if (layer_id == top_state->max_layer_num)
- return -1;
-
- /* Reparent the layer, in case the parent wasn't the _DOCUMENT */
- parent_layer = LO_GetLayerFromId(context, parent_layer_id);
- layer_id = top_state->max_layer_num;
- layer_state = lo_GetLayerStateFromId(context, layer_id);
- layer_state->is_constructed_layer = PR_TRUE;
- layer = layer_state->layer;
- CL_RemoveChild(CL_GetLayerParent(layer), layer);
- CL_InsertChild(parent_layer, layer, NULL, CL_ABOVE);
-
- return layer_id;
- }
-