home *** CD-ROM | disk | FTP | other *** search
- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * The contents of this file are subject to the Netscape Public License
- * Version 1.0 (the "NPL"); you may not use this file except in
- * compliance with the NPL. You may obtain a copy of the NPL at
- * http://www.mozilla.org/NPL/
- *
- * Software distributed under the NPL is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
- * for the specific language governing rights and limitations under the
- * NPL.
- *
- * The Initial Developer of this code under the NPL is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1998 Netscape Communications Corporation. All Rights
- * Reserved.
- */
-
-
-
- #include "xp.h"
- #include "pa_parse.h"
- #include "layout.h"
- #include "laylayer.h"
- #include "laystyle.h"
- #include "libmocha.h"
- #include "stystruc.h"
- #include "stystack.h"
- #include "layers.h"
- #ifdef NSPR20
- #ifdef XP_MAC
- #include "prpriv.h"
- #else
- #include "private/prpriv.h" /* for PR_NewNamedMonitor */
- #endif
- #endif /* NSPR20 */
- #include "intl_csi.h"
-
- #ifdef EDITOR
- #include "edt.h"
- #endif
- #ifdef PROFILE
- #pragma profile on
- #endif
-
- #ifdef XP_WIN16
- #define SIZE_LIMIT 32000
- #endif /* XP_WIN16 */
-
- #define FONT_FACE_INC 10
- #define FONT_FACE_MAX 1000
-
- void
- lo_GetElementBbox(LO_Element *element, XP_Rect *rect)
- {
- rect->left = element->lo_any.x + element->lo_any.x_offset;
- rect->top = element->lo_any.y + element->lo_any.y_offset;
- rect->right = rect->left + element->lo_any.width;
- rect->bottom = rect->top + element->lo_any.height;
-
- switch(element->type)
- {
- case LO_IMAGE:
- {
- LO_ImageStruct *image = &element->lo_image;
- rect->right += 2 * (image->border_width + image->border_horiz_space);
- rect->bottom += 2 * (image->border_width + image->border_vert_space);
- }
- break;
-
- case LO_SUBDOC:
- {
- LO_SubDocStruct *subdoc = &element->lo_subdoc;
- rect->right += 2 * (subdoc->border_width + subdoc->border_horiz_space);
- rect->bottom += 2 * (subdoc->border_width + subdoc->border_vert_space);
- }
- break;
-
- case LO_TABLE:
- {
- LO_TableStruct *table = &element->lo_table;
- rect->right += 2 * (table->border_width + table->border_horiz_space);
- rect->bottom += 2 * (table->border_width + table->border_vert_space);
- }
- break;
-
- case LO_CELL:
- {
- LO_CellStruct *cell = &element->lo_cell;
- rect->right += 2 * (cell->border_width + cell->border_horiz_space);
- rect->bottom += 2 * (cell->border_width + cell->border_vert_space);
- }
- break;
-
- case LO_EMBED:
- {
- LO_EmbedStruct *embed = &element->lo_embed;
- rect->right += 2 * (embed->border_width + embed->border_horiz_space);
- rect->bottom += 2 * (embed->border_width + embed->border_vert_space);
- }
- break;
-
- #ifdef JAVA
- case LO_JAVA:
- {
- LO_JavaAppStruct *java = &element->lo_java;
- rect->right += 2 * (java->border_width + java->border_horiz_space);
- rect->bottom += 2 * (java->border_width + java->border_vert_space);
- }
- break;
- #endif
-
- default:
- break;
- }
- }
-
- void
- lo_RefreshElement(LO_Element *element, CL_Layer *layer, Bool update_now)
- {
- XP_Rect rect;
- int32 x_offset, y_offset;
- CL_Compositor *compositor = CL_GetLayerCompositor(layer);
-
- lo_GetElementBbox(element, &rect);
-
- lo_GetLayerXYShift(layer, &x_offset, &y_offset);
- XP_OffsetRect(&rect, -x_offset, -y_offset);
- CL_UpdateLayerRect(compositor, layer, &rect, (PRBool)update_now);
- }
-
- /* Given a layout element, retrieve its anchor information. */
- LO_AnchorData *
- lo_GetElementAnchor(LO_Element *element)
- {
- switch(element->type)
- {
- case LO_TEXT:
- return element->lo_text.anchor_href;
-
- case LO_IMAGE:
- return element->lo_image.anchor_href;
-
- case LO_TABLE:
- return element->lo_table.anchor_href;
-
- case LO_SUBDOC:
- return element->lo_subdoc.anchor_href;
-
- case LO_LINEFEED:
- return element->lo_linefeed.anchor_href;
-
- default:
- return NULL;
- }
- }
-
- /* Return an element's foreground color */
- void
- lo_GetElementFGColor(LO_Element *element, LO_Color *color)
- {
- switch (element->type)
- {
- case LO_TEXT:
- color->red = element->lo_text.text_attr->fg.red;
- color->green = element->lo_text.text_attr->fg.green;
- color->blue = element->lo_text.text_attr->fg.blue;
- break;
-
- case LO_IMAGE:
- color->red = element->lo_image.text_attr->fg.red;
- color->green = element->lo_image.text_attr->fg.green;
- color->blue = element->lo_image.text_attr->fg.blue;
- break;
-
- case LO_SUBDOC:
- color->red = element->lo_subdoc.text_attr->fg.red;
- color->green = element->lo_subdoc.text_attr->fg.green;
- color->blue = element->lo_subdoc.text_attr->fg.blue;
- break;
-
- default:
- XP_ASSERT(0); /* Not implemented */
- break;
- }
- }
-
- /* Set an element's foreground color */
- void
- lo_SetElementFGColor(LO_Element *element, LO_Color *color)
- {
- switch (element->type)
- {
- case LO_TEXT:
- element->lo_text.text_attr->fg.red = color->red;
- element->lo_text.text_attr->fg.green = color->green;
- element->lo_text.text_attr->fg.blue = color->blue;
- break;
-
- case LO_IMAGE:
- element->lo_image.text_attr->fg.red = color->red;
- element->lo_image.text_attr->fg.green = color->green;
- element->lo_image.text_attr->fg.blue = color->blue;
- break;
-
- case LO_SUBDOC:
- element->lo_subdoc.text_attr->fg.red = color->red;
- element->lo_subdoc.text_attr->fg.green = color->green;
- element->lo_subdoc.text_attr->fg.blue = color->blue;
- break;
-
- default:
- XP_ASSERT(0); /* Not implemented */
- break;
- }
- }
-
- void
- lo_ShiftElementList(LO_Element *e_list, int32 dx, int32 dy)
- {
- LO_Element *eptr;
-
- if (e_list == NULL)
- {
- return;
- }
-
- eptr = e_list;
- while (eptr != NULL)
- {
- eptr->lo_any.x += dx;
- eptr->lo_any.y += dy;
- if (eptr->type == LO_CELL)
- {
- lo_ShiftCell((LO_CellStruct *)eptr, dx, dy);
- }
-
- eptr = eptr->lo_any.next;
- }
- }
-
- NET_ReloadMethod
- LO_GetReloadMethod(MWContext *context)
- {
- int32 doc_id;
- lo_TopState *top_state;
- lo_DocState *state;
-
- /*
- * 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 NET_NORMAL_RELOAD;
- }
- state = top_state->doc_state;
-
- return (FORCE_RELOAD_FLAG(state->top_state));
- }
-
-
- void
- LO_InvalidateFontData(MWContext *context)
- {
- int32 i, doc_id;
- lo_TopState *top_state;
- lo_DocState *state;
- LO_TextAttr **text_attr_hash;
- LO_TextAttr *attr_ptr;
-
- /*
- * 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;
- }
- state = top_state->doc_state;
-
- if (state->top_state->text_attr_hash == NULL)
- {
- return;
- }
-
- XP_LOCK_BLOCK(text_attr_hash, LO_TextAttr **,
- state->top_state->text_attr_hash);
- for (i=0; i < FONT_HASH_SIZE; i++)
- {
- attr_ptr = text_attr_hash[i];
- while (attr_ptr != NULL)
- {
- if (attr_ptr->FE_Data != NULL)
- {
- FE_ReleaseTextAttrFeData(context, attr_ptr);
- }
- attr_ptr->FE_Data = NULL;
- attr_ptr = attr_ptr->next;
- }
- }
- }
-
-
- static char *
- lo_find_face_in_array(char **face_list, intn len, char *face)
- {
- intn i;
- char *the_face;
-
- if (face == NULL)
- {
- return(NULL);
- }
-
- the_face = NULL;
- for (i=0; i<len; i++)
- {
- if ((face_list[i] != NULL)&&
- (XP_STRCMP(face, face_list[i]) == 0))
- {
- the_face = face_list[i];
- break;
- }
- }
-
- return(the_face);
- }
-
-
- Bool
- lo_EvalTrueOrFalse(char *str, Bool default_val)
- {
- Bool ret_val;
-
- ret_val = default_val;
-
- if (str == NULL)
- {
- return(ret_val);
- }
-
- if (pa_TagEqual("true", str))
- {
- ret_val = TRUE;
- }
- else if (pa_TagEqual("yes", str))
- {
- ret_val = TRUE;
- }
- else if (pa_TagEqual("no", str))
- {
- ret_val = FALSE;
- }
- else if (pa_TagEqual("false", str))
- {
- ret_val = FALSE;
- }
-
- return(ret_val);
- }
-
- char *
- lo_FetchFontFace(MWContext *context, lo_DocState *state, char *face)
- {
- char **face_list;
- char *new_face;
-
- /*
- * If this is our first addition, allocate the array.
- */
- if (state->top_state->font_face_array == NULL)
- {
- PA_Block buff;
-
- buff = PA_ALLOC(FONT_FACE_INC * sizeof(char *));
- if (buff == NULL)
- {
- state->top_state->out_of_memory = TRUE;
- return(NULL);
- }
- state->top_state->font_face_array = buff;
- state->top_state->font_face_array_size = FONT_FACE_INC;
- state->top_state->font_face_array_len = 0;
- }
- /*
- * Else if the list is full, grow the array.
- */
- else if (state->top_state->font_face_array_len >=
- state->top_state->font_face_array_size)
- {
- PA_Block buff;
- intn new_size;
-
- if (state->top_state->font_face_array_size >= FONT_FACE_MAX)
- {
- return(NULL);
- }
-
- new_size = state->top_state->font_face_array_size +
- FONT_FACE_INC;
- if (new_size > FONT_FACE_MAX)
- {
- new_size = FONT_FACE_MAX;
- }
- buff = XP_REALLOC_BLOCK(state->top_state->font_face_array,
- (new_size * sizeof(char *)));
- if (buff == NULL)
- {
- state->top_state->out_of_memory = TRUE;
- return(NULL);
- }
- state->top_state->font_face_array = buff;
- state->top_state->font_face_array_size = new_size;
- }
-
- PA_LOCK(face_list, char **, state->top_state->font_face_array);
- new_face = lo_find_face_in_array(face_list,
- state->top_state->font_face_array_len, face);
- if (new_face == NULL)
- {
- char *str;
-
- str = XP_STRDUP(face);
- if (str == NULL)
- {
- PA_UNLOCK(state->top_state->font_face_array);
- state->top_state->out_of_memory = TRUE;
- return(NULL);
- }
- face_list[state->top_state->font_face_array_len] = str;
- state->top_state->font_face_array_len++;
- new_face = str;
- }
- PA_UNLOCK(state->top_state->font_face_array);
- return(new_face);
- }
-
-
- Bool
- lo_IsValidTarget(char *target)
- {
- if (target == NULL)
- {
- return(FALSE);
- }
- if ((XP_IS_ALPHA(target[0]) != FALSE)||
- (XP_IS_DIGIT(target[0]) != FALSE)||
- (target[0] == '_'))
- {
- return(TRUE);
- }
- return(FALSE);
- }
-
-
- int32
- lo_StripTextNewlines(char *text, int32 text_len)
- {
- char *from_ptr;
- char *to_ptr;
- int32 len;
-
- if ((text == NULL)||(text_len < 1))
- {
- return(0);
- }
-
- /*
- * remove all non-space whitespace from the middle of the string.
- */
- from_ptr = text;
- len = text_len;
- to_ptr = text;
- while (*from_ptr != '\0')
- {
- if (XP_IS_SPACE(*from_ptr) && (*from_ptr != ' '))
- {
- from_ptr++;
- len--;
- }
- else
- {
- *to_ptr++ = *from_ptr++;
- }
- }
- *to_ptr = '\0';
-
- return(len);
- }
-
-
- PA_Block
- lo_FEToNetLinebreaks(PA_Block text_block)
- {
- PA_Block new_block;
- char *new_text;
- char *text;
- char *from_ptr;
- char *to_ptr;
- char break_char;
- int32 len, new_len;
- int32 linebreak;
-
- if (text_block == NULL)
- {
- return(NULL);
- }
- PA_LOCK(text, char *, text_block);
-
- XP_BCOPY(LINEBREAK, (char *)(&break_char), 1);
- len = 0;
- linebreak = 0;
- from_ptr = text;
- while (*from_ptr != '\0')
- {
- if (*from_ptr == break_char)
- {
- if (strncmp(from_ptr, LINEBREAK, LINEBREAK_LEN) == 0)
- {
- linebreak++;
- len += LINEBREAK_LEN;
- from_ptr = (char *)(from_ptr + LINEBREAK_LEN);
- }
- else
- {
- len++;
- from_ptr++;
- }
- }
- else
- {
- len++;
- from_ptr++;
- }
- }
-
- new_len = len - (LINEBREAK_LEN * linebreak) + (2 * linebreak);
- new_block = PA_ALLOC(new_len + 1);
- if (new_block == NULL)
- {
- PA_UNLOCK(text_block);
- return(NULL);
- }
- PA_LOCK(new_text, char *, new_block);
- from_ptr = text;
- to_ptr = new_text;
- while (*from_ptr != '\0')
- {
- if (*from_ptr == break_char)
- {
- if (strncmp(from_ptr, LINEBREAK, LINEBREAK_LEN) == 0)
- {
- from_ptr = (char *)(from_ptr + LINEBREAK_LEN);
- *to_ptr++ = CR;
- *to_ptr++ = LF;
- }
- else
- {
- *to_ptr++ = *from_ptr++;
- }
- }
- else
- {
- *to_ptr++ = *from_ptr++;
- }
- }
- *to_ptr = '\0';
-
- new_text[new_len] = '\0';
- PA_UNLOCK(new_block);
- PA_UNLOCK(text_block);
- return(new_block);
- }
-
-
- PA_Block
- lo_ConvertToFELinebreaks(char *text, int32 text_len, int32 *new_len_ptr)
- {
- PA_Block new_block;
- char *new_text;
- char *from_ptr;
- char *to_ptr;
- char break_char;
- int32 len, new_len;
- int32 skip, linebreak;
-
- if (text == NULL)
- {
- return(NULL);
- }
-
- break_char = '\0';
- len = 0;
- skip = 0;
- linebreak = 0;
- from_ptr = text;
- to_ptr = text;
- while (len < text_len)
- {
- if ((*from_ptr == CR)||(*from_ptr == LF))
- {
- if ((break_char != '\0')&&(break_char != *from_ptr))
- {
- skip++;
- break_char = '\0';
- }
- else
- {
- skip++;
- linebreak++;
- break_char = *from_ptr;
- }
- }
- from_ptr++;
- len++;
- }
-
- new_len = len - skip + (LINEBREAK_LEN * linebreak);
- new_block = PA_ALLOC(new_len + 1);
- if (new_block == NULL)
- {
- return(NULL);
- }
- PA_LOCK(new_text, char *, new_block);
- break_char = '\0';
- len = 0;
- from_ptr = text;
- to_ptr = new_text;
- while (len < text_len)
- {
- if ((*from_ptr == CR)||(*from_ptr == LF))
- {
- if ((break_char != '\0')&&(break_char != *from_ptr))
- {
- break_char = '\0';
- }
- else
- {
- XP_BCOPY(LINEBREAK, to_ptr, LINEBREAK_LEN);
- to_ptr = (char *)(to_ptr + LINEBREAK_LEN);
- break_char = *from_ptr;
- }
- from_ptr++;
- len++;
- }
- else
- {
- *to_ptr++ = *from_ptr++;
- len++;
- }
- }
-
- new_text[new_len] = '\0';
- *new_len_ptr = new_len;
- PA_UNLOCK(new_block);
- return(new_block);
- }
-
-
- intn
- lo_EvalVAlignParam(char *str)
- {
- intn alignment;
-
- alignment = LO_ALIGN_TOP;
- if (pa_TagEqual("top", str))
- {
- alignment = LO_ALIGN_TOP;
- }
- else if (pa_TagEqual("bottom", str))
- {
- alignment = LO_ALIGN_BOTTOM;
- }
- else if ((pa_TagEqual("middle", str))||
- (pa_TagEqual("center", str)))
- {
- alignment = LO_ALIGN_CENTER;
- }
- else if (pa_TagEqual("baseline", str))
- {
- alignment = LO_ALIGN_BASELINE;
- }
- return(alignment);
- }
-
-
- intn
- lo_EvalDivisionAlignParam(char *str)
- {
- intn alignment;
-
- alignment = LO_ALIGN_LEFT;
- if (pa_TagEqual("left", str))
- {
- alignment = LO_ALIGN_LEFT;
- }
- else if (pa_TagEqual("right", str))
- {
- alignment = LO_ALIGN_RIGHT;
- }
- else if (pa_TagEqual("center", str))
- {
- alignment = LO_ALIGN_CENTER;
- }
- else if (pa_TagEqual("justify", str))
- {
- alignment = LO_ALIGN_JUSTIFY;
- }
- return(alignment);
- }
-
-
- intn
- lo_EvalCellAlignParam(char *str)
- {
- intn alignment;
-
- alignment = LO_ALIGN_LEFT;
- if (pa_TagEqual("left", str))
- {
- alignment = LO_ALIGN_LEFT;
- }
- else if (pa_TagEqual("right", str))
- {
- alignment = LO_ALIGN_RIGHT;
- }
- else if ((pa_TagEqual("middle", str))||
- (pa_TagEqual("center", str)))
- {
- alignment = LO_ALIGN_CENTER;
- }
- return(alignment);
- }
-
- #ifdef EDITOR
- /* this is a replacement routine for the non-editor version and should eventually
- * replace the non-edit version. It uses an array of values. instead of an
- * unrolled loop.
- */
-
- /*
- * Indexed by LO_ALIGN_ETC
- */
- char* lo_alignStrings[] = {
- "abscenter", /* LO_ALIGN_CENTER */
- "left", /* LO_ALIGN_LEFT */
- "right", /* LO_ALIGN_RIGHT */
- "texttop", /* LO_ALIGN_TOP */
- "absbottom", /* LO_ALIGN_BOTTOM */
- "baseline", /* LO_ALIGN_BASELINE */
- "center", /* LO_ALIGN_NCSA_CENTER */
- "bottom", /* LO_ALIGN_NCSA_BOTTOM */
- "top", /* LO_ALIGN_NCSA */
- 0
- };
-
- intn
- lo_EvalAlignParam(char *str, Bool *floating)
- {
- intn alignment;
-
- *floating = FALSE;
- alignment = LO_ALIGN_BASELINE;
- if (pa_TagEqual("middle", str))
- {
- alignment = LO_ALIGN_NCSA_CENTER;
- }
- else if (pa_TagEqual("absmiddle", str))
- {
- alignment = LO_ALIGN_CENTER;
- }
- else
- {
- intn i = 0;
- Bool bFound = FALSE;
-
- while( lo_alignStrings[i] != NULL && bFound == FALSE )
- {
- if( pa_TagEqual( lo_alignStrings[i], str) )
- {
- bFound = TRUE;
- alignment = i;
- }
- i++;
- }
- }
- if( alignment == LO_ALIGN_LEFT || alignment == LO_ALIGN_RIGHT)
- {
- *floating = TRUE;
- }
- return alignment;
- }
-
- #else
-
- intn
- lo_EvalAlignParam(char *str, Bool *floating)
- {
- intn alignment;
-
- *floating = FALSE;
- alignment = LO_ALIGN_BASELINE;
- if (pa_TagEqual("top", str))
- {
- alignment = LO_ALIGN_NCSA_TOP;
- }
- else if (pa_TagEqual("texttop", str))
- {
- alignment = LO_ALIGN_TOP;
- }
- else if (pa_TagEqual("bottom", str))
- {
- alignment = LO_ALIGN_NCSA_BOTTOM;
- }
- else if (pa_TagEqual("absbottom", str))
- {
- alignment = LO_ALIGN_BOTTOM;
- }
- else if (pa_TagEqual("baseline", str))
- {
- alignment = LO_ALIGN_BASELINE;
- }
- else if ((pa_TagEqual("middle", str))||
- (pa_TagEqual("center", str)))
- {
- alignment = LO_ALIGN_NCSA_CENTER;
- }
- else if ((pa_TagEqual("absmiddle", str))||
- (pa_TagEqual("abscenter", str)))
- {
- alignment = LO_ALIGN_CENTER;
- }
- else if (pa_TagEqual("left", str))
- {
- alignment = LO_ALIGN_LEFT;
- *floating = TRUE;
- }
- else if (pa_TagEqual("right", str))
- {
- alignment = LO_ALIGN_RIGHT;
- *floating = TRUE;
- }
- return(alignment);
- }
- #endif
-
- /* set *alignment and *floating iff there
- * is a valid stylesheet alignment property.
- */
- MODULE_PRIVATE void
- lo_EvalStyleSheetAlignment(StyleStruct *style_struct,
- intn *alignment,
- Bool *floating)
- {
- char *valign, *halign;
-
- if(!style_struct)
- return;
-
- valign = STYLESTRUCT_GetString(style_struct,VERTICAL_ALIGN_STYLE);
- halign = STYLESTRUCT_GetString(style_struct,HORIZONTAL_ALIGN_STYLE);
-
- if(valign)
- {
- if (pa_TagEqual("top", valign))
- {
- *alignment = LO_ALIGN_NCSA_TOP;
- *floating = FALSE;
- }
- else if (pa_TagEqual("texttop", valign)
- || pa_TagEqual("text-top", valign))
- {
- *alignment = LO_ALIGN_TOP;
- *floating = FALSE;
- }
- else if (pa_TagEqual("bottom", valign))
- {
- *alignment = LO_ALIGN_NCSA_BOTTOM;
- *floating = FALSE;
- }
- else if (pa_TagEqual("absbottom", valign)
- || pa_TagEqual("text-bottom", valign))
- {
- *alignment = LO_ALIGN_BOTTOM;
- *floating = FALSE;
- }
- else if (pa_TagEqual("baseline", valign))
- {
- *alignment = LO_ALIGN_BASELINE;
- *floating = FALSE;
- }
- else if ((pa_TagEqual("middle", valign))||
- (pa_TagEqual("center", valign)))
- {
- *alignment = LO_ALIGN_NCSA_CENTER;
- *floating = FALSE;
- }
- else if ((pa_TagEqual("absmiddle", valign))||
- (pa_TagEqual("abscenter", valign)))
- {
- *alignment = LO_ALIGN_CENTER;
- *floating = FALSE;
- }
- }
-
- if(halign)
- {
- if (pa_TagEqual("left", halign))
- {
- *alignment = LO_ALIGN_LEFT;
- *floating = TRUE;
- }
- else if (pa_TagEqual("right", halign))
- {
- *alignment = LO_ALIGN_RIGHT;
- *floating = TRUE;
- }
- }
-
- XP_FREEIF(valign);
- XP_FREEIF(halign);
-
- return;
- }
-
- void
- lo_CalcAlignOffsets(lo_DocState *state, LO_TextInfo *text_info, intn alignment,
- int32 width, int32 height, int16 *x_offset, int32 *y_offset,
- int32 *line_inc, int32 *baseline_inc)
- {
- *line_inc = 0;
- *baseline_inc = 0;
- switch (alignment)
- {
- case LO_ALIGN_CENTER:
- *x_offset = 0;
- /*
- * Center after current text.
- */
- /*
- * If the image is shorter than the height
- * of this line, just increase y_offset
- * to get it centered.
- */
- if (height < state->line_height)
- {
- *y_offset += ((state->line_height - height)
- / 2);
- }
- /*
- * Else for images taller than the line
- * we will need to move all their
- * baselines down, plus increase the rest
- * of their lineheights to reflect the
- * big centered image.
- */
- else
- {
- *y_offset = 0;
- *baseline_inc = (height - state->line_height)
- / 2;
- *line_inc = height - state->line_height -
- *baseline_inc;
- }
- break;
- case LO_ALIGN_NCSA_CENTER:
- *x_offset = 0;
- /*
- * Center on baseline of current text.
- */
- /*
- * If the image centered on the baseline will not
- * extend below or above the current line,
- * just increase y_offset to get it centered.
- */
- if (((height / 2) <= state->baseline)&&
- ((height / 2) <= (state->line_height -
- state->baseline)))
- {
- *y_offset = state->baseline -
- (height / 2);
- }
- /*
- * Else the image extends over the bottom, but
- * not off the top.
- */
- else if ((height / 2) <= state->baseline)
- {
- *y_offset = state->baseline -
- (height / 2);
- *line_inc = *y_offset + height -
- state->line_height;
- }
- /*
- * Else for images taller than the line
- * we will need to move all their
- * baselines down, plus and maybe increase the rest
- * of their lineheights to reflect the
- * big centered image.
- */
- else
- {
- *y_offset = 0;
- *baseline_inc = (height / 2) - state->baseline;
- if ((state->baseline + (height / 2)) >
- state->line_height)
- {
- *line_inc = state->baseline +
- (height / 2) -
- state->line_height;
- }
- }
- break;
- case LO_ALIGN_TOP:
- *x_offset = 0;
- /*
- * Move the top of the image to the top of the
- * last text placed. On negative offsets
- * (such as at the start of a line) just
- * start the image at the top.
- */
- *y_offset = state->baseline - text_info->ascent;
- if (*y_offset < 0)
- {
- *y_offset = 0;
- }
-
- /*
- * Top aligned images can easily hang down and make
- * all the rest of the line taller. Set line_inc
- * to properly increase the height of all previous
- * elements.
- */
- if ((*y_offset + height) > state->line_height)
- {
- *line_inc = *y_offset + height -
- state->line_height;
- }
- break;
- case LO_ALIGN_NCSA_TOP:
- *x_offset = 0;
- /*
- * Move the top of the image to the top of the
- * line.
- */
- *y_offset = 0;
-
- /*
- * Top aligned images can easily hang down and make
- * all the rest of the line taller. Set line_inc
- * to properly increase the height of all previous
- * elements.
- */
- if ((*y_offset + height) > state->line_height)
- {
- *line_inc = *y_offset + height -
- state->line_height;
- }
- break;
- case LO_ALIGN_BOTTOM:
- *x_offset = 0;
- /*
- * Like centered images, images shorter than
- * the line just get move with y_offset.
- */
- if (height < state->line_height)
- {
- *y_offset = state->line_height - height;
- }
- /*
- * Else since they are bottom aligned.
- * they move everyone's baselines and can't
- * change the height below the baseline.
- */
- else
- {
- *y_offset = 0;
- *baseline_inc = height - state->line_height;
- }
- break;
- case LO_ALIGN_NCSA_BOTTOM:
- case LO_ALIGN_BASELINE:
- default:
- *x_offset = 0;
- /*
- * Like centered images, images shorter than
- * the baseline just get move with y_offset.
- */
- if (height < state->baseline)
- {
- *y_offset = state->baseline - height;
- }
- /*
- * Else since they are baseline aligned.
- * they move everyone's baselines and can't
- * change the height below the baseline.
- */
- else
- {
- *y_offset = 0;
- *baseline_inc = height - state->baseline;
- }
- break;
- }
- }
-
-
- int32
- lo_ValueOrPercent(char *str, Bool *is_percent)
- {
- int32 val;
- char *tptr;
-
- *is_percent = FALSE;
-
- if (str == NULL)
- {
- return(0);
- }
-
- tptr = str;
- while (*tptr != '\0')
- {
- if (*tptr == '%')
- {
- *is_percent = TRUE;
- *tptr = '\0';
- break;
- }
- tptr++;
- }
- val = XP_ATOI(str);
- if (*is_percent)
- *tptr = '%'; /* Restore original string */
- return(val);
- }
-
-
- void
- lo_SetElementTextAttr(LO_Element *element, LO_TextAttr *attr)
- {
- switch(element->type)
- {
- case LO_TEXT:
- element->lo_text.text_attr = attr;
- break;
-
- case LO_IMAGE:
- element->lo_image.text_attr = attr;
- break;
-
- case LO_SUBDOC:
- element->lo_subdoc.text_attr = attr;
- break;
-
- case LO_LINEFEED:
- element->lo_linefeed.text_attr = attr;
- break;
-
- case LO_FORM_ELE:
- element->lo_form.text_attr = attr;
- break;
-
- case LO_BULLET:
- element->lo_bullet.text_attr = attr;
- break;
-
- default:
- XP_ASSERT(0);
- }
- }
-
- LO_TextAttr *
- lo_GetElementTextAttr(LO_Element *element)
- {
- switch(element->type)
- {
- case LO_TEXT:
- return element->lo_text.text_attr;
-
- case LO_IMAGE:
- return element->lo_image.text_attr;
-
- case LO_SUBDOC:
- return element->lo_subdoc.text_attr;
-
- case LO_LINEFEED:
- return element->lo_linefeed.text_attr;
-
- case LO_FORM_ELE:
- return element->lo_form.text_attr;
-
- case LO_BULLET:
- return element->lo_bullet.text_attr;
-
- default:
- return NULL;
- }
- }
-
- void
- lo_CopyTextAttr(LO_TextAttr *old_attr, LO_TextAttr *new_attr)
- {
- if ((old_attr == NULL)||(new_attr == NULL))
- {
- return;
- }
-
- new_attr->size = old_attr->size;
- new_attr->fontmask = old_attr->fontmask;
-
- new_attr->fg.red = old_attr->fg.red;
- new_attr->fg.green = old_attr->fg.green;
- new_attr->fg.blue = old_attr->fg.blue;
-
- new_attr->bg.red = old_attr->bg.red;
- new_attr->bg.green = old_attr->bg.green;
- new_attr->bg.blue = old_attr->bg.blue;
-
- new_attr->no_background = old_attr->no_background;
- new_attr->attrmask = old_attr->attrmask;
- new_attr->font_face = old_attr->font_face;
- /*
- * FE_Data is not copied, it belongs to the FE,
- * And will need to be generated by the FE the first time this
- * new TextAttr is used.
- */
- new_attr->FE_Data = NULL;
-
- new_attr->charset = old_attr->charset;
- new_attr->point_size = old_attr->point_size;
- new_attr->font_weight = old_attr->font_weight;
- }
-
-
- LO_TextAttr *
- lo_FetchTextAttr(lo_DocState *state, LO_TextAttr *old_attr)
- {
- LO_TextAttr **text_attr_hash;
- LO_TextAttr *attr_ptr;
- int32 hash_index;
-
- if (old_attr == NULL)
- {
- return(NULL);
- }
-
- hash_index = (old_attr->fontmask & old_attr->attrmask) % FONT_HASH_SIZE;
-
- XP_LOCK_BLOCK(text_attr_hash, LO_TextAttr **,
- state->top_state->text_attr_hash);
- attr_ptr = text_attr_hash[hash_index];
-
- while (attr_ptr != NULL)
- {
- if ((attr_ptr->size == old_attr->size)&&
- (attr_ptr->fontmask == old_attr->fontmask)&&
- (attr_ptr->attrmask == old_attr->attrmask)&&
- (attr_ptr->fg.red == old_attr->fg.red)&&
- (attr_ptr->fg.green == old_attr->fg.green)&&
- (attr_ptr->fg.blue == old_attr->fg.blue)&&
- (attr_ptr->bg.red == old_attr->bg.red)&&
- (attr_ptr->bg.green == old_attr->bg.green)&&
- (attr_ptr->bg.blue == old_attr->bg.blue)&&
- (attr_ptr->font_face == old_attr->font_face)&&
- (attr_ptr->charset == old_attr->charset)&&
- (attr_ptr->point_size == old_attr->point_size)&&
- (attr_ptr->font_weight == old_attr->font_weight))
- {
- break;
- }
- attr_ptr = attr_ptr->next;
- }
- if (attr_ptr == NULL)
- {
- LO_TextAttr *new_attr;
-
- new_attr = XP_NEW(LO_TextAttr);
- if (new_attr != NULL)
- {
- lo_CopyTextAttr(old_attr, new_attr);
- new_attr->next = text_attr_hash[hash_index];
- text_attr_hash[hash_index] = new_attr;
- }
- else
- {
- state->top_state->out_of_memory = TRUE;
- }
- attr_ptr = new_attr;
- }
-
- XP_UNLOCK_BLOCK(state->top_state->text_attr_hash);
- return(attr_ptr);
- }
-
-
- void
- lo_AddMarginStack(lo_DocState *state, int32 x, int32 y,
- int32 width, int32 height,
- int32 border_width,
- int32 border_vert_space, int32 border_horiz_space,
- intn alignment)
- {
- lo_MarginStack *mptr;
-
- mptr = XP_NEW(lo_MarginStack);
- if (mptr == NULL)
- {
- state->top_state->out_of_memory = TRUE;
- return;
- }
-
- mptr->y_min = y;
- if (y >= 0)
- {
- mptr->y_max = y + height + (2 * border_width) +
- (2 * border_vert_space);
- }
- else
- {
- mptr->y_max = height + (2 * border_width) +
- (2 * border_vert_space);
- }
-
- if (alignment == LO_ALIGN_RIGHT)
- {
- if (state->right_margin_stack == NULL)
- {
- mptr->margin = state->right_margin - width -
- (2 * border_width) - (2 * border_horiz_space);
- }
- else
- {
- mptr->margin = state->right_margin_stack->margin -
- width - (2 * border_width) -
- (2 * border_horiz_space);
- }
- mptr->next = state->right_margin_stack;
- state->right_margin_stack = mptr;
- }
- else
- {
- mptr->margin = state->left_margin + width +
- (2 * border_width) + (2 * border_horiz_space);
- mptr->next = state->left_margin_stack;
- state->left_margin_stack = mptr;
- }
- }
-
-
- /*
- * When clipping lines we have essentially scrolled the document up.
- * Move the margin blocks up too.
- */
- void
- lo_ShiftMarginsUp(MWContext *context, lo_DocState *state, int32 dy)
- {
- lo_MarginStack *mptr;
- int32 y;
-
- mptr = state->left_margin_stack;
- while (mptr != NULL)
- {
- y = mptr->y_min - dy;
- if (y < 0)
- {
- y = 0;
- }
- mptr->y_min = y;
-
- y = mptr->y_max - dy;
- if (y < 0)
- {
- y = 0;
- }
- mptr->y_max = y;
- mptr = mptr->next;
- }
-
- mptr = state->right_margin_stack;
- while (mptr != NULL)
- {
- y = mptr->y_min - dy;
- if (y < 0)
- {
- y = 0;
- }
- mptr->y_min = y;
-
- y = mptr->y_max - dy;
- if (y < 0)
- {
- y = 0;
- }
- mptr->y_max = y;
- mptr = mptr->next;
- }
- }
-
-
- void
- lo_ClearToLeftMargin(MWContext *context, lo_DocState *state)
- {
- lo_MarginStack *mptr;
- int32 y;
-
- mptr = state->left_margin_stack;
- if (mptr == NULL)
- {
- return;
- }
- y = state->y;
-
- if (mptr->y_max > y)
- {
- y = mptr->y_max;
- }
- while (mptr->next != NULL)
- {
- lo_MarginStack *margin;
-
- if (mptr->y_max > y)
- {
- y = mptr->y_max;
- }
- margin = mptr;
- mptr = mptr->next;
- XP_DELETE(margin);
- }
- XP_DELETE(mptr);
- state->y = y;
- state->left_margin_stack = NULL;
- state->left_margin = state->win_left;
- state->x = state->left_margin;
-
- /*
- * Find where we hit the right margin, popping old
- * obsolete elements as we go.
- */
- mptr = state->right_margin_stack;
- while ((mptr != NULL)&&(state->y > mptr->y_max))
- {
- lo_MarginStack *margin;
-
- margin = mptr;
- mptr = mptr->next;
- XP_DELETE(margin);
- }
- if (mptr != NULL)
- {
- state->right_margin_stack = mptr;
- state->right_margin = mptr->margin;
- }
- else
- {
- state->right_margin_stack = NULL;
- state->right_margin = (state->list_stack != NULL)
- ? state->list_stack->old_right_margin
- : 0;
- }
- }
-
-
- void
- lo_ClearToRightMargin(MWContext *context, lo_DocState *state)
- {
- lo_MarginStack *mptr;
- int32 y;
-
- mptr = state->right_margin_stack;
- if (mptr == NULL)
- {
- return;
- }
- y = state->y;
-
- if (mptr->y_max > y)
- {
- y = mptr->y_max;
- }
- while (mptr->next != NULL)
- {
- lo_MarginStack *margin;
-
- if (mptr->y_max > y)
- {
- y = mptr->y_max;
- }
- margin = mptr;
- mptr = mptr->next;
- XP_DELETE(margin);
- }
- XP_DELETE(mptr);
- state->y = y;
- state->right_margin_stack = NULL;
- state->right_margin = state->win_width - state->win_right;
-
- /*
- * Find where we hit the left margin, popping old
- * obsolete elements as we go.
- */
- mptr = state->left_margin_stack;
- while ((mptr != NULL)&&(state->y > mptr->y_max))
- {
- lo_MarginStack *margin;
-
- margin = mptr;
- mptr = mptr->next;
- XP_DELETE(margin);
- }
- if (mptr != NULL)
- {
- state->left_margin_stack = mptr;
- state->left_margin = mptr->margin;
- }
- else
- {
- state->left_margin_stack = NULL;
- state->left_margin = (state->list_stack != NULL)
- ? state->list_stack->old_left_margin
- : 0;
- }
- }
-
-
- void
- lo_ClearToBothMargins(MWContext *context, lo_DocState *state)
- {
- lo_MarginStack *mptr;
- int32 y;
-
- y = state->y;
-
- mptr = state->right_margin_stack;
- if (mptr != NULL)
- {
- if (mptr->y_max > y)
- {
- y = mptr->y_max;
- }
- while (mptr->next != NULL)
- {
- lo_MarginStack *margin;
-
- if (mptr->y_max > y)
- {
- y = mptr->y_max;
- }
- margin = mptr;
- mptr = mptr->next;
- XP_DELETE(margin);
- }
- XP_DELETE(mptr);
- state->y = y;
- state->right_margin_stack = NULL;
-
- state->right_margin = state->win_width - state->win_right;
- }
-
- mptr = state->left_margin_stack;
- if (mptr != NULL)
- {
- if (mptr->y_max > y)
- {
- y = mptr->y_max;
- }
- while (mptr->next != NULL)
- {
- lo_MarginStack *margin;
-
- if (mptr->y_max > y)
- {
- y = mptr->y_max;
- }
- margin = mptr;
- mptr = mptr->next;
- XP_DELETE(margin);
- }
- XP_DELETE(mptr);
- if (y > state->y)
- {
- state->y = y;
- }
- state->left_margin_stack = NULL;
-
- state->left_margin = state->win_left;
- state->x = state->left_margin;
- }
- }
-
-
- void
- lo_FindLineMargins(MWContext *context, lo_DocState *state, Bool updateFE)
- {
- lo_MarginStack *mptr;
- LO_Element *eptr;
-
- eptr = state->float_list;
- /*
- while ((eptr != NULL)&&(eptr->lo_any.y < 0))
- */
- while (eptr != NULL)
- {
- LO_Element *next_eptr = NULL;
-
- if (eptr->lo_any.y < 0)
- {
- int32 expose_y;
- int32 expose_height;
- /* LO_Element *next_eptr; */
-
- next_eptr = NULL;
- /*
- * Float the y to our current position.
- */
- eptr->lo_any.y = state->y;
-
- /*
- * These get coppied into special variables because they
- * may get changed by a table in the floating list.
- */
- expose_y = eptr->lo_any.y;
- expose_height = eptr->lo_any.height;
-
- /*
- * Special case: If we have just placed a TABLE element,
- * we need to properly offset all the CELLs inside it.
- */
- if (eptr->type == LO_TABLE)
- {
- int32 y2;
- int32 change_y;
- LO_Element *tptr;
-
- /*
- * We need to know the bottom and top extents of
- * the table to know big an area to refresh.
- */
- y2 = expose_y + eptr->lo_any.y_offset + expose_height;
-
- /*
- * This is how far to move the cells based on
- * where the table thought it was placed.
- */
- change_y = state->y - eptr->lo_table.expected_y;
-
- /*
- * set tptr to the start of the cell list.
- */
- tptr = eptr->lo_any.next;
- while ((tptr != NULL)&&(tptr->type == LO_CELL))
- {
- /*
- * Only do this work if the table has moved.
- */
- if (change_y != 0)
- {
- tptr->lo_any.y += change_y;
- lo_ShiftCell((LO_CellStruct *)tptr,
- 0, change_y);
- }
-
- /*
- * Find upper and lower bounds of the
- * cells.
- */
- if (tptr->lo_any.y < expose_y)
- {
- expose_y = tptr->lo_any.y;
- }
- if ((tptr->lo_any.y + tptr->lo_any.y_offset +
- tptr->lo_any.height) > y2)
- {
- y2 = tptr->lo_any.y +
- tptr->lo_any.y_offset +
- tptr->lo_any.height;
- }
-
- tptr = tptr->lo_any.next;
- }
-
- /*
- * Whatever is after all the table cells will
- * really be the next eptr.
- */
- if (tptr != NULL)
- {
- next_eptr = tptr;
- }
-
- /*
- * Adjust exposed area height for lower bound.
- * Upper bound already possibly moved.
- */
- if ((y2 - expose_y - eptr->lo_any.y_offset) >
- expose_height)
- {
- expose_height = y2 - expose_y -
- eptr->lo_any.y_offset;
- }
- }
-
- if (updateFE)
- {
- /*
- * We may have been blocking display on this floating image.
- * If so deal with it here.
- */
- if ((state->display_blocked != FALSE)&&
- (state->is_a_subdoc == SUBDOC_NOT)&&
- (state->display_blocking_element_y == 0)&&
- (state->display_blocking_element_id != -1)&&
- (eptr->lo_any.ele_id >=
- state->display_blocking_element_id))
- {
- state->display_blocking_element_y =
- state->y;
- /*
- * Special case, if the blocking element
- * is on the first line, no blocking
- * at all needs to happen.
- */
- if (state->y == state->win_top)
- {
- state->display_blocked = FALSE;
- FE_SetDocPosition(context,
- FE_VIEW, 0, state->base_y);
-
- if (context->compositor)
- {
- XP_Rect rect;
-
- rect.left = 0;
- rect.top = 0;
- rect.right = state->win_width;
- rect.bottom = state->win_height;
- CL_UpdateDocumentRect(context->compositor,
- &rect, (PRBool)FALSE);
- }
- }
- }
-
- } /* end if (updateFE) */
-
-
-
- if (context->compositor)
- {
- XP_Rect rect;
-
- rect.left = eptr->lo_any.x + eptr->lo_any.x_offset;
- rect.top = expose_y + eptr->lo_any.y_offset;
- rect.right = rect.left + eptr->lo_any.width;
- rect.bottom = rect.top + expose_height;
- CL_UpdateDocumentRect(context->compositor,
- &rect, (PRBool)FALSE);
-
- }
-
- /*
- * In case these floating elements are the only thing in the
- * doc (or subdoc) we need to set the state min and max widths
- * when we place them.
- */
- {
- int32 width;
- XP_Rect rect;
-
- rect.left = 0;
- rect.right = 0;
- lo_GetElementBbox(eptr, &rect);
- width = rect.right - rect.left;
- if (width > 0)
- {
- if (width > state->min_width)
- {
- state->min_width = width;
- }
-
- /*
- * Only do this if not in a table
- */
- if (state->is_a_subdoc == SUBDOC_NOT)
- {
- width += rect.left;
- }
- if (width > state->max_width)
- {
- state->max_width = width;
- }
- }
-
- }
- /*
- eptr = eptr->lo_any.next;
- */
- /*
- * If we are skipping a table's cells, set eptr
- * properly now.
- */
- /*
- if (next_eptr != NULL)
- {
- eptr = next_eptr;
- }
- */
- } /* End if (eptr->lo_any.y < 0) */
-
- eptr = eptr->lo_any.next;
-
- /*
- * If we are skipping a table's cells, set eptr
- * properly now.
- */
- if (next_eptr != NULL)
- {
- eptr = next_eptr;
- }
- } /* End while */
-
- /*
- * Find floating elements just added to the left margin stack
- * from the last line, and set their absolute
- * coordinates.
- */
- mptr = state->left_margin_stack;
- while ((mptr != NULL)&&(mptr->y_min < 0))
- {
- mptr->y_min = state->y;
- mptr->y_max = mptr->y_min + mptr->y_max;
- mptr = mptr->next;
- }
-
- /*
- * Find where we hit the left margin, popping old
- * obsolete elements as we go.
- */
- mptr = state->left_margin_stack;
- while ((mptr != NULL)&&(state->y > mptr->y_max))
- {
- lo_MarginStack *margin;
-
- margin = mptr;
- mptr = mptr->next;
- XP_DELETE(margin);
- }
- if (mptr != NULL)
- {
- state->left_margin_stack = mptr;
- state->left_margin = mptr->margin;
- /*
- * For a list wrapped around a floating image we may
- * need to be indented from the image edge.
- */
- if (state->list_stack->old_left_margin > mptr->margin)
- {
- state->left_margin = state->list_stack->old_left_margin;
- }
- }
- else
- {
- state->left_margin_stack = NULL;
- state->left_margin = (state->list_stack != NULL)
- ? state->list_stack->old_left_margin
- : 0;
- }
-
- /*
- * Find floating elements just added to the right margin stack
- * from the last line, and set their absolute
- * coordinates.
- */
- mptr = state->right_margin_stack;
- while ((mptr != NULL)&&(mptr->y_min < 0))
- {
- mptr->y_min = state->y;
- mptr->y_max = mptr->y_min + mptr->y_max;
- mptr = mptr->next;
- }
-
- /*
- * Find where we hit the right margin, popping old
- * obsolete elements as we go.
- */
- mptr = state->right_margin_stack;
- while ((mptr != NULL)&&(state->y > mptr->y_max))
- {
- lo_MarginStack *margin;
-
- margin = mptr;
- mptr = mptr->next;
- XP_DELETE(margin);
- }
- if (mptr != NULL)
- {
- state->right_margin_stack = mptr;
- state->right_margin = mptr->margin;
- }
- else
- {
- state->right_margin_stack = NULL;
- state->right_margin = (state->list_stack != NULL)
- ? state->list_stack->old_right_margin
- : 0;
- }
- }
-
- void
- lo_RecycleElements(MWContext *context, lo_DocState *state, LO_Element *elements)
- {
- LO_Element *eptr;
-
- if (elements == NULL)
- {
- return;
- }
-
- eptr = elements;
- while(eptr->lo_any.next != NULL)
- {
- lo_ScrapeElement(context, eptr);
- eptr = eptr->lo_any.next;
- }
- lo_ScrapeElement(context, eptr);
- #ifdef MEMORY_ARENAS
- if ( EDT_IS_EDITOR(context) ) {
- eptr->lo_any.next = state->top_state->recycle_list;
- state->top_state->recycle_list = elements;
- }
- #else
- eptr->lo_any.next = state->top_state->recycle_list;
- state->top_state->recycle_list = elements;
- #endif /* MEMORY_ARENAS */
- }
-
-
- LO_Element *
- lo_NewElement(MWContext *context, lo_DocState *state, intn type,
- ED_Element *edit_element, intn edit_offset)
- {
- LO_Element *eptr;
-
- #ifdef MEMORY_ARENAS
- int32 size;
-
- switch(type)
- {
- case LO_TEXT:
- size = sizeof(LO_TextStruct);
- break;
- case LO_LINEFEED:
- size = sizeof(LO_LinefeedStruct);
- break;
- case LO_HRULE:
- size = sizeof(LO_HorizRuleStruct);
- break;
- case LO_IMAGE:
- size = sizeof(LO_ImageStruct);
- break;
- case LO_BULLET:
- size = sizeof(LO_BulletStruct);
- break;
- case LO_FORM_ELE:
- size = sizeof(LO_FormElementStruct);
- break;
- case LO_SUBDOC:
- size = sizeof(LO_SubDocStruct);
- break;
- case LO_TABLE:
- size = sizeof(LO_TableStruct);
- break;
- case LO_CELL:
- size = sizeof(LO_CellStruct);
- break;
- case LO_EMBED:
- size = sizeof(LO_EmbedStruct);
- break;
- #ifdef JAVA
- case LO_JAVA:
- size = sizeof(LO_JavaAppStruct);
- break;
- #endif
- case LO_EDGE:
- size = sizeof(LO_EdgeStruct);
- break;
- case LO_OBJECT:
- size = sizeof(LO_ObjectStruct);
- break;
- case LO_PARAGRAPH:
- size = sizeof(LO_ParagraphStruct);
- break;
- case LO_CENTER:
- size = sizeof(LO_CenterStruct);
- break;
- case LO_MULTICOLUMN:
- size = sizeof(LO_MulticolumnStruct);
- break;
- case LO_TEXTBLOCK:
- size = sizeof(LO_TextBlock);
- break;
- case LO_LIST:
- size = sizeof(LO_ListStruct);
- break;
- case LO_DESCTITLE:
- size = sizeof(LO_DescTitleStruct);
- break;
- case LO_DESCTEXT:
- size = sizeof(LO_DescTextStruct);
- break;
- case LO_BLOCKQUOTE:
- size = sizeof(LO_BlockQuoteStruct);
- break;
- case LO_LAYER:
- size = sizeof(LO_LayerStruct);
- break;
- case LO_SPACER:
- size = sizeof(LO_SpacerStruct);
- break;
- default:
- size = sizeof(LO_Any);
- break;
- }
- if ( ! EDT_IS_EDITOR(context) ) {
- eptr = (LO_Element *)lo_MemoryArenaAllocate(state->top_state, size);
- }
- else {
- if (state->top_state->recycle_list != NULL)
- {
- eptr = state->top_state->recycle_list;
- state->top_state->recycle_list = eptr->lo_any.next;
- }
- else
- {
- eptr = XP_NEW(LO_Element);
- }
- }
- #else
-
- /* sorry about all the asserts, in my debug version somehow state
- * becomes nil after a malloc failure. */
- #ifdef DEBUG
- assert (state);
- #endif
-
- if (state->top_state->recycle_list != NULL)
- {
- eptr = state->top_state->recycle_list;
- state->top_state->recycle_list = eptr->lo_any.next;
- }
- else
- {
- eptr = XP_NEW(LO_Element);
- #ifdef DEBUG
- assert (state);
- #endif
- }
- #endif /* MEMORY_ARENAS */
-
- if (eptr == NULL)
- {
- #ifdef DEBUG
- assert (state);
- #endif
- state->top_state->out_of_memory = TRUE;
- }
- else
- {
- eptr->lo_any.next = NULL;
- eptr->lo_any.prev = NULL;
- #ifdef EDITOR
- eptr->lo_any.edit_element = NULL;
- eptr->lo_any.edit_offset = 0;
-
- if( EDT_IS_EDITOR(context) )
- {
- if( lo_EditableElement( type ) )
- {
- if( edit_element == 0 ){
- edit_element = state->edit_current_element;
- edit_offset = state->edit_current_offset;
- }
- EDT_SetLayoutElement( edit_element,
- edit_offset,
- type,
- eptr );
- } else if( edit_element && (type == LO_TABLE || type == LO_CELL) )
- {
- /* _TABLE_EXPERIMENT_ SAVE POINTER TO EDIT ELEMENT IN LO STRUCT */
- eptr->lo_any.edit_element = edit_element;
-
- }
- }
- state->edit_force_offset = FALSE;
- #endif
- }
-
- return(eptr);
- }
-
-
- /* Add a named anchor to the global list of named anchors. This does not
- associate the anchor with a layout element. lo_SetNamedAnchor should be
- followed by a call to lo_BindNamedAnchorToElement in order to associate
- the named anchor with a layout element. */
- Bool
- lo_SetNamedAnchor(lo_DocState *state, PA_Block name)
- {
- lo_NameList *name_rec = NULL;
- lo_DocLists *doc_lists;
-
- /*
- * No named anchors are allowed within a
- * hacked scrolling content layout document.
- */
- if (state->top_state->scrolling_doc != FALSE)
- {
- if (name != NULL)
- {
- PA_FREE(name);
- }
- return FALSE;
- }
-
- doc_lists = lo_GetCurrentDocLists(state);
-
- #ifdef MOCHA
- if (state->in_relayout) {
- /* Look for the old lo_NameList. Its mocha_object is still valid. */
- lo_NameList *name_list = doc_lists->name_list;
- lo_NameList *prev;
- Bool no_match;
- char *s1, *s2;
-
- XP_ASSERT(name_list); /* If in relayout, this cannot be empty. */
-
- prev = name_list;
- name_rec = name_list;
- while (name_rec != NULL) {
- PA_LOCK(s1, char*, name);
- PA_LOCK(s2, char*, name_rec->name);
- no_match = XP_STRCMP(s1, s2);
- PA_UNLOCK(name_rec->name);
- PA_UNLOCK(name);
- if (!no_match) {
- if (name_rec == name_list)
- doc_lists->name_list = name_list->next;
- else
- prev->next = name_rec->next;
- PA_FREE(name_rec->name); /* No need for this, use new one. */
- break;
- }
- prev = name_rec;
- name_rec = name_rec->next;
- }
- }
- if (!name_rec || !state->in_relayout) {
- #endif /* MOCHA */
- name_rec = XP_NEW(lo_NameList);
- if (name_rec == NULL)
- {
- state->top_state->out_of_memory = TRUE;
- PA_FREE(name);
- return FALSE;
- }
- #ifdef MOCHA
- name_rec->mocha_object = NULL;
- }
- #endif /* MOCHA */
- name_rec->x = 0;
- name_rec->y = 0;
- name_rec->name = name;
- name_rec->element = NULL; /* Set by lo_BindNamedAnchorToElement. */
-
- name_rec->next = doc_lists->name_list;
- doc_lists->name_list = name_rec;
- return TRUE;
- }
-
- /* Associate a named anchor with a layout element. The named anchor should
- be the first one in the list of named anchors.*/
- Bool
- lo_BindNamedAnchorToElement(lo_DocState *state, PA_Block name,
- LO_Element *element)
- {
- Bool no_match;
- LO_Element *eptr;
- lo_NameList *name_rec;
- char *s1, *s2;
- lo_DocLists *doc_lists;
-
- doc_lists = lo_GetCurrentDocLists(state);
-
- if (element == NULL)
- {
- if (state->line_list == NULL)
- {
- eptr = state->end_last_line;
- }
- else
- {
- eptr = state->line_list;
- while (eptr->lo_any.next != NULL)
- {
- eptr = eptr->lo_any.next;
- }
- }
- }
- else
- {
- eptr = element;
- }
-
- /* Find the matching name_rec in the name_list */
- name_rec = doc_lists->name_list;
- PA_LOCK(s1, char*, name);
- while (name_rec != NULL)
- {
- PA_LOCK(s2, char*, name_rec->name);
- no_match = XP_STRCMP(s1, s2);
- PA_UNLOCK(name_rec->name);
- if (!no_match)
- break;
- name_rec = name_rec->next;
- }
- PA_UNLOCK(name);
- if (name_rec == NULL)
- return FALSE;
-
- if (eptr == NULL)
- {
- name_rec->x = 0;
- name_rec->y = 0;
- }
- else
- {
- name_rec->x = eptr->lo_any.x;
- name_rec->y = eptr->lo_any.y;
- }
-
- name_rec->element = eptr;
- return TRUE;
- }
-
-
- void
- lo_AddNameList(lo_DocState *state, lo_DocState *old_state)
- {
- /*
- * Now named anchors are added directly to the
- * top_state (or layer's) name_list, so we don't have to push
- * them up. We do, however, need to update their positions,
- * though it seems like this is done at the end of table
- * processing. Hence this code is no longer necessary.
- */
- #if 0
- lo_NameList *name_list;
- lo_NameList *nptr;
-
- name_list = old_state->name_list;
- while (name_list != NULL)
- {
- /*
- * Extract the current record from the list.
- */
- nptr = name_list;
- name_list = name_list->next;
-
- /*
- * The element almost certainly has been moved
- * from subdoc to main cell, correct its position.
- */
- if (nptr->element != NULL)
- {
- nptr->x = nptr->element->lo_any.x;
- nptr->y = nptr->element->lo_any.y;
- }
-
- /*
- * Stick it into the main name list.
- */
- nptr->next = state->name_list;
- state->name_list = nptr;
- }
- old_state->name_list = name_list;
- #endif /* 0 */
- }
-
-
- void
- lo_CheckNameList(MWContext *context, lo_DocState *state, int32 min_id)
- {
- lo_NameList *nptr;
- lo_DocLists *doc_lists;
-
- /*
- * Positions of named elements are only accurate if
- * we are not in a nested subdoc.
- */
- if (state->is_a_subdoc != SUBDOC_NOT)
- {
- return;
- }
-
- doc_lists = lo_GetCurrentDocLists(state);
-
- nptr = doc_lists->name_list;
- while (nptr != NULL)
- {
- /*
- * If the element's id is greater
- * than the passed minimum, then
- * the element almost certainly has been moved
- * during table processing,
- * correct its position.
- */
- if ((nptr->element != NULL)&&
- (nptr->element->lo_any.ele_id > min_id))
- {
- nptr->x = nptr->element->lo_any.x;
- nptr->y = nptr->element->lo_any.y;
- }
-
- /*
- * If we are blocked on a named element.
- * Check if this name is one we are waiting on.
- */
- if ((state->display_blocking_element_id == -1)&&
- (nptr->name != NULL))
- {
- char *name;
-
- PA_LOCK(name, char *, nptr->name);
- if (XP_STRCMP(name,
- (char *)(state->top_state->name_target + 1)) == 0)
- {
- XP_FREE(state->top_state->name_target);
- state->top_state->name_target = NULL;
- if (nptr->element != NULL)
- {
- state->display_blocking_element_id =
- nptr->element->lo_any.ele_id;
- }
- else
- {
- state->display_blocking_element_id =
- state->top_state->element_id;
- }
- /*
- * If the display is blocked for an element
- * we havn't reached yet, check to see if
- * it is in this line, and if so, save its
- * y position.
- */
- if ((state->display_blocked != FALSE)&&
- (state->is_a_subdoc == SUBDOC_NOT)&&
- (state->display_blocking_element_y == 0)&&
- (state->display_blocking_element_id != -1))
- {
- state->display_blocking_element_y = nptr->y;
- }
- PA_UNLOCK(nptr->name);
- }
- else
- {
- PA_UNLOCK(nptr->name);
- }
- }
-
- nptr = nptr->next;
- }
- }
-
-
- void
- lo_AppendToLineList(MWContext *context, lo_DocState *state,
- LO_Element *element, int32 baseline_inc)
- {
- LO_Element *eptr;
-
- if (state->current_named_anchor != NULL) {
- if (!lo_BindNamedAnchorToElement(state, state->current_named_anchor,
- element)) {
- XP_ASSERT(FALSE);
- }
- state->current_named_anchor = NULL;
- }
- #ifdef MOCHA
- else if (state->current_anchor) {
- state->current_anchor->element = element;
- }
- #endif /* MOCHA */
-
- element->lo_any.next = NULL;
- element->lo_any.prev = NULL;
- eptr = state->line_list;
- if (eptr == NULL)
- {
- state->line_list = element;
- }
- else
- {
- while (eptr->lo_any.next != NULL)
- {
- eptr->lo_any.y_offset += baseline_inc;
- eptr = eptr->lo_any.next;
- }
- eptr->lo_any.y_offset += baseline_inc;
- eptr->lo_any.next = element;
- element->lo_any.prev = eptr;
- }
- }
-
- void
- lo_SetLineArrayEntry(lo_DocState *state, LO_Element *eptr, int32 line)
- {
- LO_Element **line_array;
-
- #ifdef XP_WIN16
- intn a_size;
- intn a_indx;
- intn a_line;
- XP_Block *larray_array;
- #endif /* XP_WIN16 */
-
- if ((line < 0) || (line >= (state->line_num - 1)))
- {
- return;
- }
-
- #ifdef XP_WIN16
- a_size = SIZE_LIMIT / sizeof(LO_Element *);
- a_indx = (intn)(line / a_size);
- a_line = (intn)(line - (a_indx * a_size));
-
- XP_LOCK_BLOCK(larray_array, XP_Block *, state->larray_array);
- state->line_array = larray_array[a_indx];
- XP_LOCK_BLOCK(line_array, LO_Element **, state->line_array);
- line_array[a_line] = eptr;
-
- XP_UNLOCK_BLOCK(state->line_array);
- XP_UNLOCK_BLOCK(state->larray_array);
- #else
- XP_LOCK_BLOCK(line_array, LO_Element **, state->line_array);
- line_array[line] = eptr;
- XP_UNLOCK_BLOCK(state->line_array);
- #endif /* XP_WIN16 */
- }
-
- #define POSITIVE_SCALE_FACTOR 1.10 /* 10% */
- #define NEGATIVE_SCALE_FACTOR .90 /* 10% */
-
-
- /*
- * Return the scaling percentage given a font scaler
- *
- */
- double
- LO_GetScalingFactor(int32 scaler)
- {
- double scale=1.0;
- double mult;
- int32 count;
-
- if(scaler < 0)
- {
- count = -scaler;
- mult = NEGATIVE_SCALE_FACTOR;
- }
- else
- {
- count = scaler;
- mult = POSITIVE_SCALE_FACTOR;
- }
-
- /* use the percentage scaling factor to the power of the pref */
- while(count--)
- scale *= mult;
-
- return scale;
- }
-
-
- /*
- * Return the width of the window for this context in chars in the default
- * fixed width font. Return -1 on error.
- */
- int16
- LO_WindowWidthInFixedChars(MWContext *context)
- {
- int32 doc_id;
- lo_TopState *top_state;
- lo_DocState *state;
- LO_TextInfo tmp_info;
- LO_TextAttr tmp_attr;
- LO_TextStruct tmp_text;
- PA_Block buff;
- char *str;
- int32 width;
- int16 char_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((int16)-1);
- }
- state = top_state->doc_state;
-
- /*
- * Create a fake text buffer to measure an 'M'.
- */
- memset (&tmp_text, 0, sizeof (tmp_text));
- buff = PA_ALLOC(1);
- if (buff == NULL)
- {
- return((int16)-1);
- }
- PA_LOCK(str, char *, buff);
- str[0] = 'M';
- PA_UNLOCK(buff);
- tmp_text.text = buff;
- tmp_text.text_len = 1;
-
- /*
- * Fill in default fixed font information.
- */
- lo_SetDefaultFontAttr(state, &tmp_attr, context);
- tmp_attr.fontmask |= LO_FONT_FIXED;
- tmp_text.text_attr = &tmp_attr;
-
- /*
- * Get the width of that 'M'
- */
- FE_GetTextInfo(context, &tmp_text, &tmp_info);
- PA_FREE(buff);
-
- /*
- * Error if bad character width
- */
- if (tmp_info.max_width <= 0)
- {
- return((int16)-1);
- }
-
- width = state->win_width - state->win_left - state->win_right;
- char_cnt = (int16)(width / tmp_info.max_width);
- return(char_cnt);
- }
-
-
- LO_Element *
- lo_FirstElementOfLine(MWContext *context, lo_DocState *state, int32 line)
- {
- LO_Element *eptr;
- LO_Element **line_array;
-
- if ((line < 0)||(line > (state->line_num - 2)))
- {
- return(NULL);
- }
-
- #ifdef XP_WIN16
- {
- intn a_size;
- intn a_indx;
- intn a_line;
- XP_Block *larray_array;
-
- a_size = SIZE_LIMIT / sizeof(LO_Element *);
- a_indx = (intn)(line / a_size);
- a_line = (intn)(line - (a_indx * a_size));
- XP_LOCK_BLOCK(larray_array, XP_Block *,
- state->larray_array);
- state->line_array = larray_array[a_indx];
- XP_LOCK_BLOCK(line_array, LO_Element **,
- state->line_array);
- eptr = line_array[a_line];
- XP_UNLOCK_BLOCK(state->line_array);
- XP_UNLOCK_BLOCK(state->larray_array);
- }
- #else
- {
- XP_LOCK_BLOCK(line_array, LO_Element **,
- state->line_array);
- eptr = line_array[line];
- XP_UNLOCK_BLOCK(state->line_array);
- }
- #endif /* XP_WIN16 */
- return(eptr);
- }
-
-
- Bool
- lo_FindMochaExpr(char *str, char **expr_start, char **expr_end)
- {
- char *tptr;
- char *start;
- char *end;
-
- if (str == NULL)
- {
- return(FALSE);
- }
-
- start = NULL;
- end = NULL;
- tptr = str;
- while (*tptr != '\0')
- {
- if ((*tptr == '&')&&(*(char *)(tptr + 1) == '{'))
- {
- start = tptr;
- break;
- }
- tptr++;
- }
-
- if (start == NULL)
- {
- return(FALSE);
- }
-
- tptr = (char *)(start + 2);
- while (*tptr != '\0')
- {
- if ((*tptr == '}')&&(*(char *)(tptr + 1) == ';'))
- {
- end = tptr;
- break;
- }
- tptr++;
- }
-
- if (end == NULL)
- {
- return(FALSE);
- }
-
- end = (char *)(end + 1);
- *expr_start = start;
- *expr_end = end;
- return(TRUE);
- }
-
-
- static char *
- lo_add_string(char *base, char *add)
- {
- char *new;
- int32 base_len, add_len;
-
- if (add == NULL)
- {
- return(base);
- }
-
- if (base == NULL)
- {
- new = XP_STRDUP(add);
- return(new);
- }
-
- base_len = XP_STRLEN(base);
- add_len = XP_STRLEN(add);
- new = (char *)XP_ALLOC(base_len + add_len + 1);
- if (new == NULL)
- {
- return(base);
- }
-
- XP_STRCPY(new, base);
- XP_STRCAT(new, add);
- XP_FREE(base);
- return(new);
- }
-
-
- static char *
- lo_eval_javascript_entities(MWContext *context, char *orig_value,
- uint newline_count)
- {
- char *tptr;
- char *str;
- char *new_str;
- int32 len;
- char tchar;
- Bool has_mocha;
- char *start, *end;
-
- if (orig_value == NULL)
- {
- return(NULL);
- }
-
- str = orig_value;
- len = XP_STRLEN(str);
-
- new_str = NULL;
- tptr = str;
- has_mocha = lo_FindMochaExpr(tptr, &start, &end);
- while (has_mocha != FALSE)
- {
- char *expr_start, *expr_end;
-
- if (start > tptr)
- {
- tchar = *start;
- *start = '\0';
- new_str = lo_add_string(new_str, tptr);
- *start = tchar;
- }
-
- expr_start = (char *)(start + 2);
- expr_end = (char *)(end - 1);
- if (expr_end > expr_start)
- {
- char *eval_str;
-
- tchar = *expr_end;
- *expr_end = '\0';
- eval_str = LM_EvaluateAttribute(context, expr_start,
- newline_count + 1);
- *expr_end = tchar;
- new_str = lo_add_string(new_str, eval_str);
- if (eval_str != NULL)
- {
- XP_FREE(eval_str);
- }
- }
-
- tptr = (char *)(end + 1);
- has_mocha = lo_FindMochaExpr(tptr, &start, &end);
- }
- if (tptr != str)
- {
- new_str = lo_add_string(new_str, tptr);
- }
-
- if (new_str == NULL)
- {
- new_str = str;
- }
-
- return(new_str);
- }
-
-
- void
- lo_ConvertAllValues(MWContext *context, char **value_list, int32 list_len,
- uint newline_count)
- {
- int32 i;
-
- if (LM_CanDoJS(context) == FALSE)
- {
- return;
- }
-
- for (i=0; i < list_len; i++)
- {
- char *str;
- char *new_str;
-
- str = value_list[i];
- if (str != NULL)
- {
- new_str = lo_eval_javascript_entities(context, str, newline_count);
- if (new_str != str)
- {
- XP_FREE(str);
- value_list[i] = new_str;
- }
- }
- }
- }
-
-
- PA_Block
- lo_FetchParamValue(MWContext *context, PA_Tag *tag, char *param_name)
- {
- PA_Block buff;
- INTL_CharSetInfo c = LO_GetDocumentCharacterSetInfo(context);
- buff = PA_FetchParamValue(tag, param_name, INTL_GetCSIWinCSID(c));
- return(buff);
- }
-
- #include "prthread.h"
- #include "prmon.h"
-
- static PRMonitor * layout_lock_monitor = NULL;
- static PRThread * layout_lock_owner = NULL;
- static int layout_lock_count = 0;
-
- /*
- * Grab the lock around layout so that we can delete things / manipulate
- * layout owned data structures in a separate thread
- */
- void
- LO_LockLayout()
- {
- if(!layout_lock_monitor)
- layout_lock_monitor = PR_NewNamedMonitor("layout-lock");
-
- PR_EnterMonitor(layout_lock_monitor);
-
- while(TRUE) {
-
- /* no current owner or owned by this thread */
- if(layout_lock_owner == NULL ||
- layout_lock_owner == PR_CurrentThread()) {
- layout_lock_owner = PR_CurrentThread();
- layout_lock_count++;
-
- PR_ExitMonitor(layout_lock_monitor);
- return;
- }
-
- /* owned by someone else -- wait till we can get it */
- PR_Wait(layout_lock_monitor, PR_INTERVAL_NO_TIMEOUT);
-
- }
- }
-
- /*
- * Release the lock and wake up anyone who was waiting to get it if
- * we are the last release of the lock from this thread
- */
- void
- LO_UnlockLayout()
- {
-
- PR_EnterMonitor(layout_lock_monitor);
-
- #ifdef DEBUG
- /* make sure someone doesn't try to free a lock they don't own */
- XP_ASSERT(layout_lock_owner == PR_CurrentThread());
- #endif
-
- layout_lock_count--;
-
- if(layout_lock_count == 0) {
- layout_lock_owner = NULL;
- PR_Notify(layout_lock_monitor);
- }
- PR_ExitMonitor(layout_lock_monitor);
-
- }
-
-
- /*
- * A (debugging) way to make sure the current thread doesn't have the
- * layout lock
- */
- Bool
- LO_VerifyUnlockedLayout()
- {
- #ifdef DEBUG
- Bool bHolding = TRUE;
-
- if (layout_lock_monitor) {
- PR_EnterMonitor(layout_lock_monitor);
- bHolding = (layout_lock_owner != PR_CurrentThread());
- PR_ExitMonitor(layout_lock_monitor);
- }
-
- return bHolding;
-
- #else
- return TRUE;
- #endif
- }
-
-
- /*
- * The mocha lock has been released, flush the blockage to see if
- * we can get our blocked entities evaluated now.
- */
- static void
- lo_JSLockReleased(void * data)
- {
- MWContext * context = (MWContext *) data;
- lo_TopState * top_state;
-
- top_state = lo_FetchTopState(XP_DOCID(context));
- if (!top_state)
- return;
-
- /* free the fake element we created earlier */
- lo_FreeElement(context, top_state->layout_blocking_element, FALSE);
-
- /* flush the blockage */
- lo_UnblockLayout(context, top_state);
- }
-
- /*
- * see if there are any &{} constructs for this tag. If so,
- * convert them now, if we can't convert them (since we couldn't
- * get the mocha lock, for example) return FALSE
- */
- Bool
- lo_ConvertMochaEntities(MWContext * context, lo_DocState *state, PA_Tag * tag)
- {
-
- char *tptr;
- char *str;
- char *new_str;
- int32 len;
- char tchar;
- Bool has_mocha;
- char *start, *end;
- int32 cur_layer_id;
-
- PA_LOCK(str, char *, tag->data);
- len = tag->data_len;
-
- if (LM_CanDoJS(context) == FALSE)
- return TRUE;
-
- new_str = NULL;
- tptr = str;
- has_mocha = lo_FindMochaExpr(tptr, &start, &end);
-
- if (has_mocha == FALSE)
- return TRUE;
-
- /* attempt to lock JS */
- if (!LM_AttemptLockJS(lo_JSLockReleased, context))
- return FALSE;
-
- /*
- * Make sure that the current layer and all its ancestors have
- * been reflected and that the current layer has been set as the
- * active layer, since we want to ensure correct scoping and there's
- * no way to know that the reflect event has reached Mocha yet.
- * Note that reflecting the object multiple times is safe, since the
- * reflection code is idempotent.
- */
- cur_layer_id = lo_CurrentLayerId(state);
- if (cur_layer_id != LO_DOCUMENT_LAYER_ID) {
- CL_Layer *layer, *parent;
- int32 child_layer_id = cur_layer_id;
- int32 parent_layer_id;
-
- do {
- layer = LO_GetLayerFromId(context, child_layer_id);
- parent = CL_GetLayerParent(layer);
- parent_layer_id = LO_GetIdFromLayer(context, parent);
- LM_ReflectLayer(context, cur_layer_id, parent_layer_id, NULL);
- child_layer_id = parent_layer_id;
- } while (child_layer_id != LO_DOCUMENT_LAYER_ID);
-
- }
- LM_SetActiveLayer(context, cur_layer_id);
- while (has_mocha != FALSE)
- {
- char *expr_start, *expr_end;
-
- if (start > tptr)
- {
- tchar = *start;
- *start = '\0';
- new_str = lo_add_string(new_str, tptr);
- *start = tchar;
- }
-
- expr_start = (char *)(start + 2);
- expr_end = (char *)(end - 1);
- if (expr_end > expr_start)
- {
- char *eval_str;
-
- tchar = *expr_end;
- *expr_end = '\0';
- if (state->top_state && state->top_state->nurl) {
- LM_SetDecoderStream(context, NULL,
- state->top_state->nurl,
- JS_FALSE);
- }
- eval_str = LM_EvaluateAttribute(context, expr_start,
- tag->newline_count + 1);
- *expr_end = tchar;
- new_str = lo_add_string(new_str, eval_str);
- if (eval_str != NULL)
- {
- XP_FREE(eval_str);
- }
- }
-
- tptr = (char *)(end + 1);
- has_mocha = lo_FindMochaExpr(tptr, &start, &end);
- }
- if (tptr != str)
- {
- new_str = lo_add_string(new_str, tptr);
- }
-
- PA_FREE(tag->data);
- tag->data = (PA_Block) new_str;
- tag->data_len = XP_STRLEN((char *) tag->data);
- PA_UNLOCK(tag->data);
-
- LM_UnlockJS();
-
- return TRUE;
-
- }
-
- /* Called from front ends as a threadsafe way to update values of text fields. */
- void
- LO_UpdateTextData(lo_FormElementTextData * textData, const char * text) {
-
- LO_LockLayout();
-
- if(textData->current_text)
- XP_FREE(textData->current_text);
-
- textData->current_text = (PA_Block) XP_STRDUP(text);
-
- LO_UnlockLayout();
- }
-
- LO_TableStruct *lo_GetParentTable(MWContext *pContext, LO_Element *pElement)
- {
- LO_Element *tptr;
- if( !pElement )
- return NULL;
-
- if( pElement->lo_any.type == LO_CELL )
- {
- /* Supplied element is already a cell, start table search with it */
- tptr = pElement;
- } else {
- if( !pContext )
- return NULL;
-
- /* First find the cell that contains the given element */
- tptr = (LO_Element*)lo_GetParentCell(pContext, pElement);
- }
-
- /* Simply search back from current cell to find table element */
- while( tptr )
- {
- if( tptr->lo_any.type == LO_TABLE )
- {
- return (LO_TableStruct*)tptr;
- }
- tptr = tptr->lo_any.prev;
- }
- return NULL;
- }
-
-
- /* Recusively search for cell struct containing the given element
- * If table is found, it searches into that as well
- */
- LO_CellStruct *lo_GetCellContainingElement( LO_Element *pElement, LO_CellStruct *pFirstCell )
- {
- LO_CellStruct *pNestedCell = NULL;
- LO_CellStruct *pFirstNestedCell;
- LO_Element *cell_list_ptr;
- LO_CellStruct *pLoCell;
-
- pLoCell = pFirstCell;
- if( pLoCell == NULL )
- return NULL;
-
- do {
- cell_list_ptr = pLoCell->cell_list;
- while( cell_list_ptr )
- {
- if( cell_list_ptr == pElement )
- {
- /* We found the element - return cell containing it */
- return pLoCell;
- }
- if( cell_list_ptr->type == LO_TABLE )
- {
- /* We found a nested table
- * Get first cell in it and search through it
- */
- pFirstNestedCell = (LO_CellStruct*)cell_list_ptr->lo_any.next;
- XP_ASSERT(pFirstNestedCell->type == LO_CELL);
- pNestedCell = lo_GetCellContainingElement(pElement, pFirstNestedCell);
- if( pNestedCell )
- {
- /* We found cell in nested table */
- return pNestedCell;
- }
- }
- cell_list_ptr = cell_list_ptr->lo_any.next;
- }
- pLoCell = (LO_CellStruct*)pLoCell->next;
- } /* End when there's no more cells or we hit linefeed at end of line (top-level table)*/
- while (pLoCell && pLoCell->type == LO_CELL);
-
- return NULL;
- }
-
- /* Search algorithm is very similar to CEditBuffer::GetTableHitRegion()
- * (which is similar to lo_XYtoDocumentElement except it finds only cells)
- * Search for the Cell that contains pElement
- */
- LO_CellStruct *lo_GetParentCell(MWContext * pContext, LO_Element *pElement)
- {
- LO_Element *tptr;
- int32 doc_id;
- lo_TopState *top_state;
- lo_DocState *state;
- XP_Bool in_table;
- int32 line;
- LO_Element *end_ptr;
- LO_Element *tptrTable;
- int32 x, y, t_width, t_height;
-
- doc_id = XP_DOCID(pContext);
- top_state = lo_FetchTopState(doc_id);
-
- /* Supplied element is a cell - return it ??? */
- if( pElement && pElement->type == LO_CELL )
- return (LO_CellStruct*)pElement;
-
- if( pContext == NULL || pElement == NULL || top_state == NULL || top_state->doc_state == NULL )
- return NULL;
-
- state = top_state->doc_state;
- tptrTable = NULL;
- in_table = FALSE;
-
- /* Find the line that contains the supplied element
- * This defines the top-level table
- */
- x = pElement->lo_any.x+1;
- y = pElement->lo_any.y+1;
-
- line = lo_PointToLine(pContext, state, x, y);
- lo_GetLineEnds(pContext, state, line, &tptr, &end_ptr);
-
- while (tptr != end_ptr)
- {
- t_width = tptr->lo_any.width;
- t_height = tptr->lo_any.height;
-
- if (t_width <= 0)
- {
- t_width = 1;
- }
-
- if ((y >= tptr->lo_any.y) &&
- (y < tptr->lo_any.y + tptr->lo_any.y_offset + t_height) &&
- (x >= tptr->lo_any.x) &&
- (x < (tptr->lo_any.x + tptr->lo_any.x_offset + t_width)))
- {
- /* We are only interested in finding cells */
- if (tptr->type == LO_CELL)
- {
- /* Search through the cell's element list,
- * Including all nested tables in that cell
- */
- LO_CellStruct * pLoCell = lo_GetCellContainingElement(pElement, (LO_CellStruct*)tptr);
- /* We found it - done */
- if( pLoCell )
- return pLoCell;
- }
- }
- tptr = tptr->lo_any.next;
- }
-
- /* Failed to find element */
- return NULL;
- }
-
-
- /* Find the first cell with with closest left border x-value <= than the given x
- * value or, if bGetColumn=FALSE, find the cell with closest top border
- * y-value <= than the given Y value. Also returns the pointer to the
- * last LO element so we can search for other cells until pEndElement is reached.
- */
- LO_Element* lo_GetFirstCellInColumnOrRow(MWContext *pContext, LO_Element *pElement, int32 x, int32 y, XP_Bool bGetColumn, LO_Element **ppLastCellInTable)
- {
- LO_Element *pFirstCell = NULL;
- LO_Element *pLastCellInTable = NULL;
- LO_Element *tptr = NULL;
- int32 closest = 0;
- lo_DocState *state;
-
-
- if( pElement->type == LO_TABLE )
- {
- /* Start at first element after the table */
- tptr = pElement->lo_any.next;
- } else {
-
- if( pElement->type == LO_CELL )
- {
- /* Element is a cell */
- tptr = pElement;
- } else {
- /* Get parent cell of supplied element */
- tptr = (LO_Element*)lo_GetParentCell(pContext, pElement);
- }
- if( !tptr )
- return NULL;
-
- /* Search back until we are at first cell in table */
- while ( (tptr->lo_any.prev)->type != LO_TABLE )
- {
- tptr = tptr->lo_any.prev;
- }
- }
-
- /* Scan all cells to find first and last */
- do {
- if( tptr->type == LO_CELL )
- {
- if( bGetColumn && tptr->lo_any.x <= x &&
- tptr->lo_any.x > closest )
- {
- /* We found a cell candidate */
- closest = tptr->lo_any.x;
- pFirstCell = tptr;
- } else if( !bGetColumn && tptr->lo_any.y <= y &&
- tptr->lo_any.y > closest )
- {
- closest = tptr->lo_any.y;
- pFirstCell = tptr;
- }
- pLastCellInTable = tptr;
- }
- tptr = tptr->lo_any.next;
-
- /* Table ends at linefeed (top level) or null element (nested table) */
- } while (tptr && tptr->type != LO_LINEFEED );
-
- /* Return last cell element encountered */
- if( ppLastCellInTable )
- *ppLastCellInTable = pLastCellInTable;
-
- return pFirstCell;
- }
-
- /* Assumptions;
- * Given a LO_CellStruct, the table element defines the begining of table
- * and the last cell is that whose "next" pointer is NULL (nested table)
- * or a linefeed element (top-level table)
- */
- LO_Element *lo_GetFirstAndLastCellsInTable(MWContext *pContext, LO_Element *pElement, LO_Element **ppLastCell)
- {
- LO_Element *tptr = NULL;
- LO_Element *pFirstCell = NULL;
- LO_Element *pLastCell = NULL;
- LO_Element *pCurrentCell = NULL;
-
- if(pContext == NULL || pElement == NULL )
- return NULL;
-
- if( pElement->type == LO_CELL )
- {
- pCurrentCell = pElement;
- }
- else if( pElement->type == LO_TABLE )
- {
- /* First cell SHOULD be next element, but let's be sure */
- pCurrentCell = pElement->lo_table.next;
- while(pCurrentCell->type != LO_CELL)
- {
- pCurrentCell = pCurrentCell->lo_any.next;
- }
- } else {
- pCurrentCell = (LO_Element*)lo_GetParentCell(pContext, pElement);
- }
-
- if( pCurrentCell == NULL )
- return NULL;
-
- /* Scan backwards until we hit the table element
- * that's before all the cells
- */
- tptr = pCurrentCell;
- while (tptr && (tptr->lo_any.prev)->type != LO_TABLE )
- {
- tptr = tptr->lo_any.prev;
- }
-
- /* Scan forward to find last cell -- next is null or line-feed element */
- do {
- if( tptr->type == LO_CELL )
- {
- if( !pFirstCell )
- pFirstCell = tptr;
-
- pLastCell = tptr;
- }
- tptr = tptr->lo_any.next;
- } while (tptr && tptr->type != LO_LINEFEED);
-
- /* Return last cell element encountered */
- if( ppLastCell )
- *ppLastCell = pLastCell;
-
- return pFirstCell;
- }
-
- LO_Element *lo_GetFirstAndLastCellsInColumnOrRow(LO_Element *pCellElement, LO_Element **ppLastCell, XP_Bool bInColumn )
- {
- LO_Element *tptr = NULL;
- LO_Element *pFirstCell = NULL;
- LO_Element *pLastCell = NULL;
-
- if(pCellElement == NULL || pCellElement->type != LO_CELL)
- return NULL;
-
- /* Scan backwards until we hit the table element
- * that's before all the cells
- */
- tptr = pCellElement;
- while (tptr && (tptr->lo_any.prev)->type != LO_TABLE )
- {
- tptr = tptr->lo_any.prev;
- }
-
- /* Scan forward to find first and last cells,
- * based on sharing left edge (column) or top (row)
- */
- do {
- if( tptr->type == LO_CELL )
- {
- if( (bInColumn && pCellElement->lo_any.x == tptr->lo_any.x) ||
- (!bInColumn && pCellElement->lo_any.y == tptr->lo_any.y) )
- {
- if( !pFirstCell )
- pFirstCell = tptr;
-
- pLastCell = tptr;
- }
- }
- tptr = tptr->lo_any.next;
- } while (tptr && tptr->type != LO_LINEFEED);
-
- /* Return last cell element encountered */
- if( ppLastCell )
- *ppLastCell = pLastCell;
-
- return pFirstCell;
- }
-
- XP_Bool lo_AllCellsSelectedInColumnOrRow( LO_CellStruct *pCell, XP_Bool bInColumn )
- {
- LO_Element *pFirstCell;
- LO_Element *pLastCell;
- LO_Element *tptr;
-
- /* Get first and last cells in row or column */
- pFirstCell = lo_GetFirstAndLastCellsInColumnOrRow( (LO_Element*)pCell, &pLastCell, bInColumn );
- if( !pFirstCell || !pLastCell )
- return FALSE;
-
- tptr = pFirstCell;
-
- do {
- if( tptr->type == LO_CELL )
- {
- if( (bInColumn && pCell->x == tptr->lo_any.x) ||
- (!bInColumn && pCell->y == tptr->lo_any.y) )
- {
- /* If any cell is not selected, return FALSE */
- if( !(pCell->ele_attrmask & LO_ELE_SELECTED) )
- return FALSE;
- }
- }
- tptr = tptr->lo_any.next;
- } while (tptr != pLastCell);
-
- return TRUE;
- }
-
- int32 lo_GetNumberOfCellsInTable(LO_TableStruct *pTable )
- {
- int32 iCount = 0;
- if( pTable )
- {
- LO_Element *tptr = (LO_Element*)pTable;
- while( tptr && tptr->type != LO_LINEFEED )
- {
- if( tptr->type == LO_CELL)
- iCount++;
-
- tptr = tptr->lo_any.next;
- }
- }
- return iCount;
- }
-
- /* Subtract borders and inter-cell spacing to get the available table width
- * to use when cell width in HTML is "percent of table"
- */
- int32 lo_CalcTableWidthForPercentMode(LO_Element *pCellElement)
- {
- LO_Element *pLastCell;
- LO_Element *pFirstCell;
- LO_Element *pCell;
- int32 iWidth;
- XP_Bool bDone;
-
- /* Never return 0 to avoid divide by zero errors */
- if( !pCellElement || pCellElement->type != LO_CELL )
- return -1;
-
- iWidth = 0;
-
- /* We calculate the width by simply adding up widths of all cells in the row */
- pFirstCell = lo_GetFirstAndLastCellsInColumnOrRow(pCellElement, &pLastCell, FALSE );
- pCell = pFirstCell;
-
- if( pCell && pLastCell )
- {
- bDone = FALSE;
- while(!bDone)
- {
- if( pCell == pLastCell )
- bDone = TRUE;
-
- /* Add widths of all cells in the row (must have same top) */
- if( pCell->type == LO_CELL &&
- (pCell->lo_any.y == pFirstCell->lo_any.y) )
- {
- iWidth += pCell->lo_cell.width;
- }
- pCell = pCell->lo_any.next;
- }
- }
- return (iWidth > 0) ? iWidth : -1;
- }
-
- XP_Bool LO_IsEmptyCell(LO_CellStruct *cell)
- {
- if ( cell )
- {
- LO_Element *element = cell->cell_list;
-
- /* Unlikely, but if nothing inside cell, we're empty! */
- if(element)
- {
- LO_Element *pNext = element->lo_any.next;
- while(element)
- {
- /* Any non-text element except linefeed is not "empty"
- * and check for text length
- * Length of any element is 1. Length of text = real length,
- * (but we don't want to consider linefeeds)
- */
- if( element->type != LO_LINEFEED && lo_GetElementLength(element) > 0 )
- {
- return FALSE;
- }
- element = element->lo_any.next;
- }
- }
- }
- return TRUE;
- }
-
- LO_Element * lo_GetLastElementInList( LO_Element *eleList )
- {
- LO_Element *retEle = NULL;
-
- if (eleList != NULL)
- {
- while (eleList->lo_any.next != NULL)
- eleList = eleList->lo_any.next;
-
- retEle = eleList;
- }
-
- return retEle;
-
- }
-
- #ifdef DOM
- /* Checks the layout element to see if the element is enclosed within <SPAN> */
- Bool LO_IsWithinSpan( LO_Element *ele )
- {
- Bool isInSpan = FALSE;
-
- switch (ele->type) {
-
- case LO_TEXT:
- isInSpan = ele->lo_text.ele_attrmask & LO_ELE_IN_SPAN ? TRUE : FALSE;
- break;
- case LO_IMAGE:
- isInSpan = ele->lo_image.ele_attrmask & LO_ELE_IN_SPAN ? TRUE : FALSE;
- break;
- case LO_FORM_ELE:
- isInSpan = ele->lo_form.ele_attrmask & LO_ELE_IN_SPAN ? TRUE : FALSE;
- break;
- case LO_EMBED:
- isInSpan = ele->lo_embed.ele_attrmask & LO_ELE_IN_SPAN ? TRUE : FALSE;
- break;
- #ifdef JAVA
- case LO_JAVA:
- isInSpan = ele->lo_java.ele_attrmask & LO_ELE_IN_SPAN ? TRUE : FALSE;
- break;
- #endif
- }
-
- return isInSpan;
- }
- #endif
-
- #ifdef PROFILE
- #pragma profile off
- #endif
-