home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / layout / layout.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  192.8 KB  |  7,922 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19.  
  20. #include "xp.h"
  21. #include "net.h"
  22. #include "glhist.h"
  23. #include "shist.h"
  24. #include "merrors.h"
  25. #include "layout.h"
  26. #include "laylayer.h"
  27. #include "layers.h"
  28.  
  29. #define IL_CLIENT               /* XXXM12N Defined by Image Library clients */
  30. #include "libimg.h"             /* Image Library public API. */
  31.  
  32. #include "pa_parse.h"
  33. #include "edt.h"
  34. #include "libmocha.h"
  35. #include "libevent.h"
  36. #include "laystyle.h"
  37. #include "hk_funcs.h"
  38. #include "pics.h"
  39. #include "xp_ncent.h"
  40. #include "prefetch.h"
  41.  
  42. /* WEBFONTS are defined only in laytags.c and layout.c */
  43. #define WEBFONTS
  44.  
  45. #ifdef WEBFONTS
  46. #include "nf.h"
  47. #include "Mnffbu.h"
  48. #endif /* WEBFONTS */
  49.  
  50. #ifdef HTML_CERTIFICATE_SUPPORT
  51. #include "cert.h"
  52. #endif
  53.  
  54. #ifndef MAX
  55. #define MAX(a,b) ((a) > (b) ? (a) : (b))
  56. #endif
  57.  
  58. extern int MK_OUT_OF_MEMORY;
  59.  
  60.  
  61. #ifdef PROFILE
  62. #pragma profile on
  63. #endif
  64.  
  65. #ifdef TEST_16BIT
  66. #define XP_WIN16
  67. #endif /* TEST_16BIT */
  68.  
  69. #ifdef XP_WIN16
  70. #define SIZE_LIMIT        32000
  71. #endif /* XP_WIN16 */
  72.  
  73.  
  74. #define DEF_LINE_HEIGHT        20
  75. #define URL_LIST_INC        20
  76. #define LINE_INC        100
  77.  
  78.  
  79. typedef struct lo_StateList_struct {
  80.     int32 doc_id;
  81.     lo_TopState *state;
  82.     struct lo_StateList_struct *next;
  83. } lo_StateList;
  84.  
  85. static lo_StateList *StateList = NULL;
  86.  
  87. LO_Color lo_master_colors[] = {
  88.     {LO_DEFAULT_BG_RED, LO_DEFAULT_BG_GREEN, LO_DEFAULT_BG_BLUE},
  89.     {LO_DEFAULT_FG_RED, LO_DEFAULT_FG_GREEN, LO_DEFAULT_FG_BLUE},
  90.     {LO_UNVISITED_ANCHOR_RED, LO_UNVISITED_ANCHOR_GREEN,
  91.      LO_UNVISITED_ANCHOR_BLUE},
  92.     {LO_VISITED_ANCHOR_RED, LO_VISITED_ANCHOR_GREEN,
  93.      LO_VISITED_ANCHOR_BLUE},
  94.     {LO_SELECTED_ANCHOR_RED, LO_SELECTED_ANCHOR_GREEN,
  95.      LO_SELECTED_ANCHOR_BLUE}
  96. };
  97. static char *Master_backdrop_url = NULL;
  98. Bool UserOverride = FALSE;
  99.  
  100. /********** BEGIN PROTOTYPES **************/
  101.  
  102. static void lo_process_deferred_image_info(void *closure);
  103. static void lo_DisplayLine(MWContext *context, lo_DocState *state, int32 line_num,
  104.                            int32 x, int32 y, uint32 w, uint32 h);
  105. lo_SavedEmbedListData *    lo_NewDocumentEmbedListData(void);
  106. lo_SavedGridData *        lo_NewDocumentGridData(void);
  107. int32                    lo_calc_push_right_for_justify(lo_DocState *state, int32 *remainder);
  108. void                    lo_BodyMargins(MWContext *context, lo_DocState *state, PA_Tag *tag);
  109. void                    lo_FinishLayout_OutOfMemory(MWContext *context, lo_DocState *state);
  110. #ifdef MEMORY_ARENAS 
  111. void                    lo_GetRecycleList(
  112.                             MWContext* context, int32 doc_id, pa_DocData* doc_data, 
  113.                               LO_Element* *recycle_list, lo_arena* *old_arena);
  114. #else
  115. void                    lo_GetRecycleList(
  116.                             MWContext* context, int32 doc_id, pa_DocData* doc_data, 
  117.                               LO_Element* *recycle_list);
  118. #endif /* MEMORY_ARENAS */
  119. intn                    lo_ProcessTag_OutOfMemory(MWContext* context, LO_Element* recycle_list, lo_TopState* top_state);
  120.  
  121. /********** END PROTOTYPES **************/
  122.  
  123. void
  124. LO_SetDefaultBackdrop(char *url)
  125. {
  126.     if ((url != NULL)&&(*url != '\0'))
  127.     {
  128.         Master_backdrop_url = XP_STRDUP(url);
  129.     }
  130.     else
  131.     {
  132.         Master_backdrop_url = NULL;
  133.     }
  134. }
  135.  
  136.  
  137. void
  138. LO_SetUserOverride(Bool override)
  139. {
  140.     UserOverride = override;
  141. }
  142.  
  143.  
  144. void
  145. LO_SetDefaultColor(intn type, uint8 red, uint8 green, uint8 blue)
  146. {
  147.     LO_Color *color;
  148.  
  149.     if (type < sizeof lo_master_colors / sizeof lo_master_colors[0])
  150.     {
  151.         color = &lo_master_colors[type];
  152.         color->red = red;
  153.         color->green = green;
  154.         color->blue = blue;
  155.     }
  156. }
  157.  
  158. Bool
  159. lo_InitDocLists(MWContext *context, lo_DocLists *doc_lists)
  160. {
  161.     LO_AnchorData **anchor_array;
  162.     int32 i;
  163.  
  164.     doc_lists->embed_list = NULL;
  165.     doc_lists->embed_list_count = 0;
  166.     doc_lists->applet_list = NULL;
  167.     doc_lists->applet_list_count = 0;
  168.  
  169.     doc_lists->name_list = NULL;
  170.     doc_lists->image_list = doc_lists->last_image = NULL;
  171.     doc_lists->image_list_count = 0;
  172.     doc_lists->anchor_count = 0;
  173.     doc_lists->form_list = NULL;
  174.     doc_lists->current_form_num = 0;
  175.  
  176.     doc_lists->url_list = 
  177.         XP_ALLOC_BLOCK(URL_LIST_INC * sizeof(LO_AnchorData *));
  178.     if (doc_lists->url_list == NULL)
  179.     {
  180.         return(FALSE);
  181.     }
  182.     doc_lists->url_list_size = URL_LIST_INC;
  183.     /* url_list is a Handle of (LO_AnchorData*) so the pointer is a (LO_AnchorData**) */
  184.     XP_LOCK_BLOCK(anchor_array, LO_AnchorData **, 
  185.                   doc_lists->url_list);
  186.     for (i=0; i < URL_LIST_INC; i++)
  187.     {
  188.         anchor_array[i] = NULL;
  189.     }
  190.     XP_UNLOCK_BLOCK(doc_lists->url_list);
  191.     doc_lists->url_list_len = 0;
  192.  
  193. #ifdef XP_WIN16
  194.     {
  195.         XP_Block *ulist_array;
  196.  
  197.         doc_lists->ulist_array = XP_ALLOC_BLOCK(sizeof(XP_Block));
  198.         if (doc_lists->ulist_array == NULL)
  199.         {
  200.             XP_FREE_BLOCK(doc_lists->url_list);
  201.             return(FALSE);
  202.         }
  203.         XP_LOCK_BLOCK(ulist_array, XP_Block *, 
  204.                       doc_lists->ulist_array);
  205.         ulist_array[0] = doc_lists->url_list;
  206.         XP_UNLOCK_BLOCK(doc_lists->ulist_array);
  207.         doc_lists->ulist_array_size = 1;
  208.     }
  209. #endif /* XP_WIN16 */
  210.  
  211.      return TRUE;
  212. }
  213.  
  214.  
  215. lo_TopState *
  216. lo_NewTopState(MWContext *context, char *url)
  217. {
  218.     lo_TopState *top_state;
  219.     char *name_target;
  220.     LO_TextAttr **text_attr_hash;
  221.     int32 i;
  222.     lo_LayerDocState *layer_state;
  223.     
  224.     top_state = XP_NEW_ZAP(lo_TopState);
  225.     if (top_state == NULL)
  226.     {
  227.         return(NULL);
  228.     }
  229.  
  230. #ifdef MEMORY_ARENAS
  231.     if ( EDT_IS_EDITOR(context) ) {
  232.         top_state->current_arena = NULL;
  233.     }
  234.     else
  235.     {
  236.         lo_InitializeMemoryArena(top_state);
  237.         if (top_state->first_arena == NULL)
  238.         {
  239.             XP_DELETE(top_state);
  240.             return(NULL);
  241.         }
  242.     }
  243. #endif /* MEMORY_ARENAS */
  244.  
  245.     top_state->tags = NULL;
  246.     top_state->tags_end = &top_state->tags;
  247.     top_state->insecure_images = FALSE;
  248.     top_state->out_of_memory = FALSE;
  249.     top_state->force_reload = NET_DONT_RELOAD;
  250.     top_state->script_tag_count = 0;
  251.     top_state->script_lineno = 0;
  252.     top_state->in_script = SCRIPT_TYPE_NOT;
  253.     top_state->default_style_script_type = SCRIPT_TYPE_CSS;
  254.     top_state->resize_reload = FALSE;
  255.     top_state->version = JSVERSION_UNKNOWN;
  256.         top_state->scriptData = NULL;
  257.     top_state->doc_state = NULL;
  258.  
  259.     if (url == NULL)
  260.     {
  261.         top_state->url = NULL;
  262.     }
  263.     else
  264.     {
  265.         top_state->url = XP_STRDUP(url);
  266.     }
  267.     top_state->base_url = NULL;
  268.     top_state->inline_stream_blocked_base_url = NULL;
  269.     top_state->main_stream_blocked_base_url = NULL;
  270.     top_state->base_target = NULL;
  271.     lo_SetBaseUrl(top_state, url, FALSE);
  272.  
  273.     /*
  274.      * This is the special named anchor we are jumping to in this
  275.      * document, it changes the starting display position.
  276.      */
  277.     name_target = NET_ParseURL(top_state->url, GET_HASH_PART);
  278.     if ((name_target[0] != '#')||(name_target[1] == '\0'))
  279.     {
  280.         XP_FREE(name_target);
  281.         top_state->name_target = NULL;
  282.     }
  283.     else
  284.     {
  285.         top_state->name_target = name_target;
  286.     }
  287.  
  288.     top_state->element_id = 0;
  289.     top_state->layout_blocking_element = NULL;
  290.     top_state->current_script = NULL;
  291.     top_state->doc_specified_bg = FALSE;
  292.     top_state->nothing_displayed = TRUE;
  293.     top_state->in_head = TRUE;
  294.     top_state->in_body = FALSE;
  295.     top_state->body_attr = 0;
  296.     top_state->have_title = FALSE;
  297.     top_state->scrolling_doc = FALSE;
  298.     top_state->is_grid = FALSE;
  299.     top_state->ignore_tag_nest_level = 0;
  300.     top_state->ignore_layer_nest_level = 0;
  301.     top_state->in_applet = FALSE;
  302.     top_state->unknown_head_tag = NULL;
  303.     top_state->the_grid = NULL;
  304.     top_state->old_grid = NULL;
  305.  
  306.     top_state->map_list = NULL;
  307.     top_state->current_map = NULL;
  308.  
  309.     top_state->layers = NULL;
  310.     top_state->current_layer_num = -1; /* incremented on layer allocation */
  311.     top_state->num_layers_allocated = 0;
  312.     top_state->max_layer_num = 0;
  313.     
  314.     layer_state = lo_NewLayerState(context);
  315.     if (!layer_state) {
  316.         XP_FREE_BLOCK(top_state);
  317.         return NULL;
  318.     }
  319.     if (context->compositor)
  320.         layer_state->layer = CL_GetCompositorRoot(context->compositor);
  321.     lo_append_to_layer_array(context, top_state, NULL, layer_state);
  322.     lo_PushLayerState(top_state, layer_state);
  323.  
  324.     top_state->in_form = FALSE;
  325.     top_state->savedData.FormList = NULL;
  326.     top_state->savedData.EmbedList = NULL;
  327.     top_state->savedData.Grid = NULL;
  328.     top_state->savedData.OnLoad = NULL;
  329.     top_state->savedData.OnUnload = NULL;
  330.     top_state->savedData.OnFocus = NULL;
  331.     top_state->savedData.OnBlur = NULL;
  332.      top_state->savedData.OnHelp = NULL;
  333.     top_state->savedData.OnMouseOver = NULL;
  334.     top_state->savedData.OnMouseOut = NULL;
  335.     top_state->savedData.OnDragDrop = NULL;
  336.     top_state->savedData.OnMove = NULL;
  337.     top_state->savedData.OnResize = NULL;
  338.     top_state->embed_count = 0;
  339.  
  340.     top_state->total_bytes = 0;
  341.     top_state->current_bytes = 0;
  342.     top_state->layout_bytes = 0;
  343.     top_state->script_bytes = 0;
  344.     top_state->layout_percent = 0;
  345.  
  346.     top_state->text_attr_hash = XP_ALLOC_BLOCK(FONT_HASH_SIZE *
  347.         sizeof(LO_TextAttr *));
  348.     if (top_state->text_attr_hash == NULL)
  349.     {
  350.         XP_DELETE(top_state);
  351.         return(NULL);
  352.     }
  353.     XP_LOCK_BLOCK(text_attr_hash, LO_TextAttr **,top_state->text_attr_hash);
  354.     for (i=0; i<FONT_HASH_SIZE; i++)
  355.     {
  356.         text_attr_hash[i] = NULL;
  357.     }
  358.     XP_UNLOCK_BLOCK(top_state->text_attr_hash);
  359.  
  360.     top_state->font_face_array = NULL;
  361.     top_state->font_face_array_len = 0;
  362.     top_state->font_face_array_size = 0;
  363.  
  364.     if (!lo_InitDocLists(context, &top_state->doc_lists))
  365.     {
  366.         XP_FREE_BLOCK(top_state->text_attr_hash);
  367.         XP_FREE_BLOCK(top_state);
  368.         return(NULL);
  369.     }
  370.     /* Document layer state keeps its doc_lists in the top_state */
  371.     if ( layer_state->doc_lists )
  372.     {
  373.         lo_DeleteDocLists(context, layer_state->doc_lists);
  374.         XP_FREE( layer_state->doc_lists );
  375.     }
  376.     layer_state->doc_lists = &top_state->doc_lists;
  377.     
  378.     top_state->recycle_list = NULL;
  379.     top_state->trash = NULL;
  380.  
  381.     top_state->mocha_write_stream = NULL;
  382.     top_state->mocha_loading_applets_count = 0;
  383.     top_state->mocha_loading_embeds_count = 0;
  384.     top_state->mocha_has_onload = FALSE;
  385.     top_state->mocha_has_onunload = FALSE;
  386.  
  387.     top_state->doc_data = NULL;
  388.     for (i = 0; i < MAX_INPUT_WRITE_LEVEL; i++)
  389.         top_state->input_write_point[i] = NULL;
  390.     top_state->input_write_level = 0;
  391.     top_state->tag_from_inline_stream = FALSE;
  392.  
  393. #ifdef HTML_CERTIFICATE_SUPPORT
  394.     top_state->cert_list = NULL;
  395. #endif
  396.  
  397.     top_state->style_stack = SML_StyleStack_Factory_Create();
  398.     if(!top_state->style_stack)
  399.     {
  400.         XP_FREE_BLOCK(top_state->text_attr_hash);
  401.         XP_FREE_BLOCK(top_state->doc_lists.url_list);
  402.         XP_DELETE(top_state);
  403.         return(NULL);
  404.     }
  405.  
  406.     STYLESTACK_Init(top_state->style_stack, context);
  407.  
  408.     top_state->diff_state = FALSE;
  409.     top_state->state_pushes = 0;
  410.     top_state->state_pops = 0;
  411.  
  412.     top_state->object_stack = NULL;
  413.     top_state->object_cache = NULL;
  414.  
  415.     top_state->tag_count = 0;
  416.  
  417.     top_state->flushing_blockage = FALSE;
  418.     top_state->wedged_on_mocha = FALSE;
  419.     top_state->in_cell_relayout = FALSE;  /* Used for resize without reload stuff */
  420.     
  421.     return(top_state);
  422. }
  423.  
  424.  
  425. /*************************************
  426.  * Function: lo_PushStateLevel
  427.  *
  428.  * Description: Record that we're going one level further
  429.  *  in the state hierarchy.
  430.  *
  431.  * Params: Window context.
  432.  *************************************/
  433. void
  434. lo_PushStateLevel(MWContext *context)
  435. {
  436.     lo_TopState *top_state;
  437.  
  438.     top_state = lo_FetchTopState( XP_DOCID(context) );
  439.     top_state->state_pushes++;
  440.     
  441.     /*
  442.      * If we've pushed back to our original state level, then we
  443.      * need to set a flag saying that we really have a new
  444.      * state record at the original level. We know this to
  445.      * be true as we've just added a new state record to the
  446.      * end of the list.
  447.      */
  448.     if ( top_state->state_pushes == top_state->state_pops )
  449.     {
  450.         top_state->diff_state = TRUE;
  451.     }
  452. }
  453.  
  454.  
  455. /*************************************
  456.  * Function: lo_PopStateLevel
  457.  *
  458.  * Description: Record that we've popped one level up
  459.  *  in the state hierarchy.
  460.  *
  461.  * Params: Window context.
  462.  *************************************/
  463. void
  464. lo_PopStateLevel(MWContext *context)
  465. {
  466.     lo_TopState *top_state;
  467.  
  468.     top_state = lo_FetchTopState( XP_DOCID(context) );
  469.     top_state->state_pops++;
  470. }
  471.  
  472. /*************************************
  473.  * Function: lo_GetCurrentDocLists
  474.  *
  475.  * Description: Get the doc_lists for the
  476.  * "current" document i.e. from the top_state
  477.  * in the normal case, from the layer if a 
  478.  * layer is being laid out.
  479.  *
  480.  * Params: DocState
  481.  *************************************/
  482. lo_DocLists *
  483. lo_GetCurrentDocLists(lo_DocState *state)
  484. {
  485.     lo_LayerDocState *layer_state = lo_CurrentLayerState(state);
  486.     return layer_state->doc_lists;
  487. }
  488.  
  489. lo_DocLists *
  490. lo_GetDocListsById(lo_DocState *state, int32 id)
  491. {
  492.     lo_LayerDocState *layer_state;
  493.  
  494.     if (id > state->top_state->max_layer_num)
  495.         return NULL;
  496.  
  497.     layer_state = state->top_state->layers[id];
  498.     if (layer_state) {
  499.         XP_ASSERT(layer_state->doc_lists);
  500.         return layer_state->doc_lists;
  501.     }
  502.     else
  503.         return NULL;
  504. }
  505.  
  506. /*************************************
  507.  * Function: lo_NewLayout
  508.  *
  509.  * Description: This function creates and initializes a new
  510.  *    layout state structure to be used for all state information
  511.  *    about this document (or sub-document) during its lifetime.
  512.  *
  513.  * Params: Window context,
  514.  *    the width and height of the
  515.  *    window we are formatting to.
  516.  *
  517.  * Returns: A pointer to a lo_DocState structure.
  518.  *    Returns a NULL on error (such as out of memory);
  519.  *************************************/
  520. lo_DocState *
  521. lo_NewLayout(MWContext *context, int32 width, int32 height,
  522.     int32 margin_width, int32 margin_height, lo_DocState* clone_state )
  523. {
  524.     lo_DocLists *doc_lists;
  525.     lo_TopState *top_state;
  526.     lo_DocState *state;
  527. #ifdef XP_WIN16
  528.     int32 i;
  529.     PA_Block *sblock_array;
  530. #endif /* XP_WIN16 */
  531.     int32 doc_id;
  532.  
  533.     doc_id = XP_DOCID(context);
  534.     top_state = lo_FetchTopState(doc_id);
  535.     if (top_state == NULL)
  536.     {
  537.         return(NULL);
  538.     }
  539.  
  540.     state = XP_NEW(lo_DocState);
  541.     if (state == NULL)
  542.     {
  543.         top_state->out_of_memory = TRUE;
  544.         return(NULL);
  545.     }
  546.     state->top_state = top_state;
  547.  
  548.     state->subdoc_tags = NULL;
  549.     state->subdoc_tags_end = NULL;
  550.  
  551.     if (top_state->doc_state)
  552.         doc_lists = lo_GetCurrentDocLists(top_state->doc_state);
  553.     else
  554.         doc_lists = lo_GetCurrentDocLists(state);
  555.  
  556.     if (!lo_InitDocState(state, context,
  557.                          width, height, margin_width, margin_height,
  558.                          clone_state, doc_lists, PR_FALSE))
  559.     {
  560.         top_state->out_of_memory = TRUE;
  561.         XP_FREE(state);
  562.         return NULL;
  563.     }
  564.     return state;
  565. }
  566.  
  567.         
  568. lo_DocState *
  569. lo_InitDocState(lo_DocState *state, MWContext *context,
  570.                 int32 width, int32 height,
  571.                 int32 margin_width, int32 margin_height,
  572.                 lo_DocState* clone_state,
  573.                 lo_DocLists *doc_lists,
  574.                 PRBool is_for_new_layer)
  575. {
  576.     lo_TopState *top_state = state->top_state;
  577.     
  578.     /*
  579.      * Set colors early so default text is correct.
  580.      */
  581.  
  582.     if( clone_state == NULL ){
  583.         state->text_fg.red = lo_master_colors[LO_COLOR_FG].red;
  584.         state->text_fg.green = lo_master_colors[LO_COLOR_FG].green;
  585.         state->text_fg.blue = lo_master_colors[LO_COLOR_FG].blue;
  586.  
  587.         state->text_bg.red = lo_master_colors[LO_COLOR_BG].red;
  588.         state->text_bg.green = lo_master_colors[LO_COLOR_BG].green;
  589.         state->text_bg.blue = lo_master_colors[LO_COLOR_BG].blue;
  590.  
  591.         state->anchor_color.red = lo_master_colors[LO_COLOR_LINK].red;
  592.         state->anchor_color.green = lo_master_colors[LO_COLOR_LINK].green;
  593.         state->anchor_color.blue = lo_master_colors[LO_COLOR_LINK].blue;
  594.  
  595.         state->visited_anchor_color.red = lo_master_colors[LO_COLOR_VLINK].red;
  596.         state->visited_anchor_color.green = lo_master_colors[LO_COLOR_VLINK].green;
  597.         state->visited_anchor_color.blue = lo_master_colors[LO_COLOR_VLINK].blue;
  598.  
  599.         state->active_anchor_color.red = lo_master_colors[LO_COLOR_ALINK].red;
  600.         state->active_anchor_color.green = lo_master_colors[LO_COLOR_ALINK].green;
  601.         state->active_anchor_color.blue = lo_master_colors[LO_COLOR_ALINK].blue;
  602.     }
  603.     else
  604.     {
  605.         state->text_fg.red = clone_state->text_fg.red;
  606.         state->text_fg.green = clone_state->text_fg.green;
  607.         state->text_fg.blue = clone_state->text_fg.blue;
  608.  
  609.         state->text_bg.red = clone_state->text_bg.red;
  610.         state->text_bg.green = clone_state->text_bg.green;
  611.         state->text_bg.blue = clone_state->text_bg.blue;
  612.  
  613.         state->anchor_color.red = clone_state->anchor_color.red;
  614.         state->anchor_color.green = clone_state->anchor_color.green;
  615.         state->anchor_color.blue = clone_state->anchor_color.blue;
  616.  
  617.         state->visited_anchor_color.red = clone_state->visited_anchor_color.red;
  618.         state->visited_anchor_color.green = clone_state->visited_anchor_color.green;
  619.         state->visited_anchor_color.blue = clone_state->visited_anchor_color.blue;
  620.  
  621.         state->active_anchor_color.red = clone_state->active_anchor_color.red;
  622.         state->active_anchor_color.green = clone_state->active_anchor_color.green;
  623.         state->active_anchor_color.blue = clone_state->active_anchor_color.blue;
  624.     }
  625.  
  626.     state->win_top = margin_height;
  627.     state->win_bottom = margin_height;
  628.     state->win_width = width;
  629.     state->win_height = height;
  630.  
  631.     state->base_x = 0;
  632.     state->base_y = 0;
  633.     state->x = 0;
  634.     state->y = 0;
  635.     state->width = 0;
  636.  
  637.     /* Layers don't use the line array, and resetting the line_num while laying out
  638.        a layer causes display bugs when displaying the _BODY layer. */
  639.     if (!is_for_new_layer)
  640.         state->line_num = 1;
  641.  
  642.     state->win_left = margin_width;
  643.     state->win_right = margin_width;
  644.  
  645.     state->max_width = state->win_left + state->win_right;
  646.     state->max_height = state->win_top + state->win_bottom;
  647.  
  648.     state->x = state->win_left;
  649.     state->y = state->win_top;
  650.  
  651.     state->left_margin = state->win_left;
  652.     state->right_margin = state->win_width - state->win_right;
  653.     state->left_margin_stack = NULL;
  654.     state->right_margin_stack = NULL;
  655.  
  656.     state->break_holder = state->x;
  657.     state->min_width = 0;
  658.     state->text_divert = P_UNKNOWN;
  659.     state->linefeed_state = 2;
  660.     state->delay_align = FALSE;
  661.     state->breakable = TRUE;
  662.     state->allow_amp_escapes = TRUE;
  663.     state->preformatted = PRE_TEXT_NO;
  664.     state->preformat_cols = 0;
  665.  
  666.     state->in_paragraph = FALSE;
  667.  
  668.     state->display_blocked = FALSE;
  669.     state->display_blocking_element_id = 0;
  670.     state->display_blocking_element_y = 0;
  671.  
  672.     state->line_list = NULL;
  673.     state->end_last_line = NULL;
  674.     state->float_list = NULL;
  675.  
  676.     /* Don't bother creating a line array for a layer. Layers don't use them. */
  677.     if (!is_for_new_layer) {
  678.         LO_Element **line_array;
  679.  
  680.         state->line_array = XP_ALLOC_BLOCK(LINE_INC * sizeof(LO_Element *));
  681.         if (state->line_array == NULL)
  682.         {
  683.             return(NULL);
  684.         }
  685.         XP_LOCK_BLOCK(line_array, LO_Element **, state->line_array);
  686.         line_array[0] = NULL;
  687.         XP_UNLOCK_BLOCK(state->line_array);
  688.         state->line_array_size = LINE_INC;
  689.  
  690. #ifdef XP_WIN16
  691.         {
  692.             XP_Block *larray_array;
  693.  
  694.             state->larray_array = XP_ALLOC_BLOCK(sizeof(XP_Block));
  695.             if (state->larray_array == NULL)
  696.             {
  697.                 XP_FREE_BLOCK(state->line_array);
  698.                 XP_DELETE(state);
  699.                 return(NULL);
  700.             }
  701.             XP_LOCK_BLOCK(larray_array, XP_Block *, state->larray_array);
  702.             larray_array[0] = state->line_array;
  703.             XP_UNLOCK_BLOCK(state->larray_array);
  704.             state->larray_array_size = 1;
  705.         }
  706. #endif /* XP_WIN16 */
  707.     }
  708.  
  709.     /* XXX - No font information is reset upon entering a layer, nor
  710.        is it restored when the layer ends.  Is this the right thing to do ? */
  711.     if (!is_for_new_layer || !state->font_stack) {
  712.         state->base_font_size = DEFAULT_BASE_FONT_SIZE;
  713.         state->font_stack = lo_DefaultFont(state, context);
  714.         if (state->font_stack == NULL)
  715.         {
  716.             XP_FREE_BLOCK(state->line_array);
  717. #ifdef XP_WIN16
  718.             XP_FREE_BLOCK(state->larray_array);
  719. #endif /* XP_WIN16 */
  720.             return(NULL);
  721.         }
  722.         state->font_stack->text_attr->size = state->base_font_size;
  723.  
  724.         state->text_info.max_width = 0;
  725.         state->text_info.ascent = 0;
  726.         state->text_info.descent = 0;
  727.         state->text_info.lbearing = 0;
  728.         state->text_info.rbearing = 0;
  729.     }
  730.  
  731.     state->align_stack = NULL;
  732.     state->line_height_stack = NULL;
  733.  
  734.     state->list_stack = lo_DefaultList(state);
  735.     if (state->list_stack == NULL)
  736.     {
  737.         XP_FREE_BLOCK(state->line_array);
  738. #ifdef XP_WIN16
  739.         XP_FREE_BLOCK(state->larray_array);
  740. #endif /* XP_WIN16 */
  741.         XP_DELETE(state->font_stack);
  742.         return(NULL);
  743.     }
  744.  
  745.     /*
  746.      * To initialize the default line height, we need to
  747.      * jump through hoops here to get the front end
  748.      * to tell us the default fonts line height.
  749.      */
  750.     {
  751.         LO_TextStruct tmp_text;
  752.         unsigned char str[1];
  753.  
  754.         memset (&tmp_text, 0, sizeof (tmp_text));
  755.         str[0] = ' ';
  756.         tmp_text.text = (PA_Block)str;
  757.         tmp_text.text_len = 1;
  758.         tmp_text.text_attr = state->font_stack->text_attr;
  759.         FE_GetTextInfo(context, &tmp_text, &(state->text_info));
  760.  
  761.         state->default_line_height = state->text_info.ascent +
  762.             state->text_info.descent;
  763.     }
  764.     if (state->default_line_height <= 0)
  765.     {
  766.         state->default_line_height = FEUNITS_Y(DEF_LINE_HEIGHT,context);
  767.     }
  768.  
  769.     state->line_buf_size = 0;
  770.     state->line_buf = PA_ALLOC(LINE_BUF_INC * sizeof(char));
  771.     if (state->line_buf == NULL)
  772.     {
  773.         XP_FREE_BLOCK(state->line_array);
  774. #ifdef XP_WIN16
  775.         XP_FREE_BLOCK(state->larray_array);
  776. #endif /* XP_WIN16 */
  777.         XP_DELETE(state->font_stack);
  778.         return(NULL);
  779.     }
  780.     state->line_buf_size = LINE_BUF_INC;
  781.     state->line_buf_len = 0;
  782.  
  783.     state->baseline = 0;
  784.     state->line_height = 0;
  785.     state->break_pos = -1;
  786.     state->break_width = 0;
  787.     state->last_char_CR = FALSE;
  788.     state->trailing_space = FALSE;
  789.     state->at_begin_line = TRUE;
  790.     state->hide_content = FALSE;
  791.  
  792.     state->old_break = NULL;
  793.     state->old_break_block = NULL;
  794.     state->old_break_pos = -1;
  795.     state->old_break_width = 0;
  796.  
  797.     state->current_named_anchor = NULL;
  798.     state->current_anchor = NULL;
  799.  
  800.     state->cur_ele_type = LO_NONE;
  801.     state->current_ele = NULL;
  802.     state->current_java = NULL;
  803.  
  804.     state->current_table = NULL;
  805.     state->current_grid = NULL;
  806.     state->current_multicol = NULL;
  807.  
  808.     if (!is_for_new_layer)
  809.         state->layer_nest_level = 0;
  810.  
  811.     /*
  812.      * These values are saved into the (sub)doc here
  813.      * so that if it gets Relayout() later, we know where
  814.      * to reset the from counts to.
  815.      */
  816.     if (doc_lists->form_list != NULL)
  817.     {
  818.         lo_FormData *form_list;
  819.  
  820.         form_list = doc_lists->form_list;
  821.         state->form_ele_cnt = form_list->form_ele_cnt;
  822.         state->form_id = form_list->id;
  823.     }
  824.     else
  825.     {
  826.         state->form_ele_cnt = 0;
  827.         state->form_id = 0;
  828.     }
  829.     state->start_in_form = top_state->in_form;
  830.     if (top_state->savedData.FormList != NULL)
  831.     {
  832.         lo_SavedFormListData *all_form_ele;
  833.  
  834.         all_form_ele = top_state->savedData.FormList;
  835.         state->form_data_index = all_form_ele->data_index;
  836.     }
  837.     else
  838.     {
  839.         state->form_data_index = 0;
  840.     }
  841.     
  842.     /*
  843.      * Remember number of embeds we had before beginning this
  844.      * (sub)doc. This information is used in laytable.c so
  845.      * it can preserve embed indices across a relayout.
  846.      */
  847.     state->embed_count_base = top_state->embed_count;
  848.  
  849.     /*
  850.      * Ditto for anchors, images, applets and embeds
  851.      */
  852.     state->url_count_base = doc_lists->url_list_len;
  853.     state->image_list_count_base = doc_lists->image_list_count;
  854.     state->applet_list_count_base = doc_lists->applet_list_count;
  855.     state->embed_list_count_base = doc_lists->embed_list_count;
  856.     if (!is_for_new_layer) {
  857.         state->current_layer_num_base = top_state->current_layer_num;
  858.         state->current_layer_num_max = top_state->current_layer_num;
  859.     }
  860.  
  861.     state->must_relayout_subdoc = FALSE;
  862.     state->allow_percent_width = TRUE;
  863.     state->allow_percent_height = TRUE;
  864.     state->is_a_subdoc = SUBDOC_NOT;
  865.     state->current_subdoc = 0;
  866.     state->sub_documents = NULL;
  867.     state->sub_state = NULL;
  868.  
  869.     state->current_cell = NULL;
  870.  
  871.     if (!is_for_new_layer) {
  872.         state->extending_start = FALSE;
  873.         state->selection_start = NULL;
  874.         state->selection_start_pos = 0;
  875.         state->selection_end = NULL;
  876.         state->selection_end_pos = 0;
  877.         state->selection_new = NULL;
  878.         state->selection_new_pos = 0;
  879.         state->selection_layer = NULL;
  880.     }
  881.     
  882. #ifdef EDITOR
  883.     state->edit_force_offset = FALSE;
  884.     state->edit_current_element = 0;
  885.     state->edit_current_offset = 0;
  886.     state->edit_relayout_display_blocked = FALSE;
  887. #endif
  888.     state->in_relayout = FALSE;
  889.     state->tab_stop = DEF_TAB_WIDTH;
  890.     state->beginning_tag_count = top_state->tag_count;
  891.  
  892.     state->cur_text_block = NULL;
  893.     state->need_min_width = FALSE;
  894.     
  895.     return(state);
  896. }
  897.  
  898. void LO_SetBackgroundImage( MWContext *context, char *pUrl )
  899. {
  900.     lo_TopState* top_state;
  901.  
  902.     /*
  903.      * Get the unique document ID, and retreive this
  904.      * documents layout state.
  905.      */
  906.     top_state = lo_FetchTopState(XP_DOCID(context));
  907.     if ((top_state == NULL)||(top_state->doc_state == NULL))
  908.     {
  909.         return;
  910.     }
  911.     if (!top_state->doc_layer)
  912.         return;
  913.  
  914.     top_state->doc_specified_bg = TRUE;
  915.  
  916.     LO_SetLayerBackdropURL(top_state->doc_layer, pUrl);
  917. }
  918.  
  919. static void
  920. lo_load_user_backdrop(MWContext *context, lo_DocState *state)
  921. {
  922.     LO_SetBackgroundImage( context, Master_backdrop_url );
  923. }
  924.  
  925. void
  926. LO_SetDocBgColor(MWContext *context, LO_Color *rgb)
  927. {
  928.     lo_TopState* top_state;
  929.  
  930.     /*
  931.      * Get the unique document ID, and retreive this
  932.      * documents layout state.
  933.      */
  934.     top_state = lo_FetchTopState(XP_DOCID(context));
  935.     if ((top_state == NULL)||(top_state->doc_state == NULL))
  936.     {
  937.         return;
  938.     }
  939.     
  940.     if (!top_state->doc_layer)
  941.         return;
  942.     
  943. #ifdef XP_MAC
  944.     /* This allows the front end to set a background color for
  945.        this context only. Without this call, the color will
  946.        still be the one from the global table */
  947.     FE_GetDefaultBackgroundColor(context, rgb);
  948. #endif
  949.     if (context->compositor)
  950.         LO_SetLayerBgColor(top_state->doc_layer, rgb);
  951. }
  952.  
  953. int32
  954. lo_calc_push_right_for_justify(lo_DocState *state, int32 *remainder)
  955. {
  956.     int32 count = -1;  /* start at -1 */
  957.     int32 push_right;
  958.     LO_Element *tptr;
  959.     LO_Element *last;
  960.  
  961.     tptr = state->line_list;
  962.  
  963.     push_right = state->right_margin - state->x;
  964.  
  965.     if(push_right > (state->right_margin - state->left_margin)/4)
  966.     {
  967.         return 0; /* don't do justify if it's too large */
  968.     }
  969.  
  970.     while (tptr != NULL)
  971.     {
  972.         if(tptr->type == LO_TEXT 
  973.            && tptr->lo_text.text)
  974.             count++;
  975.         last = tptr;
  976.         tptr = tptr->lo_any.next;
  977.     }
  978.  
  979.     /* if the last element is a space character then
  980.      * this must be the last line of a paragraph.
  981.      * don't justify.
  982.      */
  983.     if(last->type == LO_TEXT
  984.         && (*last).lo_text.text
  985.         && !XP_STRCMP((char*)last->lo_text.text, " "))
  986.         return 0;
  987.  
  988.     /* the push_right is the number of pixels to add to
  989.      * each space
  990.      */
  991.  
  992.     if(count > 0)
  993.     {
  994.         *remainder = push_right % count;
  995.         return push_right/count;
  996.     }
  997.     else
  998.     {
  999.         return 0;
  1000.     }
  1001. }
  1002.  
  1003. PRIVATE void
  1004. lo_add_to_y_for_all_elements_in_line(lo_DocState *state, int32 y_add)
  1005. {
  1006.     LO_Element *tptr;
  1007.  
  1008.     if(!state)
  1009.         return;
  1010.  
  1011.     tptr = state->line_list;
  1012.  
  1013.     while (tptr != NULL)
  1014.     {
  1015.         tptr->lo_any.y_offset += y_add;
  1016.  
  1017.         if (tptr->type == LO_CELL)
  1018.         {
  1019.             lo_ShiftCell((LO_CellStruct *)tptr, 0, y_add);
  1020.         }
  1021.         tptr = tptr->lo_any.next;
  1022.     }
  1023. }
  1024.  
  1025. void
  1026. lo_use_default_doc_background(MWContext *context, lo_DocState *state)
  1027. {
  1028.     lo_TopState *top_state = state->top_state;
  1029.     if (top_state->doc_specified_bg == FALSE) {
  1030.         if ((Master_backdrop_url != NULL) && 
  1031.             (UserOverride == FALSE || context->type == MWContextDialog)) {
  1032.             lo_load_user_backdrop(context, state);
  1033.         } else {
  1034.             /* Force an opaque solid background. */
  1035.             LO_SetDocBgColor(context, &state->text_bg);
  1036.         }
  1037.     }
  1038. }
  1039.  
  1040. /*************************************
  1041.  * Function: lo_FlushLineList
  1042.  *
  1043.  * Description: This function adds a linefeed element to the end
  1044.  *    of the current line, and now that the line is done, it asks
  1045.  *    the front end to display the line.  This function is only
  1046.  *     called by a hard linebreak.
  1047.  *
  1048.  * Params: Window context, document state, and flag for whether this is
  1049.  *    a breaking linefeed of not.  A breaking linefeed is one inserted
  1050.  *    just to break a text flow to the current window width.
  1051.  *
  1052.  * Returns: Nothing
  1053.  *************************************/
  1054. void
  1055. lo_FlushLineList(MWContext *context, lo_DocState *state, uint32 break_type, uint32 clear_type, Bool breaking)
  1056. {
  1057.     
  1058.     LO_LinefeedStruct *linefeed;
  1059.     /*
  1060.     LO_Element **line_array;
  1061.     */
  1062.     /* int32 justification_remainder=0;*/
  1063.     /*
  1064. #ifdef XP_WIN16
  1065.     int32 a_size;
  1066.     int32 a_indx;
  1067.     int32 a_line;
  1068.     XP_Block *larray_array;
  1069. #endif 
  1070.     */
  1071.     /* XP_WIN16 */
  1072.  
  1073.     lo_UpdateStateWhileFlushingLine( context, state );
  1074.  
  1075.     /*
  1076.     if (state->top_state->nothing_displayed != FALSE) {
  1077.     */
  1078.         /*
  1079.          * If we are displaying elements we are
  1080.          * no longer in the HEAD section of the HTML
  1081.          * we are in the BODY section.
  1082.          */
  1083.     /*
  1084.         state->top_state->in_head = FALSE;
  1085.         state->top_state->in_body = TRUE;
  1086.  
  1087.         lo_use_default_doc_background(context, state);
  1088.         state->top_state->nothing_displayed = FALSE;
  1089.     }
  1090.     */
  1091.  
  1092.     /*
  1093.      * There is a break at the end of this line.
  1094.      * this may change min_width.
  1095.      */
  1096.     /*
  1097.     {
  1098.         int32 new_break_holder;
  1099.         int32 min_width;
  1100.         int32 indent;
  1101.  
  1102.         new_break_holder = state->x;
  1103.         min_width = new_break_holder - state->break_holder;
  1104.         indent = state->list_stack->old_left_margin - state->win_left;
  1105.         min_width += indent;
  1106.         if (min_width > state->min_width)
  1107.         {
  1108.             state->min_width = min_width;
  1109.         }
  1110.     */
  1111.         /* If we are not within <NOBR> content, allow break_holder
  1112.          * to be set to the new position where a line break can occur.
  1113.          * This fixes BUG #70782
  1114.          */
  1115.     /*
  1116.         if (state->breakable != FALSE) {
  1117.             state->break_holder = new_break_holder;
  1118.         }
  1119.     }
  1120.     */
  1121.  
  1122.     /*
  1123.      * If in a division centering or right aligning this line
  1124.      */
  1125.     /*
  1126.     if ((state->align_stack != NULL)&&(state->delay_align == FALSE))
  1127.     {
  1128.         int32 push_right;
  1129.         LO_Element *tptr;
  1130.  
  1131.         if (state->align_stack->alignment == LO_ALIGN_CENTER)
  1132.         {
  1133.             push_right = (state->right_margin - state->x) / 2;
  1134.         }
  1135.         else if (state->align_stack->alignment == LO_ALIGN_RIGHT)
  1136.         {
  1137.             push_right = state->right_margin - state->x;
  1138.         }
  1139.         else if(state->align_stack->alignment == LO_ALIGN_JUSTIFY)
  1140.         {
  1141.             push_right = lo_calc_push_right_for_justify(state, &justification_remainder);
  1142.         }
  1143.         else
  1144.         {
  1145.             push_right = 0;
  1146.         }
  1147.  
  1148.         if ((push_right > 0 || justification_remainder)
  1149.             &&(state->line_list != NULL))
  1150.         {
  1151.             int32 count = 0;
  1152.             int32 move_delta;
  1153.             tptr = state->line_list;
  1154.  
  1155.             if(state->align_stack->alignment == LO_ALIGN_JUSTIFY)
  1156.                 move_delta = 0;
  1157.             else
  1158.                 move_delta = push_right;
  1159.  
  1160.             while (tptr != NULL)
  1161.             {
  1162.     */
  1163.                 /* 
  1164.                  * We don't shift over inflow layers, since their contents
  1165.                  * have already been shifted over.
  1166.                  */
  1167.         /*
  1168.          * We also don't shift bullets of type BULLET_MQUOTE.
  1169.          */
  1170.     /*
  1171.                 if (((tptr->type != LO_CELL)||
  1172.             (!tptr->lo_cell.cell_inflow_layer))&&
  1173.             ((tptr->type != LO_BULLET)||
  1174.             ((tptr->type == LO_BULLET)&&
  1175.              (tptr->lo_bullet.bullet_type != BULLET_MQUOTE))))
  1176.         {
  1177.                 tptr->lo_any.x += move_delta;
  1178.         }
  1179.     */
  1180.  
  1181.                 /* justification push_rights are additive */
  1182.     /*
  1183.                 if(state->align_stack->alignment == LO_ALIGN_JUSTIFY)
  1184.                 {
  1185.                     move_delta += push_right;
  1186.     */
  1187.                     /* if there is a justification remainder, add a pixel
  1188.                      * to the first n word breaks
  1189.                      */
  1190.     /*
  1191.                     if(count < justification_remainder)
  1192.                         move_delta++;
  1193.                 }
  1194.     */
  1195.                 /* 
  1196.                  * Note that if this is an inflow layer, we don't want
  1197.                  * to shift it since the alignment has already propogated
  1198.                  * to its contents.
  1199.                  */
  1200.     /*
  1201.                 if ((tptr->type == LO_CELL) &&
  1202.                     !tptr->lo_cell.cell_inflow_layer)
  1203.                 {
  1204.                     lo_ShiftCell((LO_CellStruct *)tptr, move_delta, 0);
  1205.                 }
  1206.                 tptr = tptr->lo_any.next;
  1207.  
  1208.                 count++;
  1209.             }
  1210.  
  1211.             if(state->align_stack->alignment == LO_ALIGN_JUSTIFY)
  1212.                 state->x = state->right_margin;
  1213.             else
  1214.                 state->x += push_right;
  1215.         }
  1216.     }
  1217.     */
  1218. #if 0
  1219.     /* apply line-height stack mods (if exists) */
  1220.     if(state->line_height_stack && state->end_last_line) 
  1221.     {
  1222.         LO_LinefeedStruct *linefeed = (LO_LinefeedStruct*)state->end_last_line;
  1223.         int32 cur_line_height;
  1224.         int32 new_line_height;
  1225.         int32 line_height_diff;
  1226.  
  1227.         if(state->line_height == 0)
  1228.         {
  1229.             int32 new_height = state->text_info.ascent +
  1230.                                     state->text_info.descent;
  1231.             int32 new_baseline = state->text_info.ascent;
  1232.  
  1233.             if ((new_height <= 0)&&(state->font_stack != NULL)&&
  1234.                 (state->font_stack->text_attr != NULL))
  1235.             {
  1236.                 lo_fillin_text_info(context, state);
  1237.  
  1238.                 new_height = state->text_info.ascent + state->text_info.descent;
  1239.                 new_baseline = state->text_info.ascent;
  1240.  
  1241.             }
  1242.  
  1243.             if(new_height <= 0)
  1244.             {
  1245.                 new_height = state->default_line_height;
  1246.                 new_baseline = state->default_line_height;
  1247.             }
  1248.  
  1249.             state->line_height = new_height;
  1250.             state->baseline = new_baseline;
  1251.         }
  1252.  
  1253.         cur_line_height = (state->y + state->baseline) - 
  1254.                                 (linefeed->y + linefeed->baseline);
  1255.  
  1256.         new_line_height = state->line_height_stack->height;
  1257.         line_height_diff = new_line_height - cur_line_height;
  1258.  
  1259.         /* only allow increasing line heights 
  1260.          * explicitly disallow negative diffs    
  1261.          */
  1262.         if(line_height_diff > 0)
  1263.         {
  1264.             lo_add_to_y_for_all_elements_in_line(state, line_height_diff);
  1265.  
  1266.             state->baseline += line_height_diff;
  1267.             state->line_height += line_height_diff;
  1268.         }
  1269.     }
  1270. #endif
  1271.  
  1272.  
  1273.     /*
  1274.      * Tack a linefeed element on to the end of the line list.
  1275.      * Take advantage of this necessary pass thorugh the line's
  1276.      * elements to set the line_height field in all
  1277.      * elements, and to look and see if we have reached a
  1278.      * possibly display blocking element.
  1279.      */
  1280.     linefeed = lo_NewLinefeed(state, context, break_type, clear_type);
  1281.  
  1282.     if (linefeed != NULL)
  1283.     {
  1284.         lo_AppendLineFeed( context, state, linefeed, breaking, TRUE );
  1285.  
  1286.         /*
  1287.         LO_Element *tptr;
  1288.  
  1289.         if (breaking != FALSE)
  1290.         {
  1291.             linefeed->ele_attrmask |= LO_ELE_BREAKING;
  1292.         }
  1293.         */
  1294.  
  1295.         /*
  1296.          * Horrible bitflag overuse!!!  For multicolumn text
  1297.          * we need to know if a line of text can be used for
  1298.          * a column break, or if it cannot because it is wrapped
  1299.          * around some object in the margin.  For lines that can be
  1300.          * used for column breaks, we will set the BREAKABLE
  1301.          * flag in their element mask.
  1302.          */
  1303.         /*
  1304.         if ((state->left_margin_stack == NULL)&&
  1305.             (state->right_margin_stack == NULL))
  1306.         {
  1307.             linefeed->ele_attrmask |= LO_ELE_BREAKABLE;
  1308.         }
  1309.  
  1310.         if ((state->align_stack != NULL)&&
  1311.             (state->delay_align != FALSE)&&
  1312.             (state->align_stack->alignment != LO_ALIGN_LEFT))
  1313.         {
  1314.             if (state->align_stack->alignment == LO_ALIGN_CENTER)
  1315.             {
  1316.                 linefeed->ele_attrmask |= LO_ELE_DELAY_CENTER;
  1317.             }
  1318.             else if (state->align_stack->alignment == LO_ALIGN_RIGHT)
  1319.             {
  1320.                 linefeed->ele_attrmask |= LO_ELE_DELAY_RIGHT;
  1321.             }
  1322.         }
  1323.  
  1324.         tptr = state->line_list;
  1325.  
  1326.         if (tptr == NULL)
  1327.         {
  1328.             state->line_list = (LO_Element *)linefeed;
  1329.             linefeed->prev = NULL;
  1330.         }
  1331.         else
  1332.         {
  1333.             while (tptr != NULL)
  1334.             {
  1335.         */
  1336.                 /*
  1337.                  * If the display is blocked for an element
  1338.                  * we havn't reached yet, check to see if
  1339.                  * it is in this line, and if so, save its
  1340.                  * y position.
  1341.                  */
  1342.         /*
  1343.                 if ((state->display_blocked != FALSE)&&
  1344. #ifdef EDITOR
  1345.                     (!state->edit_relayout_display_blocked)&&
  1346. #endif
  1347.                     (state->is_a_subdoc == SUBDOC_NOT)&&
  1348.                     (state->display_blocking_element_y == 0)&&
  1349.                     (state->display_blocking_element_id != -1)&&
  1350.                     (tptr->lo_any.ele_id >=
  1351.                     state->display_blocking_element_id))
  1352.                 {
  1353.                     state->display_blocking_element_y =
  1354.                         state->y;
  1355.         */
  1356.                     /*
  1357.                      * Special case, if the blocking element
  1358.                      * is on the first line, no blocking
  1359.                      * at all needs to happen.
  1360.                      */
  1361.         /*
  1362.                     if (state->y == state->win_top)
  1363.                     {
  1364.                         state->display_blocked = FALSE;
  1365.                         FE_SetDocPosition(context,
  1366.                             FE_VIEW, 0, state->base_y);
  1367.                         if (context->compositor)
  1368.                         {
  1369.                           XP_Rect rect;
  1370.                           
  1371.                           rect.left = 0;
  1372.                           rect.top = 0;
  1373.                           rect.right = state->win_width;
  1374.                           rect.bottom = state->win_height;
  1375.                           CL_UpdateDocumentRect(context->compositor,
  1376.                                                 &rect, (PRBool)FALSE);
  1377.                         }
  1378.                     }
  1379.                 }
  1380.                 tptr->lo_any.line_height = state->line_height;
  1381.         */
  1382.                 /*
  1383.                  * Special for bullets of type BULLET_MQUOTE
  1384.                  * They should always be as tall as the line.
  1385.                  */
  1386.         /*
  1387.                 if ((tptr->type == LO_BULLET)&&
  1388.                     (tptr->lo_bullet.bullet_type ==
  1389.                         BULLET_MQUOTE))
  1390.                 {
  1391.                     tptr->lo_any.y_offset = 0;
  1392.                     tptr->lo_any.height =
  1393.                         tptr->lo_any.line_height;
  1394.                 }
  1395.                 tptr = tptr->lo_any.next;
  1396.             }
  1397.             linefeed->prev = tptr;
  1398.         }
  1399.         state->x += linefeed->width;
  1400.         */
  1401.     } 
  1402.     else
  1403.     {
  1404.         return;        /* ALEKS OUT OF MEMORY RETURN */
  1405.     }
  1406.  
  1407.     /*
  1408.      * Nothing to flush
  1409.      */
  1410.     if (state->line_list == NULL)
  1411.     {
  1412.         return;
  1413.     }
  1414.  
  1415.     /*
  1416.      * We are in a layer within this (sub)doc, stuff the line there instead.
  1417.      */
  1418.     if (state->layer_nest_level > 0)
  1419.     {
  1420.         lo_AddLineListToLayer(context, state, (LO_Element *)linefeed);
  1421.         state->line_list = NULL;
  1422.         state->old_break = NULL;
  1423.         state->old_break_block = NULL;
  1424.         state->old_break_pos = -1;
  1425.         state->old_break_width = 0;
  1426.         state->baseline = 0;
  1427.         return;
  1428.     }
  1429.  
  1430.     /*
  1431.      * If necessary, grow the line array to hold more lines.
  1432.      */
  1433. /*
  1434. #ifdef XP_WIN16
  1435.     a_size = SIZE_LIMIT / sizeof(LO_Element *);
  1436.     a_indx = (state->line_num - 1) / a_size;
  1437.     a_line = state->line_num - (a_indx * a_size);
  1438.  
  1439.     XP_LOCK_BLOCK(larray_array, XP_Block *, state->larray_array);
  1440.     state->line_array = larray_array[a_indx];
  1441.  
  1442.     if (a_line == a_size)
  1443.     {
  1444.         state->line_array = XP_ALLOC_BLOCK(LINE_INC *
  1445.                     sizeof(LO_Element *));
  1446.         if (state->line_array == NULL)
  1447.         {
  1448.             XP_UNLOCK_BLOCK(state->larray_array);
  1449.             state->top_state->out_of_memory = TRUE;
  1450.             return;
  1451.         }
  1452.         XP_LOCK_BLOCK(line_array, LO_Element **, state->line_array);
  1453.         line_array[0] = NULL;
  1454.         XP_UNLOCK_BLOCK(state->line_array);
  1455.         state->line_array_size = LINE_INC;
  1456.  
  1457.         state->larray_array_size++;
  1458.         XP_UNLOCK_BLOCK(state->larray_array);
  1459.         state->larray_array = XP_REALLOC_BLOCK(
  1460.             state->larray_array, (state->larray_array_size
  1461.             * sizeof(XP_Block)));
  1462.         if (state->larray_array == NULL)
  1463.         {
  1464.             state->top_state->out_of_memory = TRUE;
  1465.             return;
  1466.         }
  1467.         XP_LOCK_BLOCK(larray_array, XP_Block *, state->larray_array);
  1468.         larray_array[state->larray_array_size - 1] = state->line_array;
  1469.         state->line_array = larray_array[a_indx];
  1470.     }
  1471.     else if (a_line >= state->line_array_size)
  1472.     {
  1473.         state->line_array_size += LINE_INC;
  1474.         if (state->line_array_size > a_size)
  1475.         {
  1476.             state->line_array_size = (intn)a_size;
  1477.         }
  1478.         state->line_array = XP_REALLOC_BLOCK(state->line_array,
  1479.             (state->line_array_size * sizeof(LO_Element *)));
  1480.         if (state->line_array == NULL)
  1481.         {
  1482.             XP_UNLOCK_BLOCK(state->larray_array);
  1483.             state->top_state->out_of_memory = TRUE;
  1484.             return;
  1485.         }
  1486.         larray_array[a_indx] = state->line_array;
  1487.     }
  1488. */
  1489.     /*
  1490.      * Place this line of elements into the line array.
  1491.      */
  1492. /*
  1493.     XP_LOCK_BLOCK(line_array, LO_Element **, state->line_array);
  1494.     line_array[a_line - 1] = state->line_list;
  1495.     XP_UNLOCK_BLOCK(state->line_array);
  1496.  
  1497.     XP_UNLOCK_BLOCK(state->larray_array);
  1498. #else
  1499.     if (state->line_num > state->line_array_size)
  1500.     {
  1501.         int32 line_inc;
  1502.  
  1503.         if (state->line_array_size > (LINE_INC * 10))
  1504.         {
  1505.             line_inc = state->line_array_size / 10;
  1506.         }
  1507.         else
  1508.         {
  1509.             line_inc = LINE_INC;
  1510.         }
  1511.  
  1512.         state->line_array = XP_REALLOC_BLOCK(state->line_array,
  1513.             ((state->line_array_size + line_inc) *
  1514.             sizeof(LO_Element *)));
  1515.         if (state->line_array == NULL)
  1516.         {
  1517.             state->top_state->out_of_memory = TRUE;
  1518.             return;
  1519.         }
  1520.         state->line_array_size += line_inc;
  1521.     }
  1522. */
  1523.     /*
  1524.      * Place this line of elements into the line array.
  1525.      */
  1526. /*
  1527.      XP_LOCK_BLOCK(line_array, LO_Element **, state->line_array);
  1528.     line_array[state->line_num - 1] = state->line_list;
  1529.     XP_UNLOCK_BLOCK(state->line_array);
  1530. #endif */
  1531.  
  1532. /* XP_WIN16 */
  1533.  
  1534.     /*
  1535.      * connect the complete doubly linked list between this line
  1536.      * and the last one.
  1537.      */
  1538. /*
  1539.     if (state->end_last_line != NULL)
  1540.     {
  1541.         state->end_last_line->lo_any.next = state->line_list;
  1542.         state->line_list->lo_any.prev = state->end_last_line;
  1543.     }
  1544.     state->end_last_line = (LO_Element *)linefeed;
  1545.  
  1546.     state->line_list = NULL;
  1547.     state->line_num++;
  1548. */
  1549.     /* 
  1550.      *Don't draw if we're doing layers...we'll just refresh when the 
  1551.      * the layer size increases.
  1552.      */
  1553. /*
  1554. #ifdef LAYERS
  1555. */
  1556.     /*
  1557.      * Have the front end display this line.
  1558.      */
  1559.     /* For layers, only draw if a compositor doesn't exist */
  1560. /*
  1561.     if (!context->compositor)
  1562. */
  1563.         /* We need to supply a display rectangle that is guaranteed to
  1564.            encompass all elements on the line.  The special 0x3fffffff
  1565.            value is approximately half the range of a 32-bit int, so
  1566.            it leaves room for overflow if arithmetic is done on these
  1567.            values. */
  1568. /*
  1569.         lo_DisplayLine(context, state, (state->line_num - 2),
  1570.                        0, 0, 0x3fffffffL, 0x3fffffffL);
  1571. #else
  1572.         lo_DisplayLine(context, state, (state->line_num - 2),
  1573.                        0, 0, 0x3fffffffL, 0x3fffffffL);
  1574. #endif */ /* LAYERS */
  1575.  
  1576.     lo_UpdateStateAfterFlushingLine( context, state, linefeed, FALSE );
  1577.     /*
  1578.      * We are starting a new line.  Clear any old break
  1579.      * positions left over, clear the line_list, and increase
  1580.      * the line number.
  1581.      */
  1582.     /*
  1583.     state->old_break = NULL;
  1584.     state->old_break_block = NULL;
  1585.     state->old_break_pos = -1;
  1586.     state->old_break_width = 0;
  1587.     state->baseline = 0;
  1588.     */
  1589. }
  1590.  
  1591.  
  1592. /*************************************
  1593.  * Function: lo_CleanTextWhitespace
  1594.  *
  1595.  * Description: Utility function to pass through a line an clean up
  1596.  *     all its whitespace.   Compress multiple whitespace between
  1597.  *    element to a single space, and remove heading and
  1598.  *    trailing whitespace.
  1599.  *    Text is cleaned in place in the passed buffer.
  1600.  *
  1601.  * Params: Pointer to text to be cleand, and its length.
  1602.  *
  1603.  * Returns: Length of cleaned text.
  1604.  *************************************/
  1605. int32
  1606. lo_CleanTextWhitespace(char *text, int32 text_len)
  1607. {
  1608.     char *from_ptr;
  1609.     char *to_ptr;
  1610.     int32 len;
  1611.     int32 new_len;
  1612.  
  1613.     if (text == NULL)
  1614.     {
  1615.         return(0);
  1616.     }
  1617.  
  1618.     len = 0;
  1619.     new_len = 0;
  1620.     from_ptr = text;
  1621.     to_ptr = text;
  1622.  
  1623.     while (len < text_len)
  1624.     {
  1625.         /*
  1626.          * Compress chunk of whitespace
  1627.          */
  1628.         while ((len < text_len)&&(XP_IS_SPACE(*from_ptr)))
  1629.         {
  1630.             len++;
  1631.             from_ptr++;
  1632.         }
  1633.         if (len == text_len)
  1634.         {
  1635.             continue;
  1636.         }
  1637.  
  1638.         /*
  1639.          * Skip past "good" text
  1640.          */
  1641.         while ((len < text_len)&&(!XP_IS_SPACE(*from_ptr)))
  1642.         {
  1643.             *to_ptr++ = *from_ptr++;
  1644.             len++;
  1645.             new_len++;
  1646.         }
  1647.  
  1648.         /*
  1649.          * Put in one space to represent the compressed spaces.
  1650.          */
  1651.         if (len != text_len)
  1652.         {
  1653.             *to_ptr++ = ' ';
  1654.             new_len++;
  1655.         }
  1656.     }
  1657.  
  1658.     /*
  1659.      * Remove the trailing space, and terminate string.
  1660.      */
  1661.     if ((new_len > 0)&&(*(to_ptr - 1) == ' '))
  1662.     {
  1663.         to_ptr--;
  1664.         new_len--;
  1665.     }
  1666.     *to_ptr = '\0';
  1667.  
  1668.     return(new_len);
  1669. }
  1670.  
  1671.  
  1672. /*
  1673.  * Used to strip white space off of HREF parameter values to make
  1674.  * valid URLs out of them.  Remove whitespace from both ends, and
  1675.  * remove all non-space whitespace from the middle.
  1676.  */
  1677. int32
  1678. lo_StripTextWhitespace(char *text, int32 text_len)
  1679. {
  1680.     char *from_ptr;
  1681.     char *to_ptr;
  1682.     int32 len;
  1683.     int32 tail;
  1684.  
  1685.     if ((text == NULL)||(text_len < 1))
  1686.     {
  1687.         return(0);
  1688.     }
  1689.  
  1690.     len = 0;
  1691.     from_ptr = text;
  1692.     /*
  1693.      * strip leading whitespace
  1694.      */
  1695.     while ((len < text_len)&&(XP_IS_SPACE(*from_ptr)))
  1696.     {
  1697.         len++;
  1698.         from_ptr++;
  1699.     }
  1700.  
  1701.     if (len == text_len)
  1702.     {
  1703.         *text = '\0';
  1704.         return(0);
  1705.     }
  1706.  
  1707.     tail = 0;
  1708.     from_ptr = (char *)(text + text_len - 1);
  1709.     /*
  1710.      * Remove any trailing space
  1711.      */
  1712.     while (XP_IS_SPACE(*from_ptr))
  1713.     {
  1714.         from_ptr--;
  1715.         tail++;
  1716.     }
  1717.  
  1718.     /*
  1719.      * terminate string
  1720.      */
  1721.     from_ptr++;
  1722.     *from_ptr = '\0';
  1723.  
  1724.     /*
  1725.      * remove all non-space whitespace from the middle of the string.
  1726.      */
  1727.     from_ptr = (char *)(text + len);
  1728.     len = text_len - len - tail;
  1729.     to_ptr = text;
  1730.     while (*from_ptr != '\0')
  1731.     {
  1732.         if (XP_IS_SPACE(*from_ptr) && (*from_ptr != ' '))
  1733.         {
  1734.             from_ptr++;
  1735.             len--;
  1736.         }
  1737.         else
  1738.         {
  1739.             *to_ptr++ = *from_ptr++;
  1740.         }
  1741.     }
  1742.     *to_ptr = '\0';
  1743.  
  1744.     return(len);
  1745. }
  1746.  
  1747.  
  1748. LO_AnchorData *
  1749. lo_NewAnchor(lo_DocState *state, PA_Block href, PA_Block targ)
  1750. {
  1751.     LO_AnchorData *anchor_data;
  1752.     lo_LayerDocState *layer_state;
  1753.  
  1754.     anchor_data = XP_NEW_ZAP(LO_AnchorData);
  1755.     if (anchor_data)
  1756.     {
  1757.         anchor_data->anchor = href;
  1758.         anchor_data->target = targ;
  1759.         layer_state = lo_CurrentLayerState(state);
  1760.         if (layer_state )
  1761.             anchor_data->layer = layer_state->layer;
  1762.     }
  1763.     else
  1764.     {
  1765.         state->top_state->out_of_memory = TRUE;
  1766.     }
  1767.     return anchor_data;
  1768. }
  1769.  
  1770.  
  1771. void
  1772. lo_DestroyAnchor(LO_AnchorData *anchor_data)
  1773. {
  1774.     if (anchor_data->anchor != NULL)
  1775.     {
  1776.         PA_FREE(anchor_data->anchor);
  1777.     }
  1778.     if (anchor_data->target != NULL)
  1779.     {
  1780.         PA_FREE(anchor_data->target);
  1781.     }
  1782.     XP_DELETE(anchor_data);
  1783. }
  1784.  
  1785.  
  1786. /*
  1787.  * Add this url's block to the list
  1788.  * of all allocated urls so we can free
  1789.  * it later.
  1790.  */
  1791. void
  1792. lo_AddToUrlList(MWContext *context, lo_DocState *state,
  1793.     LO_AnchorData *url_buff)
  1794. {
  1795.     lo_TopState *top_state;
  1796.     int32 i;
  1797.     LO_AnchorData **anchor_array;
  1798.     intn a_url;
  1799. #ifdef XP_WIN16
  1800.     intn a_size;
  1801.     intn a_indx;
  1802.     XP_Block *ulist_array;
  1803. #endif /* XP_WIN16 */
  1804.     lo_DocLists *doc_lists;
  1805.     
  1806.     doc_lists = lo_GetCurrentDocLists(state);
  1807.  
  1808.     /*
  1809.      * Error checking
  1810.      */
  1811.     if ((url_buff == NULL)||(state == NULL))
  1812.     {
  1813.         return;
  1814.     }
  1815.  
  1816.     top_state = state->top_state;
  1817.  
  1818.     /*
  1819.      * We may need to grow the url_list.
  1820.      */
  1821. #ifdef XP_WIN16
  1822.     a_size = SIZE_LIMIT / sizeof(XP_Block *);
  1823.     a_indx = doc_lists->url_list_len / a_size;
  1824.     a_url = doc_lists->url_list_len - (a_indx * a_size);
  1825.  
  1826.     XP_LOCK_BLOCK(ulist_array, XP_Block *, doc_lists->ulist_array);
  1827.  
  1828.  
  1829.     if ((a_url == 0)&&(a_indx > 0))
  1830.     {
  1831.         doc_lists->url_list = XP_ALLOC_BLOCK(URL_LIST_INC *
  1832.                     sizeof(LO_AnchorData *));
  1833.         if (doc_lists->url_list == NULL)
  1834.         {
  1835.             XP_UNLOCK_BLOCK(doc_lists->ulist_array);
  1836.             top_state->out_of_memory = TRUE;
  1837.             return;
  1838.         }
  1839.         doc_lists->url_list_size = URL_LIST_INC;
  1840.         XP_LOCK_BLOCK(anchor_array, LO_AnchorData **,
  1841.             doc_lists->url_list);
  1842.         for (i=0; i < URL_LIST_INC; i++)
  1843.         {
  1844.             anchor_array[i] = NULL;
  1845.         }
  1846.         XP_UNLOCK_BLOCK(doc_lists->url_list);
  1847.  
  1848.         doc_lists->ulist_array_size++;
  1849.         XP_UNLOCK_BLOCK(doc_lists->ulist_array);
  1850.         doc_lists->ulist_array = XP_REALLOC_BLOCK(
  1851.             doc_lists->ulist_array, (doc_lists->ulist_array_size
  1852.             * sizeof(XP_Block)));
  1853.         if (doc_lists->ulist_array == NULL)
  1854.         {
  1855.             top_state->out_of_memory = TRUE;
  1856.             return;
  1857.         }
  1858.         XP_LOCK_BLOCK(ulist_array, XP_Block *, doc_lists->ulist_array);
  1859.         ulist_array[doc_lists->ulist_array_size - 1] = doc_lists->url_list;
  1860.         doc_lists->url_list = ulist_array[a_indx];
  1861.     }
  1862.     else if (a_url >= doc_lists->url_list_size)
  1863.     {
  1864.         int32 url_list_inc;
  1865.  
  1866.         if ((doc_lists->url_list_size / 10) > URL_LIST_INC)
  1867.         {
  1868.             url_list_inc = doc_lists->url_list_size / 10;
  1869.         }
  1870.         else
  1871.         {
  1872.             url_list_inc = URL_LIST_INC;
  1873.         }
  1874.         doc_lists->url_list_size += (intn)url_list_inc;
  1875.         if (doc_lists->url_list_size > a_size)
  1876.         {
  1877.             doc_lists->url_list_size = a_size;
  1878.         }
  1879.  
  1880.         doc_lists->url_list = ulist_array[a_indx];
  1881.         doc_lists->url_list = XP_REALLOC_BLOCK(doc_lists->url_list,
  1882.             (doc_lists->url_list_size * sizeof(LO_AnchorData *)));
  1883.         if (doc_lists->url_list == NULL)
  1884.         {
  1885.             XP_UNLOCK_BLOCK(doc_lists->ulist_array);
  1886.             top_state->out_of_memory = TRUE;
  1887.             return;
  1888.         }
  1889.         ulist_array[a_indx] = doc_lists->url_list;
  1890.         /*
  1891.          * Clear the new entries
  1892.          */
  1893.         XP_LOCK_BLOCK(anchor_array, LO_AnchorData **,
  1894.             doc_lists->url_list);
  1895.         for (i = doc_lists->url_list_len; i < doc_lists->url_list_size; i++)
  1896.         {
  1897.             anchor_array[i] = NULL;
  1898.         }
  1899.         XP_UNLOCK_BLOCK(doc_lists->url_list);
  1900.     }
  1901.     doc_lists->url_list = ulist_array[a_indx];
  1902. #else
  1903.     if (doc_lists->url_list_len ==
  1904.         doc_lists->url_list_size)
  1905.     {
  1906.         int32 url_list_inc;
  1907.  
  1908.         if ((doc_lists->url_list_size / 10) > URL_LIST_INC)
  1909.         {
  1910.             url_list_inc = doc_lists->url_list_size / 10;
  1911.         }
  1912.         else
  1913.         {
  1914.             url_list_inc = URL_LIST_INC;
  1915.         }
  1916.         doc_lists->url_list_size += url_list_inc;
  1917.         doc_lists->url_list = XP_REALLOC_BLOCK(doc_lists->url_list,
  1918.                     (doc_lists->url_list_size *
  1919.                     sizeof(LO_AnchorData *)));
  1920.         if (doc_lists->url_list == NULL)
  1921.         {
  1922.             top_state->out_of_memory = TRUE;
  1923.             return;
  1924.         }
  1925.  
  1926.         /*
  1927.          * Clear the new entries
  1928.          */
  1929.         XP_LOCK_BLOCK(anchor_array, LO_AnchorData **, doc_lists->url_list);
  1930.         for (i = doc_lists->url_list_len; i < doc_lists->url_list_size; i++)
  1931.         {
  1932.             anchor_array[i] = NULL;
  1933.         }
  1934.         XP_UNLOCK_BLOCK(doc_lists->url_list);
  1935.     }
  1936.     a_url = doc_lists->url_list_len;
  1937. #endif /* XP_WIN16 */
  1938.  
  1939.     XP_LOCK_BLOCK(anchor_array, LO_AnchorData **, doc_lists->url_list);
  1940.     if (anchor_array[a_url] != NULL)
  1941.     {
  1942.         lo_DestroyAnchor(anchor_array[a_url]);
  1943.     }
  1944.     anchor_array[a_url] = url_buff;
  1945.     doc_lists->url_list_len++;
  1946.     XP_UNLOCK_BLOCK(doc_lists->url_list);
  1947. }
  1948.  
  1949.  
  1950. void
  1951. lo_BodyMargins(MWContext *context, lo_DocState *state, PA_Tag *tag)
  1952. {
  1953.     PA_Block buff;
  1954.     char *str;
  1955.     int32 margin_width;
  1956.     int32 margin_height;
  1957.     Bool changes;
  1958.  
  1959.     margin_width = state->win_left;
  1960.     margin_height = state->win_top;
  1961.     changes = FALSE;
  1962.  
  1963.     /*
  1964.      * Get the margin width.
  1965.      */
  1966.     buff = lo_FetchParamValue(context, tag, PARAM_MARGINWIDTH);
  1967.     if (buff != NULL)
  1968.     {
  1969.         int32 val;
  1970.  
  1971.         PA_LOCK(str, char *, buff);
  1972.         val = XP_ATOI(str);
  1973.         if (val < 0)
  1974.         {
  1975.             val = 0;
  1976.         }
  1977.         margin_width = val;
  1978.         PA_UNLOCK(buff);
  1979.         PA_FREE(buff);
  1980.         margin_width = FEUNITS_X(margin_width, context);
  1981.         /*
  1982.          * Sanify based on window width.
  1983.          */
  1984.         if (margin_width > ((state->win_width  / 2) - 1))
  1985.         {
  1986.             margin_width = ((state->win_width  / 2) - 1);
  1987.         }
  1988.         state->top_state->body_attr |= BODY_ATTR_MARGINS;
  1989.         changes = TRUE;
  1990.     }
  1991.  
  1992.     /*
  1993.      * Get the margin height.
  1994.      */
  1995.     buff = lo_FetchParamValue(context, tag, PARAM_MARGINHEIGHT);
  1996.     if (buff != NULL)
  1997.     {
  1998.         int32 val;
  1999.  
  2000.         PA_LOCK(str, char *, buff);
  2001.         val = XP_ATOI(str);
  2002.         if (val < 0)
  2003.         {
  2004.             val = 0;
  2005.         }
  2006.         margin_height = val;
  2007.         PA_UNLOCK(buff);
  2008.         PA_FREE(buff);
  2009.         margin_height = FEUNITS_Y(margin_height, context);
  2010.         /*
  2011.          * Sanify based on window height.
  2012.          */
  2013.         if (margin_height > ((state->win_height  / 2) - 1))
  2014.         {
  2015.             margin_height = ((state->win_height  / 2) - 1);
  2016.         }
  2017.         state->top_state->body_attr |= BODY_ATTR_MARGINS;
  2018.         changes = TRUE;
  2019.     }
  2020.  
  2021.     if (changes != FALSE)
  2022.     {
  2023.         state->win_top = margin_height;
  2024.         state->win_bottom = margin_height;
  2025.  
  2026.         state->win_left = margin_width;
  2027.         state->win_right = margin_width;
  2028.  
  2029.         state->max_width = state->win_left + state->win_right;
  2030.         state->max_height = state->win_top + state->win_bottom;
  2031.  
  2032.         state->x = state->win_left;
  2033.         state->y = state->win_top;
  2034.  
  2035.         state->left_margin = state->win_left;
  2036.         state->right_margin = state->win_width - state->win_right;
  2037.  
  2038.         state->break_holder = state->x;
  2039.  
  2040.         /*
  2041.          * Need to reset the margin values in the default list stack
  2042.          */
  2043.         if ((state->list_stack->type == P_UNKNOWN)&&
  2044.             (state->list_stack->next == NULL))
  2045.         {
  2046.             state->list_stack->old_left_margin = state->win_left;
  2047.             state->list_stack->old_right_margin =
  2048.                     state->win_width - state->win_right;
  2049.         }
  2050.         else
  2051.         {
  2052.         /*
  2053.          * This should never happen.  If it doesm it means we somehow
  2054.          * started a list without knowing that we had entered the BODY
  2055.          * of the document.
  2056.          */
  2057.         }
  2058.     }
  2059. }
  2060.  
  2061.  
  2062. void
  2063. lo_ProcessBodyTag(MWContext *context, lo_DocState *state, PA_Tag *tag)
  2064. {
  2065.     if (tag->is_end == FALSE)
  2066.     {
  2067.         if ((state->end_last_line == NULL)&&
  2068.             ((state->top_state->body_attr & BODY_ATTR_MARGINS) == 0))
  2069.         {
  2070.             lo_BodyMargins(context, state, tag);
  2071.         }
  2072.         if (UserOverride == FALSE || context->type == MWContextDialog)
  2073.         {
  2074.             lo_BodyBackground(context, state, tag, FALSE);
  2075.         }
  2076.         if (( !EDT_IS_EDITOR( context ) )&&
  2077.             ((state->top_state->body_attr & BODY_ATTR_JAVA) == 0))
  2078.         {
  2079.             if (lo_ProcessContextEventHandlers(context, state, tag))
  2080.             {
  2081.                 state->top_state->body_attr |= BODY_ATTR_JAVA;
  2082.             }
  2083.         }
  2084.     }
  2085. }
  2086.  
  2087. void
  2088. lo_SetBaseUrl(lo_TopState *top_state, char *url, Bool is_blocked)
  2089. {
  2090.     if (url)
  2091.         url = XP_STRDUP(url);
  2092.  
  2093.     if (is_blocked)
  2094.     {
  2095.         if (top_state->tag_from_inline_stream)
  2096.         {
  2097.             XP_FREEIF(top_state->inline_stream_blocked_base_url);
  2098.             top_state->inline_stream_blocked_base_url = url;
  2099.         }
  2100.         else
  2101.         {
  2102.             XP_FREEIF(top_state->main_stream_blocked_base_url);
  2103.             top_state->main_stream_blocked_base_url = url;
  2104.         }
  2105.     }
  2106.     else 
  2107.     {
  2108.         XP_FREEIF(top_state->base_url);
  2109.         top_state->base_url = url;
  2110.     }
  2111. }
  2112.  
  2113. /*************************************
  2114.  * Function: lo_BlockTag
  2115.  *
  2116.  * Description: This function blocks the layout of the tag, and
  2117.  *    saves them in the context.
  2118.  *
  2119.  * Params: Window context and document state, and the tag to be blocked.
  2120.  *
  2121.  * Returns: Nothing
  2122.  *************************************/
  2123. void
  2124. lo_BlockTag(MWContext *context, lo_DocState *state, PA_Tag *tag)
  2125. {
  2126.     PA_Tag ***tags_end_ptr, **tags_end;    /* triple-indirect, wow! see below */
  2127.     int32 doc_id;
  2128.     lo_TopState *top_state;
  2129.     lo_DocState *new_state;
  2130.     char *save_base;
  2131.  
  2132.     /*
  2133.      * All blocked tags should be at the top level of state
  2134.      */
  2135.     doc_id = XP_DOCID(context);
  2136.     top_state = lo_FetchTopState(doc_id);
  2137.     if ((top_state == NULL)||(top_state->doc_state == NULL))
  2138.     {
  2139.         return;
  2140.     }
  2141.     state = top_state->doc_state;
  2142.  
  2143.     new_state = lo_CurrentSubState(state);
  2144.  
  2145.     if (top_state->tags == NULL)
  2146.         PA_HoldDocData(top_state->doc_data);
  2147.  
  2148.     /*
  2149.      * For everything except BASE tags, we need to use
  2150.      * the blocked base here as our real base so that
  2151.      * relative URLs are processed properly.
  2152.      */
  2153.     if (tag->type != P_BASE)
  2154.     {
  2155.         save_base = top_state->base_url;
  2156.         if (top_state->tag_from_inline_stream)
  2157.         {
  2158.             if (top_state->inline_stream_blocked_base_url)
  2159.                 top_state->base_url = top_state->inline_stream_blocked_base_url;
  2160.         }
  2161.         else
  2162.         {
  2163.             if (top_state->main_stream_blocked_base_url)
  2164.                 top_state->base_url = top_state->main_stream_blocked_base_url;
  2165.         }
  2166.     }
  2167.  
  2168.     switch (tag->type)
  2169.     {
  2170.         /*
  2171.          * We need to process these when blocked so that
  2172.          * relative URLs of images that are processed when
  2173.          * blocked are correct.
  2174.          */
  2175.         case P_BASE:
  2176.             {
  2177.                 PA_Block buff;
  2178.                 char *url;
  2179.  
  2180.                 buff = lo_FetchParamValue(context, tag,
  2181.                         PARAM_HREF);
  2182.                 if (buff != NULL)
  2183.                 {
  2184.                     PA_LOCK(url, char *, buff);
  2185.                     if (url != NULL)
  2186.                     {
  2187.                         int32 len;
  2188.  
  2189.                         len = lo_StripTextWhitespace(
  2190.                             url, XP_STRLEN(url));
  2191.                     }
  2192.                     lo_SetBaseUrl(top_state, url, TRUE);
  2193.                     PA_UNLOCK(buff);
  2194.                     PA_FREE(buff);
  2195.                 }
  2196.             }
  2197.             break;
  2198.         case P_IMAGE:
  2199.         case P_NEW_IMAGE:
  2200.             if (tag->is_end == FALSE)
  2201.             {
  2202.                 /*
  2203.                  * For images that are part of the main document, we 
  2204.                  * can use the doc_data's url as the base URL. For
  2205.                  * images that are part of a LAYER that has a SRC
  2206.                  * attribute, we use the top_state's version (the base_url
  2207.                  * is temporarily changed to that of the LAYER while
  2208.                  * we process tags within the layer). The input_write_level
  2209.                  * tells us whether the tag is part of the main document
  2210.                  * or the layer.
  2211.                  */
  2212.                 lo_BlockedImageLayout(context, new_state, tag,
  2213.                                       top_state->base_url);
  2214.             }
  2215.             break;
  2216.         case P_SCRIPT:
  2217.         case P_STYLE:
  2218.         case P_LINK:
  2219.             lo_BlockScriptTag(context, new_state, tag);
  2220.             break;
  2221.         case P_LAYER:
  2222.             lo_BlockLayerTag(context, new_state, tag);
  2223.             break;
  2224.         case P_PARAM:
  2225.             lo_ProcessParamTag(context, new_state, tag, TRUE);
  2226.             break;
  2227.         case P_OBJECT:          
  2228.             lo_ProcessObjectTag(context, new_state, tag, TRUE);
  2229.             break;
  2230.     }
  2231.     /*
  2232.      * Now restore the base that you switched if it
  2233.      * wasn't a BASE tag.
  2234.      */
  2235.     if (tag->type != P_BASE)
  2236.     {
  2237.         top_state->base_url = save_base;
  2238.     }
  2239.  
  2240.     /*
  2241.      * Unify the basis and induction cases of singly-linked list insert
  2242.      * using a double-indirect pointer.  Instead of
  2243.      *
  2244.      *    if (head == NULL)
  2245.      *        head = tail = elem;
  2246.      *    else
  2247.      *        tail = tail->next = elem;
  2248.      *
  2249.      * where head = tail = NULL is the empty state and elem->next = NULL,
  2250.      * use a pointer to the pointer to the last element:
  2251.      *
  2252.      *    *tail_ptr = elem;
  2253.      *    tail_ptr = &elem->next;
  2254.      *
  2255.      * where head = NULL, tail_ptr = &head is the empty state.
  2256.      *
  2257.      * The triple-indirection below is to avoid further splitting cases
  2258.      * based on whether we're inserting at the input_write_point or 
  2259.      * at the end of the tags list.  The 
  2260.      * 'if (top_state->input_write_level)' test is unavoidable, but 
  2261.      * once the tags_end_ptr variable is set to point at the right 
  2262.      * double-indirect "tail_ptr" (per above sketch), there is shared code.
  2263.      */
  2264.  
  2265.     if (top_state->input_write_level)
  2266.     {
  2267.         tags_end_ptr = &top_state->input_write_point[top_state->input_write_level-1];
  2268.         if (*tags_end_ptr == NULL)
  2269.         {
  2270.             *tags_end_ptr = top_state->tags_end;
  2271.         }
  2272.         if (top_state->tags_end == *tags_end_ptr)
  2273.         {
  2274.             *tags_end_ptr = &tag->next;
  2275.             tags_end_ptr = &top_state->tags_end;
  2276.         }
  2277.     }
  2278.     else
  2279.     {
  2280.         tags_end_ptr = &top_state->tags_end;
  2281.     }
  2282.     tags_end = *tags_end_ptr;
  2283.     tag->next = *tags_end;
  2284.     *tags_end = tag;
  2285.     *tags_end_ptr = &tag->next;
  2286. }
  2287.  
  2288.  
  2289. lo_DocState *
  2290. lo_TopSubState(lo_TopState *top_state)
  2291. {
  2292.     lo_DocState *new_state;
  2293.  
  2294.     if ((top_state == NULL)||(top_state->doc_state == NULL))
  2295.     {
  2296.         return(NULL);
  2297.     }
  2298.  
  2299.     new_state = top_state->doc_state;
  2300.     while (new_state->sub_state != NULL)
  2301.     {
  2302.         new_state = new_state->sub_state;
  2303.     }
  2304.  
  2305.     return(new_state);
  2306. }
  2307.  
  2308.  
  2309. lo_DocState *
  2310. lo_CurrentSubState(lo_DocState *state)
  2311. {
  2312.     lo_DocState *new_state;
  2313.  
  2314.     if (state == NULL)
  2315.     {
  2316.         return(NULL);
  2317.     }
  2318.  
  2319.     new_state = state;
  2320.     while (new_state->sub_state != NULL)
  2321.     {
  2322.         new_state = new_state->sub_state;
  2323.     }
  2324.  
  2325.     return(new_state);
  2326. }
  2327.  
  2328.  
  2329. /*************************************
  2330.  * Function: lo_FetchTopState
  2331.  *
  2332.  * Description: This function uses the document ID to locate the
  2333.  *    lo_TopState structure for this document.
  2334.  *    Eventually this state will be kept somewhere in the
  2335.  *    Window context.
  2336.  *
  2337.  * Params: A unique document ID as derived from the window context.
  2338.  *
  2339.  * Returns: A pointer to the lo_TopState structure for this document.
  2340.  *        NULL on error.
  2341.  *************************************/
  2342. lo_TopState *
  2343. lo_FetchTopState(int32 doc_id)
  2344. {
  2345.     lo_StateList *sptr;
  2346.     lo_TopState *state;
  2347.  
  2348.     sptr = StateList;
  2349.     while (sptr != NULL)
  2350.     {
  2351.         if (sptr->doc_id == doc_id)
  2352.         {
  2353.             break;
  2354.         }
  2355.         sptr = sptr->next;
  2356.     }
  2357.     if (sptr == NULL)
  2358.     {
  2359.         state = NULL;
  2360.     }
  2361.     else
  2362.     {
  2363.         state = sptr->state;
  2364.     }
  2365.  
  2366.     return(state);
  2367. }
  2368.  
  2369.  
  2370. static void
  2371. lo_RemoveTopState(int32 doc_id)
  2372. {
  2373.     lo_StateList *state;
  2374.     lo_StateList *sptr;
  2375.  
  2376.     state = StateList;
  2377.     sptr = StateList;
  2378.     while (sptr != NULL)
  2379.     {
  2380.         if (sptr->doc_id == doc_id)
  2381.         {
  2382.             break;
  2383.         }
  2384.         state = sptr;
  2385.         sptr = sptr->next;
  2386.     }
  2387.     if (sptr != NULL)
  2388.     {
  2389.         if (sptr == StateList)
  2390.         {
  2391.             StateList = StateList->next;
  2392.         }
  2393.         else
  2394.         {
  2395.             state->next = sptr->next;
  2396.         }
  2397.         XP_DELETE(sptr);
  2398.     }
  2399. }
  2400.  
  2401.  
  2402. Bool
  2403. lo_StoreTopState(int32 doc_id, lo_TopState *new_state)
  2404. {
  2405.     lo_StateList *sptr;
  2406.  
  2407.     sptr = StateList;
  2408.     while (sptr != NULL)
  2409.     {
  2410.         if (sptr->doc_id == doc_id)
  2411.         {
  2412.             break;
  2413.         }
  2414.         sptr = sptr->next;
  2415.     }
  2416.  
  2417.     if (sptr == NULL)
  2418.     {
  2419.         sptr = XP_NEW(lo_StateList);
  2420.         if (sptr == NULL)
  2421.         {
  2422.             return FALSE;
  2423.         }
  2424.         sptr->doc_id = doc_id;
  2425.         sptr->next = StateList;
  2426.         StateList = sptr;
  2427.     }
  2428.     sptr->state = new_state;
  2429.     return TRUE;
  2430. }
  2431.  
  2432.  
  2433. void
  2434. lo_SaveSubdocTags(MWContext *context, lo_DocState *state, PA_Tag *tag)
  2435. {
  2436.     PA_Tag *tag_ptr;
  2437.  
  2438.     tag->next = NULL;
  2439.  
  2440.     if (state->subdoc_tags_end == NULL)
  2441.     {
  2442.         if (state->subdoc_tags == NULL)
  2443.         {
  2444.             state->subdoc_tags = tag;
  2445.             state->subdoc_tags_end = tag;
  2446.         }
  2447.         else
  2448.         {
  2449.             state->subdoc_tags->next = tag;
  2450.             state->subdoc_tags = tag;
  2451.             state->subdoc_tags_end = tag;
  2452.         }
  2453.     }
  2454.     else
  2455.     {
  2456.         tag_ptr = state->subdoc_tags_end;
  2457.         tag_ptr->next = tag;
  2458.         state->subdoc_tags_end = tag;
  2459.     }
  2460. }
  2461.  
  2462.  
  2463.  
  2464. void
  2465. lo_FlushBlockage(MWContext *context, lo_DocState *state,
  2466.                  lo_DocState *main_doc_state)
  2467. {
  2468.     PA_Tag *tag_ptr;
  2469.     int32 doc_id;
  2470.     lo_TopState *top_state;
  2471.     lo_DocState *orig_state;
  2472.     lo_DocState *up_state;
  2473.     Bool was_blockage;
  2474.  
  2475.     /*
  2476.      * All blocked tags should be at the top level of state
  2477.      */
  2478.     doc_id = XP_DOCID(context);
  2479.     top_state = lo_FetchTopState(doc_id);
  2480.     if ((top_state == NULL)||(top_state->doc_state == NULL))
  2481.     {
  2482.         return;
  2483.     }
  2484.     /* Prevent re-entering */
  2485.     if (top_state->flushing_blockage)
  2486.         return;
  2487.     top_state->flushing_blockage = TRUE;
  2488.  
  2489.     was_blockage = (top_state->tags != NULL);
  2490.      tag_ptr = top_state->tags;
  2491.    
  2492.     orig_state = top_state->doc_state;
  2493.     
  2494.     up_state = NULL;
  2495.     state = orig_state;
  2496.     while (state->sub_state != NULL)
  2497.     {
  2498.         up_state = state;
  2499.         state = state->sub_state;
  2500.     }
  2501.  
  2502.     top_state->layout_blocking_element = NULL;
  2503.  
  2504.     while ((tag_ptr != NULL)&&(top_state->layout_blocking_element == NULL))
  2505.     {
  2506.         PA_Tag *tag;
  2507.         lo_DocState *new_state;
  2508.         lo_DocState *new_up_state;
  2509.         lo_DocState *tmp_state;
  2510.         Bool may_save;
  2511.         int32 state_diff;
  2512.  
  2513.         tag = tag_ptr;
  2514.         tag_ptr = tag_ptr->next;
  2515.         tag->next = NULL;
  2516.  
  2517.         /*
  2518.          * Always keep top_state->tags sane
  2519.          */
  2520.         top_state->tags = tag_ptr;
  2521.  
  2522.         /*
  2523.          * Since script processing is asynchronous we need to do this
  2524.          *   whenever we flush blockage
  2525.          */
  2526.         if (lo_FilterTag(context, state, tag) == FALSE)
  2527.         {
  2528.             PA_FreeTag(tag);
  2529.             continue;
  2530.         }
  2531.                 
  2532.         if ((state->is_a_subdoc == SUBDOC_CELL)||
  2533.             (state->is_a_subdoc == SUBDOC_CAPTION))
  2534.         {
  2535.             may_save = TRUE;
  2536.         }
  2537.         else
  2538.         {
  2539.             may_save = FALSE;
  2540.         }
  2541.  
  2542.         /*
  2543.          * Reset these so we can tell if anything happened
  2544.          */
  2545.         top_state->diff_state = FALSE;
  2546.         top_state->state_pushes = 0;
  2547.         top_state->state_pops = 0;
  2548.  
  2549.         if (state->top_state->out_of_memory == FALSE)
  2550.         {
  2551.             lo_LayoutTag(context, state, tag);
  2552.             if (tag->type == P_LAYER)
  2553.             {
  2554.                 lo_UnblockLayerTag(state);
  2555.             }
  2556.             if(top_state->wedged_on_mocha) {
  2557.                 top_state->wedged_on_mocha = FALSE;
  2558.                 goto done;
  2559.             }
  2560.         }
  2561.  
  2562.         /* how has our state level changed? */
  2563.         state_diff = top_state->state_pushes - top_state->state_pops;
  2564.  
  2565.         new_up_state = NULL;
  2566.         new_state = orig_state;
  2567.         while (new_state->sub_state != NULL)
  2568.         {
  2569.             new_up_state = new_state;
  2570.             new_state = new_state->sub_state;
  2571.         }
  2572.         tmp_state = new_state;
  2573.         if (may_save != FALSE)
  2574.         {
  2575.             if (state_diff == -1)
  2576.             {
  2577.                 /*
  2578.                  * That tag popped us up one state level.  If this new
  2579.                  * state is still a subdoc, save the tag there.
  2580.                 */
  2581.                 if ((tmp_state->is_a_subdoc == SUBDOC_CELL)||
  2582.                     (tmp_state->is_a_subdoc == SUBDOC_CAPTION))
  2583.                 {
  2584.  
  2585.                     /* if we just popped a table we need to insert
  2586.                      * a dummy end tag to pop the dummy start tag
  2587.                      * we shove on the stack after createing a table
  2588.                      */
  2589.                        PA_Tag *new_tag = LO_CreateStyleSheetDummyTag(tag);
  2590.                     if(new_tag)
  2591.                     {
  2592.                         lo_SaveSubdocTags(context, tmp_state, new_tag);
  2593.                     }
  2594.  
  2595.                     lo_SaveSubdocTags(context, tmp_state, tag);
  2596.                 }
  2597.                 else
  2598.                 {
  2599.                     PA_FreeTag(tag);
  2600.                 }
  2601.             }
  2602.             else if (( up_state != NULL ) &&
  2603.                 ( top_state->diff_state != FALSE ) &&
  2604.                 ( state_diff == 0 ))
  2605.             {
  2606.                 /*
  2607.                  * We have returned to the same state level but
  2608.                  * we have a different subdoc.
  2609.                  */
  2610.                 if ((up_state->is_a_subdoc == SUBDOC_CELL)||
  2611.                      (up_state->is_a_subdoc == SUBDOC_CAPTION))
  2612.                 {
  2613.                     lo_SaveSubdocTags(context, up_state, tag);
  2614.                 }
  2615.                 else
  2616.                 {
  2617.                     PA_FreeTag(tag);
  2618.                 }
  2619.             }
  2620.             else if (( top_state->diff_state == FALSE ) &&
  2621.                 ( state_diff == 0 ))
  2622.             {
  2623.                 /*
  2624.                  * We are still in the same subdoc
  2625.                  */
  2626.                 lo_SaveSubdocTags(context, state, tag);
  2627.             }
  2628.             else if (( state_diff == 1 ))
  2629.             {
  2630.                 PA_Tag *new_tag;
  2631.  
  2632.                 /*
  2633.                  * That tag started a new, nested subdoc.
  2634.                  * Add the starting tag to the parent.
  2635.                  */
  2636.                 lo_SaveSubdocTags(context, state, tag);
  2637.                 /*
  2638.                  * Since we have extended the parent chain,
  2639.                  * we need to reset the child to the new
  2640.                  * parent end-chain.
  2641.                  */
  2642.                 if ((tmp_state->is_a_subdoc == SUBDOC_CELL)||
  2643.                     (tmp_state->is_a_subdoc == SUBDOC_CAPTION))
  2644.                 {
  2645.                     tmp_state->subdoc_tags =
  2646.                         state->subdoc_tags_end;
  2647.  
  2648.                     /* add an aditional dummy tag so that style sheets
  2649.                      * can use it to query styles from for this entry
  2650.                      * that created a table
  2651.                      */
  2652.                     new_tag = LO_CreateStyleSheetDummyTag(tag);
  2653.                     if(new_tag)
  2654.                     {
  2655.                         lo_SaveSubdocTags(context, tmp_state, new_tag);
  2656.                     }
  2657.                 }
  2658.  
  2659.             }
  2660.             /*
  2661.              * This can never happen.
  2662.              */
  2663.             else
  2664.             {
  2665.                 PA_FreeTag(tag);
  2666.             }
  2667.         }
  2668.         else
  2669.         {
  2670.             if(state_diff == 1)
  2671.             {
  2672.                 /* everytime a table is started we need to save the
  2673.                  * tag that created it so that style sheets can apply
  2674.                  * styles to it.  So we will save even in the "dont save"
  2675.                  * case
  2676.                  */
  2677.                 PA_Tag *new_tag = LO_CreateStyleSheetDummyTag(tag);
  2678.                 if(new_tag)
  2679.                 {
  2680.                     /* We just pushed another table into a previous table 
  2681.                      * we need to do some table magic to make the subdoc
  2682.                      * list work right
  2683.                      */
  2684.                     lo_SaveSubdocTags(context, tmp_state, new_tag);
  2685.                 }
  2686.             }
  2687.             else if(state_diff == -1)
  2688.             {
  2689.                 /* if we just popped a table we need to insert
  2690.                  * a dummy end tag to pop the dummy start tag
  2691.                  * we shove on the stack after createing a table
  2692.                  */
  2693.                    PA_Tag *new_tag = LO_CreateStyleSheetDummyTag(tag);
  2694.                 if(new_tag)
  2695.                 {
  2696.                     lo_SaveSubdocTags(context, tmp_state, new_tag);
  2697.                 }
  2698.  
  2699.                 lo_SaveSubdocTags(context, tmp_state, tag);
  2700.  
  2701.             }
  2702.             PA_FreeTag(tag);
  2703.         }
  2704.         tag_ptr = top_state->tags;
  2705.         state = new_state;
  2706.         up_state = new_up_state;
  2707.     }
  2708.  
  2709.     if (tag_ptr != NULL)
  2710.     {
  2711.         top_state->tags = tag_ptr;
  2712.     }
  2713.     else
  2714.     {
  2715.         int i;
  2716.         top_state->tags = NULL;
  2717.         top_state->tags_end = &top_state->tags;
  2718.         for (i = 0; i < MAX_INPUT_WRITE_LEVEL; i++)
  2719.             top_state->input_write_point[i] = NULL;
  2720.         if (was_blockage) {
  2721.             NET_StreamClass s;
  2722.             s.data_object=(pa_DocData *)top_state->doc_data;
  2723.             top_state->doc_data = PA_DropDocData(&s); 
  2724.         }
  2725.     }
  2726.  
  2727.     if ((top_state->layout_blocking_element == NULL)&&
  2728.         (top_state->tags == NULL)&&
  2729.         (top_state->layout_status == PA_COMPLETE))
  2730.     {
  2731.         /*
  2732.          * makes sure we are at the bottom
  2733.          * of everything in the document.
  2734.          */
  2735.         state = lo_CurrentSubState(main_doc_state);
  2736.         lo_CloseOutLayout(context, state);
  2737.         lo_FinishLayout(context, state, EVENT_LOAD);
  2738.     }
  2739. done:
  2740.     top_state->flushing_blockage = FALSE;
  2741. }
  2742.  
  2743.  
  2744. /*************************************
  2745.  * Function: lo_DisplayLine
  2746.  *
  2747.  * Description: This function displays a single line
  2748.  *    of the document, by having the front end individually
  2749.  *    display each element in it.
  2750.  *
  2751.  * Params: Window context, docuemnt state, and an index into
  2752.  *    the line array.
  2753.  *
  2754.  * Returns: Nothing.
  2755.  *************************************/
  2756. void
  2757. lo_DisplayLine(MWContext *context, lo_DocState *state, int32 line_num,
  2758.     int32 x, int32 y, uint32 w, uint32 h)
  2759. {
  2760.     LO_Element *tptr;
  2761.     LO_Element *end_ptr;
  2762.     LO_Element **line_array;
  2763.  
  2764. #ifdef LOCAL_DEBUG
  2765. XP_TRACE(("lo_DisplayLine(%d)\n", line_num));
  2766. #endif
  2767.     if (state == NULL)
  2768.     {
  2769.         return;
  2770.     }
  2771.  
  2772.     if (state->display_blocked != FALSE)
  2773.     {
  2774.         return;
  2775.     }
  2776.  
  2777. #ifdef XP_WIN16
  2778.     {
  2779.         intn a_size;
  2780.         intn a_indx;
  2781.         intn a_line;
  2782.         XP_Block *larray_array;
  2783.  
  2784.         a_size = SIZE_LIMIT / sizeof(LO_Element *);
  2785.         a_indx = (intn)(line_num / a_size);
  2786.         a_line = (intn)(line_num - (a_indx * a_size));
  2787.  
  2788.         XP_LOCK_BLOCK(larray_array, XP_Block *, state->larray_array);
  2789.         state->line_array = larray_array[a_indx];
  2790.         XP_LOCK_BLOCK(line_array, LO_Element **, state->line_array);
  2791.         tptr = line_array[a_line];
  2792.  
  2793.         if (line_num >= (state->line_num - 2))
  2794.         {
  2795.             end_ptr = NULL;
  2796.         }
  2797.         else
  2798.         {
  2799.             if ((a_line + 1) == a_size)
  2800.             {
  2801.                 XP_UNLOCK_BLOCK(state->line_array);
  2802.                 state->line_array = larray_array[a_indx + 1];
  2803.                 XP_LOCK_BLOCK(line_array, LO_Element **,
  2804.                     state->line_array);
  2805.                 end_ptr = line_array[0];
  2806.             }
  2807.             else
  2808.             {
  2809.                 end_ptr = line_array[a_line + 1];
  2810.             }
  2811.         }
  2812.         XP_UNLOCK_BLOCK(state->line_array);
  2813.         XP_UNLOCK_BLOCK(state->larray_array);
  2814.     }
  2815. #else
  2816.     XP_LOCK_BLOCK(line_array, LO_Element **, state->line_array);
  2817.     tptr = line_array[line_num];
  2818.  
  2819.     if (line_num >= (state->line_num - 2))
  2820.     {
  2821.         end_ptr = NULL;
  2822.     }
  2823.     else
  2824.     {
  2825.         end_ptr = line_array[line_num + 1];
  2826.     }
  2827.     XP_UNLOCK_BLOCK(state->line_array);
  2828. #endif /* XP_WIN16 */
  2829.  
  2830. #ifdef LOCAL_DEBUG
  2831.     if (tptr == NULL)
  2832.     {
  2833.         XP_TRACE(("    line %d is NULL!\n", line_num));
  2834.     }
  2835. #endif
  2836.  
  2837.     while (tptr != NULL && tptr != end_ptr)
  2838.     {
  2839.         lo_DisplayElement(context, tptr,
  2840.                           state->base_x, state->base_y,
  2841.                           x, y, w, h);
  2842.       
  2843.         tptr = tptr->lo_any.next;
  2844.     }
  2845. }
  2846.  
  2847. /*************************************
  2848.  * Function: lo_PointToLine
  2849.  *
  2850.  * Description: This function calculates the line which contains
  2851.  *    a point. It's used for tracking mouse motion and button presses.
  2852.  *
  2853.  * Params: Window context, x, y position of point.
  2854.  *
  2855.  * Returns: The line that contains the point.
  2856.  *    Returns -1 on error.
  2857.  *************************************/
  2858. int32
  2859. lo_PointToLine (MWContext *context, lo_DocState *state, int32 x, int32 y)
  2860. {
  2861.     int32 line, start, middle, end;
  2862.     LO_Element **line_array;
  2863. #ifdef XP_WIN16
  2864.     int32 line_add;
  2865. #endif /* XP_WIN16 */
  2866.  
  2867.     line = -1;
  2868.  
  2869.     /*
  2870.      * No document state yet.
  2871.      */
  2872.     if (state == NULL)
  2873.     {
  2874.         return(line);
  2875.     }
  2876.  
  2877.     /*
  2878.      * No laid out lines yet.
  2879.      */
  2880.     if (state->line_num == 1 || !state->line_array)
  2881.     {
  2882.         return(line);
  2883.     }
  2884.  
  2885. #ifdef XP_WIN16
  2886.     {
  2887.         intn a_size;
  2888.         intn a_indx;
  2889.         intn a_line;
  2890.         XP_Block *larray_array;
  2891.  
  2892.         a_size = SIZE_LIMIT / sizeof(LO_Element *);
  2893.         a_indx = (intn)((state->line_num - 2) / a_size);
  2894.         a_line = (intn)((state->line_num - 2) - (a_indx * a_size));
  2895.  
  2896.         XP_LOCK_BLOCK(larray_array, XP_Block *, state->larray_array);
  2897.         while (a_indx > 0)
  2898.         {
  2899.             XP_LOCK_BLOCK(line_array, LO_Element **,
  2900.                     larray_array[a_indx]);
  2901.             if (y < line_array[0]->lo_any.y)
  2902.             {
  2903.                 XP_UNLOCK_BLOCK(larray_array[a_indx]);
  2904.                 a_indx--;
  2905.             }
  2906.             else
  2907.             {
  2908.                 XP_UNLOCK_BLOCK(larray_array[a_indx]);
  2909.                 break;
  2910.             }
  2911.         }
  2912.         state->line_array = larray_array[a_indx];
  2913.         XP_UNLOCK_BLOCK(state->larray_array);
  2914.  
  2915.         /*
  2916.          * We are about to do a binary search through the line
  2917.          * array, lock it down.
  2918.          */
  2919.         XP_LOCK_BLOCK(line_array, LO_Element **, state->line_array);
  2920.         line_add = a_indx * a_size;
  2921.         start = 0;
  2922.         end = ((a_indx + 1) * a_size) - 1;
  2923.         if (end > (state->line_num - 2))
  2924.         {
  2925.             end = state->line_num - 2;
  2926.         }
  2927.         end = end - line_add;
  2928.     }
  2929. #else
  2930.     /*
  2931.      * We are about to do a binary search through the line
  2932.      * array, lock it down.
  2933.      */
  2934.     XP_LOCK_BLOCK(line_array, LO_Element **, state->line_array);
  2935.     start = 0;
  2936.     end = (intn) state->line_num - 2;
  2937. #endif /* XP_WIN16 */
  2938.  
  2939.     /*
  2940.      * Special case if area is off the top.
  2941.      */
  2942.     if (y <= 0)
  2943.     {
  2944.         line = 0;
  2945.     }
  2946.     /*
  2947.      * Else another special case if area is off the bottom.
  2948.      */
  2949.     else if (y >= line_array[end]->lo_any.y)
  2950.     {
  2951.         line = end;
  2952.     }
  2953.     /*
  2954.      * Else a binary search through the document
  2955.      * line list to find the line that contains the point.
  2956.      */
  2957.     else
  2958.     {
  2959.         /*
  2960.          * find the containing line.
  2961.          */
  2962.         while ((end - start) > 0)
  2963.         {
  2964.             middle = (start + end + 1) / 2;
  2965.             if (y < line_array[middle]->lo_any.y)
  2966.             {
  2967.                 end = middle - 1;
  2968.             }
  2969.             else
  2970.             {
  2971.                 start = middle;
  2972.             }
  2973.         }
  2974.         line = start;
  2975.         end = (intn) state->line_num - 2; /* reset end */
  2976.     }
  2977.  
  2978.     /* check for a match higher up 
  2979.      * if it matches find the highest matching line
  2980.      *
  2981.      * matches higher up can be caused by stylesheet 
  2982.      * negative margins
  2983.      */
  2984.     while(line > 0 
  2985.           && line_array[line-1]->lo_any.y <= y 
  2986.           && line_array[line-1]->lo_any.y+line_array[line-1]->lo_any.height > y)
  2987.     {
  2988.         line--;
  2989.     }
  2990.  
  2991.     /* search through any lines that have the same Y coordinates and
  2992.      * find the closes x directly to the left of the current point
  2993.      */
  2994.     if(line != end
  2995.        && line_array[line+1]->lo_any.y <= y 
  2996.        && line_array[line+1]->lo_any.y+line_array[line+1]->lo_any.height > y)
  2997.     {
  2998.         int32 closest=line;
  2999.         int32 cur_line=line+1;
  3000.  
  3001.         for(; cur_line <= end
  3002.               && line_array[cur_line]->lo_any.y <= y 
  3003.               && line_array[cur_line]->lo_any.y+line_array[cur_line]->lo_any.height > y
  3004.             ; cur_line++)
  3005.         {
  3006.             if(line_array[cur_line]->lo_any.x < x
  3007.                 && (line_array[closest]->lo_any.x > x
  3008.                     || line_array[closest]->lo_any.x < line_array[cur_line]->lo_any.x))
  3009.             {
  3010.                 closest = cur_line;
  3011.             }
  3012.         }
  3013.  
  3014.         line = closest;
  3015.     }
  3016.  
  3017.     XP_UNLOCK_BLOCK(state->line_array);
  3018. #ifdef XP_WIN16
  3019.     line = line + line_add;
  3020. #endif /* XP_WIN16 */
  3021.     return(line);
  3022. }
  3023.  
  3024.  
  3025.  
  3026. /*************************************
  3027.  * Function: lo_RegionToLines
  3028.  *
  3029.  * Description: This function calculates the lines which intersect
  3030.  * a front end drawable region. It's used for drawing and in
  3031.  * calculating page breaks for printing.
  3032.  *
  3033.  * Params: Window context, x, y position of upper left corner,
  3034.  *    and width X height of the rectangle. Also pointers to
  3035.  * return values. dontCrop is true if we do not want to draw lines
  3036.  * which would be cropped (fall on the top/bottom region boundary).
  3037.  * This is for printing.
  3038.  *
  3039.  * Returns: Sets top and bottom to the lines numbers
  3040.  * to display. Sets them to -1 on error.
  3041.  *************************************/
  3042. void
  3043. lo_RegionToLines (MWContext *context, lo_DocState *state, int32 x, int32 y,
  3044.     uint32 width, uint32 height, Bool dontCrop, int32 * topLine, int32 * bottomLine)
  3045. {
  3046.     LO_Element **line_array;
  3047.     int32 top, bottom;
  3048.     int32 y2;
  3049.     int32    topCrop;
  3050.     int32    bottomCrop;
  3051.     
  3052.     /*
  3053.         Set drawable lines to -1 (assuming error by default)
  3054.     */
  3055.     *topLine = -1;
  3056.     *bottomLine = -1;
  3057.     
  3058.     /*
  3059.      * No document state yet.
  3060.      */
  3061.     if (state == NULL)
  3062.     {
  3063.         return;
  3064.     }
  3065.  
  3066.     /*
  3067.      * No laid out lines yet.
  3068.      */
  3069.     if (state->line_num == 1)
  3070.     {
  3071.         return;
  3072.     }
  3073.  
  3074.     y2 = y + height;
  3075.  
  3076.     top = lo_PointToLine(context, state, x, y);
  3077.     bottom = lo_PointToLine(context, state, x, y2);
  3078.  
  3079.     if ( dontCrop )
  3080.     {
  3081.         XP_LOCK_BLOCK(line_array, LO_Element**, state->line_array );
  3082.         
  3083.         topCrop = line_array[ top ]->lo_any.y;
  3084.         bottomCrop = line_array[ bottom ]->lo_any.y + line_array[ bottom ]->lo_any.line_height;
  3085.         XP_UNLOCK_BLOCK( state->line_array );
  3086.         
  3087.         if ( y > topCrop )
  3088.         {
  3089.             top++;
  3090.             if ( top > ( state->line_num - 2 ) )
  3091.                 top = -1;
  3092.         } 
  3093.         if ( y2 < bottomCrop )
  3094.             bottom--;
  3095.     }
  3096.     
  3097.     /*
  3098.      * Sanity check
  3099.      */
  3100.     if (bottom < top)
  3101.     {
  3102.         bottom = top;
  3103.     }
  3104.  
  3105.     *topLine = top;
  3106.     *bottomLine = bottom;
  3107. }
  3108.  
  3109. /*
  3110.     LO_CalcPrintArea
  3111.     
  3112.     Takes a region and adjusts it inward so that the top and bottom lines
  3113.     are not cropped. Results can be passed to LO_RefreshArea to print
  3114.     one page. To calculate the next page, use y+height as the next y.
  3115. */
  3116. intn
  3117. LO_CalcPrintArea (MWContext *context, int32 x, int32 y,
  3118.                   uint32 width, uint32 height,
  3119.                   int32 *top, int32 *bottom)
  3120. {
  3121.     LO_Element **line_array;
  3122.     int32 doc_id;
  3123.     lo_TopState *top_state;
  3124.     lo_DocState *state;
  3125.     int32        lineTop;
  3126.     int32        lineBottom;
  3127.     
  3128.     *top = -1;
  3129.     *bottom = -1;
  3130.     /*
  3131.      * Get the unique document ID, and retreive this
  3132.      * documents layout state.
  3133.      */
  3134.     doc_id = XP_DOCID(context);
  3135.     top_state = lo_FetchTopState(doc_id);
  3136.     if ((top_state == NULL)||(top_state->doc_state == NULL))
  3137.     {
  3138.         return(0);
  3139.     }
  3140.     state = top_state->doc_state;
  3141.     
  3142.     /*    
  3143.         Find which lines intersect the drawable region.
  3144.     */
  3145.     lo_RegionToLines( context, state, x, y, width, height, TRUE, &lineTop, &lineBottom );
  3146.     
  3147.     if ( lineTop != -1 && lineBottom != -1 )
  3148.     {
  3149.         XP_LOCK_BLOCK(line_array, LO_Element **, state->line_array );
  3150.     
  3151.         *top = line_array[ lineTop ]->lo_any.y;
  3152.         *bottom = line_array[ lineBottom ]->lo_any.y + line_array[ lineBottom ]->lo_any.line_height - 1;
  3153.         
  3154.         XP_UNLOCK_BLOCK( state->line_array );
  3155.         return (1);
  3156.     }
  3157.     return (0);
  3158. }
  3159.  
  3160. void
  3161. lo_CloseOutLayout(MWContext *context, lo_DocState *state)
  3162. {
  3163.     lo_FlushLineBuffer(context, state);
  3164.  
  3165.     /*
  3166.      * makes sure we are at the bottom
  3167.      * of everything in the document.
  3168.      *
  3169.      * Only close forms if we aren't in a subdoc because
  3170.      * forms can span subdocs.
  3171.      */
  3172.     if ((state->is_a_subdoc == SUBDOC_NOT)&&
  3173.         (state->top_state->in_form != FALSE))
  3174.     {
  3175.         lo_EndForm(context, state);
  3176.     }
  3177.  
  3178.     lo_SetLineBreakState( context, state, FALSE, LO_LINEFEED_BREAK_SOFT, 1, FALSE);
  3179.     lo_ClearToBothMargins(context, state);
  3180.  
  3181.     /* Dummy Floating elements on a new line at the end of a document were not getting put into
  3182.        the line_array.  This code should ensure that anything left on the line_list gets flushed
  3183.        to the line_array. */
  3184.     if (state->line_list != NULL)
  3185.         lo_AppendLineListToLineArray( context, state, NULL);
  3186. }
  3187.  
  3188. /* Relayout version of lo_CloseOutLayout() */
  3189. void lo_EndLayoutDuringReflow( MWContext *context, lo_DocState *state )
  3190. {
  3191.     /*
  3192.      * makes sure we are at the bottom
  3193.      * of everything in the document.
  3194.      *
  3195.      * Only close forms if we aren't in a subdoc because
  3196.      * forms can span subdocs.
  3197.      */
  3198.     if ((state->is_a_subdoc == SUBDOC_NOT)&&
  3199.         (state->top_state->in_form != FALSE))
  3200.     {
  3201.         state->top_state->in_form = FALSE;
  3202.     }
  3203.     
  3204.  
  3205.     lo_SetLineBreakState( context, state, FALSE, LO_LINEFEED_BREAK_SOFT, 1, TRUE);
  3206.     lo_ClearToBothMargins(context, state);
  3207. }
  3208.  
  3209. void
  3210. LO_CloseAllTags(MWContext *context)
  3211. {
  3212.     int32 doc_id;
  3213.     lo_TopState *top_state;
  3214.     lo_DocState *state;
  3215.     lo_DocState *sub_state;
  3216.  
  3217.     /*
  3218.      * Get the unique document ID, and retreive this
  3219.      * documents layout state.
  3220.      */
  3221.     doc_id = XP_DOCID(context);
  3222.     top_state = lo_FetchTopState(doc_id);
  3223.     if ((top_state == NULL)||(top_state->doc_state == NULL))
  3224.     {
  3225.         return;
  3226.     }
  3227.     state = top_state->doc_state;
  3228.  
  3229.     /*
  3230.      * If we are in a table, get us out.
  3231.      */
  3232.     sub_state = lo_CurrentSubState(state);
  3233.     while (sub_state != state)
  3234.     {
  3235.         lo_DocState *old_state;
  3236.  
  3237.         lo_CloseOutTable(context, sub_state);
  3238.         old_state = sub_state;
  3239.         sub_state = lo_CurrentSubState(state);
  3240.         /*
  3241.          * If sub_state doesn't change we could be in a loop.
  3242.          * break it here.
  3243.          */
  3244.         if (sub_state == old_state)
  3245.         {
  3246.             break;
  3247.         }
  3248.     }
  3249.     state->sub_state = NULL;
  3250.  
  3251.     /*
  3252.      * First do the normal closing.
  3253.      */
  3254.     lo_CloseOutLayout(context, state);
  3255.  
  3256.     /*
  3257.      * Reset a bunch of state variables.
  3258.      */
  3259.     state->text_divert = P_UNKNOWN;
  3260.     state->delay_align = FALSE;
  3261.     state->breakable = TRUE;
  3262.     state->allow_amp_escapes = TRUE;
  3263.     state->preformatted = PRE_TEXT_NO;
  3264.     state->preformat_cols = 0;
  3265.     state->in_paragraph = FALSE;
  3266.     /*
  3267.      * clear the alignment stack.
  3268.      */
  3269.     while (lo_PopAlignment(state) != NULL) {;}
  3270.     /*
  3271.      * clear the list stack.
  3272.      */
  3273.     while (lo_PopList(state, NULL) != NULL) {;}
  3274.     /*
  3275.      * clear all open anchors.
  3276.      */
  3277.     lo_PopAllAnchors(state);
  3278.     /*
  3279.      * clear the font stack.
  3280.      */
  3281.     while (state->font_stack->next != NULL)
  3282.     {
  3283.         (void)lo_PopFont(state, P_UNKNOWN);
  3284.     }
  3285.     state->base_font_size = DEFAULT_BASE_FONT_SIZE;
  3286.     state->font_stack->text_attr->size = state->base_font_size;
  3287.     state->current_anchor = NULL;
  3288.     state->current_ele = NULL;
  3289.     state->current_table = NULL;
  3290.     state->current_cell = NULL;
  3291.     state->current_java = NULL;
  3292.     state->current_multicol = NULL;
  3293.     state->must_relayout_subdoc = FALSE;
  3294.     state->allow_percent_width = TRUE;
  3295.     state->allow_percent_height = TRUE;
  3296.     state->is_a_subdoc = SUBDOC_NOT;
  3297.     state->current_subdoc = 0;
  3298.  
  3299.     /*
  3300.      * Escape an open script
  3301.      */
  3302.     if (top_state->in_script != SCRIPT_TYPE_NOT)
  3303.     {
  3304.         top_state->in_script = SCRIPT_TYPE_NOT;
  3305.         state->line_buf_len = 0;
  3306.         lo_UnblockLayout(context, top_state);
  3307.     }
  3308.  
  3309.     /*
  3310.      * Reset a few top_state variables.
  3311.      */
  3312.     top_state->current_map = NULL;
  3313.     top_state->in_nogrids = FALSE;
  3314.     top_state->ignore_tag_nest_level = 0;
  3315.     top_state->ignore_layer_nest_level = 0;
  3316.     top_state->in_applet = FALSE;
  3317. }
  3318.  
  3319.  
  3320. void
  3321. lo_free_layout_state_data(MWContext *context, lo_DocState *state)
  3322. {
  3323.     /*
  3324.      * Short circuit out if the state was freed out from
  3325.      * under us.
  3326.      */
  3327.     if (state == NULL)
  3328.     {
  3329.         return;
  3330.     }
  3331.  
  3332.     if (state->current_table != NULL)
  3333.     {
  3334.         lo_FreePartialTable(context, state, state->current_table);
  3335.         state->current_table = NULL;
  3336.     }
  3337.  
  3338.     if (state->left_margin_stack != NULL)
  3339.     {
  3340.         lo_MarginStack *mptr;
  3341.         lo_MarginStack *margin;
  3342.  
  3343.         mptr = state->left_margin_stack;
  3344.         while (mptr != NULL)
  3345.         {
  3346.             margin = mptr;
  3347.             mptr = mptr->next;
  3348.             XP_DELETE(margin);
  3349.         }
  3350.         state->left_margin_stack = NULL;
  3351.     }
  3352.     if (state->right_margin_stack != NULL)
  3353.     {
  3354.         lo_MarginStack *mptr;
  3355.         lo_MarginStack *margin;
  3356.  
  3357.         mptr = state->right_margin_stack;
  3358.         while (mptr != NULL)
  3359.         {
  3360.             margin = mptr;
  3361.             mptr = mptr->next;
  3362.             XP_DELETE(margin);
  3363.         }
  3364.         state->right_margin_stack = NULL;
  3365.     }
  3366.  
  3367.     if (state->line_list != NULL)
  3368.     {
  3369.         LO_Element *eptr;
  3370.         LO_Element *element;
  3371.  
  3372.         eptr = state->line_list;
  3373.         while (eptr != NULL)
  3374.         {
  3375.             element = eptr;
  3376.             eptr = eptr->lo_any.next;
  3377.             lo_FreeElement(context, element, TRUE);
  3378.         }
  3379.         state->line_list = NULL;
  3380.     }
  3381.  
  3382.     if (state->font_stack != NULL)
  3383.     {
  3384.         lo_FontStack *fstack;
  3385.         lo_FontStack *fptr;
  3386.  
  3387.         fptr = state->font_stack;
  3388.         while (fptr != NULL)
  3389.         {
  3390.             fstack = fptr;
  3391.             fptr = fptr->next;
  3392.             XP_DELETE(fstack);
  3393.         }
  3394.         state->font_stack = NULL;
  3395.     }
  3396.  
  3397.     if (state->align_stack != NULL)
  3398.     {
  3399.         lo_AlignStack *aptr;
  3400.         lo_AlignStack *align;
  3401.  
  3402.         aptr = state->align_stack;
  3403.         while (aptr != NULL)
  3404.         {
  3405.             align = aptr;
  3406.             aptr = aptr->next;
  3407.             XP_DELETE(align);
  3408.         }
  3409.         state->align_stack = NULL;
  3410.     }
  3411.  
  3412.     if (state->list_stack != NULL)
  3413.     {
  3414.         lo_ListStack *lptr;
  3415.         lo_ListStack *list;
  3416.  
  3417.         lptr = state->list_stack;
  3418.         while (lptr != NULL)
  3419.         {
  3420.             list = lptr;
  3421.             lptr = lptr->next;
  3422.             XP_DELETE(list);
  3423.         }
  3424.         state->list_stack = NULL;
  3425.     }
  3426.  
  3427.     if (state->line_height_stack != NULL)
  3428.     {
  3429.         lo_LineHeightStack *lptr;
  3430.         lo_LineHeightStack *height;
  3431.         
  3432.         lptr = state->line_height_stack;
  3433.         while (lptr != NULL) {
  3434.             height = lptr;
  3435.             lptr = lptr->next;
  3436.             XP_DELETE(height);
  3437.         }
  3438.         state->line_height_stack = NULL;
  3439.     }
  3440.             
  3441.     if (state->line_buf != NULL)
  3442.     {
  3443.         PA_FREE(state->line_buf);
  3444.         state->line_buf = NULL;
  3445.     }
  3446. }
  3447.  
  3448.  
  3449. /* Clean up the layout data structures. This used to be inside lo_FinishLayout,
  3450.  * but we needed to call it from the editor, without all of the UI code that
  3451.  * lo_FinishLayout also calls.
  3452.  */
  3453.  
  3454. void
  3455. lo_FreeLayoutData(MWContext *context, lo_DocState *state)
  3456. {
  3457.     int32 i, cnt;
  3458.  
  3459.     /*
  3460.      * Clean out the lo_DocState
  3461.      */
  3462.     lo_free_layout_state_data(context, state);
  3463.  
  3464.     /*
  3465.      * Short circuit out if the state was freed out from
  3466.      * under us.
  3467.      */
  3468.     if (state == NULL)
  3469.     {
  3470.         return;
  3471.     }
  3472.  
  3473.     LO_LockLayout();
  3474.  
  3475.     /*
  3476.      * These are tags that were blocked instead of laid out.
  3477.      * If there was an image in here, we already started the
  3478.      * layout of it, we better free it now.
  3479.      */
  3480.     if (state->top_state->tags != NULL)
  3481.     {
  3482.         PA_Tag *tptr;
  3483.         PA_Tag *tag;
  3484.  
  3485.         tptr = state->top_state->tags;
  3486.         while (tptr != NULL)
  3487.         {
  3488.             tag = tptr;
  3489.             tptr = tptr->next;
  3490.             if (((tag->type == P_IMAGE)||
  3491.                  (tag->type == P_NEW_IMAGE))&&
  3492.                 (tag->lo_data != NULL))
  3493.             {
  3494.                 LO_Element *element;
  3495.                 element = (LO_Element *)tag->lo_data;
  3496.                 lo_FreeElement(context, element, TRUE);
  3497.                 tag->lo_data = NULL;
  3498.             }
  3499.             PA_FreeTag(tag);
  3500.         }
  3501.         state->top_state->tags = NULL;
  3502.         state->top_state->tags_end = &state->top_state->tags;
  3503.         for (i = 0; i < MAX_INPUT_WRITE_LEVEL; i++)
  3504.             state->top_state->input_write_point[i] = NULL;
  3505.     }
  3506.  
  3507.     /*
  3508.      * If we were blocked on and image when we left this page, we need to
  3509.      * free up that partially loaded image structure.
  3510.      */
  3511.     if (state->top_state->layout_blocking_element != NULL)
  3512.     {
  3513.         LO_Element *element;
  3514.  
  3515.         element = state->top_state->layout_blocking_element;
  3516.         lo_FreeElement(context, element, TRUE);
  3517.         state->top_state->layout_blocking_element = NULL;
  3518.     }
  3519.  
  3520.     /* Delete object stack */ 
  3521.     if (state->top_state->object_stack != NULL)
  3522.     {
  3523.         lo_ObjectStack* top;
  3524.         lo_ObjectStack* object;
  3525.         
  3526.         top = state->top_state->object_stack;
  3527.         while (top != NULL)
  3528.         {
  3529.             object = top;
  3530.             top = top->next;
  3531.             lo_DeleteObjectStack(object);
  3532.         }
  3533.         state->top_state->object_stack = NULL;
  3534.     }
  3535.  
  3536.     /* Delete object cache */
  3537.     if (state->top_state->object_cache != NULL)
  3538.     {
  3539.         lo_ObjectStack* top;
  3540.         lo_ObjectStack* object;
  3541.         
  3542.         top = state->top_state->object_cache;
  3543.         while (top != NULL)
  3544.         {
  3545.             object = top;
  3546.             top = top->next;
  3547.             lo_DeleteObjectStack(object);
  3548.         }
  3549.         state->top_state->object_cache = NULL;
  3550.     }
  3551.  
  3552.     LO_UnlockLayout();
  3553.  
  3554.     /*
  3555.      * now we're done laying out the entire document. we had saved all
  3556.      * the layout structures from the previous document so we're throwing
  3557.      * away unused ones.
  3558.      */
  3559.     cnt = lo_FreeRecycleList(context, state->top_state->recycle_list);
  3560. #ifdef MEMORY_ARENAS
  3561.     if (state->top_state->current_arena != NULL)
  3562.     {
  3563.         cnt = lo_FreeMemoryArena(state->top_state->current_arena->next);
  3564.         state->top_state->current_arena->next = NULL;
  3565.     }
  3566. #endif /* MEMORY_ARENAS */
  3567.     state->top_state->recycle_list = NULL;
  3568. }
  3569.  
  3570.  
  3571. void
  3572. lo_CloseMochaWriteStream(lo_TopState *top_state, int mocha_event)
  3573. {
  3574.     NET_StreamClass *stream = top_state->mocha_write_stream;
  3575.  
  3576.     if (stream != NULL)
  3577.     {
  3578.         top_state->mocha_write_stream = NULL;
  3579.         if (mocha_event == EVENT_LOAD)
  3580.         {
  3581.             stream->complete(stream);
  3582.         }
  3583.         else
  3584.         {
  3585.             stream->abort(stream, top_state->layout_status);
  3586.         }
  3587.         XP_DELETE(stream);
  3588.     }
  3589. }
  3590.  
  3591.  
  3592.  
  3593. void
  3594. lo_FinishLayout_OutOfMemory(MWContext *context, lo_DocState *state)
  3595. {
  3596.     lo_TopState *top_state;
  3597.     lo_DocState *main_state;
  3598.     lo_DocState *sub_state;
  3599.  
  3600.     /* Reset state for force loading images. */
  3601.     LO_SetForceLoadImage(NULL, FALSE);
  3602.  
  3603.     /*
  3604.      * Short circuit out if the state was freed out from
  3605.      * under us.
  3606.      */
  3607.     if (state == NULL)
  3608.     {
  3609.         return;
  3610.     }
  3611.  
  3612.     /*
  3613.      * Check for dangling sub-states, and clean them up if they exist.
  3614.      */
  3615.     top_state = state->top_state;
  3616.     main_state = top_state->doc_state;
  3617.     sub_state = lo_TopSubState(top_state);
  3618.     while ((sub_state != NULL)&&(sub_state != main_state))
  3619.     {
  3620.         state = main_state;
  3621.         while ((state != NULL)&&(state->sub_state != sub_state))
  3622.         {
  3623.             state = state->sub_state;
  3624.         }
  3625.         if (state != NULL)
  3626.         {
  3627.             lo_free_layout_state_data(context, sub_state);
  3628.             XP_DELETE(sub_state);
  3629.             state->sub_state = NULL;
  3630.         }
  3631.         sub_state = lo_TopSubState(top_state);
  3632.     }
  3633.     state = lo_TopSubState(top_state);
  3634.  
  3635.     lo_CloseMochaWriteStream(top_state, EVENT_ABORT);
  3636.  
  3637.     /* Could be left over if someone forgets to close a tag */
  3638.     if (state->top_state->scriptData)
  3639.         lo_DestroyScriptData(state->top_state->scriptData);
  3640.  
  3641.     /*
  3642.      * Short circuit out if the state was freed out from
  3643.      * under us.
  3644.      */
  3645.     if (state == NULL)
  3646.     {
  3647.         return;
  3648.     }
  3649.  
  3650.     lo_free_layout_state_data(context, state);
  3651. }
  3652.  
  3653.  
  3654. void
  3655. lo_FinishLayout(MWContext *context, lo_DocState *state, int32 mocha_event)
  3656. {
  3657.     lo_TopState *top_state;
  3658.     lo_DocState *main_state;
  3659.     lo_DocState *sub_state;
  3660.  
  3661.     /* Close any layers (blocks) that were opened in this document, in
  3662.        case the document author forgot to. */
  3663.     if (state != NULL ) {
  3664.         if (state->layer_nest_level) {
  3665.             while (state->layer_nest_level > 0)
  3666.                 lo_EndLayer(context, state, PR_TRUE);
  3667.             /* 
  3668.              * This call ensures that we flush the line list (which still might
  3669.              * have something on it if we had unclosed ILAYERs).
  3670.              */
  3671.             lo_CloseOutLayout(context, state); 
  3672.         }
  3673.     }
  3674.  
  3675.     if ((state != NULL) &&
  3676.         (state->top_state != NULL))
  3677.     {
  3678.         lo_CloseMochaWriteStream(state->top_state, mocha_event);
  3679.  
  3680.         /* Could be left over if someone forgets to close a tag */
  3681.         if (state->top_state->scriptData)
  3682.             lo_DestroyScriptData(state->top_state->scriptData);
  3683.  
  3684.         /* Handle the page background for the case of a document that contains 
  3685.            no displayed layout elements. */
  3686.         if (state->top_state->nothing_displayed != FALSE)
  3687.             lo_use_default_doc_background(context, state);
  3688.     }
  3689.  
  3690.         if (state && state->top_state)
  3691.             ET_SendLoadEvent(context, mocha_event, NULL, NULL, 
  3692.                              LO_DOCUMENT_LAYER_ID, 
  3693.                              state->top_state->resize_reload);
  3694.         else
  3695.             ET_SendLoadEvent(context, mocha_event, NULL, NULL, 
  3696.                              LO_DOCUMENT_LAYER_ID, FALSE);
  3697.  
  3698.     /* Reset state for force loading images. */
  3699.     LO_SetForceLoadImage(NULL, FALSE);
  3700.  
  3701.     /*
  3702.      * Short circuit out if the state was freed out from
  3703.      * under us.
  3704.      */
  3705.     if (state == NULL)
  3706.     {
  3707.         FE_SetProgressBarPercent(context, 100);
  3708. #ifdef OLD_MSGS
  3709.         FE_Progress(context, "Layout Phase Complete");
  3710. #endif /* OLD_MSGS */
  3711.  
  3712.         /* Flush out layer callbacks so that document dimensions are correct. */
  3713.         if (context->compositor)
  3714.             CL_CompositeNow(context->compositor);
  3715.  
  3716.         FE_FinishedLayout(context);
  3717.         return;
  3718.     }
  3719.  
  3720.     /*
  3721.      * Check for dangling sub-states, and clean them up if they exist.
  3722.      */
  3723.     top_state = state->top_state;
  3724.     main_state = top_state->doc_state;
  3725.     sub_state = lo_TopSubState(top_state);
  3726.     while ((sub_state != NULL)&&(sub_state != main_state))
  3727.     {
  3728.         state = main_state;
  3729.         while ((state != NULL)&&(state->sub_state != sub_state))
  3730.         {
  3731.             state = state->sub_state;
  3732.         }
  3733.         if (state != NULL)
  3734.         {
  3735.             lo_free_layout_state_data(context, sub_state);
  3736.             XP_DELETE(sub_state);
  3737.             state->sub_state = NULL;
  3738.         }
  3739.         sub_state = lo_TopSubState(top_state);
  3740.     }
  3741.     state = lo_TopSubState(top_state);
  3742.  
  3743.     /*
  3744.      * Short circuit out if the state was freed out from
  3745.      * under us.
  3746.      */
  3747.     if (state == NULL)
  3748.     {
  3749.         FE_SetProgressBarPercent(context, 100);
  3750. #ifdef OLD_MSGS
  3751.         FE_Progress(context, "Layout Phase Complete");
  3752. #endif /* OLD_MSGS */
  3753.  
  3754.         /* Flush out layer callbacks so that document dimensions are correct. */
  3755.         if (context->compositor)
  3756.             CL_CompositeNow(context->compositor);
  3757.  
  3758.         FE_FinishedLayout(context);
  3759.         return;
  3760.     }
  3761.  
  3762.     lo_FreeLayoutData(context, state);
  3763.  
  3764.     if (state->display_blocked != FALSE)
  3765.     {
  3766.         int32 y;
  3767.  
  3768.         if (state->top_state->name_target != NULL)
  3769.         {
  3770.             XP_FREE(state->top_state->name_target);
  3771.             state->top_state->name_target = NULL;
  3772.         }
  3773.         state->display_blocking_element_id = 0;
  3774.         state->display_blocked = FALSE;
  3775.         y = state->display_blocking_element_y;
  3776.         state->display_blocking_element_y = 0;
  3777.         state->y += state->win_bottom;
  3778.  
  3779.         LO_SetDocumentDimensions(context, state->max_width, state->y);
  3780.  
  3781.         if (y != state->win_top)
  3782.         {
  3783.             y = state->y - state->win_height;
  3784.             if (y < 0)
  3785.             {
  3786.                 y = 0;
  3787.             }
  3788.         }
  3789.         FE_SetDocPosition(context, FE_VIEW, 0, y);
  3790.  
  3791.         if (context->compositor)
  3792.         {
  3793.             XP_Rect rect;
  3794.             
  3795.             rect.left = 0;
  3796.             rect.top = y;
  3797.             rect.right = state->win_width;
  3798.             rect.bottom = y + state->win_height;
  3799.             CL_UpdateDocumentRect(context->compositor,
  3800.                                   &rect, (PRBool)FALSE);
  3801.         }
  3802.     }
  3803.     else
  3804.     {
  3805.         state->y += state->win_bottom;
  3806.         LO_SetDocumentDimensions(context, state->max_width, state->y);
  3807.     }
  3808.  
  3809.     /* get rid of the style stack data since it wont
  3810.      * be needed any more
  3811.      */
  3812.     if(top_state->style_stack)
  3813.     {
  3814.         /* LJM: Need to purge stack to free memory
  3815.          */
  3816.         STYLESTACK_Purge(top_state->style_stack);
  3817.     }
  3818.  
  3819.     if(!state->top_state->is_binary)
  3820.         FE_SetProgressBarPercent(context, 100);
  3821.  
  3822. #ifdef OLD_MSGS
  3823.     FE_Progress(context, "Layout Phase Complete");
  3824. #endif /* OLD_MSGS */
  3825.  
  3826.     /* Flush out layer callbacks so that document dimensions are correct. */
  3827.     if (context->compositor)
  3828.         CL_CompositeNow(context->compositor);
  3829.  
  3830.     if (state->is_a_subdoc == SUBDOC_NOT && state->top_state && !state->top_state->have_title)
  3831.     {
  3832.         /* We never got a title. We better notify the FE that the title is blank */
  3833.         
  3834.         FE_SetDocTitle(context, "");
  3835.     }        
  3836.  
  3837.     FE_FinishedLayout(context);
  3838. #ifdef EDITOR
  3839.     if (EDT_IS_EDITOR (context))
  3840.         EDT_FinishedLayout(context);
  3841. #endif
  3842.  
  3843.     /*
  3844.      * Update the blink layers to reflect the current positions of their
  3845.      * associated text elements.
  3846.      */
  3847.     if (context->compositor)
  3848.         lo_UpdateBlinkLayers(context);
  3849. }
  3850.  
  3851. /*******************************************************************************
  3852.  * LO_ProcessTag helper routines
  3853.  ******************************************************************************/
  3854.  
  3855. #ifdef MEMORY_ARENAS 
  3856. void
  3857. lo_GetRecycleList(MWContext* context, int32 doc_id, pa_DocData* doc_data, 
  3858.                   LO_Element* *recycle_list, lo_arena* *old_arena)
  3859. #else
  3860. void
  3861. lo_GetRecycleList(MWContext* context, int32 doc_id, pa_DocData* doc_data, 
  3862.                   LO_Element* *recycle_list)
  3863. #endif /* MEMORY_ARENAS */
  3864. {
  3865.     lo_TopState* old_top_state;
  3866.     lo_DocState* old_state;
  3867.  
  3868.     LO_LockLayout();
  3869.  
  3870.     /*
  3871.      * Free up any old document displayed in this
  3872.      * window.
  3873.      */
  3874.     old_top_state = lo_FetchTopState(XP_DOCID(context));
  3875.     if (old_top_state == NULL)
  3876.     {
  3877.         old_state = NULL;
  3878.     }
  3879.     else
  3880.     {
  3881.         old_state = old_top_state->doc_state;
  3882.     }
  3883.     if (old_state != NULL)
  3884.     {
  3885. #ifdef MEMORY_ARENAS
  3886.         *old_arena = old_top_state->first_arena;
  3887. #endif /* MEMORY_ARENAS */
  3888.         lo_SaveFormElementState(context, old_state, TRUE);
  3889.         /*
  3890.          * If this document has no session history
  3891.          * there is no place to save this data.
  3892.          * It will be freed by history cleanup.
  3893.          */
  3894.         if (SHIST_GetCurrent(&context->hist) == NULL)
  3895.         {
  3896.             lo_TopState *top_state = old_state->top_state;
  3897.             top_state->savedData.FormList = NULL;
  3898.             top_state->savedData.EmbedList = NULL;
  3899.             top_state->savedData.Grid = NULL;
  3900.         }
  3901.         *recycle_list =
  3902.             lo_InternalDiscardDocument(context, old_state, doc_data, TRUE);
  3903.     }
  3904.  
  3905.     /* Now that we've discarded the old document, set the new doc_id. */
  3906.     XP_SET_DOCID(context, doc_id);
  3907.     LO_UnlockLayout();
  3908.  
  3909. }
  3910.  
  3911. intn
  3912. lo_ProcessTag_OutOfMemory(MWContext* context, LO_Element* recycle_list, lo_TopState* top_state)
  3913. {
  3914.     int32 cnt;
  3915.     
  3916.     if ((top_state != NULL)&&(top_state->doc_state != NULL))
  3917.     {
  3918.         lo_FinishLayout_OutOfMemory(context, top_state->doc_state);
  3919.     }
  3920.  
  3921.     cnt = lo_FreeRecycleList(context, recycle_list);
  3922.  
  3923. #ifdef MEMORY_ARENAS
  3924.     if ((top_state != NULL)&&(top_state->first_arena != NULL))
  3925.     {
  3926.         cnt = lo_FreeMemoryArena(top_state->first_arena->next);
  3927.         top_state->first_arena->next = NULL;
  3928.     }
  3929. #endif /* MEMORY_ARENAS */
  3930.  
  3931.     return MK_OUT_OF_MEMORY;
  3932. }
  3933.  
  3934. #define RESTORE_SAVED_DATA(Type, var, doc_data, recycle_list, top_state) \
  3935. { \
  3936.     var = (lo_Saved##Type##Data *) \
  3937.         (doc_data->url_struct->savedData.Type); \
  3938.     if (var == NULL) \
  3939.     { \
  3940.         /* \
  3941.          * A document we have never visited, insert a pointer \
  3942.          * to a form list into its history, if it has one. \
  3943.          */ \
  3944.         var = lo_NewDocument##Type##Data(); \
  3945.         if (SHIST_GetCurrent(&context->hist) != NULL) \
  3946.         { \
  3947.             SHIST_SetCurrentDoc##Type##Data(context, (void *)var); \
  3948.         } \
  3949.         /* \
  3950.          * Stuff it in the url_struct as well for \
  3951.          * continuous loading documents. \
  3952.          */ \
  3953.         doc_data->url_struct->savedData.Type = (void *)var; \
  3954.     } \
  3955.     else if (doc_data->from_net != FALSE) \
  3956.     { \
  3957.         lo_FreeDocument##Type##Data(context, var); \
  3958.     } \
  3959.      \
  3960.     /* \
  3961.      * If we don't have a form list, something very bad \
  3962.      * has happened.  Like we are out of memory. \
  3963.      */ \
  3964.     if (var == NULL) \
  3965.         return lo_ProcessTag_OutOfMemory(context, recycle_list, top_state); \
  3966.      \
  3967.     top_state->savedData.Type = var; \
  3968. }
  3969.  
  3970. /****************************************************************************
  3971.  ****************************************************************************
  3972.  **
  3973.  **  Beginning of Public Utility Functions
  3974.  **
  3975.  ****************************************************************************
  3976.  ****************************************************************************/
  3977.  
  3978.  
  3979. static void *hooked_data_object = NULL;
  3980. static intn hooked_status = 0;
  3981. static PA_Tag *hooked_tag = NULL;
  3982.  
  3983. /*************************************
  3984.  * Function: LO_ProcessTag
  3985.  *
  3986.  * Description: This function is the main layout entry point.
  3987.  *    New tags or tag lists are sent here along with the
  3988.  *    status as to where they came from.
  3989.  *
  3990.  * Params: A blank data object from the parser, right now it
  3991.  *    is parse document data.  The tag or list of tags to process.
  3992.  *     and a status field as to why it came.
  3993.  *
  3994.  * Returns: 1 - Done ok, continuing.
  3995.  *        0 - Done ok, stopping.
  3996.  *       -1 - not done, error.
  3997.  *************************************/
  3998. intn
  3999. LO_ProcessTag(void *data_object, PA_Tag *tag, intn status)
  4000. {
  4001.     pa_DocData *doc_data;
  4002.     int32 doc_id;
  4003.     MWContext *context;
  4004.     CL_Layer *doc_layer = NULL, *body_layer = NULL;
  4005.     lo_TopState *top_state;
  4006.     lo_DocState *state;
  4007.     lo_DocState *orig_state;
  4008.     lo_DocState *up_state;
  4009.  
  4010.     /*
  4011.      * If this call came from a hook feed
  4012.      */
  4013.     if (hooked_data_object != NULL)
  4014.     {
  4015.         data_object = hooked_data_object;
  4016.         status = hooked_status;
  4017.         /*
  4018.          * Ignore hooked calls with no tags.
  4019.          */
  4020.         if (tag == NULL)
  4021.         {
  4022.             return(1);
  4023.         }
  4024.         if (hooked_tag != NULL)
  4025.         {
  4026.             tag->newline_count += hooked_tag->newline_count;
  4027.         }
  4028.     }
  4029.  
  4030.     doc_data = (pa_DocData *)data_object;
  4031.     doc_id = doc_data->doc_id;
  4032.     top_state = (lo_TopState *)(doc_data->layout_state);
  4033.  
  4034.     /* 
  4035.      * If this is an "inline" stream and we don't have a top_state
  4036.      * associated with it, it's targetted at a layer in
  4037.      * the current document. In this case, we need to get the 
  4038.      * top_state using the context and not directly from the doc_data.
  4039.      */
  4040.     if ((top_state == NULL) && (doc_data->is_inline_stream == TRUE)) {
  4041.         top_state = lo_FetchTopState(doc_id);
  4042.         doc_data->layout_state = top_state;
  4043.         if (top_state) {
  4044.             top_state->doc_data = doc_data;
  4045.             top_state->nurl = doc_data->url_struct;
  4046.         }
  4047.     }
  4048.  
  4049.     if (top_state == NULL)
  4050.     {
  4051.         state = NULL;
  4052.     }
  4053.     else
  4054.     {
  4055.         state = top_state->doc_state;
  4056.     }
  4057.     context = doc_data->window_id;
  4058.     
  4059.     /*
  4060.      * if we get called with abort/complete then ignore oom condition
  4061.      * and clean up
  4062.      */
  4063.     if ((state != NULL)&&(state->top_state != NULL)&&
  4064.         (state->top_state->out_of_memory != FALSE)&&(tag != NULL))
  4065.     {
  4066.         lo_FinishLayout_OutOfMemory(context, state);
  4067.         return(MK_OUT_OF_MEMORY);
  4068.     }
  4069.  
  4070.     if ((tag != NULL)&&(context != NULL)&&(hooked_data_object == NULL)&&
  4071.         (HK_IsHook(HK_TAG, (void *)tag)))
  4072.     {
  4073.         char *tptr;
  4074.         char *in_str;
  4075.         char *out_str;
  4076.         XP_Bool delete_tag;
  4077.         XP_Bool replace_tag;
  4078.  
  4079.         out_str = NULL;
  4080.         delete_tag = FALSE;
  4081.         replace_tag = FALSE;
  4082.         if (tag->type == P_TEXT)
  4083.         {
  4084.             PA_LOCK (tptr, char *, tag->data);
  4085.             in_str = XP_ALLOC(tag->data_len + 1);
  4086.             if (in_str == NULL)
  4087.             {
  4088.                 return(MK_OUT_OF_MEMORY);
  4089.             }
  4090.             XP_BCOPY(tptr, in_str, tag->data_len);
  4091.             in_str[tag->data_len] = '\0';
  4092.             PA_UNLOCK(tag->data);
  4093.         }
  4094.         else if (tag->type == P_UNKNOWN)
  4095.         {
  4096.             int32 start;
  4097.  
  4098.             PA_LOCK (tptr, char *, tag->data);
  4099.             in_str = XP_ALLOC(tag->data_len + 3);
  4100.             if (in_str == NULL)
  4101.             {
  4102.                 return(MK_OUT_OF_MEMORY);
  4103.             }
  4104.             in_str[0] = '<';
  4105.             start = 1;
  4106.             if (tag->is_end != FALSE)
  4107.             {
  4108.                 in_str[1] = '/';
  4109.                 start = 2;
  4110.             }
  4111.             XP_BCOPY(tptr, (char *)(in_str + start), tag->data_len);
  4112.             in_str[tag->data_len + start] = '\0';
  4113.             PA_UNLOCK(tag->data);
  4114.         }
  4115.         else
  4116.         {
  4117.             XP_Bool free_tag_str;
  4118.             const char *tag_str;
  4119.             int32 start;
  4120.  
  4121.             free_tag_str = FALSE;
  4122.             tag_str = PA_TagString((int32)tag->type);
  4123.             if (tag_str == NULL)
  4124.             {
  4125.                 tag_str = XP_STRDUP("UNKNOWN");
  4126.                 if (tag_str == NULL)
  4127.                 {
  4128.                     return(MK_OUT_OF_MEMORY);
  4129.                 }
  4130.                 free_tag_str = TRUE;
  4131.             }
  4132.             start = XP_STRLEN(tag_str);
  4133.  
  4134.             PA_LOCK (tptr, char *, tag->data);
  4135.             in_str = XP_ALLOC(tag->data_len + start + 3);
  4136.             if (in_str == NULL)
  4137.             {
  4138.                 if (free_tag_str != FALSE)
  4139.                 {
  4140.                     XP_FREE((char *)tag_str);
  4141.                 }
  4142.                 return(MK_OUT_OF_MEMORY);
  4143.             }
  4144.             in_str[0] = '<';
  4145.             in_str[1] = '\0';
  4146.             start += 1;
  4147.             if (tag->is_end != FALSE)
  4148.             {
  4149.                 in_str[1] = '/';
  4150.                 in_str[2] = '\0';
  4151.                 start += 1;
  4152.             }
  4153.             XP_STRCAT(in_str, tag_str);
  4154.             XP_BCOPY(tptr, (char *)(in_str + start), tag->data_len);
  4155.             in_str[tag->data_len + start] = '\0';
  4156.             PA_UNLOCK(tag->data);
  4157.             if (free_tag_str != FALSE)
  4158.             {
  4159.                 XP_FREE((char *)tag_str);
  4160.             }
  4161.         }
  4162.         if (HK_CallHook(HK_TAG, (void *)tag, XP_CONTEXTID(context),
  4163.             in_str, &out_str))
  4164.         {
  4165.             /*
  4166.              * out_str of NULL means change nothing.
  4167.              * Returning the same string passed in also
  4168.              * changes nothing.
  4169.              */
  4170.             if ((out_str != NULL)&&(out_str[0] == '\0'))
  4171.             {
  4172.                 delete_tag = TRUE;
  4173.             }
  4174.             else if ((out_str != NULL)&&
  4175.                 (XP_STRCMP(in_str, out_str) != 0))
  4176.             {
  4177.                 replace_tag = TRUE;
  4178.             }
  4179.         }
  4180.         XP_FREE(in_str);
  4181.  
  4182.         if (delete_tag != FALSE)
  4183.         {
  4184.             PA_FreeTag(tag);
  4185.             tag = NULL;
  4186.             XP_FREE(out_str);
  4187.             return(1);
  4188.         }
  4189.         else if (replace_tag != FALSE)
  4190.         {
  4191.             intn ok;
  4192.  
  4193.             hooked_data_object = data_object;
  4194.             hooked_status = status;
  4195.             hooked_tag = tag;
  4196.  
  4197.             ok = PA_ParseStringToTags(context,
  4198.                 out_str, XP_STRLEN(out_str),
  4199.                 (void *)LO_ProcessTag);
  4200.  
  4201.             hooked_data_object = NULL;
  4202.  
  4203.             /*
  4204.              * This tag has been replaced, and never happened.
  4205.              */
  4206.             if (ok)
  4207.             {
  4208.                 PA_FreeTag(tag);
  4209.                 tag = NULL;
  4210.                 XP_FREE(out_str);
  4211.                 return(1);
  4212.             }
  4213.         }
  4214.         if (out_str != NULL)
  4215.         {
  4216.             XP_FREE(out_str);
  4217.         }
  4218.     }
  4219.  
  4220.     /*    
  4221.         Test to see if this is a new stream.
  4222.         If it is, kill the old one (NET_InterruptStream(url)),
  4223.         free its data, and continue.
  4224.     */
  4225.     if (!state) { /* this is a new document being laid out */
  4226.         /* is there already a state for this context? */
  4227.         lo_TopState *top_state;
  4228.         lo_DocState *old_state;
  4229.  
  4230.         /* initialize PICS */
  4231.         PICS_Init(context);
  4232.  
  4233.         top_state = lo_FetchTopState(doc_id);
  4234.         if (top_state == NULL)
  4235.         {
  4236.             old_state = NULL;
  4237.         }
  4238.         else
  4239.         {
  4240.             old_state = top_state->doc_state;
  4241.         }
  4242.  
  4243.         if (old_state) {
  4244.             if (top_state->nurl) { /* is it still running? */
  4245. /* ALEKS                NET_InterruptStream (top_state->nurl); */
  4246.                 /* We've done a complete "cancel" now. We shouldn't need to do any more
  4247.                 work; we'll find this "old state" again and recycle it */
  4248.             }
  4249.         }
  4250.     }
  4251.         
  4252.     /*
  4253.      * We be done.
  4254.      */
  4255.     if (tag == NULL)
  4256.     {
  4257.         /* 
  4258.          * If this is an inline stream that is not the result of a
  4259.          * dynamic layer src change, then don't do anything. The
  4260.          * layer will be closed out by the closing </LAYER> tag
  4261.          */
  4262.         if (doc_data && doc_data->is_inline_stream && (!state || 
  4263.             (lo_InsideLayer(state) && !lo_IsCurrentLayerDynamic(state))))
  4264.             return 0;
  4265.         
  4266.         if (status == PA_ABORT)
  4267.         {
  4268. #ifdef OLD_MSGS
  4269.             FE_Progress (context, "Document Load Aborted");
  4270. #endif /* OLD_MSGS */
  4271.             lo_process_deferred_image_info(NULL);
  4272.             if (state != NULL)
  4273.             {
  4274.                 state->top_state->layout_status = status;
  4275.             }
  4276.         /*
  4277.          * If this is an inline stream (the result of a dynamic
  4278.          * layer src change) close out the layer.
  4279.          */
  4280.         if (doc_data && doc_data->is_inline_stream)
  4281.             lo_FinishLayerLayout(context, state, EVENT_ABORT);
  4282.         else 
  4283.             lo_FinishLayout(context, state, EVENT_ABORT);
  4284.         }
  4285.         else if (status == PA_COMPLETE)
  4286.         {
  4287.             orig_state = state;
  4288.             state = lo_CurrentSubState(state);
  4289.  
  4290.             /*
  4291.              * If this is an inline stream (the result of a dynamic
  4292.              * layer src change) close out the layer.
  4293.              */
  4294.             if (doc_data && doc_data->is_inline_stream)
  4295.                 lo_FinishLayerLayout(context, state, EVENT_LOAD);
  4296.             else 
  4297.             /*
  4298.              * IF the document is complete, we need to flush
  4299.              * out any remaining unfinished elements.
  4300.              */
  4301.             if (state != NULL)
  4302.             {
  4303.                 state->top_state->total_bytes = state->top_state->current_bytes;
  4304.  
  4305.                 if (state->top_state->layout_blocking_element != NULL)
  4306.                 {
  4307. #ifdef OLD_MSGS
  4308.                     FE_Progress(context, "Layout Phase Complete but Blocked");
  4309. #endif /* OLD_MSGS */
  4310.                 }
  4311.                 else
  4312.                 {
  4313.                     /*
  4314.                      * makes sure we are at the bottom
  4315.                      * of everything in the document.
  4316.                      */
  4317.                     lo_CloseOutLayout(context, state);
  4318.  
  4319. #ifdef OLD_MSGS
  4320.                     FE_Progress(context, "Layout Phase Complete");
  4321. #endif /* OLD_MSGS */
  4322.  
  4323.                     lo_FinishLayout(context, state, EVENT_LOAD);
  4324.                 }
  4325.                 orig_state->top_state->layout_status = status;
  4326.             }
  4327.             else
  4328.             {
  4329.                 LO_Element *recycle_list = NULL;
  4330.                 int32 cnt;
  4331.                 int32 width, height;
  4332.                 int32 margin_width, margin_height;
  4333. #ifdef MEMORY_ARENAS
  4334.                 lo_arena *old_arena = NULL;
  4335.  
  4336.                 lo_GetRecycleList(context, doc_id, doc_data,
  4337.                           &recycle_list, &old_arena);
  4338. #else
  4339.                 lo_GetRecycleList(context, doc_id, doc_data,
  4340.                           &recycle_list);
  4341. #endif /* MEMORY_ARENAS */
  4342.                 margin_width = 0;
  4343.                 margin_height = 0;
  4344.  
  4345.                 /* Because Mocha is in a separate thread, the
  4346.                    complete destruction of contexts is deferred until
  4347.                    Mocha cleans up its data structures.  (See
  4348.                    ET_RemoveWindowContext()).  If this context was
  4349.                    previously a frameset context, it may still have grid
  4350.                    children that haven't been deleted yet.  Pull them
  4351.                    off the grid_children list so that we don't mistakenly
  4352.                    conclude that this context is a frameset context. */
  4353.                 if (context->grid_children) {
  4354.                     XP_ListDestroy (context->grid_children);
  4355.                     context->grid_children = 0;
  4356.                 }
  4357.                 FE_LayoutNewDocument(context,
  4358.                              doc_data->url_struct,
  4359.                              &width, &height,
  4360.                              &margin_width,
  4361.                              &margin_height);
  4362.  
  4363.                 if(context && doc_data && doc_data->url_struct) {
  4364.                     /*  Tell XP NavCenter API about the new document.
  4365.                      */
  4366.                     XP_SetNavCenterUrl(context, doc_data->url_struct->address);
  4367.                 }
  4368.  
  4369.                 /* see first lo_FreeRecycleList comment. safe */
  4370.                 cnt = lo_FreeRecycleList(context, recycle_list);
  4371. #ifdef MEMORY_ARENAS
  4372.                 cnt = lo_FreeMemoryArena(old_arena);
  4373. #endif /* MEMORY_ARENAS */
  4374.  
  4375.                 FE_SetDocPosition(context, FE_VIEW, 0, 0);
  4376.                 FE_SetDocDimension(context, FE_VIEW, 1, 1);
  4377.  
  4378. #ifdef OLD_MSGS
  4379.                 FE_Progress(context, "Layout Phase Complete");
  4380. #endif /* OLD_MSGS */
  4381.                 lo_FinishLayout(context, state, EVENT_LOAD);
  4382.             }
  4383.         }
  4384.  
  4385.         /*
  4386.          * Since lo_FinishLayout make have caused state to be
  4387.          * freed if it was a dangling sub_state, we need to
  4388.          * reinitialize state here so it is safe to use it.
  4389.          */
  4390.         state = lo_TopSubState(top_state);
  4391.  
  4392.         if (state != NULL)
  4393.         {
  4394.             /* done with netlib stream */
  4395.             state->top_state->nurl = NULL;
  4396.             state->top_state->doc_data = NULL;
  4397.         }
  4398.  
  4399.  
  4400.         /*
  4401.          * Make sure we are done with all images now.
  4402.          */
  4403.         lo_NoMoreImages(context);
  4404.  
  4405.         return(0);
  4406.     }
  4407.  
  4408.     /*
  4409.      * Check if this is a new document being laid out
  4410.      */
  4411.     if (top_state == NULL)
  4412.     {
  4413.         int32 width, height;
  4414.         int32 margin_width, margin_height;
  4415.         lo_SavedFormListData *form_list;
  4416.         lo_SavedEmbedListData *embed_list;
  4417.         lo_SavedGridData *grid_data;
  4418.         LO_Element *recycle_list = NULL;
  4419.         int32 start_element;
  4420.  
  4421. #ifdef MEMORY_ARENAS 
  4422.         lo_arena *old_arena = NULL;
  4423.  
  4424.         lo_GetRecycleList(context, doc_id, doc_data, &recycle_list, &old_arena);    /* whh */
  4425. #else
  4426.         lo_GetRecycleList(context, doc_id, doc_data, &recycle_list);    /* whh */
  4427. #endif /* MEMORY_ARENAS */
  4428.  
  4429. #ifdef LOCAL_DEBUG
  4430. XP_TRACE(("Initializing new doc %d\n", doc_id));
  4431. #endif /* DEBUG */
  4432.         width = 1;
  4433.         height = 1;
  4434.         margin_width = 0;
  4435.         margin_height = 0;
  4436.         /*
  4437.          * Grid cells can set their own margin dimensions.
  4438.          */
  4439.         if (context->is_grid_cell != FALSE)
  4440.         {
  4441.             lo_GetGridCellMargins(context,
  4442.                 &margin_width, &margin_height);
  4443.         }
  4444.  
  4445.         /* Because Mocha is in a separate thread, the complete
  4446.            destruction of contexts is deferred until Mocha cleans up
  4447.            its data structures.  (See ET_RemoveWindowContext()).  If
  4448.            this context was previously a frameset context, it may
  4449.            still have grid children that haven't been deleted yet.
  4450.            Pull them off the grid_children list so that we don't
  4451.            mistakenly conclude that this context is a frameset
  4452.            context. */
  4453.         if (context->grid_children) {
  4454.             XP_ListDestroy (context->grid_children);
  4455.             context->grid_children = 0;
  4456.         }
  4457.         FE_LayoutNewDocument(context, doc_data->url_struct,
  4458.             &width, &height, &margin_width, &margin_height);
  4459.  
  4460.         if(context && doc_data && doc_data->url_struct) {
  4461.             /*  Tell XP NavCenter API about the new document.
  4462.              */
  4463.             XP_SetNavCenterUrl(context, doc_data->url_struct->address);
  4464.         }
  4465.  
  4466.         if (context->compositor) {
  4467.             lo_CreateDefaultLayers(context, &doc_layer, &body_layer);
  4468.             CL_ScrollCompositorWindow(context->compositor, 0, 0);
  4469.             CL_SetCompositorEnabled(context->compositor, PR_TRUE);
  4470.         }
  4471.         
  4472.         top_state = lo_NewTopState(context, doc_data->url);
  4473.         if ((context->compositor && (!doc_layer || !body_layer)) ||
  4474.                     top_state == NULL)
  4475.         {
  4476. #ifdef MEMORY_ARENAS
  4477.             if (old_arena != NULL)
  4478.             {
  4479.                 int32 cnt;
  4480.  
  4481.                 cnt = lo_FreeMemoryArena(old_arena);
  4482.             }
  4483. #endif /* MEMORY_ARENAS */
  4484.             return lo_ProcessTag_OutOfMemory(context, recycle_list, top_state);
  4485.         }
  4486. #ifdef MEMORY_ARENAS
  4487.         if ( ! EDT_IS_EDITOR(context) ) {
  4488.             top_state->first_arena->next = old_arena;
  4489.         }
  4490. #endif /* MEMORY_ARENAS */
  4491.  
  4492.         /* take a special hacks from URL_Struct */
  4493.         top_state->auto_scroll =(intn)doc_data->url_struct->auto_scroll;
  4494.         top_state->is_binary = doc_data->url_struct->is_binary;
  4495.         /*
  4496.          * Security dialogs only for FO_PRESENT docs.
  4497.          */
  4498.         if (CLEAR_CACHE_BIT(doc_data->format_out) == FO_PRESENT)
  4499.         {
  4500.             top_state->security_level =
  4501.                 doc_data->url_struct->security_on;
  4502.         }
  4503.         else
  4504.         {
  4505.             top_state->security_level = 0;
  4506.         }
  4507.         top_state->doc_layer = doc_layer;
  4508.         top_state->body_layer = body_layer;
  4509.         top_state->force_reload = doc_data->url_struct->force_reload;
  4510.         top_state->nurl = doc_data->url_struct;
  4511.         top_state->total_bytes = doc_data->url_struct->content_length;
  4512.         top_state->doc_data = doc_data;
  4513.         top_state->resize_reload = doc_data->url_struct->resize_reload;
  4514.  
  4515.         if (top_state->auto_scroll != 0)
  4516.         {
  4517.             top_state->scrolling_doc = TRUE;
  4518.             if (top_state->auto_scroll < 1)
  4519.             {
  4520.                 top_state->auto_scroll = 1;
  4521.             }
  4522.             if (top_state->auto_scroll > 1000)
  4523.             {
  4524.                 top_state->auto_scroll = 1000;
  4525.             }
  4526.         }
  4527.  
  4528.         /*
  4529.          * give the parser a pointer to the layout data so we can
  4530.          * get to it next time
  4531.          */
  4532.         doc_data->layout_state = top_state;
  4533.  
  4534.         /*
  4535.          * Add this new top state to the global state list.
  4536.          */
  4537.         if (lo_StoreTopState(doc_id, top_state) == FALSE)
  4538.         {
  4539.             return lo_ProcessTag_OutOfMemory(context, recycle_list,
  4540.                              top_state);
  4541.         }
  4542.  
  4543. #ifdef EDITOR
  4544.         /* LTNOTE: maybe this should be passed into New_Layout.
  4545.          * For now, it is not.
  4546.          */
  4547.         top_state->edit_buffer = doc_data->edit_buffer;
  4548. #endif
  4549.         state = lo_NewLayout(context, width, height,
  4550.             margin_width, margin_height, NULL);
  4551.         if (state == NULL)
  4552.             return lo_ProcessTag_OutOfMemory(context, recycle_list, top_state);
  4553.         top_state->doc_state = state;
  4554.  
  4555.         /* The DOCUMENT layer's height is always the height of the
  4556.            window, at least for the purpose of computing percentage
  4557.            heights in child layers. */
  4558.         top_state->layers[LO_DOCUMENT_LAYER_ID]->height = 
  4559.             state->win_top + state->win_height + state->win_bottom;
  4560.  
  4561.         /* Reset the scoping for any JavaScript to be the top-level layer. */
  4562.         ET_SetActiveLayer(context, LO_DOCUMENT_LAYER_ID);
  4563.  
  4564.         /* RESTORE style stack 
  4565.          */
  4566.         if(top_state->resize_reload)
  4567.         {
  4568.             History_entry *he = SHIST_GetCurrent(&context->hist);
  4569.             if (he)
  4570.             {
  4571.                 if(he->savedData.style_stack)
  4572.                 {
  4573.                     if(top_state->style_stack)
  4574.                         STYLESTACK_Delete(top_state->style_stack);
  4575.                     top_state->style_stack = he->savedData.style_stack;
  4576.                     he->savedData.style_stack = NULL;
  4577.                 }
  4578.             }
  4579.         }
  4580.         
  4581.         /*
  4582.          * Take care of forms.
  4583.          * If we have been here before, we can pull the old form
  4584.          * data out of the URL_Struct.  It may be invalid if the
  4585.          * form was interrupted.
  4586.          */
  4587.         RESTORE_SAVED_DATA(FormList, form_list, doc_data, recycle_list, top_state);
  4588.         if (!form_list->valid)
  4589.             lo_FreeDocumentFormListData(context, form_list);
  4590.         form_list->data_index = 0;
  4591.  
  4592.         /*
  4593.          * Take care of embeds.
  4594.          * If we have been here before, we can pull the old embed
  4595.          * data out of the URL_Struct.
  4596.          */
  4597.         RESTORE_SAVED_DATA(EmbedList, embed_list, doc_data, recycle_list, top_state);
  4598.  
  4599.         /*
  4600.          * Take care of saved grid data.
  4601.          * If we have been here before, we can pull the old
  4602.          * grid data out of the URL_Struct.
  4603.          */
  4604.         RESTORE_SAVED_DATA(Grid, grid_data, doc_data, recycle_list, top_state);
  4605.  
  4606.         /* XXX just in case a grid had onLoad or onUnload handlers */
  4607.         if (!doc_data->url_struct->resize_reload)
  4608.         {
  4609.             lo_RestoreContextEventHandlers(context, state, tag,
  4610.                         &doc_data->url_struct->savedData);
  4611.         }
  4612.  
  4613.         top_state->recycle_list = recycle_list;
  4614.  
  4615.         if (state->top_state->name_target != NULL)
  4616.         {
  4617.             state->display_blocking_element_id = -1;
  4618.         }
  4619.  
  4620.         start_element = doc_data->url_struct->position_tag;
  4621.         if (start_element == 1)
  4622.         {
  4623.             start_element = 0;
  4624.         }
  4625.  
  4626.         if (start_element > 0)
  4627.         {
  4628.             state->display_blocking_element_id = start_element;
  4629.         }
  4630.  
  4631.         if ((state->display_blocking_element_id > state->top_state->element_id)||
  4632.             (state->display_blocking_element_id  == -1))
  4633.         {
  4634.             state->display_blocked = TRUE;
  4635.         }
  4636.         else
  4637.         {
  4638.             FE_SetDocPosition(context, FE_VIEW, 0, state->base_y);
  4639.         }
  4640.  
  4641.         if ((Master_backdrop_url != NULL)&&(UserOverride != FALSE)
  4642.             &&(context->type != MWContextDialog))
  4643.         {
  4644.             lo_load_user_backdrop(context, state);
  4645.         }
  4646.     }
  4647.  
  4648.     if (state == NULL)
  4649.     {
  4650.         return(-1);
  4651.     }
  4652.  
  4653.     /* 
  4654.      * If we're processing an inline stream, we need to make a note of it
  4655.      * so that the tag goes into the correct place.
  4656.      */
  4657.     if (doc_data && doc_data->is_inline_stream && 
  4658.         (top_state->doc_data != doc_data)) 
  4659.     {
  4660.         if (top_state->input_write_level >= MAX_INPUT_WRITE_LEVEL-1) {
  4661.             top_state->out_of_memory = TRUE;
  4662.             return (MK_OUT_OF_MEMORY);
  4663.         }
  4664.         top_state->input_write_level++;
  4665.         top_state->tag_from_inline_stream = TRUE;
  4666.     }
  4667.     
  4668.     if (tag->data != NULL)
  4669.     {
  4670.         state->top_state->current_bytes += tag->data_len;
  4671.     }
  4672.  
  4673.     /*
  4674.      * Divert all tags to the current sub-document if there is one.
  4675.      */
  4676.     up_state = NULL;
  4677.     orig_state = state;
  4678.     while (state->sub_state != NULL)
  4679.     {
  4680.         up_state = state;
  4681.         state = state->sub_state;
  4682.     }
  4683.  
  4684.     orig_state->top_state->layout_status = status;
  4685.  
  4686.     /*
  4687.      * The filter checks for all the NOFRAMES, NOEMBED, NOSCRIPT, and
  4688.      * the APPLET ignore setup.
  4689.      */
  4690.     if (top_state->layout_blocking_element != NULL)
  4691.     {
  4692.         lo_BlockTag(context, state, tag);
  4693.     }
  4694.     else if (lo_FilterTag(context, state, tag) == FALSE)
  4695.     {
  4696.         PA_FreeTag(tag);
  4697.     }
  4698.     else
  4699.     {
  4700.         lo_DocState *tmp_state;
  4701.         Bool may_save;
  4702.         int32 state_diff;
  4703.  
  4704.         if ((state->is_a_subdoc == SUBDOC_CELL)||
  4705.             (state->is_a_subdoc == SUBDOC_CAPTION))
  4706.         {
  4707.             may_save = TRUE;
  4708.         }
  4709.         else
  4710.         {
  4711.             may_save = FALSE;
  4712.         }
  4713.  
  4714.         /*
  4715.          * Reset these so we can tell if anything happened
  4716.          */
  4717.         top_state->diff_state = FALSE;
  4718.         top_state->state_pushes = 0;
  4719.         top_state->state_pops = 0;
  4720.         
  4721.         lo_LayoutTag(context, state, tag);
  4722.  
  4723.         if (top_state->wedged_on_mocha) {
  4724.             top_state->wedged_on_mocha = FALSE;
  4725.             return(1);
  4726.         }
  4727.  
  4728.         tmp_state = lo_CurrentSubState(orig_state);
  4729.  
  4730.         /* how has our state level changed? */
  4731.         state_diff = top_state->state_pushes - top_state->state_pops;
  4732.         
  4733.         if (may_save != FALSE)
  4734.         {
  4735.             /*
  4736.              * Store the tag in the correct subdoc.
  4737.              */
  4738.             if (state_diff == -1)
  4739.             {
  4740.                 /*
  4741.                  * That tag popped us up one state level.  If this new
  4742.                  * state is still a subdoc, save the tag there.
  4743.                 */
  4744.                 if ((tmp_state->is_a_subdoc == SUBDOC_CELL)||
  4745.                     (tmp_state->is_a_subdoc == SUBDOC_CAPTION))
  4746.                 {
  4747.                     /* if we just popped a table we need to insert
  4748.                      * a dummy end tag to pop the dummy start tag
  4749.                      * we shove on the stack after createing a table
  4750.                      */
  4751.                        PA_Tag *new_tag = LO_CreateStyleSheetDummyTag(tag);
  4752.                     if(new_tag)
  4753.                     {
  4754.                         lo_SaveSubdocTags(context, tmp_state, new_tag);
  4755.                     }
  4756.  
  4757.                     lo_SaveSubdocTags(context, tmp_state, tag);
  4758.                 }
  4759.                 else
  4760.                 {
  4761.                     PA_FreeTag(tag);
  4762.                 }
  4763.             }
  4764.             else if (( up_state != NULL ) &&
  4765.                 ( top_state->diff_state != FALSE ) &&
  4766.                 ( state_diff == 0 ))
  4767.             {
  4768.                 /*
  4769.                  * We have returned to the same state level but
  4770.                  * we have a different subdoc.
  4771.                  */
  4772.                 if ((up_state->is_a_subdoc == SUBDOC_CELL)||
  4773.                      (up_state->is_a_subdoc == SUBDOC_CAPTION))
  4774.                 {
  4775.                     lo_SaveSubdocTags(context, up_state, tag);
  4776.                 }
  4777.                 else
  4778.                 {
  4779.                     PA_FreeTag(tag);
  4780.                 }
  4781.             }
  4782.             else if (( top_state->diff_state == FALSE ) &&
  4783.                 ( state_diff == 0 ))
  4784.             {
  4785.                 /*
  4786.                  * We are still in the same subdoc
  4787.                  */
  4788.                 lo_SaveSubdocTags(context, state, tag);
  4789.             }
  4790.             else if (( state_diff == 1 ))
  4791.             {
  4792.                 PA_Tag *new_tag;
  4793.  
  4794.                 /*
  4795.                  * That tag started a new, nested subdoc.
  4796.                  * Add the starting tag to the parent.
  4797.                  */
  4798.                 lo_SaveSubdocTags(context, state, tag);
  4799.                 /*
  4800.                  * Since we have extended the parent chain,
  4801.                  * we need to reset the child to the new
  4802.                  * parent end-chain.
  4803.                  */
  4804.                 if ((tmp_state->is_a_subdoc == SUBDOC_CELL)||
  4805.                     (tmp_state->is_a_subdoc == SUBDOC_CAPTION))
  4806.                 {
  4807.                     tmp_state->subdoc_tags =
  4808.                         state->subdoc_tags_end;
  4809.  
  4810.                     /* add an aditional dummy tag so that style sheets
  4811.                      * can use it to query styles from for this entry
  4812.                      * that created a table
  4813.                      */
  4814.                     new_tag = LO_CreateStyleSheetDummyTag(tag);
  4815.                     if(new_tag)
  4816.                     {
  4817.                         lo_SaveSubdocTags(context, tmp_state, new_tag);
  4818.                     }
  4819.                 }
  4820.             }
  4821.             /*
  4822.              * This can never happen.
  4823.              */
  4824.             else
  4825.             {
  4826.                 PA_FreeTag(tag);
  4827.             }
  4828.  
  4829.             state = tmp_state;
  4830.         }
  4831.         else
  4832.         {
  4833.             if(state_diff == 1)
  4834.             {
  4835.                 /* everytime a table is started we need to save the
  4836.                  * tag that created it so that style sheets can apply
  4837.                  * styles to it.  So we will save even in the "dont save"
  4838.                  * case
  4839.                  */
  4840.                 PA_Tag *new_tag = LO_CreateStyleSheetDummyTag(tag);
  4841.                 if(new_tag)
  4842.                 {
  4843.                     /* We just pushed another table into a previous table 
  4844.                      * we need to do some table magic to make the subdoc
  4845.                      * list work right
  4846.                      */
  4847.                     lo_SaveSubdocTags(context, tmp_state, new_tag);
  4848.                 }
  4849.             }                                            
  4850.             else if(state_diff == -1)
  4851.             {
  4852.                 /* if we just popped a table we need to insert
  4853.                  * a dummy end tag to pop the dummy start tag
  4854.                  * we shove on the stack after createing a table
  4855.                  */
  4856.                    PA_Tag *new_tag = LO_CreateStyleSheetDummyTag(tag);
  4857.                 if(new_tag)
  4858.                 {
  4859.                     lo_SaveSubdocTags(context, tmp_state, new_tag);
  4860.                 }
  4861.             }
  4862.  
  4863.             PA_FreeTag(tag);
  4864.         }
  4865.     }
  4866.  
  4867.     if (doc_data && doc_data->is_inline_stream && 
  4868.         (top_state->doc_data != doc_data))
  4869.     {
  4870.         top_state->input_write_level--;
  4871.     }
  4872.     top_state->tag_from_inline_stream = FALSE;
  4873.  
  4874.     if (state->top_state->out_of_memory != FALSE)
  4875.     {
  4876.         lo_FinishLayout_OutOfMemory(context, state);
  4877.         return(MK_OUT_OF_MEMORY);
  4878.     }
  4879.  
  4880.     /*
  4881.      * The parser (libparse/pa_parse.c) only calls us with these status
  4882.      * codes when tag is null, and we handled that case far above (in fact,
  4883.      * we will crash less far above on a null tag pointer, so we can't get
  4884.      * here when aborting or completing).
  4885.      */
  4886.     XP_ASSERT(status != PA_ABORT && status != PA_COMPLETE);
  4887.  
  4888.     return(1);
  4889. }
  4890.  
  4891. void
  4892. lo_RefreshDocumentArea(MWContext *context, lo_DocState *state, int32 x, int32 y,
  4893.     uint32 width, uint32 height)
  4894. {
  4895.     LO_Element *eptr;
  4896.     int32 i;
  4897.     int32 top, bottom;
  4898.  
  4899.     if (state->display_blocked != FALSE)
  4900.     {
  4901.         return;
  4902.     }
  4903.     
  4904.     /*    
  4905.      * Find which lines intersect the drawable region.
  4906.      */
  4907.     lo_RegionToLines (context, state, x, y, width, height, FALSE,
  4908.         &top, &bottom);
  4909.  
  4910.     /*
  4911.      * Display all these lines, if there are any.
  4912.      */
  4913.     if (bottom >= 0)
  4914.     {
  4915.         for (i=top; i <= bottom; i++)
  4916.         {
  4917.             lo_DisplayLine(context, state, i,
  4918.                 x, y, width, height);
  4919.         }
  4920.     }
  4921.  
  4922.     /*
  4923.      * Check the floating element list.
  4924.      */
  4925.     eptr = state->float_list;
  4926.     while (eptr != NULL)
  4927.     {
  4928.         /* I'm not sure exactly why we need to do this, but this code
  4929.            has been here, in some form or another, since this file was
  4930.            first created -- fur. */
  4931.         if (eptr->type == LO_SUBDOC)
  4932.         {
  4933.             LO_SubDocStruct *subdoc;
  4934.             lo_DocState *sub_state;
  4935.         
  4936.             subdoc = (LO_SubDocStruct *)eptr;
  4937.             sub_state = (lo_DocState *)subdoc->state;
  4938.  
  4939.             if (sub_state == NULL)
  4940.                 break;
  4941.  
  4942.             if (sub_state->base_y < 0)
  4943.                 sub_state->display_blocked = FALSE;
  4944.         }
  4945.         lo_DisplayElement(context, eptr,
  4946.                           state->base_x, state->base_y,
  4947.                           x, y, width, height);
  4948.         eptr = eptr->lo_any.next;
  4949.     }
  4950. }
  4951.  
  4952.  
  4953. /*************************************
  4954.  * Function: LO_RefreshArea
  4955.  *
  4956.  * Description: This is a public function that allows the front end
  4957.  *    to ask that a particulat portion of the document be refreshed.
  4958.  *    The layout then finds the relevant elements, and calls
  4959.  *    the appropriate front end functions to display those
  4960.  *    elements.
  4961.  *
  4962.  * Params: Window context, x, y position of upper left corner,
  4963.  *    and width X height of the rectangle.
  4964.  *
  4965.  * Returns: Nothing
  4966.  *************************************/
  4967. void
  4968. LO_RefreshArea(MWContext *context, int32 x, int32 y,
  4969.     uint32 width, uint32 height)
  4970. {
  4971.     int32 doc_id;
  4972.     lo_TopState *top_state;
  4973.     lo_DocState *state;
  4974.     
  4975.     /*
  4976.      * Get the unique document ID, and retreive this
  4977.      * documents layout state.
  4978.      */
  4979.     doc_id = XP_DOCID(context);
  4980.     top_state = lo_FetchTopState(doc_id);
  4981.     if ((top_state == NULL)||(top_state->doc_state == NULL))
  4982.     {
  4983.         return;
  4984.     }
  4985.     state = top_state->doc_state;
  4986.  
  4987.     lo_RefreshDocumentArea(context, state, x, y, width, height);
  4988. }
  4989.  
  4990.  
  4991. /*************************************
  4992.  * Function: lo_GetLineEnds
  4993.  *
  4994.  * Description: This is a private function that returns the line ends for
  4995.  * a particular line.
  4996.  *
  4997.  * Params: Window context, line number.
  4998.  *
  4999.  * Returns: A pointer to the first and last elements in the line at that location,
  5000.  *    or NULLs if there is no matching line.
  5001.  *************************************/
  5002. void
  5003. lo_GetLineEnds(MWContext *context, lo_DocState *state,
  5004.     int32 line, LO_Element** retBegin, LO_Element** retEnd)
  5005. {
  5006.     LO_Element **line_array;
  5007.  
  5008.     *retBegin = NULL;
  5009.     *retEnd = NULL;
  5010.  
  5011.     /*
  5012.      * No document state yet.
  5013.      */
  5014.     if (state == NULL)
  5015.     {
  5016.         return;
  5017.     }
  5018.  
  5019.     if (line >= 0)
  5020. #ifdef XP_WIN16
  5021.     {
  5022.         intn a_size;
  5023.         intn a_indx;
  5024.         intn a_line;
  5025.         XP_Block *larray_array;
  5026.  
  5027.         a_size = SIZE_LIMIT / sizeof(LO_Element *);
  5028.         a_indx = (intn)(line / a_size);
  5029.         a_line = (intn)(line - (a_indx * a_size));
  5030.  
  5031.         XP_LOCK_BLOCK(larray_array, XP_Block *, state->larray_array);
  5032.         state->line_array = larray_array[a_indx];
  5033.         XP_LOCK_BLOCK(line_array, LO_Element **, state->line_array);
  5034.         *retBegin = line_array[a_line];
  5035.  
  5036.         if (line >= (state->line_num - 2))
  5037.         {
  5038.             *retEnd = NULL;
  5039.         }
  5040.         else
  5041.         {
  5042.             if ((a_line + 1) == a_size)
  5043.             {
  5044.                 XP_UNLOCK_BLOCK(state->line_array);
  5045.                 state->line_array = larray_array[a_indx + 1];
  5046.                 XP_LOCK_BLOCK(line_array, LO_Element **,
  5047.                     state->line_array);
  5048.                 *retEnd = line_array[0];
  5049.             }
  5050.             else
  5051.             {
  5052.                 *retEnd = line_array[a_line + 1];
  5053.             }
  5054.         }
  5055.         XP_UNLOCK_BLOCK(state->line_array);
  5056.         XP_UNLOCK_BLOCK(state->larray_array);
  5057.     }
  5058. #else
  5059.     {
  5060.         XP_LOCK_BLOCK(line_array, LO_Element **, state->line_array);
  5061.         *retBegin = line_array[line];
  5062.         if (line == (state->line_num - 2))
  5063.         {
  5064.             *retEnd = NULL;
  5065.         }
  5066.         else
  5067.         {
  5068.             *retEnd = line_array[line + 1];
  5069.         }
  5070.         XP_UNLOCK_BLOCK(state->line_array);
  5071.     }
  5072. #endif /* XP_WIN16 */
  5073. }
  5074.  
  5075. Bool lo_IsDummyLayoutElement(LO_Element *ele)
  5076. {
  5077.     Bool isDummy = FALSE;
  5078.     switch(ele->lo_any.type)
  5079.     {
  5080.         case LO_PARAGRAPH:
  5081.         case LO_CENTER:
  5082.         case LO_MULTICOLUMN:
  5083.         case LO_FLOAT:
  5084.         case LO_TEXTBLOCK:
  5085.         case LO_LIST:
  5086.         case LO_DESCTITLE:
  5087.         case LO_DESCTEXT:
  5088.         case LO_BLOCKQUOTE:
  5089.         case LO_LAYER:
  5090.         case LO_HEADING:
  5091.         case LO_SPAN:
  5092.         case LO_DIV:
  5093.             isDummy = TRUE;
  5094.             break;
  5095.     }
  5096.     return isDummy;
  5097. }
  5098.  
  5099. /*************************************
  5100.  * Function: lo_XYToDocumentElement
  5101.  *
  5102.  * Description: This is a public function that allows the front end
  5103.  *    to ask for the particular element residing at the passed
  5104.  *    (x, y) position in the window.  This is very important
  5105.  *    for resolving button clicks on anchors.
  5106.  *
  5107.  * Params: Window context, x, y position of the window location.
  5108.  *
  5109.  * Returns: A pointer to the element record at that location,
  5110.  *    or NULL if there is no matching element.
  5111.  *************************************/
  5112. LO_Element *
  5113. lo_XYToDocumentElement2(MWContext *context, lo_DocState *state,
  5114.     int32 x, int32 y, Bool check_float, Bool into_cells, Bool into_ilayers,
  5115.     Bool editMode, int32 *ret_x, int32 *ret_y)
  5116. {
  5117.     Bool in_table, is_inflow_layer;
  5118.     int32 line;
  5119.     LO_Element *tptr, *eptr;
  5120.     LO_Element *end_ptr;
  5121.     LO_Element *tptrTable = NULL;
  5122.     LO_Element *tptrCell = NULL;
  5123.  
  5124.     /*
  5125.      * No document state yet.
  5126.      */
  5127.     if (state == NULL)
  5128.     {
  5129.         return(NULL);
  5130.     }
  5131.  
  5132.     tptr = NULL;
  5133.  
  5134.     line = lo_PointToLine(context, state, x, y);
  5135.  
  5136. #ifdef LOCAL_DEBUG
  5137. XP_TRACE(("lo_PointToLine says line %d\n", line));
  5138. #endif /* LOCAL_DEBUG */
  5139.  
  5140.     lo_GetLineEnds(context, state, line, &tptr, &end_ptr);
  5141.  
  5142.     in_table = FALSE;
  5143.     while (tptr != end_ptr)
  5144.     {
  5145.         int32 y2;
  5146.         int32 x1;
  5147.         int32 t_width, t_height;
  5148.  
  5149.         if (lo_IsDummyLayoutElement(tptr))
  5150.         {
  5151.             tptr = tptr->lo_any.next;
  5152.             continue;
  5153.         }
  5154.  
  5155.         x1 = tptr->lo_any.x + tptr->lo_any.x_offset;
  5156.  
  5157.         t_width = tptr->lo_any.width;
  5158.         /*
  5159.          * Images need to account for border width
  5160.          */
  5161.         if (tptr->type == LO_IMAGE)
  5162.         {
  5163.             t_width = t_width + (2 * tptr->lo_image.border_width);
  5164.             /*
  5165.              * If we're editing, images also account for their border space
  5166.              */
  5167.             if ( editMode )
  5168.             {
  5169.                 t_width += 2 * tptr->lo_image.border_horiz_space;
  5170.                 x1 -= tptr->lo_image.border_horiz_space;
  5171.             }
  5172.         }
  5173.         if (t_width <= 0)
  5174.         {
  5175.             t_width = 1;
  5176.         }
  5177.  
  5178.         t_height = tptr->lo_any.height;
  5179.         /*
  5180.          * Images need to account for border width
  5181.          */
  5182.         if (tptr->type == LO_IMAGE)
  5183.         {
  5184.             t_height = t_height + (2 * tptr->lo_image.border_width);
  5185.  
  5186.             /*
  5187.              * If we're editing, images also account for their border space
  5188.              */
  5189.             if ( editMode )
  5190.             {
  5191.                 t_height += 2 * tptr->lo_image.border_vert_space;
  5192.             }
  5193.         }
  5194.  
  5195.         is_inflow_layer =
  5196.             (tptr->type == LO_CELL) && tptr->lo_cell.cell_inflow_layer;
  5197.                 
  5198.         if (!in_table && !is_inflow_layer)
  5199.         {
  5200.             y2 = tptr->lo_any.y + tptr->lo_any.line_height;
  5201.             if (tptr->lo_any.line_height <= 0)
  5202.             {
  5203.                 y2 = tptr->lo_any.y + tptr->lo_any.y_offset + t_height;
  5204.             }
  5205.         }
  5206.         else
  5207.         {
  5208.             y2 = tptr->lo_any.y + tptr->lo_any.y_offset +
  5209.                 t_height;
  5210.         }
  5211.         if ((y >= tptr->lo_any.y)&&(y < y2)&&
  5212.             (x >= tptr->lo_any.x)&&
  5213.             (x < (x1 + t_width)))
  5214.         {
  5215.                         
  5216.             /*
  5217.              * Tables are containers.  Don't stop on them,
  5218.              * look inside them.
  5219.              */
  5220.             if (tptr->type != LO_TABLE)
  5221.             {
  5222.                 /* Inflow layers look just like table cells, but we
  5223.                    always look inside them, as if the layout elements
  5224.                    were part of the line's list of element's. */
  5225.                 if (is_inflow_layer && into_ilayers) {
  5226.                     eptr = lo_XYToCellElement(context, state,
  5227.                                               (LO_CellStruct *)tptr, x, y,
  5228.                                               TRUE, into_cells, into_ilayers);
  5229.                     if (eptr) {
  5230.                         tptr = eptr;
  5231.                         break;
  5232.                     }
  5233.  
  5234.                     /* No matching element found inside cell, keep
  5235.                        looking on rest of line. */
  5236.                 } else
  5237.                     break;
  5238.             }
  5239.             else
  5240.             {
  5241.                 in_table = TRUE;
  5242.                 /*
  5243.                  * Save the table element
  5244.                  *  to return if no other element is found
  5245.                 */
  5246.                 tptrTable = tptr;
  5247.             }
  5248.         }
  5249.         tptr = tptr->lo_any.next;
  5250.     }
  5251.     if (tptr == end_ptr)
  5252.     {
  5253.         tptr = NULL;
  5254.     }
  5255.  
  5256.     /*
  5257.      * Check the floating element list.
  5258.      */
  5259.     if ((tptr == NULL)&&(check_float != FALSE))
  5260.     {
  5261.         LO_Element *eptr;
  5262.  
  5263.         eptr = state->float_list;
  5264.         while (eptr != NULL)
  5265.         {
  5266.             int32 t_width, t_height;
  5267.  
  5268.             t_width = eptr->lo_any.width;
  5269.             /*
  5270.              * Images need to account for border width
  5271.              */
  5272.             if (eptr->type == LO_IMAGE)
  5273.             {
  5274.                 t_width = t_width +
  5275.                     (2 * eptr->lo_image.border_width);
  5276.             }
  5277.             if (t_width <= 0)
  5278.             {
  5279.                 t_width = 1;
  5280.             }
  5281.  
  5282.             t_height = eptr->lo_any.height;
  5283.             /*
  5284.              * Images need to account for border width
  5285.              */
  5286.             if (eptr->type == LO_IMAGE)
  5287.             {
  5288.                 t_height = t_height +
  5289.                     (2 * eptr->lo_image.border_width);
  5290.             }
  5291.  
  5292.             if ((y >= eptr->lo_any.y)&&
  5293.                 (y < (eptr->lo_any.y + eptr->lo_any.y_offset +
  5294.                     t_height)))
  5295.             {
  5296.                 if ((x >= eptr->lo_any.x)&&
  5297.                     (x < (eptr->lo_any.x +
  5298.                         eptr->lo_any.x_offset +
  5299.                         t_width)))
  5300.                 {
  5301.                     /*
  5302.                      * Tables are containers.
  5303.                      * Don't stop on them,
  5304.                      * look inside them.
  5305.                      */
  5306.                     if (eptr->type != LO_TABLE)
  5307.                     {
  5308.                         break;
  5309.                     }
  5310.                 }
  5311.             }
  5312.             eptr = eptr->lo_any.next;
  5313.         }
  5314.         tptr = eptr;
  5315.     }
  5316.  
  5317.     if ((tptr != NULL)&&(tptr->type == LO_SUBDOC))
  5318.     {
  5319.         LO_SubDocStruct *subdoc;
  5320.         int32 new_x, new_y;
  5321.         int32 ret_new_x, ret_new_y;
  5322.  
  5323.         subdoc = (LO_SubDocStruct *)tptr;
  5324.  
  5325.         new_x = x - (subdoc->x + subdoc->x_offset +
  5326.             subdoc->border_width);
  5327.         new_y = y - (subdoc->y + subdoc->y_offset +
  5328.             subdoc->border_width);
  5329.         tptr = lo_XYToDocumentElement(context,
  5330.             (lo_DocState *)subdoc->state, new_x, new_y, check_float,
  5331.             into_cells, into_ilayers, &ret_new_x, &ret_new_y);
  5332.         x = ret_new_x;
  5333.         y = ret_new_y;
  5334.     }
  5335.     else if ((tptr != NULL)&&(tptr->type == LO_CELL)&&(into_cells != FALSE))
  5336.     {
  5337.         /*
  5338.          * Save the cell element
  5339.          *  to return if no other element is found
  5340.         */
  5341.         tptrCell = tptr;
  5342.         tptr = lo_XYToCellElement(context, state,
  5343.             (LO_CellStruct *)tptr, x, y, TRUE, into_cells, into_ilayers);
  5344.     }
  5345.  
  5346.     *ret_x = x;
  5347.     *ret_y = y;
  5348.  
  5349.     return(tptr);
  5350. }
  5351.  
  5352. LO_Element *
  5353. lo_XYToDocumentElement(MWContext *context, lo_DocState *state,
  5354.     int32 x, int32 y, Bool check_float, Bool into_cells, Bool into_ilayers,
  5355.     int32 *ret_x, int32 *ret_y)
  5356. {
  5357.     return lo_XYToDocumentElement2(context, state, x, y, check_float, into_cells, into_ilayers, FALSE, ret_x, ret_y);
  5358. }
  5359.  
  5360. /*************************************
  5361.  * Function: LO_XYToElement
  5362.  *
  5363.  * Description: This is a public function that allows the front end
  5364.  *    to ask for the particular element residing at the passed
  5365.  *    (x, y) position in the window.  This is very important
  5366.  *    for resolving button clicks on anchors.
  5367.  *
  5368.  * Params: Window context, x, y position of the window location.
  5369.  *
  5370.  * Returns: A pointer to the element record at that location,
  5371.  *    or NULL if there is no matching element.
  5372.  *************************************/
  5373. LO_Element *
  5374. LO_XYToElement(MWContext *context, int32 x, int32 y, CL_Layer *layer)
  5375. {
  5376.     int32 doc_id;
  5377.     lo_TopState *top_state;
  5378.     lo_DocState *state;
  5379.     LO_Element *tptr = NULL;
  5380.     int32 ret_x, ret_y;
  5381.     LO_CellStruct *layer_cell;
  5382.  
  5383.     /*
  5384.      * Get the unique document ID, and retreive this
  5385.      * documents layout state.
  5386.      */
  5387.     doc_id = XP_DOCID(context);
  5388.     top_state = lo_FetchTopState(doc_id);
  5389.     if ((top_state == NULL)||(top_state->doc_state == NULL))
  5390.     {
  5391.         return(NULL);
  5392.     }
  5393.     state = top_state->doc_state;
  5394.  
  5395.     layer_cell = lo_GetCellFromLayer(context, layer);
  5396.     
  5397.     if (layer_cell != NULL) {
  5398.         tptr = lo_XYToCellElement(context,
  5399.                                   state,
  5400.                                   layer_cell,
  5401.                                   x, y, TRUE, TRUE, TRUE);
  5402.     }
  5403.     else
  5404.         tptr = lo_XYToDocumentElement(context, state, x, y, TRUE, TRUE, TRUE,
  5405.                                       &ret_x, &ret_y);
  5406.  
  5407.     if ((tptr == NULL)&&(top_state->is_grid != FALSE))
  5408.     {
  5409.         tptr = lo_XYToGridEdge(context, state, x, y);
  5410.     }
  5411.  
  5412.     /*
  5413.      * Make sure we do not return an invisible edge.
  5414.      */
  5415.     if ((tptr != NULL)&&(tptr->type == LO_EDGE)&&
  5416.         (tptr->lo_edge.visible == FALSE))
  5417.     {
  5418.         tptr = NULL;
  5419.     }
  5420.     return(tptr);
  5421. }
  5422.  
  5423. static void
  5424. lo_set_image_info(MWContext *context, int32 ele_id, int32 width, int32 height)
  5425. {
  5426.     int32 doc_id;
  5427.     lo_TopState *top_state;
  5428.     lo_DocState *main_doc_state;
  5429.     lo_DocState *state;
  5430.     LO_ImageStruct *image;
  5431.  
  5432. #ifdef EDITOR
  5433.     if ( ele_id == ED_IMAGE_LOAD_HACK_ID ){
  5434.         EDT_SetImageInfo( context, ele_id, width, height );
  5435.         return;
  5436.     }
  5437. #endif
  5438.  
  5439.  
  5440.     /*
  5441.      * Get the unique document ID, and retreive this
  5442.      * documents layout state.
  5443.      */
  5444.     doc_id = XP_DOCID(context);
  5445.     top_state = lo_FetchTopState(doc_id);
  5446.     if ((top_state == NULL)||(top_state->doc_state == NULL))
  5447.     {
  5448.         return;
  5449.     }
  5450.     main_doc_state = top_state->doc_state;
  5451.     state = lo_CurrentSubState(main_doc_state);
  5452.  
  5453.     /*
  5454.      * If the font stack has already been freed, we are too far gone
  5455.      * to deal with delayed images coming in.  Ignore them.
  5456.      */
  5457.     if (state->font_stack == NULL)
  5458.     {
  5459.         top_state->layout_blocking_element = NULL;
  5460.         return;
  5461.     }
  5462.  
  5463.     if ((top_state->layout_blocking_element != NULL)&&
  5464.         (top_state->layout_blocking_element->lo_any.ele_id == ele_id))
  5465.     {
  5466.         image = (LO_ImageStruct *)top_state->layout_blocking_element;
  5467.  
  5468.         if (image->image_attr->attrmask & LO_ATTR_BACKDROP)
  5469.         {
  5470.             return;
  5471.         }
  5472.  
  5473.         image->width = width;
  5474.         image->height = height;
  5475.         lo_FinishImage(context, state, image);
  5476.         lo_FlushBlockage(context, state, main_doc_state);
  5477.     }
  5478.     else if (top_state->tags != NULL)
  5479.     {
  5480.         PA_Tag *tag_ptr;
  5481.  
  5482.         tag_ptr = top_state->tags;
  5483.         while (tag_ptr != NULL)
  5484.         {
  5485.             if (((tag_ptr->type == P_IMAGE)||
  5486.                 (tag_ptr->type == P_NEW_IMAGE))&&
  5487.                 (tag_ptr->lo_data != NULL)&&
  5488.                 (tag_ptr->is_end == FALSE))
  5489.             {
  5490.                 image = (LO_ImageStruct *)tag_ptr->lo_data;
  5491.                 if (image->ele_id == ele_id)
  5492.                 {
  5493.                     image->width = width;
  5494.                     image->height = height;
  5495.                     break;
  5496.                 }
  5497.             }
  5498.             tag_ptr = tag_ptr->next;
  5499.         }
  5500.     }
  5501. }
  5502.  
  5503. typedef struct setImageInfoClosure_struct
  5504. {
  5505.     MWContext      *context;
  5506.     int32           ele_id;
  5507.     int32           width;
  5508.     int32           height;
  5509.     struct setImageInfoClosure_struct
  5510.                    *next;
  5511. } setImageInfoClosure;
  5512.  
  5513. static int8 deferred_list_busy = 0;
  5514. static int8 destroy_deferred_list = 0;
  5515.  
  5516. /* List of images for which image size info is available,
  5517.    but for which the layout process is deferred */                             
  5518. static setImageInfoClosure *image_info_deferred_list;
  5519. static void *deferred_image_info_timeout = NULL;
  5520.  
  5521. static void
  5522. lo_discard_unprocessed_deferred_images(MWContext *context)
  5523. {                                    
  5524.     setImageInfoClosure *c, *prev_c;
  5525.  
  5526.     prev_c = NULL;
  5527.     c = image_info_deferred_list;
  5528.     if (deferred_list_busy)
  5529.     {
  5530.         /* set a flag to cause the list to get destroyed
  5531.          * as soon as we are not reentrant
  5532.          */
  5533.         destroy_deferred_list = TRUE;
  5534.         return;
  5535.     }
  5536.     else
  5537.     {
  5538.         destroy_deferred_list = FALSE;
  5539.     }
  5540.  
  5541.     while (c) {
  5542.         if(c->context == context) {
  5543.             setImageInfoClosure *free_tmp;
  5544.  
  5545.             if(prev_c)
  5546.                 prev_c->next = c->next;
  5547.             else
  5548.                 image_info_deferred_list = c->next;
  5549.  
  5550.             free_tmp = c;
  5551.             c = c->next;
  5552.             XP_FREE(free_tmp);
  5553.         }
  5554.         else
  5555.         {
  5556.             prev_c = c;
  5557.             c = c->next;
  5558.         }
  5559.     }
  5560. }
  5561.  
  5562. /* Handle image dimension information that has been reported to
  5563.    layout since the last time we were called. */
  5564. static void
  5565. lo_process_deferred_image_info(void *closure)
  5566. {
  5567.     setImageInfoClosure *c, *next_c;
  5568.  
  5569.     /* Don't allow reentrant calls. */
  5570.     if (deferred_list_busy)
  5571.         return;
  5572.  
  5573.     deferred_list_busy = 1;
  5574.     for (c = image_info_deferred_list; c; c = next_c) {
  5575.         next_c = c->next;
  5576.         lo_set_image_info(c->context, c->ele_id, c->width, c->height);
  5577.  
  5578.         if(destroy_deferred_list)
  5579.         {
  5580.             /* discared the images for the context that just tried to
  5581.              * call lo_discard_unprocessed_deferred_images.  After
  5582.              * that continue to pump this list until empty.
  5583.              */
  5584.             image_info_deferred_list = c;
  5585.             deferred_list_busy = FALSE;
  5586.             lo_discard_unprocessed_deferred_images(image_info_deferred_list->context);
  5587.             deferred_list_busy = TRUE;
  5588.             next_c = image_info_deferred_list;
  5589.         }
  5590.         else
  5591.         {
  5592.             XP_FREE(c);
  5593.         }
  5594.     }
  5595.     deferred_list_busy = 0;
  5596.     image_info_deferred_list = NULL;
  5597.     deferred_image_info_timeout = NULL;
  5598. }
  5599.  
  5600. /* Tell layout the dimensions of an image.  Actually, to avoid subtle
  5601.    bugs involving mutual recursion between the imagelib and the
  5602.    netlib, we don't process this information immediately, but rather
  5603.    thread it on a list to be processed later. */
  5604. void
  5605. LO_SetImageInfo(MWContext *context, int32 ele_id, int32 width, int32 height)
  5606. {
  5607.     setImageInfoClosure *c = XP_NEW(setImageInfoClosure);
  5608.  
  5609.     if (! c)
  5610.         return;
  5611.     c->context  = context;
  5612.     c->ele_id   = ele_id;
  5613.     c->width    = width;
  5614.     c->height   = height;
  5615.     c->next     = image_info_deferred_list;
  5616.     image_info_deferred_list = c;
  5617.  
  5618.     if (! deferred_image_info_timeout) {
  5619.         deferred_image_info_timeout = 
  5620.             FE_SetTimeout(lo_process_deferred_image_info, NULL, 0);
  5621.     }
  5622. }
  5623.  
  5624. void
  5625. lo_DeleteDocLists(MWContext *context, lo_DocLists *doc_lists)
  5626. {
  5627.     if ( doc_lists->url_list != NULL)
  5628.     {
  5629.         int i;
  5630.         LO_AnchorData **anchor_array;
  5631.  
  5632. #ifdef XP_WIN16
  5633.         {
  5634.         XP_Block *ulist_array;
  5635.         int32 j;
  5636.         intn a_size, a_indx, a_url;
  5637.  
  5638.         a_size = SIZE_LIMIT / sizeof(XP_Block *);
  5639.         a_indx = doc_lists->url_list_len / a_size;
  5640.         a_url = doc_lists->url_list_len - (a_indx * a_size);
  5641.  
  5642.         XP_LOCK_BLOCK(ulist_array, XP_Block *, doc_lists->ulist_array);
  5643.         for (j=0; j < (doc_lists->ulist_array_size - 1); j++)
  5644.         {
  5645.             doc_lists->url_list = ulist_array[j];
  5646.             XP_LOCK_BLOCK(anchor_array, LO_AnchorData **,
  5647.                 doc_lists->url_list);
  5648.             for (i=0; i < a_size; i++)
  5649.             {
  5650.                 if (anchor_array[i] != NULL)
  5651.                 {
  5652.                     lo_DestroyAnchor(anchor_array[i]);
  5653.                 }
  5654.             }
  5655.             XP_UNLOCK_BLOCK(doc_lists->url_list);
  5656.             XP_FREE_BLOCK(doc_lists->url_list);
  5657.         }
  5658.         doc_lists->url_list = ulist_array[doc_lists->ulist_array_size - 1];
  5659.         XP_LOCK_BLOCK(anchor_array, LO_AnchorData **,
  5660.             doc_lists->url_list);
  5661.         for (i=0; i < a_url; i++)
  5662.         {
  5663.             if (anchor_array[i] != NULL)
  5664.             {
  5665.                 lo_DestroyAnchor(anchor_array[i]);
  5666.             }
  5667.         }
  5668.         XP_UNLOCK_BLOCK(doc_lists->url_list);
  5669.         XP_FREE_BLOCK(doc_lists->url_list);
  5670.  
  5671.         XP_UNLOCK_BLOCK(doc_lists->ulist_array);
  5672.         XP_FREE_BLOCK(doc_lists->ulist_array);
  5673.         }
  5674. #else
  5675.         XP_LOCK_BLOCK(anchor_array, LO_AnchorData **,
  5676.             doc_lists->url_list);
  5677.         for (i=0; i < doc_lists->url_list_len; i++)
  5678.         {
  5679.             if (anchor_array[i] != NULL)
  5680.             {
  5681.                 lo_DestroyAnchor(anchor_array[i]);
  5682.             }
  5683.         }
  5684.         XP_UNLOCK_BLOCK(doc_lists->url_list);
  5685.         XP_FREE_BLOCK(doc_lists->url_list);
  5686. #endif /* XP_WIN16 */
  5687.         doc_lists->url_list = NULL;
  5688.         doc_lists->url_list_len = 0;
  5689.     }
  5690.  
  5691.     if (doc_lists->name_list != NULL)
  5692.     {
  5693.         lo_NameList *nptr;
  5694.  
  5695.         nptr = doc_lists->name_list;
  5696.         while (nptr != NULL)
  5697.         {
  5698.             lo_NameList *name_rec;
  5699.  
  5700.             name_rec = nptr;
  5701.             nptr = nptr->next;
  5702.             if (name_rec->name != NULL)
  5703.             {
  5704.                 PA_FREE(name_rec->name);
  5705.             }
  5706.             XP_DELETE(name_rec);
  5707.         }
  5708.         doc_lists->name_list = NULL;
  5709.         doc_lists->anchor_count = 0;
  5710.     }
  5711.  
  5712.     if ( doc_lists->form_list != NULL)
  5713.     {
  5714.         lo_FormData *fptr;
  5715.  
  5716.         fptr = doc_lists->form_list;
  5717.         while (fptr != NULL)
  5718.         {
  5719.             lo_FormData *form;
  5720.  
  5721.             form = fptr;
  5722.             fptr = fptr->next;
  5723.             if (form->name != NULL)
  5724.             {
  5725.                 PA_FREE(form->name);
  5726.             }
  5727.             if (form->action != NULL)
  5728.             {
  5729.                 PA_FREE(form->action);
  5730.             }
  5731.             if (form->form_elements != NULL)
  5732.             {
  5733.                 PA_FREE(form->form_elements);
  5734.             }
  5735.             XP_DELETE(form);
  5736.         }
  5737.         doc_lists->form_list = NULL;
  5738.         doc_lists->current_form_num = 0;
  5739.     }
  5740.  
  5741.     doc_lists->embed_list = NULL;
  5742.     doc_lists->embed_list_count = 0;
  5743.     doc_lists->applet_list = NULL;
  5744.     doc_lists->applet_list_count = 0;
  5745.     doc_lists->image_list = doc_lists->last_image = NULL;
  5746.     doc_lists->image_list_count = 0;
  5747. }
  5748.  
  5749. /* XXX need to pass resize_reload through FE_FreeGridWindow */
  5750. static pa_DocData *lo_internal_doc_data;
  5751.  
  5752. LO_Element *
  5753. lo_InternalDiscardDocument(MWContext *context, lo_DocState *state,
  5754.                            pa_DocData *doc_data, Bool bWholeDoc)
  5755. {
  5756.     int32 doc_id;
  5757.     LO_Element *recycle_list;
  5758.     LO_Element **line_array;
  5759.     LO_TextAttr **text_attr_hash;
  5760.  
  5761.     /* Look in doc_data->url_struct for the *new* document's reload flag. */
  5762.     JSBool resize_reload = 
  5763.         (JSBool)(doc_data != NULL && doc_data->url_struct->resize_reload);
  5764.  
  5765.     /* XXX We're not getting rid of stuff on the deferred image list when
  5766.      * the editor does a relayout. The problem is that there might still be
  5767.      * entries on the list that corresponds to the old state of the document.
  5768.      */
  5769.     if (bWholeDoc)
  5770.         lo_discard_unprocessed_deferred_images(context);
  5771.  
  5772.     /*
  5773.      * Order is crucial here: run the onunload handlers in a frames tree
  5774.      * from the top down, but destroy frames bottom-up.  Look for the
  5775.      * LM_ReleaseDocument call below, almost at the end of this function.
  5776.      * This way, onunload handlers get to use their kids' properties, and
  5777.      * kids get to use their parent's properties and functions.
  5778.      */
  5779.     if (bWholeDoc)
  5780.     {
  5781.         pa_DocData *old_doc_data;
  5782.         
  5783.         old_doc_data = state->top_state->doc_data;
  5784.         if (old_doc_data != NULL)
  5785.         {
  5786.             NET_StreamClass *parser_stream;
  5787.             parser_stream = old_doc_data->parser_stream;
  5788.             parser_stream->abort(parser_stream, 0);
  5789.             state->top_state->doc_data = NULL;
  5790.         }
  5791.     }
  5792.  
  5793.     if ( state->top_state->trash != NULL)
  5794.     {
  5795.         lo_RecycleElements(context, state,
  5796.             state->top_state->trash);
  5797.         state->top_state->trash = NULL;
  5798.     }
  5799.  
  5800.     if (state->float_list != NULL)
  5801.     {
  5802.         lo_RecycleElements(context, state, state->float_list);
  5803.         state->float_list = NULL;
  5804.     }
  5805.  
  5806.     if (state->line_array != NULL)
  5807.     {
  5808.         LO_Element *eptr;
  5809.         LO_Element **line_array_tmp;
  5810.  
  5811. #ifdef XP_WIN16
  5812.         {
  5813.             XP_Block *larray_array;
  5814.             intn cnt;
  5815.  
  5816.             XP_LOCK_BLOCK(larray_array, XP_Block *,
  5817.                     state->larray_array);
  5818.             cnt = state->larray_array_size - 1;
  5819.             while (cnt > 0)
  5820.             {
  5821.                 XP_FREE_BLOCK(larray_array[cnt]);
  5822.                 cnt--;
  5823.             }
  5824.             state->line_array = larray_array[0];
  5825.             XP_UNLOCK_BLOCK(state->larray_array);
  5826.             XP_FREE_BLOCK(state->larray_array);
  5827.         }
  5828. #endif /* XP_WIN16 */
  5829.  
  5830.         eptr = NULL;
  5831.         XP_LOCK_BLOCK(line_array, LO_Element **, state->line_array);
  5832.         eptr = line_array[0];
  5833.         line_array_tmp = (LO_Element **)state->line_array;
  5834.         state->line_array = NULL;
  5835.  
  5836.         /* If this is a relayout delete, the elements are already owned by the document. So
  5837.          * don't recycle them.
  5838.          */
  5839.         if ( bWholeDoc && eptr != NULL)
  5840.         {
  5841.             lo_RecycleElements(context, state, eptr);
  5842.         }
  5843.         XP_UNLOCK_BLOCK(line_array_tmp);
  5844.         XP_FREE_BLOCK(line_array_tmp);
  5845.     }
  5846.  
  5847.     if ( bWholeDoc && state->top_state->text_attr_hash != NULL)
  5848.     {
  5849.         LO_TextAttr *attr;
  5850.         LO_TextAttr *attr_ptr;
  5851.         int i;
  5852.  
  5853.         XP_LOCK_BLOCK(text_attr_hash, LO_TextAttr **,
  5854.             state->top_state->text_attr_hash);
  5855.         for (i=0; i<FONT_HASH_SIZE; i++)
  5856.         {
  5857.             attr_ptr = text_attr_hash[i];
  5858.             while (attr_ptr != NULL)
  5859.             {
  5860.                 attr = attr_ptr;
  5861.                 if (attr->FE_Data != NULL)
  5862.                 {
  5863.                     FE_ReleaseTextAttrFeData(context, attr);
  5864.                     attr->FE_Data = NULL;
  5865.                 }
  5866.                 attr_ptr = attr_ptr->next;
  5867.                 XP_DELETE(attr);
  5868.             }
  5869.             text_attr_hash[i] = NULL;
  5870.         }
  5871.         XP_UNLOCK_BLOCK(state->top_state->text_attr_hash);
  5872.         XP_FREE_BLOCK(state->top_state->text_attr_hash);
  5873.         state->top_state->text_attr_hash = NULL;
  5874.     }
  5875.  
  5876.     if ( bWholeDoc && state->top_state->font_face_array != NULL)
  5877.     {
  5878.         int i;
  5879.         char **face_list;
  5880.  
  5881.         PA_LOCK(face_list, char **, state->top_state->font_face_array);
  5882.         for (i=0; i < state->top_state->font_face_array_len; i++)
  5883.         {
  5884.             XP_FREE(face_list[i]);
  5885.         }
  5886.         PA_UNLOCK(state->top_state->font_face_array);
  5887.         PA_FREE(state->top_state->font_face_array);
  5888.         state->top_state->font_face_array = NULL;
  5889.         state->top_state->font_face_array_len = 0;
  5890.         state->top_state->font_face_array_size = 0;
  5891.     }
  5892.  
  5893.     if ( bWholeDoc && state->top_state->map_list != NULL)
  5894.     {
  5895.         lo_MapRec *map_list;
  5896.  
  5897.         map_list = state->top_state->map_list;
  5898.         while (map_list != NULL)
  5899.         {
  5900.             map_list = lo_FreeMap(map_list);
  5901.         }
  5902.         state->top_state->map_list = NULL;
  5903.     }
  5904.  
  5905.     if (bWholeDoc)
  5906.         lo_DeleteDocLists(context, &state->top_state->doc_lists);
  5907.     else if (state->top_state->doc_lists.name_list != NULL)
  5908.     {
  5909.         lo_NameList *nptr;
  5910.  
  5911.         nptr = state->top_state->doc_lists.name_list;
  5912.         while (nptr != NULL)
  5913.         {
  5914.             lo_NameList *name_rec;
  5915.  
  5916.             name_rec = nptr;
  5917.             nptr = nptr->next;
  5918.             if (name_rec->name != NULL)
  5919.             {
  5920.                 PA_FREE(name_rec->name);
  5921.             }
  5922.             XP_DELETE(name_rec);
  5923.         }
  5924.         state->top_state->doc_lists.name_list = NULL;
  5925.     }
  5926.  
  5927.     if ( bWholeDoc && state->top_state->the_grid != NULL)
  5928.     {
  5929.         pa_DocData *save;
  5930.         lo_GridRec *grid;
  5931.         lo_GridCellRec *cell_ptr;
  5932.         Bool incomplete;
  5933.  
  5934.         save = lo_internal_doc_data;
  5935.         lo_internal_doc_data = doc_data;
  5936.         grid = state->top_state->the_grid;
  5937.         cell_ptr = grid->cell_list;
  5938.         /*
  5939.          * If this grid document finished loading, save
  5940.          * its grid data to be restored when we return through
  5941.          * history.
  5942.          * We still have to free the FE grid windows.
  5943.          */
  5944.         incomplete = (state->top_state->layout_status != PA_COMPLETE);
  5945.         if (incomplete == FALSE)
  5946.         {
  5947.             while (cell_ptr != NULL)
  5948.             {
  5949.                 intn cell_status;
  5950.                 char *old_url;
  5951.  
  5952.                 cell_status =
  5953.                     lo_GetCurrentGridCellStatus(cell_ptr);
  5954.  
  5955.                 /*
  5956.                  * Only save cell history for COMPLETE cells.
  5957.                  */
  5958.                 if (cell_status == PA_COMPLETE)
  5959.                 {
  5960.                     /*
  5961.                      * free the original url for this cell.
  5962.                      */
  5963.                     old_url = cell_ptr->url;
  5964.                     if (cell_ptr->url != NULL)
  5965.                     {
  5966.                         XP_FREE(cell_ptr->url);
  5967.                     }
  5968.  
  5969.                     /*
  5970.                      * Fetch the url for the current contents
  5971.                      * of the cell, and save that.
  5972.                      */
  5973.                     cell_ptr->url =
  5974.                     lo_GetCurrentGridCellUrl(cell_ptr);
  5975.  
  5976.                     cell_ptr->hist_list = NULL;
  5977.                     if (cell_ptr->context != NULL)
  5978.                     {
  5979.                     cell_ptr->hist_list = FE_FreeGridWindow(
  5980.                         cell_ptr->context, TRUE);
  5981.                     }
  5982.                 }
  5983.                 else
  5984.                 {
  5985.                     incomplete = TRUE;
  5986.                     cell_ptr->hist_list = NULL;
  5987.                     if (cell_ptr->context != NULL)
  5988.                     {
  5989.                     (void)FE_FreeGridWindow(
  5990.                         cell_ptr->context, FALSE);
  5991.                     }
  5992.                 }
  5993.                 cell_ptr->context = NULL;
  5994.  
  5995.                 cell_ptr = cell_ptr->next;
  5996.             }
  5997.         }
  5998.         /*
  5999.          * Check again in case one or more frames were incomplete.
  6000.          * Also, some special windows have no history (such as
  6001.          * the document info window).  We can't save grid
  6002.          * data for those windows and should free it instead.
  6003.          */
  6004.         if ((incomplete == FALSE)&&
  6005.             (state->top_state->savedData.Grid != NULL))
  6006.         {
  6007.             state->top_state->savedData.Grid->the_grid =
  6008.                 state->top_state->the_grid;
  6009.             state->top_state->savedData.Grid->main_width =
  6010.                 grid->main_width;
  6011.             state->top_state->savedData.Grid->main_height =
  6012.                 grid->main_height;
  6013.         }
  6014.         /*
  6015.          * Else free up everything now.
  6016.          */
  6017.         else
  6018.         {
  6019.             cell_ptr = grid->cell_list;
  6020.             /*
  6021.              * It is important to NULL out the cell_list
  6022.              * now because FE_FreeGridWindow() could lead to
  6023.              * somone trying to traverse it while we are in
  6024.              * the middle of deleting it.
  6025.              */
  6026.             grid->cell_list = NULL;
  6027.             while (cell_ptr != NULL)
  6028.             {
  6029.                 lo_GridCellRec *tmp_cell;
  6030.  
  6031.                 if (cell_ptr->context != NULL)
  6032.                 {
  6033.                     /*
  6034.                      * The context still owns its history
  6035.                      * list, so null the cell's pointer to
  6036.                      * be clear.  If this cell doesn't have
  6037.                      * a context, then it owns the history
  6038.                      * list and lo_FreeGridCellRec() will
  6039.                      * free it.
  6040.                      */
  6041.                     cell_ptr->hist_list = NULL;
  6042.                     (void)FE_FreeGridWindow(
  6043.                         cell_ptr->context, FALSE);
  6044.                 }
  6045.                 tmp_cell = cell_ptr;
  6046.                 cell_ptr = cell_ptr->next;
  6047.                 lo_FreeGridCellRec(context, grid, tmp_cell);
  6048.             }
  6049.             lo_FreeGridRec(grid);
  6050.         }
  6051.         state->top_state->the_grid = NULL;
  6052.         lo_internal_doc_data = save;
  6053.     }
  6054.  
  6055.     if ( bWholeDoc && state->top_state->url != NULL)
  6056.     {
  6057.         XP_FREE(state->top_state->url);
  6058.         state->top_state->url = NULL;
  6059.     }
  6060.  
  6061.     if ( bWholeDoc )
  6062.     {
  6063.         XP_FREEIF(state->top_state->inline_stream_blocked_base_url);
  6064.         XP_FREEIF(state->top_state->main_stream_blocked_base_url);
  6065.         XP_FREEIF(state->top_state->base_url);
  6066.     }
  6067.  
  6068.     if ( bWholeDoc && state->top_state->base_target != NULL)
  6069.     {
  6070.         XP_FREE(state->top_state->base_target);
  6071.         state->top_state->base_target = NULL;
  6072.     }
  6073.  
  6074.     if ( bWholeDoc && state->top_state->name_target != NULL)
  6075.     {
  6076.         XP_FREE(state->top_state->name_target);
  6077.         state->top_state->name_target = NULL;
  6078.     }
  6079.  
  6080. #ifdef HTML_CERTIFICATE_SUPPORT
  6081.     if ( bWholeDoc && state->top_state->cert_list != NULL)
  6082.     {
  6083.         lo_Certificate *cptr;
  6084.  
  6085.         cptr = state->top_state->cert_list;
  6086.         while (cptr != NULL)
  6087.         {
  6088.             lo_Certificate *lo_cert;
  6089.  
  6090.             lo_cert = cptr;
  6091.             cptr = cptr->next;
  6092.             if (lo_cert->name != NULL)
  6093.             {
  6094.                 PA_FREE(lo_cert->name);
  6095.             }
  6096.             if (lo_cert->cert != NULL)
  6097.             {
  6098.                 CERT_DestroyCertificate(lo_cert->cert);
  6099.             }
  6100.             XP_DELETE(lo_cert);
  6101.         }
  6102.         state->top_state->cert_list = NULL;
  6103.     }
  6104. #endif /* HTML_CERTIFICATE_SUPPORT */
  6105.  
  6106.     if (bWholeDoc && state->top_state->unknown_head_tag != NULL)
  6107.     {
  6108.         XP_FREE(state->top_state->unknown_head_tag);
  6109.         state->top_state->unknown_head_tag = NULL;
  6110.     }
  6111.  
  6112.     if(resize_reload)
  6113.     {
  6114.         /* LJM: Save the JSS state in the hist so that we can get it
  6115.           * once the resize is complete
  6116.          */
  6117.         History_entry *he = SHIST_GetCurrent(&context->hist);
  6118.         if (he)
  6119.         {
  6120.             he->savedData.style_stack = state->top_state->style_stack;
  6121.             state->top_state->style_stack = 0;
  6122.         }
  6123.         else
  6124.         {
  6125.             if (state->top_state->style_stack != 0)
  6126.                 STYLESTACK_Delete(state->top_state->style_stack);
  6127.             state->top_state->style_stack = 0;
  6128.         }
  6129.     }
  6130.     else
  6131.     {
  6132.         if (state->top_state->style_stack != 0)
  6133.             STYLESTACK_Delete(state->top_state->style_stack);
  6134.         state->top_state->style_stack = 0;
  6135.     }
  6136.  
  6137.     /* XXX all this because grid docs are never re-parsed after first load. */
  6138.     if (!resize_reload &&
  6139.         ((state->top_state->savedData.OnLoad != NULL)||
  6140.          (state->top_state->savedData.OnUnload != NULL)||
  6141.          (state->top_state->savedData.OnFocus != NULL)||
  6142.          (state->top_state->savedData.OnBlur != NULL)||
  6143.          (state->top_state->savedData.OnHelp != NULL)||
  6144.          (state->top_state->savedData.OnMouseOver != NULL)||
  6145.          (state->top_state->savedData.OnMouseOut != NULL)||
  6146.          (state->top_state->savedData.OnDragDrop != NULL)||
  6147.          (state->top_state->savedData.OnMove != NULL)||
  6148.          (state->top_state->savedData.OnResize != NULL)))
  6149.     {
  6150.         History_entry *he = SHIST_GetCurrent(&context->hist);
  6151.         if (he)
  6152.         {
  6153.             he->savedData.OnLoad = state->top_state->savedData.OnLoad;
  6154.             he->savedData.OnUnload = state->top_state->savedData.OnUnload;
  6155.             he->savedData.OnFocus = state->top_state->savedData.OnFocus;
  6156.             he->savedData.OnBlur = state->top_state->savedData.OnBlur;
  6157.              he->savedData.OnHelp = state->top_state->savedData.OnHelp;
  6158.              he->savedData.OnMouseOver = state->top_state->savedData.OnMouseOver;
  6159.              he->savedData.OnMouseOut = state->top_state->savedData.OnMouseOut;
  6160.              he->savedData.OnDragDrop = state->top_state->savedData.OnDragDrop;
  6161.              he->savedData.OnMove = state->top_state->savedData.OnMove;
  6162.              he->savedData.OnResize = state->top_state->savedData.OnResize;
  6163.         }
  6164.         else
  6165.         {
  6166.             if (state->top_state->savedData.OnLoad != NULL)
  6167.                 PA_FREE(state->top_state->savedData.OnLoad);
  6168.             if (state->top_state->savedData.OnUnload != NULL)
  6169.                 PA_FREE(state->top_state->savedData.OnUnload);
  6170.             if (state->top_state->savedData.OnFocus != NULL)
  6171.                 PA_FREE(state->top_state->savedData.OnFocus);
  6172.             if (state->top_state->savedData.OnBlur != NULL)
  6173.                 PA_FREE(state->top_state->savedData.OnBlur);
  6174.             if (state->top_state->savedData.OnHelp != NULL)
  6175.                 PA_FREE(state->top_state->savedData.OnHelp);
  6176.             if (state->top_state->savedData.OnMouseOver != NULL)
  6177.                 PA_FREE(state->top_state->savedData.OnMouseOver);
  6178.             if (state->top_state->savedData.OnMouseOut != NULL)
  6179.                 PA_FREE(state->top_state->savedData.OnMouseOut);
  6180.             if (state->top_state->savedData.OnDragDrop != NULL)
  6181.                 PA_FREE(state->top_state->savedData.OnDragDrop);
  6182.             if (state->top_state->savedData.OnMove != NULL)
  6183.                 PA_FREE(state->top_state->savedData.OnMove);
  6184.             if (state->top_state->savedData.OnResize != NULL)
  6185.                 PA_FREE(state->top_state->savedData.OnResize);
  6186.         }
  6187.         state->top_state->savedData.OnLoad = NULL;
  6188.         state->top_state->savedData.OnUnload = NULL;
  6189.         state->top_state->savedData.OnFocus = NULL;
  6190.         state->top_state->savedData.OnBlur = NULL;
  6191.         state->top_state->savedData.OnHelp = NULL;
  6192.         state->top_state->savedData.OnMouseOver = NULL;
  6193.         state->top_state->savedData.OnMouseOut = NULL;
  6194.         state->top_state->savedData.OnDragDrop = NULL;
  6195.         state->top_state->savedData.OnMove = NULL;
  6196.         state->top_state->savedData.OnResize = NULL;
  6197.     }
  6198.  
  6199.  
  6200.     if ( bWholeDoc )
  6201.     {
  6202. #ifdef WEBFONTS
  6203.         /* Release webfonts loaded by this document */
  6204.         if (WF_fbu && !resize_reload)
  6205.         {
  6206.             nffbu_ReleaseWebfonts(WF_fbu, context, NULL);
  6207.         }
  6208. #endif /* WEBFONTS */
  6209.  
  6210.         recycle_list = state->top_state->recycle_list;
  6211.  
  6212.         /* Some lo_ImageStructs may have been reclaimed by the Memory Arenas
  6213.            code without actually calling IL_DestroyImage first.  This call
  6214.            frees up any remaining image lib requests. */
  6215.         IL_DestroyImageGroup(context->img_cx);
  6216.  
  6217.         lo_DestroyBlinkers(context);
  6218.         if (state->top_state->layers) 
  6219.         {
  6220.             int i;
  6221.             lo_TopState *top_state = state->top_state;
  6222.  
  6223.             /* If we're resizing, prevent the GC'ing of the JS object
  6224.              * associated with this layer when the layer destructor is
  6225.              * called, since we want to preserve it across a resize,
  6226.              * except for those layers created with JS's new operator,
  6227.              * which aren't preserved across resize.  */
  6228.             if (resize_reload)
  6229.             {
  6230.                 for (i = 1; i <= state->top_state->max_layer_num; i++)
  6231.                 {
  6232.                     lo_LayerDocState *layer_state = state->top_state->layers[i];
  6233.                     if (!layer_state || layer_state->is_constructed_layer)
  6234.                         continue;
  6235.                 
  6236.                     layer_state->mocha_object = NULL;
  6237.                     state->top_state->layers[i] = NULL;
  6238.                 }
  6239.             }
  6240.  
  6241.             /* Delete the main document layer_state */
  6242.             top_state->layers[0]->layer = NULL;
  6243.             lo_DeleteLayerState(context, state, top_state->layers[0]);
  6244.             
  6245.             top_state->num_layers_allocated = 0;
  6246.             top_state->max_layer_num = 0;
  6247.  
  6248.             lo_DeleteLayerStack(state);
  6249.         }
  6250.  
  6251.         if (context->compositor){
  6252.             lo_DestroyLayers(context);
  6253.  
  6254.             /* Reset the compositor to do on-screen compositing by default. */
  6255.             CL_SetCompositorOffscreenDrawing(context->compositor,
  6256.                                              CL_OFFSCREEN_AUTO);
  6257.             CL_SetCompositorEnabled(context->compositor, PR_FALSE);
  6258.         }
  6259.         XP_FREEIF(state->top_state->layers);
  6260.     }
  6261.  
  6262.     if ( bWholeDoc ) {
  6263.         /* throw out mocha cruft */
  6264.         ET_ReleaseDocument(context, resize_reload);
  6265.  
  6266.         XP_DELETE(state->top_state);
  6267.         XP_DELETE(state);
  6268.         /*
  6269.          * Get the unique document ID, and remove this
  6270.          * documents layout state.
  6271.          */
  6272.         doc_id = XP_DOCID(context);
  6273.         lo_RemoveTopState(doc_id);
  6274.  
  6275.     }
  6276.     else
  6277.     {
  6278.         XP_DELETE(state);
  6279.         recycle_list = NULL;
  6280.     }
  6281.     return(recycle_list);
  6282. }
  6283.  
  6284.  
  6285. void
  6286. LO_DiscardDocument(MWContext *context)
  6287. {
  6288.     int32 doc_id;
  6289.     lo_TopState *top_state;
  6290.     lo_DocState *state;
  6291.     LO_Element *recycle_list;
  6292.     int32 cnt;
  6293. #ifdef MEMORY_ARENAS
  6294.     lo_arena *old_arena;
  6295. #endif /* MEMORY_ARENAS */
  6296.  
  6297.     /*
  6298.      * Get the unique document ID, and retreive this
  6299.      * documents layout state.
  6300.      */
  6301.     doc_id = XP_DOCID(context);
  6302.     top_state = lo_FetchTopState(doc_id);
  6303.     if ((top_state == NULL)||(top_state->doc_state == NULL))
  6304.     {
  6305.         return;
  6306.     }
  6307.     state = top_state->doc_state;
  6308.     
  6309. #ifdef MEMORY_ARENAS
  6310.     if ( ! EDT_IS_EDITOR(context) ) {
  6311.         old_arena = top_state->first_arena;
  6312.     }
  6313. #endif /* MEMORY_ARENAS */
  6314.  
  6315.     /*
  6316.      * Order is crucial here: run the onunload handlers in a frames tree
  6317.      * from the top down, but destroy frames bottom-up.  Look for the
  6318.      * LM_ReleaseDocument call below, almost at the end of this function.
  6319.      * This way, onunload handlers get to use their kids' properties, and
  6320.      * kids get to use their parent's properties and functions.
  6321.      */
  6322.     ET_SendLoadEvent(context, EVENT_UNLOAD, NULL, NULL,
  6323.              LO_DOCUMENT_LAYER_ID, FALSE);
  6324.  
  6325.     /* make sure no other threads are looking at our structures */
  6326.     LO_LockLayout();
  6327.  
  6328.     lo_SaveFormElementState(context, state, TRUE);
  6329.     /*
  6330.      * If this document has no session history
  6331.      * this data is not saved.
  6332.      * It will be freed by history cleanup.
  6333.      */
  6334.     if (SHIST_GetCurrent(&context->hist) == NULL)
  6335.     {
  6336.         top_state->savedData.FormList = NULL;
  6337.         top_state->savedData.EmbedList = NULL;
  6338.         top_state->savedData.Grid = NULL;
  6339.     }
  6340.     recycle_list =
  6341.         lo_InternalDiscardDocument(context, state, lo_internal_doc_data, TRUE);
  6342.     /* see first lo_FreeRecycleList comment. safe */
  6343.     cnt = lo_FreeRecycleList(context, recycle_list);
  6344. #ifdef MEMORY_ARENAS
  6345.     if ( ! EDT_IS_EDITOR(context) ) {
  6346.         cnt = lo_FreeMemoryArena(old_arena);
  6347.     }
  6348. #endif /* MEMORY_ARENAS */
  6349.  
  6350.     /* we currently have no document loaded */
  6351.     context->doc_id = 0;
  6352.  
  6353.     /* the danger has passed.  let others look up our shorts again */
  6354.     LO_UnlockLayout();
  6355.  
  6356. }
  6357.  
  6358.  
  6359. lo_SavedFormListData *
  6360. lo_NewDocumentFormListData(void)
  6361. {
  6362.     lo_SavedFormListData *fptr;
  6363.  
  6364.     fptr = XP_NEW(lo_SavedFormListData);
  6365.     if (fptr == NULL)
  6366.     {
  6367.         return(NULL);
  6368.     }
  6369.  
  6370.     fptr->valid = FALSE;
  6371.     fptr->data_index = 0;
  6372.     fptr->data_count = 0;
  6373.     fptr->data_list = NULL;
  6374.     fptr->next = NULL;
  6375.  
  6376.     return(fptr);
  6377. }
  6378.  
  6379.  
  6380. void
  6381. LO_FreeDocumentFormListData(MWContext *context, void *data)
  6382. {
  6383.     lo_SavedFormListData *forms = (lo_SavedFormListData *)data;
  6384.  
  6385.     if (forms != NULL)
  6386.     {
  6387.         lo_FreeDocumentFormListData(context, forms);
  6388.         XP_DELETE(forms);
  6389.     }
  6390. }
  6391.  
  6392.  
  6393. lo_SavedGridData *
  6394. lo_NewDocumentGridData(void)
  6395. {
  6396.     lo_SavedGridData *sgptr;
  6397.  
  6398.     sgptr = XP_NEW(lo_SavedGridData);
  6399.     if (sgptr == NULL)
  6400.     {
  6401.         return(NULL);
  6402.     }
  6403.  
  6404.     sgptr->main_width = 0;
  6405.     sgptr->main_height = 0;
  6406.     sgptr->the_grid = NULL;
  6407.  
  6408.     return(sgptr);
  6409. }
  6410.  
  6411.  
  6412. void
  6413. LO_FreeDocumentGridData(MWContext *context, void *data)
  6414. {
  6415.     lo_SavedGridData *sgptr = (lo_SavedGridData *)data;
  6416.  
  6417.     if (sgptr != NULL)
  6418.     {
  6419.         lo_FreeDocumentGridData(context, sgptr);
  6420.         XP_DELETE(sgptr);
  6421.     }
  6422. }
  6423.  
  6424.  
  6425. lo_SavedEmbedListData *
  6426. lo_NewDocumentEmbedListData(void)
  6427. {
  6428.     lo_SavedEmbedListData *eptr;
  6429.  
  6430.     eptr = XP_NEW(lo_SavedEmbedListData);
  6431.     if (eptr == NULL)
  6432.     {
  6433.         return(NULL);
  6434.     }
  6435.  
  6436.     eptr->embed_count = 0;
  6437.     eptr->embed_data_list = NULL;
  6438.  
  6439.     return(eptr);
  6440. }
  6441.  
  6442.  
  6443. void
  6444. LO_FreeDocumentEmbedListData(MWContext *context, void *data)
  6445. {
  6446.     lo_SavedEmbedListData *eptr = (lo_SavedEmbedListData *)data;
  6447.  
  6448.     if (eptr != NULL)
  6449.     {
  6450.         lo_FreeDocumentEmbedListData(context, eptr);
  6451.         XP_DELETE(eptr);
  6452.     }
  6453. }
  6454.  
  6455. void
  6456. LO_HighlightAnchor(MWContext *context, LO_Element *element, Bool on)
  6457. {
  6458.     int32 doc_id;
  6459.     lo_TopState *top_state;
  6460.     lo_DocState *state;
  6461.     LO_Element *start, *end;
  6462.     LO_AnchorData *anchor;
  6463.  
  6464.     /*
  6465.      * Get the unique document ID, and retrieve this
  6466.      * documents layout state.
  6467.      */
  6468.     doc_id = XP_DOCID(context);
  6469.     top_state = lo_FetchTopState(doc_id);
  6470.     if ((top_state == NULL)||(top_state->doc_state == NULL))
  6471.     {
  6472.         return;
  6473.     }
  6474.     state = top_state->doc_state;
  6475.  
  6476.     if (element == NULL)
  6477.         return;
  6478.  
  6479.     anchor = lo_GetElementAnchor(element);
  6480.     if (anchor == NULL)
  6481.         return;
  6482.  
  6483.     /* Find all the preceding layout elements that share the same anchor. */
  6484.     start = element;
  6485.     while (start->lo_any.prev)
  6486.     {
  6487.         LO_AnchorData *anchor2 = lo_GetElementAnchor(start->lo_any.prev);
  6488.         if (anchor != anchor2)
  6489.             break;
  6490.         start = start->lo_any.prev;
  6491.     }
  6492.  
  6493.     /* Find all the following layout elements that share the same anchor. */
  6494.     end = element;
  6495.     while (end->lo_any.next)
  6496.     {
  6497.         LO_AnchorData *anchor2 = lo_GetElementAnchor(end->lo_any.next);
  6498.         if (anchor != anchor2)
  6499.             break;
  6500.         end = end->lo_any.next;
  6501.     }
  6502.  
  6503.     end = end->lo_any.next;
  6504.     element = start;
  6505.     while (element != end)
  6506.     {
  6507.         Bool restoreUnselected;
  6508.         LO_Color save_fg;
  6509.  
  6510.         element->lo_any.x += state->base_x;
  6511.         element->lo_any.y += state->base_y;
  6512.  
  6513.         restoreUnselected = FALSE;
  6514.         switch (element->type)
  6515.         {
  6516.         case LO_IMAGE:
  6517.             /* Save image selection state */
  6518.             if (! (element->lo_image.ele_attrmask & LO_ELE_SELECTED))
  6519.                 restoreUnselected = TRUE;
  6520.             
  6521.             /* Force display of selection rectangle. */
  6522.             element->lo_image.ele_attrmask = LO_ELE_SELECTED;
  6523.  
  6524.             /* Fall through ... */
  6525.  
  6526.         case LO_TEXT:
  6527.         case LO_SUBDOC:
  6528.  
  6529.             /* Temporarily set element color to selection color. */
  6530.             if (on) {
  6531.                 lo_GetElementFGColor(element, &save_fg);
  6532.                 lo_SetElementFGColor(element, &state->active_anchor_color);
  6533.             }
  6534.  
  6535.             /* Use the compositor to synchronously update the element's area. */
  6536.             lo_RefreshElement(element, anchor->layer, TRUE);
  6537.  
  6538.             /* Restore the element's color. */
  6539.             if (on)
  6540.                 lo_SetElementFGColor(element, &save_fg);
  6541.  
  6542.             /* Restore image selection state */
  6543.             if (restoreUnselected)
  6544.                 element->lo_image.ele_attrmask &= ~(LO_ELE_SELECTED);
  6545.  
  6546.         default:
  6547.             /* No highlighting for other types of elements */
  6548.             break;
  6549.         }
  6550.  
  6551.         element->lo_any.x -= state->base_x;
  6552.         element->lo_any.y -= state->base_y;
  6553.  
  6554.         element = element->lo_any.next;
  6555.     }
  6556. }
  6557.  
  6558. LO_Element *
  6559. LO_XYToNearestElement(MWContext *context, int32 x, int32 y, CL_Layer *layer)
  6560. {
  6561.     int32 doc_id;
  6562.     lo_TopState *top_state;
  6563.     lo_DocState *state;
  6564.     LO_Element *eptr;
  6565.     LO_Element **line_array;
  6566.     int32 ret_x, ret_y;
  6567.     LO_CellStruct *layer_cell;
  6568.  
  6569.     /*
  6570.      * Get the unique document ID, and retreive this
  6571.      * documents layout state.
  6572.      */
  6573.     doc_id = XP_DOCID(context);
  6574.     top_state = lo_FetchTopState(doc_id);
  6575.     if ((top_state == NULL)||(top_state->doc_state == NULL))
  6576.     {
  6577.         return(NULL);
  6578.     }
  6579.     state = top_state->doc_state;
  6580.  
  6581.     layer_cell = lo_GetCellFromLayer(context, layer);
  6582.     if (layer_cell != NULL)
  6583.     {
  6584.         int32 new_x, new_y;
  6585.  
  6586.         new_y = y;
  6587.         if (new_y > layer_cell->height)
  6588.             new_y = layer_cell->height - 1;
  6589.         if (new_y < 0)
  6590.             new_y = 0;
  6591.         
  6592.         new_x = x;
  6593.         if (new_x > layer_cell->width)
  6594.             new_x = layer_cell->width - 1;
  6595.         if (new_x < 0)
  6596.             new_x = 0;
  6597.         eptr = lo_XYToNearestCellElement(context, 
  6598.                                          state,
  6599.                                          layer_cell, new_x, new_y);
  6600.         return eptr;
  6601.     }
  6602.  
  6603.     if (x <= state->win_left)
  6604.     {
  6605.         x = state->win_left + 1;
  6606.     }
  6607.  
  6608.     if (y < state->win_top)
  6609.     {
  6610.         y = state->win_top + 1;
  6611.     }
  6612.  
  6613.     eptr = lo_XYToDocumentElement(context, state, x, y, TRUE, TRUE, TRUE,
  6614.         &ret_x, &ret_y);
  6615.  
  6616.     if (eptr == NULL)
  6617.     {
  6618.         int32 top, bottom;
  6619.  
  6620.         /*    
  6621.          * Find the nearest line.
  6622.          */
  6623.         lo_RegionToLines (context, state, x, y, 1, 1, FALSE,
  6624.             &top, &bottom);
  6625.  
  6626.         if (top >= 0)
  6627. #ifdef XP_WIN16
  6628.         {
  6629.             intn a_size;
  6630.             intn a_indx;
  6631.             intn a_line;
  6632.             XP_Block *larray_array;
  6633.  
  6634.             a_size = SIZE_LIMIT / sizeof(LO_Element *);
  6635.             a_indx = (intn)(top / a_size);
  6636.             a_line = (intn)(top - (a_indx * a_size));
  6637.             XP_LOCK_BLOCK(larray_array, XP_Block *,
  6638.                     state->larray_array);
  6639.             state->line_array = larray_array[a_indx];
  6640.             XP_LOCK_BLOCK(line_array, LO_Element **,
  6641.                     state->line_array);
  6642.             eptr = line_array[a_line];
  6643.             XP_UNLOCK_BLOCK(state->line_array);
  6644.             XP_UNLOCK_BLOCK(state->larray_array);
  6645.         }
  6646. #else
  6647.         {
  6648.             XP_LOCK_BLOCK(line_array, LO_Element **,
  6649.                     state->line_array);
  6650.             eptr = line_array[top];
  6651.             XP_UNLOCK_BLOCK(state->line_array);
  6652.         }
  6653. #endif /* XP_WIN16 */
  6654.  
  6655.         /*
  6656.          * The nearest line may be a table with cells.  In which case
  6657.          * we really need to move into that table to find the nearest
  6658.          * cell, and possibly nearest element in that cell.
  6659.          */
  6660.         if ((eptr != NULL)&&(eptr->type == LO_TABLE)&&
  6661.             (eptr->lo_any.next->type == LO_CELL))
  6662.         {
  6663.             LO_Element *new_eptr;
  6664.  
  6665.             new_eptr = eptr->lo_any.next;
  6666.             /*
  6667.              * Find the cell that overlaps in Y.  Move to the lower
  6668.              * cell if between cells.
  6669.              */
  6670.             while ((new_eptr != NULL)&&(new_eptr->type == LO_CELL))
  6671.             {
  6672.             int32 y2;
  6673.  
  6674.             y2 = new_eptr->lo_any.y + new_eptr->lo_any.y_offset +
  6675.                 new_eptr->lo_any.height +
  6676.                 (2 * new_eptr->lo_cell.border_width);
  6677.             if (y <= y2)
  6678.             {
  6679.                 break;
  6680.             }
  6681.             new_eptr = new_eptr->lo_any.next;
  6682.             }
  6683.             /*
  6684.              * If we walked through the table to a non-cell element
  6685.              * and still didn't match, match to the last cell in
  6686.              * the table.
  6687.              */
  6688.             if ((new_eptr != NULL)&&(new_eptr->type != LO_CELL))
  6689.             {
  6690.             new_eptr = new_eptr->lo_any.prev;
  6691.             }
  6692.  
  6693.             /*
  6694.              * If new_eptr is not NULL it is the cell we matched.
  6695.              * Move us just into that cell and see if we can match
  6696.              * an element inside it.
  6697.              */
  6698.             if ((new_eptr != NULL)&&(new_eptr->type == LO_CELL))
  6699.             {
  6700.             LO_Element *cell_eptr;
  6701.             int32 new_x, new_y;
  6702.  
  6703.             new_y = y;
  6704.             if (new_y >= (new_eptr->lo_any.y +
  6705.                     new_eptr->lo_any.y_offset +
  6706.                     new_eptr->lo_cell.border_width +
  6707.                     new_eptr->lo_any.height))
  6708.             {
  6709.                 new_y = new_eptr->lo_any.y +
  6710.                     new_eptr->lo_any.y_offset +
  6711.                     new_eptr->lo_cell.border_width +
  6712.                     new_eptr->lo_any.height - 1;
  6713.             }
  6714.             if (new_y < (new_eptr->lo_any.y +
  6715.                     new_eptr->lo_any.y_offset +
  6716.                     new_eptr->lo_cell.border_width))
  6717.             {
  6718.                 new_y = new_eptr->lo_any.y +
  6719.                     new_eptr->lo_any.y_offset +
  6720.                     new_eptr->lo_cell.border_width;
  6721.             }
  6722.             new_x = x;
  6723.             if (new_x >= (new_eptr->lo_any.x +
  6724.                     new_eptr->lo_any.x_offset +
  6725.                     new_eptr->lo_cell.border_width +
  6726.                     new_eptr->lo_any.width))
  6727.             {
  6728.                 new_x = new_eptr->lo_any.x +
  6729.                     new_eptr->lo_any.x_offset +
  6730.                     new_eptr->lo_cell.border_width +
  6731.                     new_eptr->lo_any.width - 1;
  6732.             }
  6733.             if (new_x < (new_eptr->lo_any.x +
  6734.                     new_eptr->lo_any.x_offset +
  6735.                     new_eptr->lo_cell.border_width))
  6736.             {
  6737.                 new_x = new_eptr->lo_any.x +
  6738.                     new_eptr->lo_any.x_offset +
  6739.                     new_eptr->lo_cell.border_width;
  6740.             }
  6741.             cell_eptr = lo_XYToNearestCellElement(context, state,
  6742.                 (LO_CellStruct *)new_eptr, new_x, new_y);
  6743.             if (cell_eptr != NULL)
  6744.             {
  6745.                 new_eptr = cell_eptr;
  6746.             }
  6747.             }
  6748.             if (new_eptr != NULL)
  6749.             {
  6750.             eptr = new_eptr;
  6751.             }
  6752.         }
  6753.     }
  6754.  
  6755.     return(eptr);
  6756. }
  6757.  
  6758. static void
  6759. lo_RefreshCellAnchors(lo_DocState *state, LO_CellStruct *cell);
  6760.  
  6761. /* return TRUE if the color of the current anchor is
  6762.  * one of the two default visted or unvisited colors
  6763.  * it will be FALSE in the case that style sheets sets
  6764.  * a specific color for the anchor
  6765.  */
  6766. static Bool
  6767. lo_is_default_anchor_color(lo_DocState *state, LO_TextAttr *tmp_attr)
  6768. {
  6769.     if(  (tmp_attr->fg.red      == STATE_VISITED_ANCHOR_RED(state)
  6770.           && tmp_attr->fg.green == STATE_VISITED_ANCHOR_GREEN(state)
  6771.           && tmp_attr->fg.blue  == STATE_VISITED_ANCHOR_BLUE(state))
  6772.           || (tmp_attr->fg.red      == STATE_UNVISITED_ANCHOR_RED(state)
  6773.           && tmp_attr->fg.green == STATE_UNVISITED_ANCHOR_GREEN(state)
  6774.           && tmp_attr->fg.blue  == STATE_UNVISITED_ANCHOR_BLUE(state)))
  6775.         return TRUE;
  6776.  
  6777.     return FALSE;
  6778. }
  6779.  
  6780. static void
  6781. lo_RefreshElementAnchor(lo_DocState *state, LO_Element *element)
  6782. {
  6783.     LO_TextAttr tmp_attr, *new_attr, *attr;
  6784.     LO_AnchorData *anchor_href;
  6785.     char *url;
  6786.  
  6787.     if (element->type == LO_CELL) {
  6788.         lo_RefreshCellAnchors(state, (LO_CellStruct *)element);
  6789.         return;
  6790.     }
  6791.  
  6792.     attr = lo_GetElementTextAttr(element);
  6793.     if (! attr)
  6794.         return;
  6795.     if (! (attr->attrmask & LO_ATTR_ANCHOR))
  6796.         return;
  6797.  
  6798.     anchor_href = lo_GetElementAnchor(element);
  6799.     if (!anchor_href)
  6800.         return;
  6801.  
  6802.     if(!lo_is_default_anchor_color(state, attr))
  6803.         return;
  6804.  
  6805.     lo_CopyTextAttr(attr, &tmp_attr);
  6806.  
  6807.     url = (char*)anchor_href->anchor;
  6808.     if (GH_CheckGlobalHistory(url) != -1)
  6809.     {
  6810.         tmp_attr.fg.red   = STATE_VISITED_ANCHOR_RED(state);
  6811.         tmp_attr.fg.green = STATE_VISITED_ANCHOR_GREEN(state);
  6812.         tmp_attr.fg.blue  = STATE_VISITED_ANCHOR_BLUE(state);
  6813.     }
  6814.     else
  6815.     {
  6816.         tmp_attr.fg.red   = STATE_UNVISITED_ANCHOR_RED(state);
  6817.         tmp_attr.fg.green = STATE_UNVISITED_ANCHOR_GREEN(state);
  6818.         tmp_attr.fg.blue  = STATE_UNVISITED_ANCHOR_BLUE(state);
  6819.     }
  6820.  
  6821.     new_attr = lo_FetchTextAttr(state, &tmp_attr);
  6822.     
  6823.     if (new_attr != attr) {
  6824.         lo_SetElementTextAttr(element, new_attr);
  6825.         if (element->type == LO_TEXT || element->type == LO_IMAGE) {
  6826.             element->lo_any.x += state->base_x;
  6827.             element->lo_any.y += state->base_y;
  6828.             lo_RefreshElement(element, anchor_href->layer, TRUE);
  6829.             element->lo_any.x -= state->base_x;
  6830.             element->lo_any.y -= state->base_y;
  6831.         }
  6832.     }
  6833. }
  6834.  
  6835. static void
  6836. lo_RefreshCellAnchors(lo_DocState *state, LO_CellStruct *cell)
  6837. {
  6838.     LO_Element *eptr;
  6839.  
  6840.     eptr = cell->cell_list;
  6841.     while (eptr)
  6842.     {
  6843.         lo_RefreshElementAnchor(state, eptr);
  6844.         eptr = eptr->lo_any.next;
  6845.     }
  6846.  
  6847.     eptr = cell->cell_float_list;
  6848.     while (eptr)
  6849.     {
  6850.         lo_RefreshElementAnchor(state, eptr);
  6851.         eptr = eptr->lo_any.next;
  6852.     }
  6853. }
  6854.  
  6855. void
  6856. LO_RefreshAnchors(MWContext *context)
  6857. {
  6858.     int32 doc_id;
  6859.     lo_TopState *top_state;
  6860.     lo_DocState *state;
  6861.     LO_Element *eptr;
  6862.     LO_Element **line_array;
  6863.  
  6864.         if (!context->compositor)
  6865.             return;
  6866.  
  6867.     /*
  6868.      * Get the unique document ID, and retrieve this
  6869.      * document's layout state.
  6870.      */
  6871.     doc_id = XP_DOCID(context);
  6872.     top_state = lo_FetchTopState(doc_id);
  6873.     if ((top_state == NULL)||(top_state->doc_state == NULL))
  6874.         return;
  6875.     state = top_state->doc_state;
  6876.  
  6877.     /*
  6878.      * line_array could be NULL when discarding the document, so
  6879.      * check it and exit early to avoid dereferencing it below.
  6880.      */
  6881.     if (state->line_array == NULL)
  6882.         return;
  6883.  
  6884. #ifdef XP_WIN16
  6885.     {
  6886.         XP_Block *larray_array;
  6887.  
  6888.         XP_LOCK_BLOCK(larray_array, XP_Block *, state->larray_array);
  6889.         state->line_array = larray_array[0];
  6890.         XP_UNLOCK_BLOCK(state->larray_array);
  6891.     }
  6892. #endif /* XP_WIN16 */
  6893.  
  6894.     XP_LOCK_BLOCK(line_array, LO_Element **, state->line_array);
  6895.     eptr = line_array[0];
  6896.     XP_UNLOCK_BLOCK(state->line_array);
  6897.  
  6898.     for (; eptr; eptr = eptr->lo_any.next)
  6899.         lo_RefreshElementAnchor(state, eptr);
  6900. }
  6901.  
  6902. static void
  6903. lo_split_named_anchor(char *url, char **cmp_url, char **cmp_name)
  6904. {
  6905.     char tchar, *tptr, *tname;
  6906.  
  6907.     *cmp_url = NULL;
  6908.     
  6909.     if ( cmp_name )
  6910.         *cmp_name = NULL;
  6911.  
  6912.     if (url == NULL)
  6913.     {
  6914.         return;
  6915.     }
  6916.  
  6917.     tptr = url;
  6918.     while (((tchar = *tptr) != '\0')&&(tchar != '#'))
  6919.     {
  6920.         tptr++;
  6921.     }
  6922.     if (tchar == '\0')
  6923.     {
  6924.         *cmp_url = (char *)XP_STRDUP(url);
  6925.         return;
  6926.     }
  6927.  
  6928.     *tptr = '\0';
  6929.     *cmp_url = (char *)XP_STRDUP(url);
  6930.     *tptr = tchar;
  6931.     tname = ++tptr;
  6932.     while (((tchar = *tptr) != '\0')&&(tchar != '?'))
  6933.     {
  6934.         tptr++;
  6935.     }
  6936.     *tptr = '\0';
  6937.     if ( cmp_name )
  6938.         *cmp_name = (char *)XP_STRDUP(tname);
  6939.     *tptr = tchar;
  6940.     if (tchar == '?')
  6941.     {
  6942.         StrAllocCat(*cmp_url, tptr);
  6943.     }
  6944. }
  6945.  
  6946.  
  6947. /*
  6948.  * Is this anchor local to this document?
  6949.  */
  6950. Bool
  6951. lo_IsAnchorInDoc(lo_DocState *state, char *url)
  6952. {
  6953.     char *cmp_url;
  6954.     char *doc_url;
  6955.     Bool local;
  6956.  
  6957.     local = FALSE;
  6958.     /*
  6959.      * Extract the base from the name part.
  6960.      */
  6961.     lo_split_named_anchor(url, &cmp_url, NULL);
  6962.  
  6963.     /*
  6964.      * Extract the base from the name part.
  6965.      */
  6966.     doc_url = NULL;
  6967.     lo_split_named_anchor(state->top_state->url, &doc_url, NULL);
  6968.  
  6969.     /*
  6970.      * If the document itself has no base URL (probably an error)
  6971.      * then the only way we are local is if the passed in url has no
  6972.      * base either.
  6973.      */
  6974.     if (doc_url == NULL)
  6975.     {
  6976.         if (cmp_url == NULL)
  6977.         {
  6978.             local = TRUE;
  6979.         }
  6980.     }
  6981.     /*
  6982.      * Else if the passed in url has no base, and we have a bas, you must
  6983.      * be local because you are relative to our base.
  6984.      */
  6985.     else if (cmp_url == NULL)
  6986.     {
  6987.         local = TRUE;
  6988.     }
  6989.     /*
  6990.      * Else if the base of the two urls is equal, you are local.
  6991.      */
  6992.     else if (XP_STRCMP(cmp_url, doc_url) == 0)
  6993.     {
  6994.         local = TRUE;
  6995.     }
  6996.  
  6997.     if (cmp_url != NULL)
  6998.     {
  6999.         XP_FREE(cmp_url);
  7000.     }
  7001.     if (doc_url != NULL)
  7002.     {
  7003.         XP_FREE(doc_url);
  7004.     }
  7005.     return(local);
  7006. }
  7007.  
  7008.  
  7009. static LO_Element *
  7010. lo_cell_id_to_element(lo_DocState *state, int32 ele_id, LO_CellStruct *cell)
  7011. {
  7012.     LO_Element *eptr;
  7013.  
  7014.     if (cell == NULL)
  7015.     {
  7016.         return(NULL);
  7017.     }
  7018.  
  7019.     eptr = cell->cell_list;
  7020.     while (eptr != NULL)
  7021.     {
  7022.         if (eptr->lo_any.ele_id == ele_id)
  7023.         {
  7024.             break;
  7025.         }
  7026.         if (eptr->type == LO_CELL)
  7027.         {
  7028.             LO_Element *cell_eptr;
  7029.  
  7030.             cell_eptr = lo_cell_id_to_element(state, ele_id,
  7031.                         (LO_CellStruct *)eptr);
  7032.             if (cell_eptr != NULL)
  7033.             {
  7034.                 eptr = cell_eptr;
  7035.                 break;
  7036.             }
  7037.         }
  7038.         if (eptr->lo_any.ele_id > ele_id)
  7039.         {
  7040.             break;
  7041.         }
  7042.         eptr = eptr->lo_any.next;
  7043.     }
  7044.     return(eptr);
  7045. }
  7046.  
  7047.  
  7048. /*
  7049.  * Find the x, y, coords of the element id passed in, and return them.
  7050.  * If can't find the exact element, return the closest (next greater)
  7051.  * element id's position.
  7052.  * We need to walk into cells.
  7053.  * On severe error return 0, 0.
  7054.  */
  7055. static void
  7056. lo_element_id_to_xy(lo_DocState *state, int32 ele_id, int32 *xpos, int32 *ypos)
  7057. {
  7058.     LO_Element *eptr;
  7059.     LO_Element **line_array;
  7060.  
  7061.     *xpos = 0;
  7062.     *ypos = 0;
  7063.  
  7064.     /*
  7065.      * On error return the top
  7066.      */
  7067.     if (state == NULL)
  7068.     {
  7069.         return;
  7070.     }
  7071.  
  7072. #ifdef XP_WIN16
  7073.     {
  7074.         XP_Block *larray_array;
  7075.  
  7076.         XP_LOCK_BLOCK(larray_array, XP_Block *, state->larray_array);
  7077.         state->line_array = larray_array[0];
  7078.         XP_UNLOCK_BLOCK(state->larray_array);
  7079.     }
  7080. #endif /* XP_WIN16 */
  7081.  
  7082.     XP_LOCK_BLOCK(line_array, LO_Element **, state->line_array);
  7083.     eptr = line_array[0];
  7084.     XP_UNLOCK_BLOCK(state->line_array);
  7085.  
  7086.     while (eptr != NULL)
  7087.     {
  7088.         /*
  7089.          * Exact match?
  7090.          */
  7091.         if (eptr->lo_any.ele_id == ele_id)
  7092.         {
  7093.             *xpos = eptr->lo_any.x;
  7094.             *ypos = eptr->lo_any.y;
  7095.             break;
  7096.         }
  7097.  
  7098.         /*
  7099.          * Look for a match in this cell
  7100.          */
  7101.         if (eptr->type == LO_CELL)
  7102.         {
  7103.             LO_Element *cell_eptr;
  7104.  
  7105.             cell_eptr = lo_cell_id_to_element(state, ele_id,
  7106.                         (LO_CellStruct *)eptr);
  7107.             if (cell_eptr != NULL)
  7108.             {
  7109.                 *xpos = cell_eptr->lo_any.x;
  7110.                 *ypos = cell_eptr->lo_any.y;
  7111.                 break;
  7112.             }
  7113.         }
  7114.  
  7115.         /*
  7116.          * If we passed it, fake a match.
  7117.          */
  7118.         if (eptr->lo_any.ele_id > ele_id)
  7119.         {
  7120.             *xpos = eptr->lo_any.x;
  7121.             *ypos = eptr->lo_any.y;
  7122.             break;
  7123.         }
  7124.         eptr = eptr->lo_any.next;
  7125.     }
  7126. }
  7127.  
  7128.  
  7129. /*
  7130.  * Check the current URL to see if it is the URL for this doc, and if
  7131.  * so return the position of the named anchor referenced after the '#' in
  7132.  * the URL.  If there is no name or no match, return 0,0.  In comparing URLs
  7133.  * both NULL are considered equal
  7134.  */
  7135. Bool
  7136. LO_LocateNamedAnchor(MWContext *context, URL_Struct *url_struct,
  7137.             int32 *xpos, int32 *ypos)
  7138. {
  7139.     int i;
  7140.     int32 doc_id;
  7141.     lo_TopState *top_state;
  7142.     lo_DocState *state;
  7143.     lo_NameList *nptr;
  7144.     char *url;
  7145.     char *cmp_url;
  7146.     char *cmp_name;
  7147.  
  7148.     /*
  7149.      * Get the unique document ID, and retreive this
  7150.      * documents layout state.
  7151.      */
  7152.     doc_id = XP_DOCID(context);
  7153.     top_state = lo_FetchTopState(doc_id);
  7154.     if ((top_state == NULL)||(top_state->doc_state == NULL))
  7155.     {
  7156.         return(FALSE);
  7157.     }
  7158.     state = top_state->doc_state;
  7159.  
  7160.     /*
  7161.      * obvious error
  7162.      */
  7163.     if ((url_struct == NULL)||(url_struct->address == NULL))
  7164.     {
  7165.         return(FALSE);
  7166.     }
  7167.  
  7168.     /*
  7169.      * Extract the URL we are going to.
  7170.      */
  7171.     url = url_struct->address;
  7172.  
  7173.  
  7174.     /*
  7175.      * Split the passed url into the real url part
  7176.      * and the name part.  The parts (if non-NULL) must
  7177.      * be freed.
  7178.      */
  7179.     cmp_url = NULL;
  7180.     cmp_name = NULL;
  7181.     lo_split_named_anchor(url, &cmp_url, &cmp_name);
  7182.  
  7183.     /*
  7184.      * can't strcmp on NULL strings.
  7185.      */
  7186.     if (state->top_state->url == NULL)
  7187.     {
  7188.         /*
  7189.          * 2 NULLs are considered equal.
  7190.          * If not equal fail here
  7191.          */
  7192.         if (cmp_url != NULL)
  7193.         {
  7194.             if (cmp_name != NULL)
  7195.             {
  7196.                 XP_FREE(cmp_name);
  7197.             }
  7198.             return(FALSE);
  7199.         }
  7200.     }
  7201.     /*
  7202.      * Else lets compare the 2 URLs now
  7203.      */
  7204.     else
  7205.     {
  7206.         /*
  7207.          * The current URL might itself have a name part.  Lose it.
  7208.          */
  7209.         char *this_url;
  7210.         int same_p;
  7211.  
  7212.         lo_split_named_anchor(state->top_state->url, &this_url, NULL);
  7213.         /*
  7214.          * If the 2 URLs are not equal fail out here
  7215.          */
  7216.         same_p = ((this_url)&&(XP_STRCMP(cmp_url, this_url) == 0));
  7217.  
  7218.         if (this_url != NULL)
  7219.         {
  7220.             XP_FREE (this_url);
  7221.         }
  7222.  
  7223.         if (!same_p)
  7224.         {
  7225.             XP_FREE(cmp_url);
  7226.             if (cmp_name != NULL)
  7227.             {
  7228.                 XP_FREE(cmp_name);
  7229.             }
  7230.             return(FALSE);
  7231.         }
  7232.     }
  7233.  
  7234.     /*
  7235.      * If we got here the URLs are considered equal.
  7236.      * Free this one.
  7237.      */
  7238.     if (cmp_url != NULL)
  7239.     {
  7240.         XP_FREE(cmp_url);
  7241.     }
  7242.  
  7243.     /*
  7244.      * Do we have a saved element ID that is not the start
  7245.      * of the document to return to because we are moving through history?
  7246.      * If so, go there and return.
  7247.      */
  7248.     if (url_struct->position_tag > 1)
  7249.     {
  7250.         lo_element_id_to_xy(state, url_struct->position_tag,
  7251.             xpos, ypos);
  7252.         return(TRUE);
  7253.     }
  7254.  
  7255.     /*
  7256.      * Special case for going to a NULL or empty
  7257.      * name to return the beginning of the
  7258.      * document.
  7259.      */
  7260.     if (cmp_name == NULL)
  7261.     {
  7262.         *xpos = 0;
  7263.         *ypos = 0;
  7264.  
  7265.         if (state->top_state->url != NULL)
  7266.         {
  7267.             XP_FREE(state->top_state->url);
  7268.         }
  7269.         state->top_state->url = XP_STRDUP(url);
  7270.         return(TRUE);
  7271.     }
  7272.     else if (*cmp_name == '\0')
  7273.     {
  7274.         *xpos = 0;
  7275.         *ypos = 0;
  7276.         XP_FREE(cmp_name);
  7277.  
  7278.         if (state->top_state->url != NULL)
  7279.         {
  7280.             XP_FREE(state->top_state->url);
  7281.         }
  7282.         state->top_state->url = XP_STRDUP(url);
  7283.         return(TRUE);
  7284.     }
  7285.  
  7286.     /*
  7287.      * Actually search the name list for a matching name.
  7288.      */
  7289.     for (i = 0; i <= state->top_state->max_layer_num; i++)
  7290.     {
  7291.         lo_LayerDocState *layer_state = state->top_state->layers[i];
  7292.         CL_Layer *layer;
  7293.         if (!layer_state)
  7294.             continue;
  7295.         layer = layer_state->layer;
  7296.         nptr = layer_state->doc_lists->name_list;
  7297.         
  7298.         while (nptr != NULL)
  7299.         {
  7300.             char *name;
  7301.  
  7302.             PA_LOCK(name, char *, nptr->name);
  7303.             /*
  7304.              * If this is a match, return success
  7305.              * here.
  7306.              */
  7307.             if (XP_STRCMP(cmp_name, name) == 0)
  7308.             {
  7309.                 PA_UNLOCK(nptr->name);
  7310.                 if (nptr->element == NULL)
  7311.                 {
  7312.                     *xpos = 0;
  7313.                     *ypos = 0;
  7314.                 }
  7315.                 else
  7316.                 {
  7317.                     /* Convert from element coordinates to document coordinates */
  7318.                     lo_GetLayerXYShift(layer, xpos, ypos);
  7319.                     *xpos = - *xpos;
  7320.                     *ypos = - *ypos;
  7321.                     *xpos += nptr->element->lo_any.x + CL_GetLayerXOrigin(layer);
  7322.                     *ypos += nptr->element->lo_any.y + CL_GetLayerYOrigin(layer);
  7323.                 }
  7324.                 XP_FREE(cmp_name);
  7325.  
  7326.                 if (state->top_state->url != NULL)
  7327.                 {
  7328.                     XP_FREE(state->top_state->url);
  7329.                 }
  7330.                 state->top_state->url = XP_STRDUP(url);
  7331.                 LM_SendOnLocate(context, nptr);
  7332.                 return(TRUE);
  7333.             }
  7334.             PA_UNLOCK(nptr->name);
  7335.             nptr = nptr->next;
  7336.         }
  7337.     }
  7338.  
  7339.     /*
  7340.      * Failed to find the matchng name.
  7341.      * If no match return the top of the doc.
  7342.      */
  7343.     XP_FREE(cmp_name);
  7344.     *xpos = 0;
  7345.     *ypos = 0;
  7346.  
  7347.     if (state->top_state->url != NULL)
  7348.     {
  7349.         XP_FREE(state->top_state->url);
  7350.     }
  7351.     state->top_state->url = XP_STRDUP(url);
  7352.     return(TRUE);
  7353. }
  7354.  
  7355.  
  7356. Bool
  7357. LO_HasBGImage(MWContext *context)
  7358. {
  7359.     int32 doc_id;
  7360.     lo_TopState *top_state;
  7361.  
  7362.     /*
  7363.      * Get the unique document ID, and retreive this
  7364.      * documents layout state.
  7365.      */
  7366.     doc_id = XP_DOCID(context);
  7367.     top_state = lo_FetchTopState(doc_id);
  7368.     if (top_state == NULL)
  7369.         return(FALSE);
  7370.  
  7371. #ifdef XP_WIN
  7372.     /*
  7373.      * Evil hack alert.
  7374.      * We don't want print context's under windows to use backdrops
  7375.      *  currently as it causes bad display (black in the transparent
  7376.      *  area due to drawing problems under windows).
  7377.      */
  7378.      if(context->type == MWContextPrint || context->type == MWContextMetaFile)
  7379.      {
  7380.          return(FALSE);
  7381.      }
  7382. #endif
  7383.  
  7384.      return (LO_GetLayerBackdropURL(top_state->doc_layer) != NULL);
  7385. }
  7386.  
  7387. void
  7388. LO_GetDocumentMargins(MWContext *context,
  7389.     int32 *margin_width, int32 *margin_height)
  7390. {
  7391.     int32 doc_id;
  7392.     lo_TopState *top_state;
  7393.     lo_DocState *state;
  7394.  
  7395.     /*
  7396.      * Get the unique document ID, and retreive this
  7397.      * documents layout state.
  7398.      */
  7399.     doc_id = XP_DOCID(context);
  7400.     top_state = lo_FetchTopState(doc_id);
  7401.     if ((top_state == NULL)||(top_state->doc_state == NULL))
  7402.     {
  7403.         return;
  7404.     }
  7405.     state = top_state->doc_state;
  7406.  
  7407.     *margin_width = state->win_left;
  7408.     *margin_height = state->win_top;
  7409. }
  7410.  
  7411.  
  7412. /*
  7413.  * Provide a way for the parser to see if the currently loaded
  7414.  *   document who might need a call to mocha to unload
  7415.  */
  7416. Bool
  7417. LO_CheckForUnload(MWContext *context)
  7418. {
  7419.     lo_TopState *top_state;
  7420.  
  7421.     top_state = lo_FetchTopState(XP_DOCID(context));
  7422.     if (!top_state)
  7423.         return FALSE;
  7424.  
  7425.     return top_state->mocha_has_onunload;
  7426. }
  7427.  
  7428. /*
  7429.  * netlib is done sending data to the parser
  7430.  */
  7431. void 
  7432. LO_NetlibComplete(MWContext * context)
  7433. {
  7434.     lo_TopState *top_state;
  7435.  
  7436.     top_state = lo_FetchTopState(XP_DOCID(context));
  7437.     if (!top_state)
  7438.         return;
  7439.     top_state->nurl = NULL;
  7440. }
  7441.  
  7442. /*
  7443.  * Even though netlib is idle someone could be shoving data
  7444.  *   through layout/libparse.  Provide a way for people on
  7445.  *   the outside to tell if this is the case or not.
  7446.  */
  7447.  
  7448. Bool
  7449. LO_LayingOut(MWContext * context)
  7450. {
  7451.     lo_TopState *top_state;
  7452.  
  7453.     top_state = lo_FetchTopState(XP_DOCID(context));
  7454.     if (!top_state)
  7455.         return FALSE;
  7456.     return (top_state->doc_data != NULL);
  7457. }
  7458.  
  7459.  
  7460. void lo_UpdateStateWhileFlushingLine( MWContext *context, lo_DocState *state )
  7461. {
  7462.   int32 justification_remainder=0;
  7463.  
  7464.   if (state->top_state->nothing_displayed != FALSE) {
  7465.     /*
  7466.      * If we are displaying elements we are
  7467.      * no longer in the HEAD section of the HTML
  7468.      * we are in the BODY section.
  7469.      */
  7470.     state->top_state->in_head = FALSE;
  7471.     state->top_state->in_body = TRUE;
  7472.  
  7473.     lo_use_default_doc_background(context, state);
  7474.     state->top_state->nothing_displayed = FALSE;
  7475.   }
  7476.  
  7477.   /*
  7478.      * There is a break at the end of this line.
  7479.      * this may change min_width.
  7480.      */
  7481.   {
  7482.     int32 new_break_holder;
  7483.     int32 min_width;
  7484.     int32 indent;
  7485.  
  7486.     new_break_holder = state->x;
  7487.     min_width = new_break_holder - state->break_holder;
  7488.     indent = state->list_stack->old_left_margin - state->win_left;
  7489.     min_width += indent;
  7490.     if (min_width > state->min_width)
  7491.       {
  7492.     state->min_width = min_width;
  7493.       }
  7494.     /* If we are not within <NOBR> content, allow break_holder
  7495.      * to be set to the new position where a line break can occur.
  7496.      * This fixes BUG #70782
  7497.      */
  7498.     if (state->breakable != FALSE) {
  7499.       state->break_holder = new_break_holder;
  7500.     }
  7501.   }
  7502.  
  7503.   /*
  7504.      * If in a division centering or right aligning this line
  7505.      */
  7506.   if ((state->align_stack != NULL)&&(state->delay_align == FALSE))
  7507.     {
  7508.       int32 push_right;
  7509.       LO_Element *tptr;
  7510.  
  7511.       if (state->align_stack->alignment == LO_ALIGN_CENTER)
  7512.     {
  7513.       push_right = (state->right_margin - state->x) / 2;
  7514.     }
  7515.       else if (state->align_stack->alignment == LO_ALIGN_RIGHT)
  7516.     {
  7517.       push_right = state->right_margin - state->x;
  7518.     }
  7519.       else if(state->align_stack->alignment == LO_ALIGN_JUSTIFY)
  7520.     {
  7521.       push_right = lo_calc_push_right_for_justify(state, &justification_remainder);
  7522.     }
  7523.       else
  7524.     {
  7525.       push_right = 0;
  7526.     }
  7527.  
  7528.       if ((push_right > 0 || justification_remainder)
  7529.       &&(state->line_list != NULL))
  7530.     {
  7531.       int32 count = 0;
  7532.       int32 move_delta;
  7533.       tptr = state->line_list;
  7534.  
  7535.       if(state->align_stack->alignment == LO_ALIGN_JUSTIFY)
  7536.         move_delta = 0;
  7537.       else
  7538.         move_delta = push_right;
  7539.  
  7540.       while (tptr != NULL)
  7541.         {
  7542.           /* 
  7543.            * We don't shift over inflow layers, since their contents
  7544.            * have already been shifted over.
  7545.            */
  7546.           /*
  7547.            * We also don't shift bullets of type BULLET_MQUOTE.
  7548.            */
  7549.           if (((tptr->type != LO_CELL)||
  7550.            (!tptr->lo_cell.cell_inflow_layer))&&
  7551.           ((tptr->type != LO_BULLET)||
  7552.            ((tptr->type == LO_BULLET)&&
  7553.             (tptr->lo_bullet.bullet_type != BULLET_MQUOTE))))
  7554.         {
  7555.           tptr->lo_any.x += move_delta;
  7556.         }
  7557.  
  7558.           {
  7559.         CL_Layer *layer = NULL;
  7560.         int32 x, y;
  7561.         int32 border_width;
  7562.         int32 x_offset, y_offset;
  7563.  
  7564.         border_width = 0;
  7565.         x = tptr->lo_any.x;
  7566.         y = tptr->lo_any.y;
  7567.         x_offset = tptr->lo_any.x_offset;
  7568.         y_offset = tptr->lo_any.y_offset;
  7569.  
  7570.         switch (tptr->type)
  7571.           {
  7572.           case LO_IMAGE:
  7573.             layer = tptr->lo_image.layer;
  7574.             border_width = tptr->lo_image.border_width;
  7575.             break;
  7576. #ifdef JAVA
  7577.           case LO_JAVA:
  7578.             layer = tptr->lo_java.layer;
  7579.             border_width = tptr->lo_java.border_width;
  7580.             break;
  7581. #endif
  7582.           case LO_EMBED:
  7583.             layer = tptr->lo_embed.layer;
  7584.             border_width = tptr->lo_embed.border_width;
  7585.             break;
  7586.           case LO_FORM_ELE:
  7587.             layer = tptr->lo_form.layer;
  7588.             break;
  7589.           default:
  7590.             layer = NULL;
  7591.             break;
  7592.           }
  7593.  
  7594.         if (layer)
  7595.           CL_MoveLayer(layer,
  7596.                    x + x_offset + border_width,
  7597.                    y + y_offset + border_width);
  7598.           }
  7599.  
  7600.                 /* justification push_rights are additive */
  7601.           if(state->align_stack->alignment == LO_ALIGN_JUSTIFY)
  7602.         {
  7603.           move_delta += push_right;
  7604.  
  7605.           /* if there is a justification remainder, add a pixel
  7606.            * to the first n word breaks
  7607.            */
  7608.           if(count < justification_remainder)
  7609.             move_delta++;
  7610.         }
  7611.  
  7612.           /* 
  7613.            * Note that if this is an inflow layer, we don't want
  7614.            * to shift it since the alignment has already propogated
  7615.            * to its contents.
  7616.            */
  7617.           if ((tptr->type == LO_CELL) &&
  7618.           !tptr->lo_cell.cell_inflow_layer)
  7619.         {
  7620.           lo_ShiftCell((LO_CellStruct *)tptr, move_delta, 0);
  7621.         }
  7622.           tptr = tptr->lo_any.next;
  7623.  
  7624.           count++;
  7625.         }
  7626.  
  7627.       if(state->align_stack->alignment == LO_ALIGN_JUSTIFY)
  7628.         state->x = state->right_margin;
  7629.       else
  7630.         state->x += push_right;
  7631.     }
  7632.     }
  7633. }
  7634.  
  7635. /* Add line feed to line list, update doc state, and set line height of
  7636.    other elements on that line */
  7637. void lo_AppendLineFeed( MWContext *context, lo_DocState *state, LO_LinefeedStruct *linefeed, int32 breaking, Bool updateFE )
  7638. {
  7639.     LO_Element *tptr;
  7640.  
  7641.     if (breaking != FALSE)
  7642.     {
  7643.         linefeed->ele_attrmask |= LO_ELE_BREAKING;
  7644.     }
  7645.  
  7646.     /*
  7647.      * Horrible bitflag overuse!!!  For multicolumn text
  7648.      * we need to know if a line of text can be used for
  7649.      * a column break, or if it cannot because it is wrapped
  7650.      * around some object in the margin.  For lines that can be
  7651.      * used for column breaks, we will set the BREAKABLE
  7652.      * flag in their element mask.
  7653.      */
  7654.     if ((state->left_margin_stack == NULL)&&
  7655.         (state->right_margin_stack == NULL))
  7656.     {
  7657.         linefeed->ele_attrmask |= LO_ELE_BREAKABLE;
  7658.     }
  7659.  
  7660.     if ((state->align_stack != NULL)&&
  7661.         (state->delay_align != FALSE)&&
  7662.         (state->align_stack->alignment != LO_ALIGN_LEFT))
  7663.     {
  7664.         if (state->align_stack->alignment == LO_ALIGN_CENTER)
  7665.         {
  7666.             linefeed->ele_attrmask |= LO_ELE_DELAY_CENTER;
  7667.         }
  7668.         else if (state->align_stack->alignment == LO_ALIGN_RIGHT)
  7669.         {
  7670.             linefeed->ele_attrmask |= LO_ELE_DELAY_RIGHT;
  7671.         }
  7672.     }
  7673.  
  7674.     tptr = state->line_list;
  7675.  
  7676.     if (tptr == NULL)
  7677.     {
  7678.         state->line_list = (LO_Element *)linefeed;
  7679.         linefeed->prev = NULL;
  7680.     }
  7681.     else
  7682.     {
  7683.         LO_Element *next_tptr = tptr;
  7684.         do
  7685.         {
  7686.             tptr = next_tptr;
  7687.             if (updateFE) 
  7688.             {
  7689.                 /*
  7690.                  * If the display is blocked for an element
  7691.                  * we havn't reached yet, check to see if
  7692.                  * it is in this line, and if so, save its
  7693.                  * y position.
  7694.                  */
  7695.                 if ((state->display_blocked != FALSE)&&
  7696.     #ifdef EDITOR
  7697.                     (!state->edit_relayout_display_blocked)&&
  7698.     #endif
  7699.                     (state->is_a_subdoc == SUBDOC_NOT)&&
  7700.                     (state->display_blocking_element_y == 0)&&
  7701.                     (state->display_blocking_element_id != -1)&&
  7702.                     (tptr->lo_any.ele_id >=
  7703.                     state->display_blocking_element_id))
  7704.                 {
  7705.                     state->display_blocking_element_y =
  7706.                         state->y;
  7707.                     /*
  7708.                      * Special case, if the blocking element
  7709.                      * is on the first line, no blocking
  7710.                      * at all needs to happen.
  7711.                      */
  7712.                     if (state->y == state->win_top)
  7713.                     {
  7714.                         state->display_blocked = FALSE;
  7715.                         FE_SetDocPosition(context,
  7716.                             FE_VIEW, 0, state->base_y);
  7717.                         if (context->compositor)
  7718.                         {
  7719.                           XP_Rect rect;
  7720.                           
  7721.                           rect.left = 0;
  7722.                           rect.top = 0;
  7723.                           rect.right = state->win_width;
  7724.                           rect.bottom = state->win_height;
  7725.                           CL_UpdateDocumentRect(context->compositor,
  7726.                                                 &rect, (PRBool)FALSE);
  7727.                         }
  7728.                     }
  7729.                 }
  7730.             }
  7731.  
  7732.             tptr->lo_any.line_height = state->line_height;
  7733.             /*
  7734.              * Special for bullets of type BULLET_MQUOTE
  7735.              * They should always be as tall as the line.
  7736.              */
  7737.             if ((tptr->type == LO_BULLET)&&
  7738.                 (tptr->lo_bullet.bullet_type ==
  7739.                     BULLET_MQUOTE))
  7740.             {
  7741.                 tptr->lo_any.y_offset = 0;
  7742.                 tptr->lo_any.height =
  7743.                     tptr->lo_any.line_height;
  7744.             }
  7745.             
  7746.             if ( (next_tptr = tptr->lo_any.next) == NULL )
  7747.             {
  7748.                 tptr->lo_any.next = (LO_Element*)linefeed;
  7749.                 linefeed->prev = tptr;
  7750.             }
  7751.         } while( next_tptr != NULL );
  7752.     }
  7753.     state->x += linefeed->width;
  7754. }
  7755.  
  7756. void lo_AppendLineListToLineArray( MWContext *context, lo_DocState *state, LO_Element *lastElementOnLineList)
  7757. {
  7758.     LO_Element **line_array;
  7759. #ifdef XP_WIN16
  7760.     int32 a_size;
  7761.     int32 a_indx;
  7762.     int32 a_line;
  7763.     XP_Block *larray_array;
  7764. #endif /* XP_WIN16 */
  7765.  
  7766.     /*
  7767.      * If necessary, grow the line array to hold more lines.
  7768.      */
  7769. #ifdef XP_WIN16
  7770.     a_size = SIZE_LIMIT / sizeof(LO_Element *);
  7771.     a_indx = (state->line_num - 1) / a_size;
  7772.     a_line = state->line_num - (a_indx * a_size);
  7773.  
  7774.     XP_LOCK_BLOCK(larray_array, XP_Block *, state->larray_array);
  7775.     state->line_array = larray_array[a_indx];
  7776.  
  7777.     if (a_line == a_size)
  7778.     {
  7779.         state->line_array = XP_ALLOC_BLOCK(LINE_INC *
  7780.                     sizeof(LO_Element *));
  7781.         if (state->line_array == NULL)
  7782.         {
  7783.             XP_UNLOCK_BLOCK(state->larray_array);
  7784.             state->top_state->out_of_memory = TRUE;
  7785.             return;
  7786.         }
  7787.         XP_LOCK_BLOCK(line_array, LO_Element **, state->line_array);
  7788.         line_array[0] = NULL;
  7789.         XP_UNLOCK_BLOCK(state->line_array);
  7790.         state->line_array_size = LINE_INC;
  7791.  
  7792.         state->larray_array_size++;
  7793.         XP_UNLOCK_BLOCK(state->larray_array);
  7794.         state->larray_array = XP_REALLOC_BLOCK(
  7795.             state->larray_array, (state->larray_array_size
  7796.             * sizeof(XP_Block)));
  7797.         if (state->larray_array == NULL)
  7798.         {
  7799.             state->top_state->out_of_memory = TRUE;
  7800.             return;
  7801.         }
  7802.         XP_LOCK_BLOCK(larray_array, XP_Block *, state->larray_array);
  7803.         larray_array[state->larray_array_size - 1] = state->line_array;
  7804.         state->line_array = larray_array[a_indx];
  7805.     }
  7806.     else if (a_line >= state->line_array_size)
  7807.     {
  7808.         state->line_array_size += LINE_INC;
  7809.         if (state->line_array_size > a_size)
  7810.         {
  7811.             state->line_array_size = (intn)a_size;
  7812.         }
  7813.         state->line_array = XP_REALLOC_BLOCK(state->line_array,
  7814.             (state->line_array_size * sizeof(LO_Element *)));
  7815.         if (state->line_array == NULL)
  7816.         {
  7817.             XP_UNLOCK_BLOCK(state->larray_array);
  7818.             state->top_state->out_of_memory = TRUE;
  7819.             return;
  7820.         }
  7821.         larray_array[a_indx] = state->line_array;
  7822.     }
  7823.  
  7824.     /*
  7825.      * Place this line of elements into the line array.
  7826.      */
  7827.     XP_LOCK_BLOCK(line_array, LO_Element **, state->line_array);
  7828.     line_array[a_line - 1] = state->line_list;
  7829.     XP_UNLOCK_BLOCK(state->line_array);
  7830.  
  7831.     XP_UNLOCK_BLOCK(state->larray_array);
  7832. #else
  7833.     if (state->line_num > state->line_array_size)
  7834.     {
  7835.         int32 line_inc;
  7836.  
  7837.         if (state->line_array_size > (LINE_INC * 10))
  7838.         {
  7839.             line_inc = state->line_array_size / 10;
  7840.         }
  7841.         else
  7842.         {
  7843.             line_inc = LINE_INC;
  7844.         }
  7845.  
  7846.         state->line_array = XP_REALLOC_BLOCK(state->line_array,
  7847.             ((state->line_array_size + line_inc) *
  7848.             sizeof(LO_Element *)));
  7849.         if (state->line_array == NULL)
  7850.         {
  7851.             state->top_state->out_of_memory = TRUE;
  7852.             return;
  7853.         }
  7854.         state->line_array_size += line_inc;
  7855.     }
  7856.  
  7857.     /*
  7858.      * Place this line of elements into the line array.
  7859.      */
  7860.     XP_LOCK_BLOCK(line_array, LO_Element **, state->line_array);
  7861.     line_array[state->line_num - 1] = state->line_list;
  7862.     XP_UNLOCK_BLOCK(state->line_array);
  7863. #endif /* XP_WIN16 */
  7864.  
  7865.     /*
  7866.      * connect the complete doubly linked list between this line
  7867.      * and the last one.
  7868.      */
  7869.     if (state->end_last_line != NULL)
  7870.     {
  7871.         state->end_last_line->lo_any.next = state->line_list;
  7872.         state->line_list->lo_any.prev = state->end_last_line;
  7873.     }
  7874.     state->end_last_line = lastElementOnLineList;
  7875.  
  7876.     state->line_list = NULL;
  7877.     state->line_num++;
  7878. }
  7879.  
  7880. void lo_UpdateStateAfterFlushingLine( MWContext *context, lo_DocState *state, LO_LinefeedStruct *linefeed, Bool inRelayout )
  7881. {
  7882.     /* LO_LinefeedStruct *linefeed; */
  7883.     
  7884.     lo_AppendLineListToLineArray( context, state, (LO_Element *) linefeed );
  7885.  
  7886.     /* 
  7887.      *Don't draw if we're doing layers...we'll just refresh when the 
  7888.      * the layer size increases.
  7889.      */
  7890.     /*
  7891.      * Have the front end display this line.
  7892.      */
  7893.     /* For layers, only draw if a compositor doesn't exist */
  7894.     if (!context->compositor && !inRelayout)
  7895.         /* We need to supply a display rectangle that is guaranteed to
  7896.            encompass all elements on the line.  The special 0x3fffffff
  7897.            value is approximately half the range of a 32-bit int, so
  7898.            it leaves room for overflow if arithmetic is done on these
  7899.            values. */
  7900.         lo_DisplayLine(context, state, (state->line_num - 2),
  7901.                        0, 0, 0x3fffffffL, 0x3fffffffL);
  7902.  
  7903.     /*
  7904.      * We are starting a new line.  Clear any old break
  7905.      * positions left over, clear the line_list, and increase
  7906.      * the line number.
  7907.      */
  7908.     state->old_break = NULL;
  7909.     state->old_break_block = NULL;
  7910.     state->old_break_pos = -1;
  7911.     state->old_break_width = 0;
  7912.     state->baseline = 0;
  7913. }
  7914.  
  7915. #ifdef TEST_16BIT
  7916. #undef XP_WIN16
  7917. #endif /* TEST_16BIT */
  7918.  
  7919. #ifdef PROFILE
  7920. #pragma profile off
  7921. #endif
  7922.