gecko-dev/lib/layout/layfree.c

1052 lines
23 KiB
C

/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "xp.h"
#include "layout.h"
#ifdef EDITOR
#include "edt.h"
#endif
#ifdef JAVA
#include "java.h"
#endif
#include "layers.h"
#include "pa_parse.h"
#define IL_CLIENT /* XXXM12N Defined by Image Library clients */
#include "libimg.h" /* Image Library public API. */
extern void NPL_DeleteSessionData(MWContext*, void*);
#ifdef PROFILE
#pragma profile on
#endif
static void
lo_FreeNVListItems(lo_NVList* list)
{
if (list->names != NULL)
{
uint32 current;
for (current=0; current<list->n; current++)
{
PA_FREE(list->names[current]);
list->names[current] = NULL;
}
PA_FREE(list->names);
list->names = NULL;
}
if (list->values != NULL)
{
int32 current;
for (current=0; current<list->n; current++)
{
PA_FREE(list->values[current]);
list->values[current] = NULL;
}
PA_FREE(list->values);
list->values = NULL;
}
list->n = 0;
}
void
lo_FreeFormElementData(LO_FormElementData *element_data)
{
int32 element_type;
if (element_data == NULL)
{
return;
}
element_type = element_data->type;
switch(element_type)
{
case FORM_TYPE_TEXT:
case FORM_TYPE_PASSWORD:
case FORM_TYPE_FILE:
{
lo_FormElementTextData *form_data;
form_data = (lo_FormElementTextData *)
element_data;
if (form_data->name != NULL)
{
PA_FREE(form_data->name);
}
if (form_data->default_text != NULL)
{
PA_FREE(form_data->default_text);
}
if (form_data->current_text != NULL)
{
PA_FREE(form_data->current_text);
}
}
break;
case FORM_TYPE_SUBMIT:
case FORM_TYPE_RESET:
case FORM_TYPE_BUTTON:
case FORM_TYPE_HIDDEN:
case FORM_TYPE_READONLY:
{
lo_FormElementMinimalData *form_data;
form_data = (lo_FormElementMinimalData *)
element_data;
if (form_data->name != NULL)
{
PA_FREE(form_data->name);
}
if (form_data->value != NULL)
{
PA_FREE(form_data->value);
}
}
break;
case FORM_TYPE_RADIO:
case FORM_TYPE_CHECKBOX:
{
lo_FormElementToggleData *form_data;
form_data = (lo_FormElementToggleData *)
element_data;
if (form_data->name != NULL)
{
PA_FREE(form_data->name);
}
if (form_data->value != NULL)
{
PA_FREE(form_data->value);
}
}
break;
case FORM_TYPE_TEXTAREA:
#ifdef ENDER
case FORM_TYPE_HTMLAREA :
#endif /*ENDER*/
{
lo_FormElementTextareaData *form_data;
form_data = (lo_FormElementTextareaData *)
element_data;
if (form_data->name != NULL)
{
PA_FREE(form_data->name);
}
if (form_data->default_text != NULL)
{
PA_FREE(form_data->default_text);
}
if (form_data->current_text != NULL)
{
PA_FREE(form_data->current_text);
}
}
break;
case FORM_TYPE_SELECT_ONE:
case FORM_TYPE_SELECT_MULT:
{
int i;
lo_FormElementSelectData *form_data;
lo_FormElementOptionData *options;
form_data = (lo_FormElementSelectData *)
element_data;
if (form_data->name != NULL)
{
PA_FREE(form_data->name);
}
if (form_data->option_cnt > 0)
{
PA_LOCK(options,
lo_FormElementOptionData *,
form_data->options);
for (i=0; i < form_data->option_cnt; i++)
{
if (options[i].text_value != NULL)
{
PA_FREE(options[i].text_value);
}
if (options[i].value != NULL)
{
PA_FREE(options[i].value);
}
}
PA_UNLOCK(form_data->options);
PA_FREE(form_data->options);
}
}
break;
case FORM_TYPE_KEYGEN:
{
lo_FormElementKeygenData *form_data;
form_data = (lo_FormElementKeygenData *)
element_data;
if (form_data->name != NULL)
{
PA_FREE(form_data->name);
}
if (form_data->challenge != NULL)
{
PA_FREE(form_data->challenge);
}
if (form_data->value_str != NULL)
{
XP_FREE(form_data->value_str);
}
}
break;
case FORM_TYPE_OBJECT:
{
lo_FormElementObjectData *form_data;
form_data = (lo_FormElementObjectData *)
element_data;
if (form_data->name != NULL)
{
PA_FREE(form_data->name);
}
}
break;
default:
break;
}
}
void
lo_CleanFormElementData(LO_FormElementData *element_data)
{
int32 element_type;
if (element_data == NULL)
{
return;
}
element_type = element_data->type;
switch(element_type)
{
case FORM_TYPE_TEXT:
case FORM_TYPE_PASSWORD:
case FORM_TYPE_FILE:
{
lo_FormElementTextData *form_data;
form_data = (lo_FormElementTextData *)
element_data;
if (form_data->name != NULL)
{
PA_FREE(form_data->name);
form_data->name = NULL;
}
if (form_data->default_text != NULL)
{
PA_FREE(form_data->default_text);
form_data->default_text = NULL;
}
}
break;
case FORM_TYPE_SUBMIT:
case FORM_TYPE_RESET:
case FORM_TYPE_BUTTON:
case FORM_TYPE_READONLY:
{
lo_FormElementMinimalData *form_data;
form_data = (lo_FormElementMinimalData *)
element_data;
if (form_data->name != NULL)
{
PA_FREE(form_data->name);
form_data->name = NULL;
}
if (form_data->value != NULL)
{
PA_FREE(form_data->value);
form_data->value = NULL;
}
}
break;
case FORM_TYPE_HIDDEN:
{
lo_FormElementMinimalData *form_data;
form_data = (lo_FormElementMinimalData *)
element_data;
if (form_data->name != NULL)
{
PA_FREE(form_data->name);
form_data->name = NULL;
}
}
break;
case FORM_TYPE_RADIO:
case FORM_TYPE_CHECKBOX:
{
lo_FormElementToggleData *form_data;
form_data = (lo_FormElementToggleData *)
element_data;
if (form_data->name != NULL)
{
PA_FREE(form_data->name);
form_data->name = NULL;
}
if (form_data->value != NULL)
{
PA_FREE(form_data->value);
form_data->value = NULL;
}
}
break;
case FORM_TYPE_TEXTAREA:
#ifdef ENDER
case FORM_TYPE_HTMLAREA :
#endif /*ENDER*/
{
lo_FormElementTextareaData *form_data;
form_data = (lo_FormElementTextareaData *)
element_data;
if (form_data->name != NULL)
{
PA_FREE(form_data->name);
form_data->name = NULL;
}
if (form_data->default_text != NULL)
{
PA_FREE(form_data->default_text);
form_data->default_text = NULL;
}
}
break;
case FORM_TYPE_SELECT_ONE:
case FORM_TYPE_SELECT_MULT:
{
/* OPTION arrays are freed later
int i;
lo_FormElementOptionData *options;
*/
lo_FormElementSelectData *form_data;
form_data = (lo_FormElementSelectData *)
element_data;
if (form_data->name != NULL)
{
PA_FREE(form_data->name);
form_data->name = NULL;
}
/* OPTION arrays are freed later
if (form_data->option_cnt > 0)
{
PA_LOCK(options,
lo_FormElementOptionData *,
form_data->options);
for (i=0; i < form_data->option_cnt; i++)
{
if (options[i].text_value != NULL)
{
PA_FREE(options[i].text_value);
}
if (options[i].value != NULL)
{
PA_FREE(options[i].value);
}
}
PA_UNLOCK(form_data->options);
PA_FREE(form_data->options);
}
*/
}
break;
case FORM_TYPE_KEYGEN:
{
lo_FormElementKeygenData *form_data;
form_data = (lo_FormElementKeygenData *)
element_data;
if (form_data->name != NULL)
{
PA_FREE(form_data->name);
form_data->name = NULL;
}
if (form_data->challenge != NULL)
{
PA_FREE(form_data->challenge);
form_data->challenge = NULL;
}
if (form_data->value_str != NULL)
{
XP_FREE(form_data->value_str);
form_data->value_str = NULL;
}
}
break;
case FORM_TYPE_OBJECT:
{
lo_FormElementObjectData *form_data;
form_data = (lo_FormElementObjectData *)
element_data;
if (form_data->name != NULL)
{
PA_FREE(form_data->name);
form_data->name = NULL;
}
}
break;
default:
break;
}
}
PRIVATE
Bool
lo_remove_image(lo_DocLists *doc_lists, LO_Element *element)
{
LO_ImageStruct *image, *last = NULL;
for (image = doc_lists->image_list;
image != (LO_ImageStruct *)element;
image = image->next_image)
{
if (image == NULL)
break;
last = image;
}
if (image != NULL)
{
if (last != NULL)
{
last->next_image = image->next_image;
}
else
{
doc_lists->image_list = image->next_image;
}
if (image == doc_lists->last_image)
{
doc_lists->last_image = last;
}
return TRUE;
}
return FALSE;
}
/* freeTableOrCellState should should be set to TRUE to free the
associated lo_TableRec for the LO_TABLE layout element or the
lo_TableCell for an LO_CELL layout element */
void
lo_ScrapeElement(MWContext *context, LO_Element *element, Bool freeTableOrCellState )
{
if (element == NULL)
{
return;
}
#ifdef EDITOR
if ( EDT_IS_EDITOR(context) )
{
if ( element->lo_any.edit_element != NULL )
{
EDT_ResetLayoutElement(element->lo_any.edit_element, element->lo_any.edit_offset, element);
element->lo_any.edit_element = NULL;
element->lo_any.edit_offset = 0;
}
}
#endif
switch(element->type)
{
case LO_TEXT:
/* BRAIN DAMAGE: We currently override LO_ELE_INVISIBLE to flag that the text element uses the */
/* new layout scheme and hence the text ptr is not a real ptr */
if ( ( element->lo_text.text != NULL ) && !( element->lo_text.ele_attrmask & LO_ELE_INVISIBLE ))
{
PA_FREE(element->lo_text.text);
element->lo_text.text = NULL;
}
break;
case LO_LINEFEED:
case LO_HRULE:
case LO_BULLET:
break;
case LO_EDGE:
FE_FreeEdgeElement(context, (LO_EdgeStruct *)element);
break;
case LO_FORM_ELE:
/*
* these are now persistent, don't free element->lo_form.element_data
*/
element->lo_form.element_data = NULL;
break;
case LO_EMBED:
FE_FreeEmbedElement(context, (LO_EmbedStruct *)element);
if (element->lo_embed.embed_src != NULL)
{
PA_FREE(element->lo_embed.embed_src);
}
element->lo_embed.embed_src = NULL;
lo_FreeNVListItems( &element->lo_embed.attributes );
lo_FreeNVListItems( &element->lo_embed.parameters );
/*
* If there is session data here after we
* return from the front end freeing the embed
* element, they want us to save this in history,
* and pass it back if/when we come back here.
* Otherwise, save the NULL.
*/
lo_AddEmbedData(context,
element->lo_embed.objTag.session_data,
NPL_DeleteSessionData,
element->lo_embed.objTag.embed_index);
element->lo_embed.objTag.session_data = NULL;
break;
case LO_BUILTIN:
FE_FreeBuiltinElement (context, (LO_BuiltinStruct *)element);
/* maybe other stuff here */
break;
#ifdef JAVA
case LO_JAVA:
FE_HideJavaAppElement(context, element->lo_java.objTag.session_data);
if (element->lo_java.attr_code != NULL)
{
PA_FREE(element->lo_java.attr_code);
element->lo_java.attr_code = NULL;
}
if (element->lo_java.attr_codebase != NULL)
{
PA_FREE(element->lo_java.attr_codebase);
element->lo_java.attr_codebase = NULL;
}
if (element->lo_java.attr_archive != NULL)
{
PA_FREE(element->lo_java.attr_archive);
element->lo_java.attr_archive = NULL;
}
if (element->lo_java.attr_name != NULL)
{
PA_FREE(element->lo_java.attr_name);
element->lo_java.attr_name = NULL;
}
if (element->lo_java.objTag.base_url != NULL)
{
PA_FREE(element->lo_java.objTag.base_url);
element->lo_java.objTag.base_url = NULL;
}
lo_FreeNVListItems( &element->lo_java.attributes );
lo_FreeNVListItems( &element->lo_java.parameters );
/*
* If there is session data here after we
* return from the front end freeing the java applet
* element, they want us to save this in history,
* and pass it back if/when we come back here.
* Otherwise, save the NULL.
*/
lo_AddEmbedData(context,
element->lo_java.objTag.session_data,
LJ_DeleteSessionData,
element->lo_java.objTag.embed_index);
element->lo_java.objTag.session_data = NULL;
break;
#endif /* JAVA */
case LO_IMAGE:
if (element->lo_image.image_req != NULL)
IL_DestroyImage(element->lo_image.image_req);
element->lo_image.image_req = NULL;
if (element->lo_image.image_attr &&
!(element->lo_image.image_attr->attrmask & LO_ATTR_BACKDROP) &&
element->lo_image.layer) {
CL_Layer *parent = CL_GetLayerParent(element->lo_image.layer);
/* We might not have yet attached the image layer to its parent
because we don't know which layer it should be place in. */
if (parent)
CL_RemoveChild(parent, element->lo_image.layer);
CL_DestroyLayer(element->lo_image.layer);
element->lo_image.layer = NULL;
}
if (element->lo_image.alt != NULL)
{
PA_FREE(element->lo_image.alt);
}
element->lo_image.alt = NULL;
if (element->lo_image.image_url != NULL)
{
PA_FREE(element->lo_image.image_url);
}
element->lo_image.image_url = NULL;
if (element->lo_image.lowres_image_url != NULL)
{
PA_FREE(element->lo_image.lowres_image_url);
}
element->lo_image.lowres_image_url = NULL;
lo_FreeImageAttributes(element->lo_image.image_attr);
element->lo_image.image_attr = NULL;
/*
* make sure this element isn't sitting on the
* image list
*/
{
int32 doc_id;
lo_TopState *top_state;
doc_id = XP_DOCID(context);
top_state = lo_FetchTopState(doc_id);
if (top_state == NULL)
break;
/* need to remove from the top_state->image_list */
lo_remove_image(&top_state->doc_lists,
element);
}
break;
case LO_CELL:
{
int32 doc_id;
lo_TopState *top_state;
doc_id = XP_DOCID(context);
top_state = lo_FetchTopState(doc_id);
if ((top_state != NULL)&&
(top_state->doc_state != NULL))
{
lo_DocState *state;
state = top_state->doc_state;
if (element->lo_cell.cell_list != NULL)
{
if (element->lo_cell.cell_list_end != NULL)
{
element->lo_cell.cell_list_end->lo_any.next = NULL;
}
lo_RecycleElements(context, state,
element->lo_cell.cell_list);
element->lo_cell.cell_list = NULL;
element->lo_cell.cell_list_end = NULL;
}
if (element->lo_cell.cell_float_list != NULL)
{
lo_RecycleElements(context, state,
element->lo_cell.cell_float_list);
element->lo_cell.cell_float_list = NULL;
}
XP_FREEIF(element->lo_cell.backdrop.bg_color);
}
/* Free the background layer */
if ( element->lo_cell.cell_bg_layer != NULL)
{
CL_Layer *layer = element->lo_cell.cell_bg_layer;
CL_RemoveChild(CL_GetLayerParent(layer),
layer);
CL_DestroyLayer(layer);
element->lo_cell.cell_bg_layer = NULL;
}
/* Free the lo_TableCell record associated with this cell */
if ( freeTableOrCellState && element->lo_cell.table_cell != NULL )
{
lo_TopState *top_state;
lo_DocState *state;
top_state = lo_FetchTopState( XP_DOCID(context) );
state = top_state->doc_state;
if (state != NULL)
lo_free_cell_record( context, state, element->lo_cell.table_cell );
}
}
break;
case LO_TABLE:
{
if (freeTableOrCellState)
lo_ScrapeTableElement( context, (LO_TableStruct *) element );
}
break;
case LO_LIST:
if (element->lo_list.tag != NULL)
{
PA_FreeTag(element->lo_list.tag);
element->lo_list.tag = NULL;
}
break;
case LO_MULTICOLUMN:
/* should we do this? */
if (element->lo_multicolumn.tag != NULL)
{
PA_FreeTag(element->lo_multicolumn.tag);
if (element->lo_multicolumn.multicol == NULL)
{
XP_DELETE(element->lo_multicolumn.multicol);
}
element->lo_multicolumn.tag = NULL;
}
break;
case LO_BLOCKQUOTE:
/* should we do this? */
if (element->lo_blockquote.tag != NULL)
{
PA_FreeTag(element->lo_blockquote.tag);
element->lo_blockquote.tag = NULL;
}
break;
case LO_SPACER:
if (element->lo_spacer.tag != NULL)
{
PA_FreeTag(element->lo_spacer.tag);
element->lo_spacer.tag = NULL;
}
break;
case LO_TEXTBLOCK:
/* LO_TEXTBLOCK */
if ( element->lo_textBlock.text_buffer != NULL )
{
XP_FREE ( element->lo_textBlock.text_buffer );
element->lo_textBlock.text_buffer = NULL;
}
if ( element->lo_textBlock.break_table != NULL )
{
XP_FREE ( element->lo_textBlock.break_table );
element->lo_textBlock.break_table = NULL;
}
break;
}
}
void
lo_FreeElement(MWContext *context, LO_Element *element, Bool do_scrape)
{
if (element == NULL)
{
return;
}
if (do_scrape != FALSE)
{
lo_ScrapeElement(context, element, FALSE);
}
#ifdef MEMORY_ARENAS
if (EDT_IS_EDITOR(context)) {
XP_DELETE(element);
}
#else
XP_DELETE(element);
#endif /* MEMORY_ARENAS */
}
void
lo_FreeImageAttributes(LO_ImageAttr *image_attr)
{
if (image_attr)
{
if (image_attr->usemap_name)
{
XP_FREE(image_attr->usemap_name);
image_attr->usemap_name = NULL;
}
/* ***** WARNING ***** Do NOT free "usemap_ptr" here since it is a pointer
into a shared list in top_state that will get freed later. */
XP_DELETE(image_attr);
}
}
#ifdef XP_WIN16
#include <malloc.h>
#endif
int32
lo_FreeRecycleList(MWContext* context, LO_Element *recycle_list)
{
LO_Element *element;
LO_Element *eptr;
int32 cnt;
LO_LockLayout();
cnt = 0;
#ifdef MEMORY_ARENAS
if ( EDT_IS_EDITOR(context) ) {
#endif /* MEMORY_ARENAS */
eptr = recycle_list;
while (eptr != NULL)
{
element = eptr;
eptr = eptr->lo_any.next;
element->lo_any.next = NULL;
element->lo_any.prev = NULL;
XP_DELETE(element);
cnt++;
}
cnt = cnt * sizeof(LO_Element);
#ifdef MEMORY_ARENAS
}
#endif /* MEMORY_ARENAS */
#ifdef XP_WIN16
_heapmin();
#endif
LO_UnlockLayout();
return(cnt);
}
void
lo_FreeElementList(MWContext *context, LO_Element *elist)
{
LO_Element *eptr;
LO_Element *element;
eptr = elist;
while (eptr != NULL)
{
element = eptr;
eptr = eptr->lo_any.next;
lo_FreeElement(context, element, TRUE);
}
}
void
lo_FreeDocumentFormListData(MWContext *context, lo_SavedFormListData *fptr)
{
int i;
LO_FormElementData **data_list;
if (fptr == NULL)
{
return;
}
fptr->valid = FALSE;
PA_LOCK(data_list, LO_FormElementData **, fptr->data_list);
if (data_list != NULL)
{
for (i=0; i < (fptr->data_count); i++)
{
if (data_list[i] != NULL)
{
FE_FreeFormElement(context, (LO_FormElementData *)data_list[i]);
lo_FreeFormElementData(data_list[i]);
XP_DELETE(data_list[i]);
}
}
}
PA_UNLOCK(fptr->data_list);
if (fptr->data_list != NULL)
{
PA_FREE(fptr->data_list);
}
fptr->data_index = 0;
fptr->data_count = 0;
fptr->data_list = NULL;
fptr->next = NULL;
}
void
lo_FreeDocumentEmbedListData(MWContext *context, lo_SavedEmbedListData *eptr)
{
if (eptr == NULL)
{
return;
}
/* MWH -- If this routine is changed, place make sure that cmd\winfe\cxprint.cpp and
cmd\winfe\cxmeat.cpp is changed also. */
#ifdef XP_WIN
/* do not free the data, we need it for printing and metafile.*/
if (context->type == MWContextPrint || context->type == MWContextMetaFile)
return;
#endif
if (eptr->embed_data_list != NULL)
{
int32 i;
lo_EmbedDataElement* embed_data_list;
PA_LOCK(embed_data_list, lo_EmbedDataElement*, eptr->embed_data_list);
for (i=0; i < eptr->embed_count; i++)
{
if (embed_data_list[i].freeProc && embed_data_list[i].data)
(*(embed_data_list[i].freeProc))(context, embed_data_list[i].data);
}
PA_UNLOCK(eptr->embed_data_list);
PA_FREE(eptr->embed_data_list);
}
eptr->embed_count = 0;
eptr->embed_data_list = NULL;
}
void
lo_FreeDocumentGridData(MWContext *context, lo_SavedGridData *sgptr)
{
if (sgptr == NULL)
{
return;
}
if (sgptr->the_grid != NULL)
{
lo_GridRec *grid;
lo_GridCellRec *cell_ptr;
grid = sgptr->the_grid;
cell_ptr = grid->cell_list;
while (cell_ptr != NULL)
{
lo_GridCellRec *tmp_cell;
tmp_cell = cell_ptr;
cell_ptr = cell_ptr->next;
lo_FreeGridCellRec(context, grid, tmp_cell);
}
lo_FreeGridRec(grid);
}
sgptr->main_width = 0;
sgptr->main_height = 0;
sgptr->the_grid = NULL;
}
void
LO_FreeSubmitData(LO_FormSubmitData *submit_data)
{
int32 i;
PA_Block *name_array, *value_array;
if (submit_data == NULL)
{
return;
}
if (submit_data->action != NULL)
{
PA_FREE(submit_data->action);
}
PA_LOCK(name_array, PA_Block *, submit_data->name_array);
PA_LOCK(value_array, PA_Block *, submit_data->value_array);
for (i=0; i < (submit_data->value_cnt); i++)
{
if (name_array[i] != NULL)
{
PA_FREE(name_array[i]);
}
if (value_array[i] != NULL)
{
PA_FREE(value_array[i]);
}
}
PA_UNLOCK(submit_data->value_array);
PA_UNLOCK(submit_data->name_array);
if (submit_data->name_array != NULL)
{
PA_FREE(submit_data->name_array);
}
if (submit_data->value_array != NULL)
{
PA_FREE(submit_data->value_array);
}
if (submit_data->type_array != NULL)
{
PA_FREE(submit_data->type_array);
}
XP_DELETE(submit_data);
}
int32
LO_EmptyRecyclingBin(MWContext *context)
{
int32 doc_id;
lo_TopState *top_state;
int32 cnt;
/*
* Get the unique document ID, and retreive this
* documents layout state.
*/
doc_id = XP_DOCID(context);
top_state = lo_FetchTopState(doc_id);
if ((top_state == NULL)||(top_state->doc_state == NULL))
{
return(0);
}
cnt = lo_FreeRecycleList(context, top_state->recycle_list);
top_state->recycle_list = NULL;
#ifdef MEMORY_ARENAS
if (top_state->current_arena != NULL)
{
int32 cnt2;
cnt2 = lo_FreeMemoryArena(top_state->current_arena->next);
top_state->current_arena->next = NULL;
cnt += cnt2;
}
#endif /* MEMORY_ARENAS */
return(cnt);
}
#ifdef PROFILE
#pragma profile off
#endif